@@ -58,53 +58,12 @@ func GetPathPrefix(conn *connparse.Connection) string {
58
58
return pathPrefix
59
59
}
60
60
61
- func PrefixCopyInternal (ctx context.Context , srcConn , destConn * connparse.Connection , c fstype.FileShareClient , opts * wshrpc.FileCopyOpts , listEntriesPrefix func (ctx context.Context , host string , path string ) ([]string , error ), copyFunc func (ctx context.Context , host string , path string ) error ) error {
61
+ func PrefixCopyInternal (ctx context.Context , srcConn , destConn * connparse.Connection , c fstype.FileShareClient , opts * wshrpc.FileCopyOpts , listEntriesPrefix func (ctx context.Context , host string , path string ) ([]string , error ), copyFunc func (ctx context.Context , host string , path string ) error ) ( bool , error ) {
62
62
log .Printf ("PrefixCopyInternal: %v -> %v" , srcConn .GetFullURI (), destConn .GetFullURI ())
63
- merge := opts != nil && opts .Merge
64
- overwrite := opts != nil && opts .Overwrite
65
- if overwrite && merge {
66
- return fmt .Errorf ("cannot specify both overwrite and merge" )
67
- }
68
63
srcHasSlash := strings .HasSuffix (srcConn .Path , fspath .Separator )
69
- srcPath , err := CleanPathPrefix (srcConn .Path )
70
- if err != nil {
71
- return fmt .Errorf ("error cleaning source path: %w" , err )
72
- }
73
- destHasSlash := strings .HasSuffix (destConn .Path , fspath .Separator )
74
- destPath , err := CleanPathPrefix (destConn .Path )
75
- if err != nil {
76
- return fmt .Errorf ("error cleaning destination path: %w" , err )
77
- }
78
- if ! srcHasSlash {
79
- if ! destHasSlash {
80
- destPath += fspath .Separator
81
- }
82
- destPath += fspath .Base (srcPath )
83
- }
84
- destConn .Path = destPath
85
- destInfo , err := c .Stat (ctx , destConn )
86
- destExists := err == nil && ! destInfo .NotFound
87
- if err != nil && ! errors .Is (err , fs .ErrNotExist ) {
88
- return fmt .Errorf ("error getting destination file info: %w" , err )
89
- }
90
-
91
- srcInfo , err := c .Stat (ctx , srcConn )
64
+ srcPath , destPath , srcInfo , err := DetermineCopyDestPath (ctx , srcConn , destConn , c , c , opts )
92
65
if err != nil {
93
- return fmt .Errorf ("error getting source file info: %w" , err )
94
- }
95
- if destExists {
96
- if overwrite {
97
- err = c .Delete (ctx , destConn , true )
98
- if err != nil {
99
- return fmt .Errorf ("error deleting conflicting destination file: %w" , err )
100
- }
101
- } else if destInfo .IsDir && srcInfo .IsDir {
102
- if ! merge {
103
- return fmt .Errorf ("destination and source are both directories, neither merge nor overwrite specified: %v" , destConn .GetFullURI ())
104
- }
105
- } else {
106
- return fmt .Errorf ("destination already exists, overwrite not specified: %v" , destConn .GetFullURI ())
107
- }
66
+ return false , err
108
67
}
109
68
if srcInfo .IsDir {
110
69
if ! srcHasSlash {
@@ -114,7 +73,7 @@ func PrefixCopyInternal(ctx context.Context, srcConn, destConn *connparse.Connec
114
73
log .Printf ("Copying directory: %v -> %v" , srcPath , destPath )
115
74
entries , err := listEntriesPrefix (ctx , srcConn .Host , srcPath )
116
75
if err != nil {
117
- return fmt .Errorf ("error listing source directory: %w" , err )
76
+ return false , fmt .Errorf ("error listing source directory: %w" , err )
118
77
}
119
78
120
79
tree := pathtree .NewTree (srcPath , fspath .Separator )
@@ -129,7 +88,7 @@ func PrefixCopyInternal(ctx context.Context, srcConn, destConn *connparse.Connec
129
88
if ! srcHasSlash {
130
89
prefixToRemove = fspath .Dir (srcPath ) + fspath .Separator
131
90
}
132
- return tree .Walk (func (path string , numChildren int ) error {
91
+ return true , tree .Walk (func (path string , numChildren int ) error {
133
92
// since this is a prefix filesystem, we only care about leafs
134
93
if numChildren > 0 {
135
94
return nil
@@ -138,56 +97,15 @@ func PrefixCopyInternal(ctx context.Context, srcConn, destConn *connparse.Connec
138
97
return copyFunc (ctx , path , destFilePath )
139
98
})
140
99
} else {
141
- return copyFunc (ctx , srcPath , destPath )
100
+ return false , copyFunc (ctx , srcPath , destPath )
142
101
}
143
102
}
144
103
145
- func PrefixCopyRemote (ctx context.Context , srcConn , destConn * connparse.Connection , srcClient , destClient fstype.FileShareClient , destPutFile func (host string , path string , size int64 , reader io.Reader ) error , opts * wshrpc.FileCopyOpts ) error {
146
- merge := opts != nil && opts .Merge
147
- overwrite := opts != nil && opts .Overwrite
148
- if overwrite && merge {
149
- return fmt .Errorf ("cannot specify both overwrite and merge" )
150
- }
151
- srcHasSlash := strings .HasSuffix (srcConn .Path , fspath .Separator )
152
- destHasSlash := strings .HasSuffix (destConn .Path , fspath .Separator )
153
- destPath , err := CleanPathPrefix (destConn .Path )
154
- if err != nil {
155
- return fmt .Errorf ("error cleaning destination path: %w" , err )
156
- }
157
- if ! srcHasSlash {
158
- if ! destHasSlash {
159
- destPath += fspath .Separator
160
- }
161
- destPath += fspath .Base (srcConn .Path )
162
- }
163
- destConn .Path = destPath
164
- destInfo , err := destClient .Stat (ctx , destConn )
165
- destExists := err == nil && ! destInfo .NotFound
166
- if err != nil && ! errors .Is (err , fs .ErrNotExist ) {
167
- return fmt .Errorf ("error getting destination file info: %w" , err )
168
- }
169
-
170
- srcInfo , err := srcClient .Stat (ctx , srcConn )
171
- if err != nil {
172
- return fmt .Errorf ("error getting source file info: %w" , err )
173
- }
174
- if destExists {
175
- if overwrite {
176
- err = destClient .Delete (ctx , destConn , true )
177
- if err != nil {
178
- return fmt .Errorf ("error deleting conflicting destination file: %w" , err )
179
- }
180
- } else if destInfo .IsDir && srcInfo .IsDir {
181
- if ! merge {
182
- return fmt .Errorf ("destination and source are both directories, neither merge nor overwrite specified: %v" , destConn .GetFullURI ())
183
- }
184
- } else {
185
- return fmt .Errorf ("destination already exists, overwrite not specified: %v" , destConn .GetFullURI ())
186
- }
187
- }
104
+ func PrefixCopyRemote (ctx context.Context , srcConn , destConn * connparse.Connection , srcClient , destClient fstype.FileShareClient , destPutFile func (host string , path string , size int64 , reader io.Reader ) error , opts * wshrpc.FileCopyOpts ) (bool , error ) {
105
+ _ , destPath , srcInfo , err := DetermineCopyDestPath (ctx , srcConn , destConn , srcClient , destClient , opts )
188
106
if err != nil {
189
107
if ! errors .Is (err , fs .ErrNotExist ) {
190
- return err
108
+ return false , err
191
109
}
192
110
}
193
111
log .Printf ("Copying: %v -> %v" , srcConn .GetFullURI (), destConn .GetFullURI ())
@@ -202,8 +120,8 @@ func PrefixCopyRemote(ctx context.Context, srcConn, destConn *connparse.Connecti
202
120
return fmt .Errorf ("protocol error: source is a directory, but only a single file is being copied" )
203
121
}
204
122
fileName , err := CleanPathPrefix (fspath .Join (destPath , next .Name ))
205
- if singleFile && ! destHasSlash {
206
- fileName , err = CleanPathPrefix ( destConn . Path )
123
+ if singleFile {
124
+ fileName = destPath
207
125
}
208
126
if err != nil {
209
127
return fmt .Errorf ("error cleaning path: %w" , err )
@@ -213,9 +131,67 @@ func PrefixCopyRemote(ctx context.Context, srcConn, destConn *connparse.Connecti
213
131
})
214
132
if err != nil {
215
133
cancel (err )
216
- return err
134
+ return false , err
135
+ }
136
+ return srcInfo .IsDir , nil
137
+ }
138
+
139
+ func DetermineCopyDestPath (ctx context.Context , srcConn , destConn * connparse.Connection , srcClient , destClient fstype.FileShareClient , opts * wshrpc.FileCopyOpts ) (srcPath , destPath string , srcInfo * wshrpc.FileInfo , err error ) {
140
+ merge := opts != nil && opts .Merge
141
+ overwrite := opts != nil && opts .Overwrite
142
+ if overwrite && merge {
143
+ return "" , "" , nil , fmt .Errorf ("cannot specify both overwrite and merge" )
144
+ }
145
+
146
+ srcHasSlash := strings .HasSuffix (srcConn .Path , fspath .Separator )
147
+ srcPath , err = CleanPathPrefix (srcConn .Path )
148
+ if err != nil {
149
+ return "" , "" , nil , fmt .Errorf ("error cleaning source path: %w" , err )
150
+ }
151
+ destHasSlash := strings .HasSuffix (destConn .Path , fspath .Separator )
152
+ destPath , err = CleanPathPrefix (destConn .Path )
153
+ if err != nil {
154
+ return "" , "" , nil , fmt .Errorf ("error cleaning destination path: %w" , err )
155
+ }
156
+
157
+ srcInfo , err = srcClient .Stat (ctx , srcConn )
158
+ if err != nil {
159
+ return "" , "" , nil , fmt .Errorf ("error getting source file info: %w" , err )
160
+ }
161
+ destInfo , err := destClient .Stat (ctx , destConn )
162
+ destExists := err == nil && ! destInfo .NotFound
163
+ if err != nil && ! errors .Is (err , fs .ErrNotExist ) {
164
+ return "" , "" , nil , fmt .Errorf ("error getting destination file info: %w" , err )
165
+ }
166
+ originalDestPath := destPath
167
+ if ! srcHasSlash {
168
+ if destInfo .IsDir || (! destExists && ! destHasSlash && srcInfo .IsDir ) {
169
+ destPath = fspath .Join (destPath , fspath .Base (srcConn .Path ))
170
+ }
171
+ }
172
+ destConn .Path = destPath
173
+ if originalDestPath != destPath {
174
+ destInfo , err = destClient .Stat (ctx , destConn )
175
+ destExists = err == nil && ! destInfo .NotFound
176
+ if err != nil && ! errors .Is (err , fs .ErrNotExist ) {
177
+ return "" , "" , nil , fmt .Errorf ("error getting destination file info: %w" , err )
178
+ }
179
+ }
180
+ if destExists {
181
+ if overwrite {
182
+ err = destClient .Delete (ctx , destConn , true )
183
+ if err != nil {
184
+ return "" , "" , nil , fmt .Errorf ("error deleting conflicting destination file: %w" , err )
185
+ }
186
+ } else if destInfo .IsDir && srcInfo .IsDir {
187
+ if ! merge {
188
+ return "" , "" , nil , fmt .Errorf ("destination and source are both directories, neither merge nor overwrite specified: %v" , destConn .GetFullURI ())
189
+ }
190
+ } else {
191
+ return "" , "" , nil , fmt .Errorf ("destination already exists, overwrite not specified: %v" , destConn .GetFullURI ())
192
+ }
217
193
}
218
- return nil
194
+ return srcPath , destPath , srcInfo , nil
219
195
}
220
196
221
197
// CleanPathPrefix corrects paths for prefix filesystems (i.e. ones that don't have directories)
0 commit comments