|
@@ -7,6 +7,8 @@ import (
|
|
|
"path/filepath"
|
|
|
"strings"
|
|
|
"time"
|
|
|
+
|
|
|
+ "imuslab.com/arozos/mod/disk/diskcapacity/dftool"
|
|
|
)
|
|
|
|
|
|
/*
|
|
@@ -69,7 +71,7 @@ func executeVersionBackup(backupConfig *BackupTask) (string, error) {
|
|
|
deletedFileList := map[string]string{}
|
|
|
|
|
|
//First pass: Check if there are any updated file from source and backup it to backup drive
|
|
|
- fastWalk(parentRootAbs, func(filename string) error {
|
|
|
+ err = fastWalk(parentRootAbs, func(filename string) error {
|
|
|
if filepath.Ext(filename) == ".db" || filepath.Ext(filename) == ".lock" {
|
|
|
//Reserved filename, skipping
|
|
|
return nil
|
|
@@ -107,20 +109,29 @@ func executeVersionBackup(backupConfig *BackupTask) (string, error) {
|
|
|
linkedFileList[relPath] = nameOfSnapshot
|
|
|
} else {
|
|
|
//File hash mismatch. Do file copy to renew data
|
|
|
- copyFileToBackupLocation(filename, fileBackupLocation)
|
|
|
+ err = copyFileToBackupLocation(backupConfig, filename, fileBackupLocation)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
copiedFileList = append(copiedFileList, fileBackupLocation)
|
|
|
}
|
|
|
} else {
|
|
|
//Invalid snapshot linkage. Assume new and do copy
|
|
|
log.Println("[HybridBackup] Link lost. Cloning source file to snapshot.")
|
|
|
- copyFileToBackupLocation(filename, fileBackupLocation)
|
|
|
+ err = copyFileToBackupLocation(backupConfig, filename, fileBackupLocation)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
copiedFileList = append(copiedFileList, fileBackupLocation)
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
//This file is not in snapshot link file.
|
|
|
//This is new file. Copy it to backup
|
|
|
- copyFileToBackupLocation(filename, fileBackupLocation)
|
|
|
+ err = copyFileToBackupLocation(backupConfig, filename, fileBackupLocation)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
copiedFileList = append(copiedFileList, fileBackupLocation)
|
|
|
}
|
|
|
|
|
@@ -185,6 +196,11 @@ func executeVersionBackup(backupConfig *BackupTask) (string, error) {
|
|
|
return nil
|
|
|
})
|
|
|
|
|
|
+ if err != nil {
|
|
|
+ //Copy error. Mostly because of disk fulled
|
|
|
+ return err.Error(), err
|
|
|
+ }
|
|
|
+
|
|
|
//2nd pass: Check if there are anything exists in the previous backup but no longer exists in the source now
|
|
|
//For case where the file is backed up in previous snapshot but now the file has been removed
|
|
|
if previousSnapshotExists {
|
|
@@ -207,7 +223,6 @@ func executeVersionBackup(backupConfig *BackupTask) (string, error) {
|
|
|
if !fileExists(sourcAssumeLocation) {
|
|
|
//File exists in yesterday snapshot but not in the current source
|
|
|
//Assume it has been deleted, create a dummy indicator file
|
|
|
- //ioutil.WriteFile(todaySnapshotLocation+".deleted", []byte(""), 0755)
|
|
|
deletedFileList[relPath] = todayFolderName
|
|
|
}
|
|
|
return nil
|
|
@@ -308,12 +323,47 @@ func getPreviousSnapshotName(backupConfig *BackupTask, currentSnapshotName strin
|
|
|
return previousSnapshotName, nil
|
|
|
}
|
|
|
|
|
|
-func copyFileToBackupLocation(filename string, fileBackupLocation string) error {
|
|
|
+func copyFileToBackupLocation(task *BackupTask, filename string, fileBackupLocation string) error {
|
|
|
+ //Make dir the target dir if not exists
|
|
|
if !fileExists(filepath.Dir(fileBackupLocation)) {
|
|
|
os.MkdirAll(filepath.Dir(fileBackupLocation), 0755)
|
|
|
}
|
|
|
|
|
|
- err := BufferedLargeFileCopy(filename, fileBackupLocation, 4096)
|
|
|
+ //Check if the target disk can fit the new file
|
|
|
+ capinfo, err := dftool.GetCapacityInfoFromPath(filepath.Dir(fileBackupLocation))
|
|
|
+ if err == nil {
|
|
|
+ //Capacity info return normally. Estimate if the file will fit
|
|
|
+ srcSize := fileSize(filename)
|
|
|
+ diskSpace := capinfo.Avilable
|
|
|
+ if diskSpace < srcSize {
|
|
|
+ //Merge older snapshots. Maxium merging is 1 week
|
|
|
+ for i := 0; i < 6; i++ {
|
|
|
+ //Merge the oldest snapshot
|
|
|
+ err = mergeOldestSnapshots(task)
|
|
|
+ if err != nil {
|
|
|
+ log.Println("[HybridBackup] " + err.Error())
|
|
|
+ return errors.New("No space left on device")
|
|
|
+ }
|
|
|
+
|
|
|
+ //Check if there are enough space again
|
|
|
+ capinfo, err := dftool.GetCapacityInfoFromPath(filepath.Dir(fileBackupLocation))
|
|
|
+ if err != nil {
|
|
|
+ log.Println("[HybridBackup] " + err.Error())
|
|
|
+ return errors.New("No space left on device")
|
|
|
+ }
|
|
|
+ srcSize = fileSize(filename)
|
|
|
+ diskSpace = capinfo.Avilable
|
|
|
+ if diskSpace > srcSize {
|
|
|
+ //Space enough. Break out
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.Println("[HybridBackup] Error: No space left on device! Require ", srcSize, "bytes but only ", diskSpace, " bytes left")
|
|
|
+ return errors.New("No space left on device")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ err = BufferedLargeFileCopy(filename, fileBackupLocation, 4096)
|
|
|
if err != nil {
|
|
|
log.Println("[HybridBackup] Failed to copy file: ", filepath.Base(filename)+". "+err.Error())
|
|
|
return err
|