@@ -5,13 +5,15 @@ import (
55 "archive/zip"
66 "bytes"
77 "compress/gzip"
8+ "errors"
89 "fmt"
910 "io"
1011 "os"
1112 "path"
1213 "path/filepath"
1314 "strings"
1415 "sync"
16+ "syscall"
1517
1618 C "github.com/metacubex/mihomo/constant"
1719 "github.com/metacubex/mihomo/log"
@@ -308,14 +310,67 @@ func moveDir(src string, dst string) error {
308310 }
309311
310312 for _ , dirEntry := range dirEntryList {
311- err = os .Rename (filepath .Join (src , dirEntry .Name ()), filepath .Join (dst , dirEntry .Name ()))
313+ srcDir := filepath .Join (src , dirEntry .Name ())
314+ dstDir := filepath .Join (dst , dirEntry .Name ())
315+ err = os .Rename (srcDir , dstDir )
316+ if err != nil {
317+ // Fallback for invalid cross-device link (errno:18).
318+ if errors .Is (err , syscall .Errno (18 )) {
319+ err = copyDir (srcDir , dstDir )
320+ _ = os .RemoveAll (srcDir )
321+ }
322+ }
312323 if err != nil {
313324 return err
314325 }
315326 }
316327 return nil
317328}
318329
330+ // copyDir copy the src directory to dst
331+ // modify from [os.CopyFS]
332+ func copyDir (src , dst string ) error {
333+ return filepath .Walk (src , func (path string , info os.FileInfo , err error ) error {
334+ if err != nil {
335+ return err
336+ }
337+ fpath , err := filepath .Rel (src , path )
338+ if err != nil {
339+ return err
340+ }
341+ newPath := filepath .Join (dst , fpath )
342+
343+ switch info .Mode ().Type () {
344+ case os .ModeDir :
345+ return os .MkdirAll (newPath , info .Mode ().Perm ())
346+ case os .ModeSymlink :
347+ target , err := os .Readlink (path )
348+ if err != nil {
349+ return err
350+ }
351+ return os .Symlink (target , newPath )
352+ case 0 :
353+ r , err := os .Open (path )
354+ if err != nil {
355+ return err
356+ }
357+ defer r .Close ()
358+ w , err := os .OpenFile (newPath , os .O_CREATE | os .O_EXCL | os .O_WRONLY , info .Mode ().Perm ())
359+ if err != nil {
360+ return err
361+ }
362+
363+ if _ , err := io .Copy (w , r ); err != nil {
364+ w .Close ()
365+ return & os.PathError {Op : "Copy" , Path : newPath , Err : err }
366+ }
367+ return w .Close ()
368+ default :
369+ return & os.PathError {Op : "CopyFS" , Path : path , Err : os .ErrInvalid }
370+ }
371+ })
372+ }
373+
319374func inDest (fpath , dest string ) bool {
320375 if rel , err := filepath .Rel (dest , fpath ); err == nil {
321376 if filepath .IsLocal (rel ) {
0 commit comments