Skip to content

Commit 10c7ebb

Browse files
authored
fix(local): cross-device file move (#7430)
1 parent d0cda62 commit 10c7ebb

File tree

3 files changed

+25
-14
lines changed

3 files changed

+25
-14
lines changed

drivers/local/driver.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/alist-org/alist/v3/pkg/utils"
2323
"github.com/alist-org/alist/v3/server/common"
2424
"github.com/alist-org/times"
25+
cp "github.com/otiai10/copy"
2526
log "github.com/sirupsen/logrus"
2627
_ "golang.org/x/image/webp"
2728
)
@@ -241,11 +242,22 @@ func (d *Local) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
241242
if utils.IsSubPath(srcPath, dstPath) {
242243
return fmt.Errorf("the destination folder is a subfolder of the source folder")
243244
}
244-
err := os.Rename(srcPath, dstPath)
245-
if err != nil {
245+
if err := os.Rename(srcPath, dstPath); err != nil && strings.Contains(err.Error(), "invalid cross-device link") {
246+
// Handle cross-device file move in local driver
247+
if err = d.Copy(ctx, srcObj, dstDir); err != nil {
248+
return err
249+
} else {
250+
// Directly remove file without check recycle bin if successfully copied
251+
if srcObj.IsDir() {
252+
err = os.RemoveAll(srcObj.GetPath())
253+
} else {
254+
err = os.Remove(srcObj.GetPath())
255+
}
256+
return err
257+
}
258+
} else {
246259
return err
247260
}
248-
return nil
249261
}
250262

251263
func (d *Local) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
@@ -258,22 +270,18 @@ func (d *Local) Rename(ctx context.Context, srcObj model.Obj, newName string) er
258270
return nil
259271
}
260272

261-
func (d *Local) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
273+
func (d *Local) Copy(_ context.Context, srcObj, dstDir model.Obj) error {
262274
srcPath := srcObj.GetPath()
263275
dstPath := filepath.Join(dstDir.GetPath(), srcObj.GetName())
264276
if utils.IsSubPath(srcPath, dstPath) {
265277
return fmt.Errorf("the destination folder is a subfolder of the source folder")
266278
}
267-
var err error
268-
if srcObj.IsDir() {
269-
err = utils.CopyDir(srcPath, dstPath)
270-
} else {
271-
err = utils.CopyFile(srcPath, dstPath)
272-
}
273-
if err != nil {
274-
return err
275-
}
276-
return nil
279+
// Copy using otiai10/copy to perform more secure & efficient copy
280+
return cp.Copy(srcPath, dstPath, cp.Options{
281+
Sync: true, // Sync file to disk after copy, may have performance penalty in filesystem such as ZFS
282+
PreserveTimes: true,
283+
NumOfWorkers: 0, // Serialized copy without using goroutine
284+
})
277285
}
278286

279287
func (d *Local) Remove(ctx context.Context, obj model.Obj) error {

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ require (
189189
github.com/multiformats/go-multihash v0.2.3 // indirect
190190
github.com/multiformats/go-multistream v0.4.1 // indirect
191191
github.com/multiformats/go-varint v0.0.7 // indirect
192+
github.com/otiai10/copy v1.14.0
192193
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
193194
github.com/pierrec/lz4/v4 v4.1.18 // indirect
194195
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
391391
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
392392
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831 h1:K3T3eu4h5aYIOzUtLjN08L4Qt4WGaJONMgcaD0ayBJQ=
393393
github.com/orzogc/fake115uploader v0.3.3-0.20230715111618-58f9eb76f831/go.mod h1:lSHD4lC4zlMl+zcoysdJcd5KFzsWwOD8BJbyg1Ws9Ng=
394+
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
395+
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
394396
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
395397
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
396398
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=

0 commit comments

Comments
 (0)