diff --git a/GUIDE.md b/GUIDE.md index 4bda8e8..f0d4d19 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -87,18 +87,21 @@ OPTIONS: -hash detect file differences by hash (rather than size and timestamp) -overwrite overwrite existing files in the repository -delete delete files not in the snapshot + -ignore-owner do not set the original uid/gid on restored files -stats show statistics during and after restore -threads number of downloading threads -limit-rate the maximum download rate (in kilobytes/sec) -storage restore from the specified storage instead of the default one ``` -The *restore* command restores the repository to a previous revision. By default the restore procedure will treat files that have the same sizes and timestamps as those in the snapshot as unchanged files, but with the -hash option, every file will be fully scanned to make sure they are in fact unchanged. +The *restore* command restores the repository to a previous revision. By default the restore procedure will treat files that have the same sizes and timestamps as those in the snapshot as unchanged files, but with the `-hash` option, every file will be fully scanned to make sure they are in fact unchanged. By default the restore procedure will not overwriting existing files, unless the `-overwrite` option is specified. The `-delete` option indicates that files not in the snapshot will be removed. +If the `-ignore-owner` option is specified, the restore procedure will not attempt to restore the original user/group id ownership on restored files (all restored files will be owned by the current user); this can be useful when restoring to a new or different machine. + If the `-stats` option is specified, statistical information such as transfer speed, and number of chunks will be displayed throughout the restore procedure. The `-threads` option can be used to specify more than one thread to download chunks. diff --git a/duplicacy/duplicacy_main.go b/duplicacy/duplicacy_main.go index 9d93850..c922b01 100644 --- a/duplicacy/duplicacy_main.go +++ b/duplicacy/duplicacy_main.go @@ -691,6 +691,8 @@ func restoreRepository(context *cli.Context) { quickMode := !context.Bool("hash") overwrite := context.Bool("overwrite") deleteMode := context.Bool("delete") + setOwner := !context.Bool("ignore-owner") + showStatistics := context.Bool("stats") var patterns []string @@ -732,7 +734,7 @@ func restoreRepository(context *cli.Context) { duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) - backupManager.Restore(repository, revision, true, quickMode, threads, overwrite, deleteMode, showStatistics, patterns) + backupManager.Restore(repository, revision, true, quickMode, threads, overwrite, deleteMode, setOwner, showStatistics, patterns) runScript(context, preference.Name, "post") } @@ -1279,6 +1281,10 @@ func main() { Name: "delete", Usage: "delete files not in the snapshot", }, + cli.BoolFlag{ + Name: "ignore-owner", + Usage: "do not set the original uid/gid on restored files", + }, cli.BoolFlag{ Name: "stats", Usage: "show statistics during and after restore", diff --git a/src/duplicacy_backupmanager.go b/src/duplicacy_backupmanager.go index ccc21af..32ffabb 100644 --- a/src/duplicacy_backupmanager.go +++ b/src/duplicacy_backupmanager.go @@ -711,7 +711,7 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta // the same as 'top'. 'quickMode' will bypass files with unchanged sizes and timestamps. 'deleteMode' will // remove local files that don't exist in the snapshot. 'patterns' is used to include/exclude certain files. func (manager *BackupManager) Restore(top string, revision int, inPlace bool, quickMode bool, threads int, overwrite bool, - deleteMode bool, showStatistics bool, patterns []string) bool { + deleteMode bool, setOwner bool, showStatistics bool, patterns []string) bool { startTime := time.Now().Unix() @@ -878,7 +878,8 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu if quickMode { if file.IsSameAsFileInfo(stat) { LOG_TRACE("RESTORE_SKIP", "File %s unchanged (by size and timestamp)", file.Path) - file.RestoreMetadata(fullPath, &stat) + // shouldn't this be skipped? + // file.RestoreMetadata(fullPath, &stat) continue } } @@ -903,7 +904,7 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu } newFile.Close() - file.RestoreMetadata(fullPath, nil) + file.RestoreMetadata(fullPath, nil, setOwner) if !showStatistics { LOG_INFO("DOWNLOAD_DONE", "Downloaded %s (0)", file.Path) } @@ -915,9 +916,9 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu totalFileSize, downloadedFileSize, startDownloadingTime) { downloadedFileSize += file.Size downloadedFiles = append(downloadedFiles, file) + file.RestoreMetadata(fullPath, nil, setOwner) } - file.RestoreMetadata(fullPath, nil) } if deleteMode && len(patterns) == 0 { @@ -933,7 +934,7 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu for _, entry := range remoteSnapshot.Files { if entry.IsDir() && !entry.IsLink() { dir := joinPath(top, entry.Path) - entry.RestoreMetadata(dir, nil) + entry.RestoreMetadata(dir, nil, setOwner) } } diff --git a/src/duplicacy_entry.go b/src/duplicacy_entry.go index 512dfd6..e1cbbd1 100644 --- a/src/duplicacy_entry.go +++ b/src/duplicacy_entry.go @@ -286,7 +286,7 @@ func (entry *Entry) String(maxSizeDigits int) string { return fmt.Sprintf("%*d %s %64s %s", maxSizeDigits, entry.Size, modifiedTime, entry.Hash, entry.Path) } -func (entry *Entry) RestoreMetadata(fullPath string, fileInfo *os.FileInfo) bool { +func (entry *Entry) RestoreMetadata(fullPath string, fileInfo *os.FileInfo, setOwner bool) bool { if fileInfo == nil { stat, err := os.Stat(fullPath) @@ -318,7 +318,11 @@ func (entry *Entry) RestoreMetadata(fullPath string, fileInfo *os.FileInfo) bool entry.SetAttributesToFile(fullPath) } - return SetOwner(fullPath, entry, fileInfo) + if setOwner { + return SetOwner(fullPath, entry, fileInfo) + } else { + return true + } } // Return -1 if 'left' should appear before 'right', 1 if opposite, and 0 if they are the same.