66 "fmt"
77 "path"
88 "sort"
9+ "strings"
910 "sync"
1011 "time"
1112
@@ -27,7 +28,8 @@ type syncCopyMove struct {
2728 DoMove bool
2829 copyEmptySrcDirs bool
2930 deleteEmptySrcDirs bool
30- dir string
31+ dstDir string
32+ srcDir string
3133 // internal state
3234 ctx context.Context // internal context for controlling go-routines
3335 cancel func () // cancel the context
@@ -64,9 +66,10 @@ type syncCopyMove struct {
6466 renameCheck []fs.Object // accumulate files to check for rename here
6567 compareCopyDest fs.Fs // place to check for files to server side copy
6668 backupDir fs.Fs // place to store overwrites/deletes
69+ useSrcBaseName bool // use only source basename when coping or moving to destination directory
6770}
6871
69- func newSyncCopyMove (ctx context.Context , fdst , fsrc fs.Fs , deleteMode fs.DeleteMode , DoMove bool , deleteEmptySrcDirs bool , copyEmptySrcDirs bool ) (* syncCopyMove , error ) {
72+ func newSyncCopyMove (ctx context.Context , fdst fs. Fs , remoteDst string , fsrc fs.Fs , remoteSrc string , deleteMode fs.DeleteMode , DoMove bool , deleteEmptySrcDirs bool , copyEmptySrcDirs bool , useSrcBaseName bool ) (* syncCopyMove , error ) {
7073 if (deleteMode != fs .DeleteModeOff || DoMove ) && operations .Overlapping (fdst , fsrc ) {
7174 return nil , fserrors .FatalError (fs .ErrorOverlapping )
7275 }
@@ -77,7 +80,8 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
7780 DoMove : DoMove ,
7881 copyEmptySrcDirs : copyEmptySrcDirs ,
7982 deleteEmptySrcDirs : deleteEmptySrcDirs ,
80- dir : "" ,
83+ dstDir : remoteDst ,
84+ srcDir : remoteSrc ,
8185 srcFilesChan : make (chan fs.Object , fs .Config .Checkers + fs .Config .Transfers ),
8286 srcFilesResult : make (chan error , 1 ),
8387 dstFilesResult : make (chan error , 1 ),
@@ -89,6 +93,7 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
8993 trackRenames : fs .Config .TrackRenames ,
9094 commonHash : fsrc .Hashes ().Overlap (fdst .Hashes ()).GetOne (),
9195 trackRenamesCh : make (chan fs.Object , fs .Config .Checkers ),
96+ useSrcBaseName : useSrcBaseName ,
9297 }
9398 var err error
9499 s .toBeChecked , err = newPipe (fs .Config .OrderBy , accounting .Stats (ctx ).SetCheckQueue , fs .Config .MaxBacklog )
@@ -325,15 +330,32 @@ func (s *syncCopyMove) pairCopyOrMove(ctx context.Context, in *pipe, fdst fs.Fs,
325330 return
326331 }
327332 src := pair .Src
333+ name := s .dstObjectName (pair )
328334 if s .DoMove {
329- _ , err = operations .Move (ctx , fdst , pair .Dst , src . Remote () , src )
335+ _ , err = operations .Move (ctx , fdst , pair .Dst , name , src )
330336 } else {
331- _ , err = operations .Copy (ctx , fdst , pair .Dst , src . Remote () , src )
337+ _ , err = operations .Copy (ctx , fdst , pair .Dst , name , src )
332338 }
333339 s .processError (err )
334340 }
335341}
336342
343+ // dstObjectName returns full name of the object as it should be on the
344+ // destination after copy or move.
345+ func (s * syncCopyMove ) dstObjectName (pair fs.ObjectPair ) string {
346+ if ! s .useSrcBaseName {
347+ return pair .Src .Remote ()
348+ }
349+
350+ // Example when coping:
351+ // data:test_keyspace/snapshots/123/bla/somefile.file
352+ // to
353+ // s3:bucket/backup/long/path/to/123
354+ // this should return backup/long/path/to/123/bla/somefile.file
355+ // So we get full path on the destination fs.
356+ return path .Join (s .dstDir , strings .TrimPrefix (pair .Src .Remote (), s .srcDir ))
357+ }
358+
337359// This starts the background checkers.
338360func (s * syncCopyMove ) startCheckers () {
339361 s .checkerWg .Add (fs .Config .Checkers )
@@ -696,8 +718,9 @@ func (s *syncCopyMove) run() error {
696718 m := & march.March {
697719 Ctx : s .ctx ,
698720 Fdst : s .fdst ,
721+ DstDir : s .dstDir ,
699722 Fsrc : s .fsrc ,
700- Dir : s . dir ,
723+ SrcDir : s . srcDir ,
701724 NoTraverse : s .noTraverse ,
702725 Callback : s ,
703726 DstIncludeAll : filter .Active .Opt .DeleteExcluded ,
@@ -899,7 +922,7 @@ func (s *syncCopyMove) Match(ctx context.Context, dst, src fs.DirEntry) (recurse
899922// If DoMove is true then files will be moved instead of copied
900923//
901924// dir is the start directory, "" for root
902- func runSyncCopyMove (ctx context.Context , fdst , fsrc fs.Fs , deleteMode fs.DeleteMode , DoMove bool , deleteEmptySrcDirs bool , copyEmptySrcDirs bool ) error {
925+ func runSyncCopyMove (ctx context.Context , fdst fs. Fs , fsrc fs.Fs , deleteMode fs.DeleteMode , DoMove bool , deleteEmptySrcDirs bool , copyEmptySrcDirs bool ) error {
903926 if deleteMode != fs .DeleteModeOff && DoMove {
904927 return fserrors .FatalError (errors .New ("can't delete and move at the same time" ))
905928 }
@@ -909,7 +932,7 @@ func runSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
909932 return fserrors .FatalError (errors .New ("can't use --delete-before with --track-renames" ))
910933 }
911934 // only delete stuff during in this pass
912- do , err := newSyncCopyMove (ctx , fdst , fsrc , fs .DeleteModeOnly , false , deleteEmptySrcDirs , copyEmptySrcDirs )
935+ do , err := newSyncCopyMove (ctx , fdst , "" , fsrc , "" , fs .DeleteModeOnly , false , deleteEmptySrcDirs , copyEmptySrcDirs , false )
913936 if err != nil {
914937 return err
915938 }
@@ -920,7 +943,7 @@ func runSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
920943 // Next pass does a copy only
921944 deleteMode = fs .DeleteModeOff
922945 }
923- do , err := newSyncCopyMove (ctx , fdst , fsrc , deleteMode , DoMove , deleteEmptySrcDirs , copyEmptySrcDirs )
946+ do , err := newSyncCopyMove (ctx , fdst , "" , fsrc , "" , deleteMode , DoMove , deleteEmptySrcDirs , copyEmptySrcDirs , false )
924947 if err != nil {
925948 return err
926949 }
@@ -937,6 +960,15 @@ func CopyDir(ctx context.Context, fdst, fsrc fs.Fs, copyEmptySrcDirs bool) error
937960 return runSyncCopyMove (ctx , fdst , fsrc , fs .DeleteModeOff , false , false , copyEmptySrcDirs )
938961}
939962
963+ // CopyDir2 copies files from fsrc/remoteSrc into fdst/remoteDst.
964+ func CopyDir2 (ctx context.Context , fdst fs.Fs , remoteDst string , fsrc fs.Fs , remoteSrc string , copyEmptySrcDirs bool ) error {
965+ do , err := newSyncCopyMove (ctx , fdst , remoteDst , fsrc , remoteSrc , fs .DeleteModeOff , false , false , copyEmptySrcDirs , true )
966+ if err != nil {
967+ return err
968+ }
969+ return do .run ()
970+ }
971+
940972// moveDir moves fsrc into fdst
941973func moveDir (ctx context.Context , fdst , fsrc fs.Fs , deleteEmptySrcDirs bool , copyEmptySrcDirs bool ) error {
942974 return runSyncCopyMove (ctx , fdst , fsrc , fs .DeleteModeOff , true , deleteEmptySrcDirs , copyEmptySrcDirs )
0 commit comments