diff --git a/duplicacy/duplicacy_main.go b/duplicacy/duplicacy_main.go index f99938f..7fab830 100644 --- a/duplicacy/duplicacy_main.go +++ b/duplicacy/duplicacy_main.go @@ -22,9 +22,7 @@ import ( "github.com/gilbertchen/cli" - "io/ioutil" - - "github.com/gilbertchen/duplicacy/src" + duplicacy "github.com/gilbertchen/duplicacy/src" ) const ( @@ -316,7 +314,7 @@ func configRepository(context *cli.Context, init bool) { // write real path into .duplicacy file inside repository duplicacyFileName := path.Join(repository, duplicacy.DUPLICACY_FILE) d1 := []byte(preferencePath) - err = ioutil.WriteFile(duplicacyFileName, d1, 0644) + err = os.WriteFile(duplicacyFileName, d1, 0644) if err != nil { duplicacy.LOG_ERROR("REPOSITORY_PATH", "Failed to write %s file inside repository %v", duplicacyFileName, err) return @@ -705,7 +703,7 @@ func changePassword(context *cli.Context) { } configPath := path.Join(duplicacy.GetDuplicacyPreferencePath(), "config") - err = ioutil.WriteFile(configPath, description, 0600) + err = os.WriteFile(configPath, description, 0600) if err != nil { duplicacy.LOG_ERROR("CONFIG_SAVE", "Failed to save the old config to %s: %v", configPath, err) return @@ -789,7 +787,12 @@ func backupRepository(context *cli.Context) { uploadRateLimit := context.Int("limit-rate") enumOnly := context.Bool("enum-only") storage.SetRateLimits(0, uploadRateLimit) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile, preference.FiltersFile, preference.ExcludeByAttribute) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, + &duplicacy.BackupManagerOptions{ + NoBackupFile: preference.NobackupFile, + FiltersFile: preference.FiltersFile, + ExcludeByAttribute: preference.ExcludeByAttribute, + }) duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) @@ -850,20 +853,6 @@ func restoreRepository(context *cli.Context) { password = duplicacy.GetPassword(*preference, "password", "Enter storage password:", false, false) } - options := duplicacy.RestoreOptions{ - InPlace: true, - QuickMode: !context.Bool("hash"), - Overwrite: context.Bool("overwrite"), - DeleteMode: context.Bool("delete"), - SetOwner: !context.Bool("ignore-owner"), - ShowStatistics: context.Bool("stats"), - AllowFailures: context.Bool("persist"), - ExcludeXattrs: preference.ExcludeXattrs, - NormalizeXattrs: preference.NormalizeXattrs, - IncludeSpecials: preference.IncludeSpecials, - FileFlagsMask: uint32(preference.FileFlagsMask), - } - var patterns []string for _, pattern := range context.Args() { @@ -880,20 +869,45 @@ func restoreRepository(context *cli.Context) { patterns = append(patterns, pattern) } - options.Patterns = duplicacy.ProcessFilterLines(patterns, make([]string, 0)) + patterns = duplicacy.ProcessFilterLines(patterns, make([]string, 0)) duplicacy.LOG_DEBUG("REGEX_DEBUG", "There are %d compiled regular expressions stored", len(duplicacy.RegexMap)) duplicacy.LOG_INFO("SNAPSHOT_FILTER", "Loaded %d include/exclude pattern(s)", len(patterns)) storage.SetRateLimits(context.Int("limit-rate"), 0) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile, preference.FiltersFile, preference.ExcludeByAttribute) + + excludeOwner := preference.ExcludeOwner + // TODO: for backward compat, eventually make them all overridable? + if context.IsSet("ignore-owner") { + excludeOwner = context.Bool("ignore-owner") + } + + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, + &duplicacy.BackupManagerOptions{ + NoBackupFile: preference.NobackupFile, + FiltersFile: preference.FiltersFile, + ExcludeByAttribute: preference.ExcludeByAttribute, + SetOwner: excludeOwner, + ExcludeXattrs: preference.ExcludeXattrs, + NormalizeXattrs: preference.NormalizeXattrs, + IncludeSpecials: preference.IncludeSpecials, + FileFlagsMask: uint32(preference.FileFlagsMask), + }) + duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), context.String("key-passphrase"), preference, backupManager, false) backupManager.SetupSnapshotCache(preference.Name) - failed := backupManager.Restore(repository, revision, options) + failed := backupManager.Restore(repository, revision, &duplicacy.RestoreOptions{ + InPlace: true, + QuickMode: !context.Bool("hash"), + Overwrite: context.Bool("overwrite"), + DeleteMode: context.Bool("delete"), + ShowStatistics: context.Bool("stats"), + AllowFailures: context.Bool("persist"), + }) if failed > 0 { duplicacy.LOG_ERROR("RESTORE_FAIL", "%d file(s) were not restored correctly", failed) return @@ -933,7 +947,8 @@ func listSnapshots(context *cli.Context) { tag := context.String("t") revisions := getRevisions(context) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "", preference.ExcludeByAttribute) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, + &duplicacy.BackupManagerOptions{ExcludeByAttribute: preference.ExcludeByAttribute}) duplicacy.SavePassword(*preference, "password", password) id := preference.SnapshotID @@ -989,7 +1004,7 @@ func checkSnapshots(context *cli.Context) { tag := context.String("t") revisions := getRevisions(context) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "", false) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, nil) duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), context.String("key-passphrase"), preference, backupManager, false) @@ -1049,8 +1064,7 @@ func printFile(context *cli.Context) { snapshotID = context.String("id") } - - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "", false) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, nil) duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), context.String("key-passphrase"), preference, backupManager, false) @@ -1108,7 +1122,7 @@ func diff(context *cli.Context) { } compareByHash := context.Bool("hash") - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "", false) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, nil) duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), context.String("key-passphrase"), preference, backupManager, false) @@ -1153,7 +1167,7 @@ func showHistory(context *cli.Context) { revisions := getRevisions(context) showLocalHash := context.Bool("hash") - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "", false) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, nil) duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) @@ -1216,7 +1230,7 @@ func pruneSnapshots(context *cli.Context) { os.Exit(ArgumentExitCode) } - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "", false) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, nil) duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) @@ -1261,7 +1275,7 @@ func copySnapshots(context *cli.Context) { sourcePassword = duplicacy.GetPassword(*source, "password", "Enter source storage password:", false, false) } - sourceManager := duplicacy.CreateBackupManager(source.SnapshotID, sourceStorage, repository, sourcePassword, "", "", false) + sourceManager := duplicacy.CreateBackupManager(source.SnapshotID, sourceStorage, repository, sourcePassword, nil) sourceManager.SetupSnapshotCache(source.Name) duplicacy.SavePassword(*source, "password", sourcePassword) @@ -1296,7 +1310,7 @@ func copySnapshots(context *cli.Context) { destinationStorage.SetRateLimits(0, context.Int("upload-limit-rate")) destinationManager := duplicacy.CreateBackupManager(destination.SnapshotID, destinationStorage, repository, - destinationPassword, "", "", false) + destinationPassword, nil) duplicacy.SavePassword(*destination, "password", destinationPassword) destinationManager.SetupSnapshotCache(destination.Name) @@ -1421,7 +1435,7 @@ func benchmark(context *cli.Context) { if storage == nil { return } - duplicacy.Benchmark(repository, storage, int64(fileSize) * 1024 * 1024, chunkSize * 1024 * 1024, chunkCount, uploadThreads, downloadThreads) + duplicacy.Benchmark(repository, storage, int64(fileSize)*1024*1024, chunkSize*1024*1024, chunkCount, uploadThreads, downloadThreads) } func main() { @@ -1460,8 +1474,8 @@ func main() { Argument: "", }, cli.BoolFlag{ - Name: "zstd", - Usage: "short for -zstd default", + Name: "zstd", + Usage: "short for -zstd default", }, cli.IntFlag{ Name: "iterations", @@ -1536,8 +1550,8 @@ func main() { Argument: "", }, cli.BoolFlag{ - Name: "zstd", - Usage: "short for -zstd default", + Name: "zstd", + Usage: "short for -zstd default", }, cli.BoolFlag{ Name: "vss", @@ -1570,7 +1584,6 @@ func main() { Usage: "the maximum number of entries kept in memory (defaults to 1M)", Argument: "", }, - }, Usage: "Save a snapshot of the repository to the storage", ArgsUsage: " ", @@ -1630,7 +1643,7 @@ func main() { cli.BoolFlag{ Name: "persist", Usage: "continue processing despite chunk errors or existing files (without -overwrite), reporting any affected files", - }, + }, cli.StringFlag{ Name: "key-passphrase", Usage: "the passphrase to decrypt the RSA private key", @@ -1988,8 +2001,8 @@ func main() { Argument: "", }, cli.BoolFlag{ - Name: "zstd", - Usage: "short for -zstd default", + Name: "zstd", + Usage: "short for -zstd default", }, cli.IntFlag{ Name: "iterations", @@ -2254,8 +2267,8 @@ func main() { Usage: "add a comment to identify the process", }, cli.StringSliceFlag{ - Name: "suppress, s", - Usage: "suppress logs with the specified id", + Name: "suppress, s", + Usage: "suppress logs with the specified id", Argument: "", }, cli.BoolFlag{ diff --git a/src/duplicacy_backupmanager.go b/src/duplicacy_backupmanager.go index 2a5e5db..06f0166 100644 --- a/src/duplicacy_backupmanager.go +++ b/src/duplicacy_backupmanager.go @@ -32,32 +32,33 @@ type BackupManager struct { SnapshotManager *SnapshotManager // the snapshot manager snapshotCache *FileStorage // for copies of chunks needed by snapshots - config *Config // contains a number of options - - nobackupFile string // don't backup directory when this file name is found - filtersFile string // the path to the filters file - excludeByAttribute bool // don't backup file based on file attribute + config *Config // contains a number of options + options BackupManagerOptions cachePath string } -type BackupOptions struct { +type BackupManagerOptions struct { + NoBackupFile string // don't backup directory when this file name is found + FiltersFile string // the path to the filters file + ExcludeByAttribute bool // don't backup file based on file attribute + SetOwner bool + ExcludeXattrs bool + NormalizeXattrs bool + IncludeFileFlags bool + IncludeSpecials bool + FileFlagsMask uint32 } type RestoreOptions struct { - Threads int - Patterns []string - InPlace bool - QuickMode bool - Overwrite bool - DeleteMode bool - SetOwner bool - ShowStatistics bool - AllowFailures bool - ExcludeXattrs bool - NormalizeXattrs bool - IncludeSpecials bool - FileFlagsMask uint32 + Threads int + Patterns []string + InPlace bool + QuickMode bool + Overwrite bool + DeleteMode bool + ShowStatistics bool + AllowFailures bool } func (manager *BackupManager) SetDryRun(dryRun bool) { @@ -71,7 +72,8 @@ func (manager *BackupManager) SetCompressionLevel(level int) { // CreateBackupManager creates a backup manager using the specified 'storage'. 'snapshotID' is a unique id to // identify snapshots created for this repository. 'top' is the top directory of the repository. 'password' is the // master key which can be nil if encryption is not enabled. -func CreateBackupManager(snapshotID string, storage Storage, top string, password string, nobackupFile string, filtersFile string, excludeByAttribute bool) *BackupManager { +func CreateBackupManager(snapshotID string, storage Storage, top string, password string, + options *BackupManagerOptions) *BackupManager { config, _, err := DownloadConfig(storage, password) if err != nil { @@ -91,13 +93,11 @@ func CreateBackupManager(snapshotID string, storage Storage, top string, passwor SnapshotManager: snapshotManager, - config: config, - - nobackupFile: nobackupFile, - - filtersFile: filtersFile, - - excludeByAttribute: excludeByAttribute, + config: config, + options: *options, + } + if options != nil { + backupManager.options = *options } if IsDebugging() { @@ -170,7 +170,7 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta LOG_INFO("BACKUP_KEY", "RSA encryption is enabled") } - if manager.excludeByAttribute { + if manager.options.ExcludeByAttribute { LOG_INFO("BACKUP_EXCLUDE", "Exclude files with no-backup attributes") } @@ -255,7 +255,8 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta go func() { // List local files defer CatchLogException() - localSnapshot.ListLocalFiles(shadowTop, manager.nobackupFile, manager.filtersFile, manager.excludeByAttribute, localListingChannel, &skippedDirectories, &skippedFiles) + localSnapshot.ListLocalFiles(shadowTop, manager.options.NoBackupFile, manager.options.FiltersFile, + manager.options.ExcludeByAttribute, localListingChannel, &skippedDirectories, &skippedFiles) }() go func() { @@ -642,7 +643,7 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta // Restore downloads the specified snapshot, compares it with what's on the repository, and then downloads // files that are different.'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, options RestoreOptions) int { +func (manager *BackupManager) Restore(top string, revision int, options *RestoreOptions) int { if options.Threads < 1 { options.Threads = 1 } @@ -653,10 +654,10 @@ func (manager *BackupManager) Restore(top string, revision int, options RestoreO allowFailures := options.AllowFailures metadataOptions := RestoreMetadataOptions{ - SetOwner: options.SetOwner, - ExcludeXattrs: options.ExcludeXattrs, - NormalizeXattrs: options.NormalizeXattrs, - FileFlagsMask: options.FileFlagsMask, + SetOwner: manager.options.SetOwner, + ExcludeXattrs: manager.options.ExcludeXattrs, + NormalizeXattrs: manager.options.NormalizeXattrs, + FileFlagsMask: manager.options.FileFlagsMask, } startTime := time.Now().Unix() @@ -715,7 +716,8 @@ func (manager *BackupManager) Restore(top string, revision int, options RestoreO go func() { // List local files defer CatchLogException() - localSnapshot.ListLocalFiles(top, manager.nobackupFile, manager.filtersFile, manager.excludeByAttribute, localListingChannel, nil, nil) + localSnapshot.ListLocalFiles(top, manager.options.NoBackupFile, manager.options.FiltersFile, + manager.options.ExcludeByAttribute, localListingChannel, nil, nil) }() remoteSnapshot := manager.SnapshotManager.DownloadSnapshot(manager.snapshotID, revision) @@ -857,12 +859,12 @@ func (manager *BackupManager) Restore(top string, revision int, options RestoreO return 0 } } - err = remoteEntry.RestoreEarlyDirFlags(fullPath, options.FileFlagsMask) + err = remoteEntry.RestoreEarlyDirFlags(fullPath, manager.options.FileFlagsMask) if err != nil { LOG_WARN("DOWNLOAD_FLAGS", "Failed to set early file flags on %s: %v", fullPath, err) } directoryEntries = append(directoryEntries, remoteEntry) - } else if remoteEntry.IsSpecial() && options.IncludeSpecials { + } else if remoteEntry.IsSpecial() && manager.options.IncludeSpecials { if stat, _ := os.Lstat(fullPath); stat != nil { if remoteEntry.IsSameSpecial(stat) { remoteEntry.RestoreMetadata(fullPath, nil, metadataOptions) diff --git a/src/duplicacy_backupmanager_test.go b/src/duplicacy_backupmanager_test.go index 2255250..b783387 100644 --- a/src/duplicacy_backupmanager_test.go +++ b/src/duplicacy_backupmanager_test.go @@ -251,21 +251,20 @@ func TestBackupManager(t *testing.T) { time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager := CreateBackupManager("host1", storage, testDir, password, "", "", false) + backupManager := CreateBackupManager("host1", storage, testDir, password, nil) backupManager.SetupSnapshotCache("default") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "first", false, false, 0, false, 1024, 1024) time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles := backupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles := backupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: false, QuickMode: false, Overwrite: true, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: false, }) @@ -292,14 +291,13 @@ func TestBackupManager(t *testing.T) { backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "second", false, false, 0, false, 1024, 1024) time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles = backupManager.Restore(testDir+"/repository2", 2, RestoreOptions{ + failedFiles = backupManager.Restore(testDir+"/repository2", 2, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: true, Overwrite: true, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: false, }) @@ -330,14 +328,13 @@ func TestBackupManager(t *testing.T) { createRandomFile(testDir+"/repository2/dir5/file5", 100) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles = backupManager.Restore(testDir+"/repository2", 3, RestoreOptions{ + failedFiles = backupManager.Restore(testDir+"/repository2", 3, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: true, DeleteMode: true, - SetOwner: false, ShowStatistics: false, AllowFailures: false, }) @@ -367,14 +364,13 @@ func TestBackupManager(t *testing.T) { os.Remove(testDir + "/repository1/file2") os.Remove(testDir + "/repository1/dir1/file3") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - failedFiles = backupManager.Restore(testDir+"/repository1", 3, RestoreOptions{ + failedFiles = backupManager.Restore(testDir+"/repository1", 3, &RestoreOptions{ Threads: threads, Patterns: []string{"+file2", "+dir1/file3", "-*"}, InPlace: true, QuickMode: false, Overwrite: true, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: false, }) @@ -564,7 +560,7 @@ func TestPersistRestore(t *testing.T) { // do unencrypted backup SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - unencBackupManager := CreateBackupManager("host1", unencStorage, testDir, "", "", "", false) + unencBackupManager := CreateBackupManager("host1", unencStorage, testDir, "", nil) unencBackupManager.SetupSnapshotCache("default") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") @@ -573,7 +569,7 @@ func TestPersistRestore(t *testing.T) { // do encrypted backup SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - encBackupManager := CreateBackupManager("host1", storage, testDir, password, "", "", false) + encBackupManager := CreateBackupManager("host1", storage, testDir, password, nil) encBackupManager.SetupSnapshotCache("default") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") @@ -651,14 +647,13 @@ func TestPersistRestore(t *testing.T) { // test restore all uncorrupted to repository3 SetDuplicacyPreferencePath(testDir + "/repository3/.duplicacy") - failedFiles := unencBackupManager.Restore(testDir+"/repository3", 1, RestoreOptions{ + failedFiles := unencBackupManager.Restore(testDir+"/repository3", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: false, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: false, }) @@ -706,14 +701,13 @@ func TestPersistRestore(t *testing.T) { // test restore corrupted, inPlace = true, corrupted files will have hash failures os.RemoveAll(testDir + "/repository2") SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles = unencBackupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles = unencBackupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: false, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) @@ -724,14 +718,13 @@ func TestPersistRestore(t *testing.T) { os.RemoveAll(testDir + "/repository2") SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles = encBackupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles = encBackupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: false, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) @@ -744,14 +737,13 @@ func TestPersistRestore(t *testing.T) { // test restore corrupted, inPlace = false, corrupted files will be missing os.RemoveAll(testDir + "/repository2") SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles = unencBackupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles = unencBackupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: false, QuickMode: false, Overwrite: false, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) @@ -762,14 +754,13 @@ func TestPersistRestore(t *testing.T) { os.RemoveAll(testDir + "/repository2") SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") - failedFiles = encBackupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles = encBackupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: false, QuickMode: false, Overwrite: false, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) @@ -782,27 +773,25 @@ func TestPersistRestore(t *testing.T) { // with overwrite=true, corrupted file1 from unenc will be restored correctly from enc // the latter will not touch the existing file3 with correct hash os.RemoveAll(testDir + "/repository2") - failedFiles = unencBackupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles = unencBackupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: false, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) assertRestoreFailures(t, failedFiles, 1) - failedFiles = encBackupManager.Restore(testDir+"/repository2", 1, RestoreOptions{ + failedFiles = encBackupManager.Restore(testDir+"/repository2", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: true, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) @@ -812,28 +801,26 @@ func TestPersistRestore(t *testing.T) { // restore to repository3, with overwrite and allowFailures (true/false), quickMode = false (use hashes) // should always succeed as uncorrupted files already exist with correct hash, so these will be ignored SetDuplicacyPreferencePath(testDir + "/repository3/.duplicacy") - failedFiles = unencBackupManager.Restore(testDir+"/repository3", 1, RestoreOptions{ + failedFiles = unencBackupManager.Restore(testDir+"/repository3", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: true, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: false, }) assertRestoreFailures(t, failedFiles, 0) checkAllUncorrupted("/repository3") - failedFiles = unencBackupManager.Restore(testDir+"/repository3", 1, RestoreOptions{ + failedFiles = unencBackupManager.Restore(testDir+"/repository3", 1, &RestoreOptions{ Threads: threads, Patterns: nil, InPlace: true, QuickMode: false, Overwrite: true, DeleteMode: false, - SetOwner: false, ShowStatistics: false, AllowFailures: true, }) diff --git a/src/duplicacy_preference.go b/src/duplicacy_preference.go index 8a147f4..94f9dae 100644 --- a/src/duplicacy_preference.go +++ b/src/duplicacy_preference.go @@ -50,6 +50,7 @@ type Preference struct { NobackupFile string `json:"nobackup_file"` Keys map[string]string `json:"keys"` FiltersFile string `json:"filters"` + ExcludeOwner bool `json:"exclude_owner"` ExcludeByAttribute bool `json:"exclude_by_attribute"` ExcludeXattrs bool `json:"exclude_xattrs"` NormalizeXattrs bool `json:"normalize_xattrs"`