1
1
package common
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"files/pkg/errors"
6
7
"files/pkg/files"
@@ -10,9 +11,11 @@ import (
10
11
"github.com/spf13/afero"
11
12
"k8s.io/klog/v2"
12
13
"os"
14
+ "os/exec"
13
15
"path"
14
16
"path/filepath"
15
17
"strings"
18
+ "time"
16
19
)
17
20
18
21
func CheckParent (src , dst string ) error {
@@ -51,7 +54,147 @@ func AddVersionSuffix(source string, fs afero.Fs, isDir bool) string {
51
54
return source
52
55
}
53
56
54
- func MoveDir (ctx context.Context , fs afero.Fs , source , dest string , fileCache fileutils.FileCache ) error {
57
+ func pathExistsInLsOutput (path string , isDir bool ) (bool , error ) {
58
+ dir := filepath .Dir (path )
59
+ base := filepath .Base (path )
60
+
61
+ cmd := exec .Command ("ls" , "-l" , dir )
62
+ var out bytes.Buffer
63
+ var stderr bytes.Buffer
64
+ cmd .Stdout = & out
65
+ cmd .Stderr = & stderr
66
+
67
+ err := cmd .Run ()
68
+ if err != nil {
69
+ klog .Errorf ("ls -l %s failed: %v, stderr: %s" , path , err , stderr .String ())
70
+ }
71
+
72
+ lsOutput := out .String ()
73
+
74
+ lines := strings .Split (lsOutput , "\n " )
75
+ for _ , line := range lines {
76
+ if line == "" {
77
+ continue
78
+ }
79
+
80
+ fileType := line [:1 ]
81
+
82
+ parts := strings .Fields (line )
83
+ if len (parts ) < 9 {
84
+ continue
85
+ }
86
+ fileName := parts [len (parts )- 1 ]
87
+
88
+ if fileName == base {
89
+ if fileType == "d" && isDir {
90
+ return true , nil
91
+ } else if fileType == "-" && ! isDir {
92
+ return true , nil
93
+ }
94
+ }
95
+ }
96
+ return false , nil
97
+ }
98
+
99
+ func Rmrf (path string ) error {
100
+ for {
101
+ cmd := exec .Command ("rm" , "-rf" , path )
102
+
103
+ //cmdStr := fmt.Sprintf("%s %s", cmd.Path, strings.Join(cmd.Args[1:], " "))
104
+ //klog.Infoln("~~~Debug log: Executing command:", cmdStr)
105
+
106
+ var stdout , stderr bytes.Buffer
107
+ cmd .Stdout = & stdout
108
+ cmd .Stderr = & stderr
109
+
110
+ err := cmd .Run ()
111
+ if err != nil {
112
+ klog .Infoln ("Error executing rm -rf:" , err )
113
+ }
114
+ //klog.Infoln("Command stdout:", stdout.String())
115
+ //klog.Infoln("Command stderr:", stderr.String())
116
+
117
+ exists , err := pathExistsInLsOutput (path , true )
118
+ if ! exists && err == nil {
119
+ klog .Infoln ("Path successfully removed:" , path )
120
+ return nil
121
+ } else if err != nil {
122
+ klog .Infoln ("Error checking path existence:" , err )
123
+ } else {
124
+ klog .Infoln ("Path still exists, retrying..." )
125
+ }
126
+ time .Sleep (500 * time .Millisecond )
127
+ }
128
+ }
129
+
130
+ func safeRemoveAll (fs afero.Fs , source string ) error {
131
+ // TODO: not used for the time being
132
+ realPath := filepath .Join (RootPrefix , source )
133
+ for {
134
+ klog .Infof ("~~~Debug log: Attempting to delete folder %s" , realPath )
135
+
136
+ err := fs .RemoveAll (source )
137
+ if err != nil {
138
+ klog .Errorf ("Error attempting to delete folder %s: %v" , realPath , err )
139
+ } else {
140
+ exists , err := pathExistsInLsOutput (filepath .Join (RootPrefix , source ), true )
141
+ if ! exists && err == nil {
142
+ klog .Infof ("Successfully deleted folder %s" , realPath )
143
+ return nil
144
+ } else if err != nil {
145
+ klog .Errorf ("Error checking folder existence after deletion attempt for %s: %v" , realPath , err )
146
+ } else {
147
+ klog .Warningf ("Folder %s still exists after deletion attempt, retrying..." , realPath )
148
+ }
149
+ }
150
+
151
+ time .Sleep (500 * time .Millisecond )
152
+ }
153
+ }
154
+
155
+ func MoveDir (ctx context.Context , fs afero.Fs , source , dest , srcExternalType , dstExternalType string , fileCache fileutils.FileCache , delete bool ) error {
156
+ var err error
157
+ if delete {
158
+ // first recursively delete all thumbs
159
+ err = filepath .Walk (RootPrefix + source , func (path string , info os.FileInfo , err error ) error {
160
+ if err != nil {
161
+ return err
162
+ }
163
+
164
+ if ! info .IsDir () {
165
+ file , err := files .NewFileInfo (files.FileOptions {
166
+ Fs : files .DefaultFs ,
167
+ Path : path ,
168
+ Modify : true ,
169
+ Expand : false ,
170
+ ReadHeader : false ,
171
+ })
172
+ if err != nil {
173
+ return err
174
+ }
175
+
176
+ // delete thumbnails
177
+ err = preview .DelThumbs (ctx , fileCache , file )
178
+ if err != nil {
179
+ return err
180
+ }
181
+ }
182
+ return nil
183
+ })
184
+ if err != nil {
185
+ klog .Infoln ("Error walking the directory:" , err )
186
+ } else {
187
+ klog .Infoln ("Directory traversal completed." )
188
+ }
189
+ }
190
+
191
+ // no matter what situation, try to rename all first
192
+ if fs .Rename (source , dest ) == nil {
193
+ return nil
194
+ }
195
+
196
+ // if rename all failed, recursively do things below, without delthumbs any more
197
+
55
198
// Get properties of source.
56
199
srcinfo , err := fs .Stat (source )
57
200
if err != nil {
@@ -78,13 +221,13 @@ func MoveDir(ctx context.Context, fs afero.Fs, source, dest string, fileCache fi
78
221
79
222
if obj .IsDir () {
80
223
// Create sub-directories, recursively.
81
- err = MoveDir (ctx , fs , fsource , fdest , fileCache )
224
+ err = MoveDir (ctx , fs , fsource , fdest , srcExternalType , dstExternalType , fileCache , false )
82
225
if err != nil {
83
226
errs = append (errs , err )
84
227
}
85
228
} else {
86
229
// Perform the file copy.
87
- err = MoveFile (ctx , fs , fsource , fdest , fileCache )
230
+ err = MoveFile (ctx , fs , fsource , fdest , fileCache , false )
88
231
if err != nil {
89
232
errs = append (errs , err )
90
233
}
@@ -97,46 +240,61 @@ func MoveDir(ctx context.Context, fs afero.Fs, source, dest string, fileCache fi
97
240
}
98
241
99
242
if errString != "" {
100
- err = fs .Remove (dest )
243
+ klog .Infof ("Rollbacking: Dest ExternalType is %s" , dstExternalType )
244
+ if dstExternalType == "smb" {
245
+ err = Rmrf (RootPrefix + dest )
246
+ } else {
247
+ err = fs .RemoveAll (dest )
248
+ }
101
249
if err != nil {
102
250
errString += err .Error () + "\n "
103
251
}
104
252
return fmt .Errorf (errString )
105
253
}
106
254
107
- err = fs .Remove (source )
108
- if err != nil {
109
- return err
255
+ // finally delete all for folder is OK
256
+ if delete {
257
+ klog .Infof ("Moving is going to Delete folder %s with ExternalType %s" , RootPrefix + source , srcExternalType )
258
+ if srcExternalType == "smb" {
259
+ err = Rmrf (RootPrefix + source )
260
+ } else {
261
+ err = fs .RemoveAll (source )
262
+ }
263
+ if err != nil {
264
+ return err
265
+ }
110
266
}
111
267
112
268
return nil
113
269
}
114
270
115
- func MoveFile (ctx context.Context , fs afero.Fs , src , dst string , fileCache fileutils.FileCache ) error {
271
+ func MoveFile (ctx context.Context , fs afero.Fs , src , dst string , fileCache fileutils.FileCache , delete bool ) error {
116
272
src = path .Clean ("/" + src )
117
273
dst = path .Clean ("/" + dst )
118
274
119
- file , err := files .NewFileInfo (files.FileOptions {
120
- Fs : files .DefaultFs ,
121
- Path : src ,
122
- Modify : true ,
123
- Expand : false ,
124
- ReadHeader : false ,
125
- })
126
- if err != nil {
127
- return err
128
- }
275
+ if delete {
276
+ file , err := files .NewFileInfo (files.FileOptions {
277
+ Fs : files .DefaultFs ,
278
+ Path : src ,
279
+ Modify : true ,
280
+ Expand : false ,
281
+ ReadHeader : false ,
282
+ })
283
+ if err != nil {
284
+ return err
285
+ }
129
286
130
- // delete thumbnails
131
- err = preview .DelThumbs (ctx , fileCache , file )
132
- if err != nil {
133
- return err
287
+ // delete thumbnails
288
+ err = preview .DelThumbs (ctx , fileCache , file )
289
+ if err != nil {
290
+ return err
291
+ }
134
292
}
135
293
136
294
return fileutils .MoveFile (fs , src , dst )
137
295
}
138
296
139
- func Move (ctx context.Context , fs afero.Fs , src , dst string , fileCache fileutils.FileCache ) error {
297
+ func Move (ctx context.Context , fs afero.Fs , src , dst , srcExternalType , dstExternalType string , fileCache fileutils.FileCache ) error {
140
298
if src = path .Clean ("/" + src ); src == "" {
141
299
return os .ErrNotExist
142
300
}
@@ -160,18 +318,18 @@ func Move(ctx context.Context, fs afero.Fs, src, dst string, fileCache fileutils
160
318
}
161
319
162
320
if info .IsDir () {
163
- return MoveDir (ctx , fs , src , dst , fileCache )
321
+ return MoveDir (ctx , fs , src , dst , srcExternalType , dstExternalType , fileCache , true )
164
322
}
165
323
166
- return MoveFile (ctx , fs , src , dst , fileCache )
324
+ return MoveFile (ctx , fs , src , dst , fileCache , true )
167
325
}
168
326
169
- func PatchAction (ctx context.Context , action , src , dst string , fileCache fileutils.FileCache ) error {
327
+ func PatchAction (ctx context.Context , action , src , dst , srcExternalType , dstExternalType string , fileCache fileutils.FileCache ) error {
170
328
switch action {
171
329
case "copy" :
172
330
return fileutils .Copy (files .DefaultFs , src , dst )
173
331
case "rename" :
174
- return Move (ctx , files .DefaultFs , src , dst , fileCache )
332
+ return Move (ctx , files .DefaultFs , src , dst , srcExternalType , dstExternalType , fileCache )
175
333
default :
176
334
return fmt .Errorf ("unsupported action %s: %w" , action , errors .ErrInvalidRequestParams )
177
335
}
0 commit comments