@@ -33,6 +33,9 @@ type Local struct {
33
33
Addition
34
34
mkdirPerm int32
35
35
36
+ // directory size data
37
+ directoryMap DirectoryMap
38
+
36
39
// zero means no limit
37
40
thumbConcurrency int
38
41
thumbTokenBucket TokenBucket
@@ -66,6 +69,15 @@ func (d *Local) Init(ctx context.Context) error {
66
69
}
67
70
d .Addition .RootFolderPath = abs
68
71
}
72
+ if d .DirectorySize {
73
+ d .directoryMap .root = d .GetRootPath ()
74
+ _ , err := d .directoryMap .CalculateDirSize (d .GetRootPath ())
75
+ if err != nil {
76
+ return err
77
+ }
78
+ } else {
79
+ d .directoryMap .Clear ()
80
+ }
69
81
if d .ThumbCacheFolder != "" && ! utils .Exists (d .ThumbCacheFolder ) {
70
82
err := os .MkdirAll (d .ThumbCacheFolder , os .FileMode (d .mkdirPerm ))
71
83
if err != nil {
@@ -124,6 +136,9 @@ func (d *Local) GetAddition() driver.Additional {
124
136
func (d * Local ) List (ctx context.Context , dir model.Obj , args model.ListArgs ) ([]model.Obj , error ) {
125
137
fullPath := dir .GetPath ()
126
138
rawFiles , err := readDir (fullPath )
139
+ if d .DirectorySize && args .Refresh {
140
+ d .directoryMap .RecalculateDirSize ()
141
+ }
127
142
if err != nil {
128
143
return nil , err
129
144
}
@@ -147,7 +162,12 @@ func (d *Local) FileInfoToObj(ctx context.Context, f fs.FileInfo, reqPath string
147
162
}
148
163
isFolder := f .IsDir () || isSymlinkDir (f , fullPath )
149
164
var size int64
150
- if ! isFolder {
165
+ if isFolder {
166
+ node , ok := d .directoryMap .Get (filepath .Join (fullPath , f .Name ()))
167
+ if ok {
168
+ size = node .fileSum + node .directorySum
169
+ }
170
+ } else {
151
171
size = f .Size ()
152
172
}
153
173
var ctime time.Time
@@ -186,7 +206,12 @@ func (d *Local) Get(ctx context.Context, path string) (model.Obj, error) {
186
206
isFolder := f .IsDir () || isSymlinkDir (f , path )
187
207
size := f .Size ()
188
208
if isFolder {
189
- size = 0
209
+ node , ok := d .directoryMap .Get (path )
210
+ if ok {
211
+ size = node .fileSum + node .directorySum
212
+ }
213
+ } else {
214
+ size = f .Size ()
190
215
}
191
216
var ctime time.Time
192
217
t , err := times .Stat (path )
@@ -271,22 +296,31 @@ func (d *Local) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
271
296
if utils .IsSubPath (srcPath , dstPath ) {
272
297
return fmt .Errorf ("the destination folder is a subfolder of the source folder" )
273
298
}
274
- if err := os .Rename (srcPath , dstPath ); err != nil && strings .Contains (err .Error (), "invalid cross-device link" ) {
275
- // Handle cross-device file move in local driver
276
- if err = d .Copy (ctx , srcObj , dstDir ); err != nil {
277
- return err
278
- } else {
279
- // Directly remove file without check recycle bin if successfully copied
280
- if srcObj .IsDir () {
281
- err = os .RemoveAll (srcObj .GetPath ())
282
- } else {
283
- err = os .Remove (srcObj .GetPath ())
284
- }
299
+ err := os .Rename (srcPath , dstPath )
300
+ if err != nil && strings .Contains (err .Error (), "invalid cross-device link" ) {
301
+ // 跨设备移动,先复制再删除
302
+ if err := d .Copy (ctx , srcObj , dstDir ); err != nil {
285
303
return err
286
304
}
287
- } else {
288
- return err
305
+ // 复制成功后直接删除源文件/文件夹
306
+ if srcObj .IsDir () {
307
+ return os .RemoveAll (srcObj .GetPath ())
308
+ }
309
+ return os .Remove (srcObj .GetPath ())
310
+ }
311
+ if err == nil {
312
+ srcParent := filepath .Dir (srcPath )
313
+ dstParent := filepath .Dir (dstPath )
314
+ if d .directoryMap .Has (srcParent ) {
315
+ d .directoryMap .UpdateDirSize (srcParent )
316
+ d .directoryMap .UpdateDirParents (srcParent )
317
+ }
318
+ if d .directoryMap .Has (dstParent ) {
319
+ d .directoryMap .UpdateDirSize (dstParent )
320
+ d .directoryMap .UpdateDirParents (dstParent )
321
+ }
289
322
}
323
+ return err
290
324
}
291
325
292
326
func (d * Local ) Rename (ctx context.Context , srcObj model.Obj , newName string ) error {
@@ -296,6 +330,14 @@ func (d *Local) Rename(ctx context.Context, srcObj model.Obj, newName string) er
296
330
if err != nil {
297
331
return err
298
332
}
333
+
334
+ if srcObj .IsDir () {
335
+ if d .directoryMap .Has (srcPath ) {
336
+ d .directoryMap .DeleteDirNode (srcPath )
337
+ d .directoryMap .CalculateDirSize (dstPath )
338
+ }
339
+ }
340
+
299
341
return nil
300
342
}
301
343
@@ -306,11 +348,21 @@ func (d *Local) Copy(_ context.Context, srcObj, dstDir model.Obj) error {
306
348
return fmt .Errorf ("the destination folder is a subfolder of the source folder" )
307
349
}
308
350
// Copy using otiai10/copy to perform more secure & efficient copy
309
- return cp .Copy (srcPath , dstPath , cp.Options {
351
+ err := cp .Copy (srcPath , dstPath , cp.Options {
310
352
Sync : true , // Sync file to disk after copy, may have performance penalty in filesystem such as ZFS
311
353
PreserveTimes : true ,
312
354
PreserveOwner : true ,
313
355
})
356
+ if err != nil {
357
+ return err
358
+ }
359
+
360
+ if d .directoryMap .Has (filepath .Dir (dstPath )) {
361
+ d .directoryMap .UpdateDirSize (filepath .Dir (dstPath ))
362
+ d .directoryMap .UpdateDirParents (filepath .Dir (dstPath ))
363
+ }
364
+
365
+ return nil
314
366
}
315
367
316
368
func (d * Local ) Remove (ctx context.Context , obj model.Obj ) error {
@@ -331,6 +383,19 @@ func (d *Local) Remove(ctx context.Context, obj model.Obj) error {
331
383
if err != nil {
332
384
return err
333
385
}
386
+ if obj .IsDir () {
387
+ if d .directoryMap .Has (obj .GetPath ()) {
388
+ d .directoryMap .DeleteDirNode (obj .GetPath ())
389
+ d .directoryMap .UpdateDirSize (filepath .Dir (obj .GetPath ()))
390
+ d .directoryMap .UpdateDirParents (filepath .Dir (obj .GetPath ()))
391
+ }
392
+ } else {
393
+ if d .directoryMap .Has (filepath .Dir (obj .GetPath ())) {
394
+ d .directoryMap .UpdateDirSize (filepath .Dir (obj .GetPath ()))
395
+ d .directoryMap .UpdateDirParents (filepath .Dir (obj .GetPath ()))
396
+ }
397
+ }
398
+
334
399
return nil
335
400
}
336
401
@@ -354,6 +419,11 @@ func (d *Local) Put(ctx context.Context, dstDir model.Obj, stream model.FileStre
354
419
if err != nil {
355
420
log .Errorf ("[local] failed to change time of %s: %s" , fullPath , err )
356
421
}
422
+ if d .directoryMap .Has (dstDir .GetPath ()) {
423
+ d .directoryMap .UpdateDirSize (dstDir .GetPath ())
424
+ d .directoryMap .UpdateDirParents (dstDir .GetPath ())
425
+ }
426
+
357
427
return nil
358
428
}
359
429
0 commit comments