diff --git a/fs/sync/sync.go b/fs/sync/sync.go index 8febf769d..d0b5a2545 100644 --- a/fs/sync/sync.go +++ b/fs/sync/sync.go @@ -464,6 +464,40 @@ func deleteEmptyDirectories(f fs.Fs, entries fs.DirEntries) error { return nil } +// This copies the empty directories in the slice passed in and logs +// any errors copying the directories +func copyEmptyDirectories(f fs.Fs, entries fs.DirEntries) error { + if len(entries) == 0 { + return nil + } + + var okCount int + for i := len(entries) - 1; i >= 0; i-- { + entry := entries[i] + dir, ok := entry.(fs.Directory) + if ok { + err := f.Mkdir(dir.Remote()) + if err != nil { + fs.Errorf(fs.LogDirName(f, dir.Remote()), "Failed to Mkdir: %v", err) + accounting.Stats.Error(err) + } else { + okCount++ + } + } else { + fs.Errorf(f, "Not a directory: %v", entry) + } + } + + if accounting.Stats.Errored() { + fs.Debugf(f, "failed to copy %d directories", accounting.Stats.GetErrors()) + } + + if okCount > 0 { + fs.Debugf(f, "copied %d directories", okCount) + } + return nil +} + // renameHash makes a string with the size and the hash for rename detection // // it may return an empty string in which case no hash could be made @@ -622,6 +656,9 @@ func (s *syncCopyMove) run() error { s.stopTransfers() s.stopDeleters() + // Create empty fsrc subdirectories in fdst + s.processError(copyEmptyDirectories(s.fdst, s.srcEmptyDirs)) + // Delete files after if s.deleteMode == fs.DeleteModeAfter { if s.currentError() != nil && !fs.Config.IgnoreErrors { diff --git a/fs/sync/sync_test.go b/fs/sync/sync_test.go index e88990c84..bd4ffc555 100644 --- a/fs/sync/sync_test.go +++ b/fs/sync/sync_test.go @@ -79,6 +79,32 @@ func TestCopyWithDepth(t *testing.T) { fstest.CheckItems(t, r.Fremote, file2) } +// Test copy empty directories +func TestCopyEmptyDirectories(t *testing.T) { + r := fstest.NewRun(t) + defer r.Finalise() + file1 := r.WriteFile("sub dir/hello world", "hello world", t1) + err := operations.Mkdir(r.Flocal, "sub dir2") + require.NoError(t, err) + r.Mkdir(r.Fremote) + + err = CopyDir(r.Fremote, r.Flocal) + require.NoError(t, err) + + fstest.CheckListingWithPrecision( + t, + r.Fremote, + []fstest.Item{ + file1, + }, + []string{ + "sub dir", + "sub dir2", + }, + fs.Config.ModifyWindow, + ) +} + // Test a server side copy if possible, or the backup path if not func TestServerSideCopy(t *testing.T) { r := fstest.NewRun(t)