diff --git a/cmd/check/check.go b/cmd/check/check.go index ebace4f2a..793e0e2b6 100644 --- a/cmd/check/check.go +++ b/cmd/check/check.go @@ -9,11 +9,13 @@ import ( // Globals var ( download = false + oneway = false ) func init() { cmd.Root.AddCommand(commandDefintion) commandDefintion.Flags().BoolVarP(&download, "download", "", download, "Check by downloading rather than with hash.") + commandDefintion.Flags().BoolVarP(&oneway, "one-way", "", oneway, "Check one way only, source files must exist on remote") } var commandDefintion = &cobra.Command{ @@ -31,15 +33,19 @@ If you supply the --download flag, it will download the data from both remotes and check them against each other on the fly. This can be useful for remotes that don't support hashes or if you really want to check all the data. + +If you supply the --one-way flag, it will only check that files in source +match the files in destination, not the other way around. Meaning extra files in +destination that are not in the source will not trigger an error. `, Run: func(command *cobra.Command, args []string) { cmd.CheckArgs(2, 2, command, args) fsrc, fdst := cmd.NewFsSrcDst(args) cmd.Run(false, false, command, func() error { if download { - return operations.CheckDownload(fdst, fsrc) + return operations.CheckDownload(fdst, fsrc, oneway) } - return operations.Check(fdst, fsrc) + return operations.Check(fdst, fsrc, oneway) }) }, } diff --git a/cmd/cryptcheck/cryptcheck.go b/cmd/cryptcheck/cryptcheck.go index 02143bac2..1a8fcd4da 100644 --- a/cmd/cryptcheck/cryptcheck.go +++ b/cmd/cryptcheck/cryptcheck.go @@ -10,8 +10,14 @@ import ( "github.com/spf13/cobra" ) +// Globals +var ( + oneway = false +) + func init() { cmd.Root.AddCommand(commandDefintion) + commandDefintion.Flags().BoolVarP(&oneway, "one-way", "", oneway, "Check one way only, source files must exist on destination") } var commandDefintion = &cobra.Command{ @@ -40,6 +46,10 @@ the files in remote:path. rclone cryptcheck remote:path encryptedremote:path After it has run it will log the status of the encryptedremote:. + +If you supply the --one-way flag, it will only check that files in source +match the files in destination, not the other way around. Meaning extra files in +destination that are not in the source will not trigger an error. `, Run: func(command *cobra.Command, args []string) { cmd.CheckArgs(2, 2, command, args) @@ -100,5 +110,5 @@ func cryptCheck(fdst, fsrc fs.Fs) error { return false, false } - return operations.CheckFn(fcrypt, fsrc, checkIdentical) + return operations.CheckFn(fcrypt, fsrc, checkIdentical, oneway) } diff --git a/fs/operations/operations.go b/fs/operations/operations.go index 848811519..9ca423b9c 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -561,6 +561,7 @@ type checkFn func(a, b fs.Object) (differ bool, noHash bool) type checkMarch struct { fdst, fsrc fs.Fs check checkFn + oneway bool differences int32 noHashes int32 srcFilesMissing int32 @@ -571,6 +572,9 @@ type checkMarch struct { func (c *checkMarch) DstOnly(dst fs.DirEntry) (recurse bool) { switch dst.(type) { case fs.Object: + if c.oneway { + return false + } err := errors.Errorf("File not in %v", c.fsrc) fs.Errorf(dst, "%v", err) fs.CountError(err) @@ -666,11 +670,12 @@ func (c *checkMarch) Match(dst, src fs.DirEntry) (recurse bool) { // // it returns true if differences were found // it also returns whether it couldn't be hashed -func CheckFn(fdst, fsrc fs.Fs, check checkFn) error { +func CheckFn(fdst, fsrc fs.Fs, check checkFn, oneway bool) error { c := &checkMarch{ - fdst: fdst, - fsrc: fsrc, - check: check, + fdst: fdst, + fsrc: fsrc, + check: check, + oneway: oneway, } // set up a march over fdst and fsrc @@ -696,8 +701,8 @@ func CheckFn(fdst, fsrc fs.Fs, check checkFn) error { } // Check the files in fsrc and fdst according to Size and hash -func Check(fdst, fsrc fs.Fs) error { - return CheckFn(fdst, fsrc, checkIdentical) +func Check(fdst, fsrc fs.Fs, oneway bool) error { + return CheckFn(fdst, fsrc, checkIdentical, oneway) } // CheckEqualReaders checks to see if in1 and in2 have the same @@ -754,7 +759,7 @@ func CheckIdentical(dst, src fs.Object) (differ bool, err error) { // CheckDownload checks the files in fsrc and fdst according to Size // and the actual contents of the files. -func CheckDownload(fdst, fsrc fs.Fs) error { +func CheckDownload(fdst, fsrc fs.Fs, oneway bool) error { check := func(a, b fs.Object) (differ bool, noHash bool) { differ, err := CheckIdentical(a, b) if err != nil { @@ -764,7 +769,7 @@ func CheckDownload(fdst, fsrc fs.Fs) error { } return differ, false } - return CheckFn(fdst, fsrc, check) + return CheckFn(fdst, fsrc, check, oneway) } // ListFn lists the Fs to the supplied function diff --git a/fs/operations/operations_test.go b/fs/operations/operations_test.go index a5227c5ed..d295dfcd1 100644 --- a/fs/operations/operations_test.go +++ b/fs/operations/operations_test.go @@ -238,14 +238,14 @@ func TestDelete(t *testing.T) { fstest.CheckItems(t, r.Fremote, file3) } -func testCheck(t *testing.T, checkFunction func(fdst, fsrc fs.Fs) error) { +func testCheck(t *testing.T, checkFunction func(fdst, fsrc fs.Fs, oneway bool) error) { r := fstest.NewRun(t) defer r.Finalise() - check := func(i int, wantErrors int64) { + check := func(i int, wantErrors int64, oneway bool) { fs.Debugf(r.Fremote, "%d: Starting check test", i) oldErrors := accounting.Stats.GetErrors() - err := checkFunction(r.Flocal, r.Fremote) + err := checkFunction(r.Fremote, r.Flocal, oneway) gotErrors := accounting.Stats.GetErrors() - oldErrors if wantErrors == 0 && err != nil { t.Errorf("%d: Got error when not expecting one: %v", i, err) @@ -262,15 +262,15 @@ func testCheck(t *testing.T, checkFunction func(fdst, fsrc fs.Fs) error) { file1 := r.WriteBoth("rutabaga", "is tasty", t3) fstest.CheckItems(t, r.Fremote, file1) fstest.CheckItems(t, r.Flocal, file1) - check(1, 0) + check(1, 0, false) file2 := r.WriteFile("potato2", "------------------------------------------------------------", t1) fstest.CheckItems(t, r.Flocal, file1, file2) - check(2, 1) + check(2, 1, false) file3 := r.WriteObject("empty space", "", t2) fstest.CheckItems(t, r.Fremote, file1, file3) - check(3, 2) + check(3, 2, false) file2r := file2 if fs.Config.SizeOnly { @@ -279,11 +279,16 @@ func testCheck(t *testing.T, checkFunction func(fdst, fsrc fs.Fs) error) { r.WriteObject("potato2", "------------------------------------------------------------", t1) } fstest.CheckItems(t, r.Fremote, file1, file2r, file3) - check(4, 1) + check(4, 1, false) r.WriteFile("empty space", "", t2) fstest.CheckItems(t, r.Flocal, file1, file2, file3) - check(5, 0) + check(5, 0, false) + + file4 := r.WriteObject("remotepotato", "------------------------------------------------------------", t1) + fstest.CheckItems(t, r.Fremote, file1, file2r, file3, file4) + check(6, 1, false) + check(7, 0, true) } func TestCheck(t *testing.T) {