From 0b317b2ee83ec4337fec0eae52c0ab493d756eda Mon Sep 17 00:00:00 2001 From: Laurynas Gadliauskas Date: Fri, 24 Mar 2023 13:27:31 +0200 Subject: [PATCH] feat: handle symlink copying --- fileutils/copy.go | 35 +++++++++++++++++++++++++++++++---- fileutils/dir.go | 18 +++++++++++------- frontend/package-lock.json | 14 +++++++------- frontend/package.json | 2 +- http/resource.go | 2 +- 5 files changed, 51 insertions(+), 20 deletions(-) diff --git a/fileutils/copy.go b/fileutils/copy.go index 57c961daab..e1515b511c 100644 --- a/fileutils/copy.go +++ b/fileutils/copy.go @@ -3,12 +3,14 @@ package fileutils import ( "os" "path" + "path/filepath" + "strings" "github.com/spf13/afero" ) // Copy copies a file or folder from one place to another. -func Copy(fs afero.Fs, src, dst string) error { +func Copy(fs afero.Fs, src, dst, scope string) error { if src = path.Clean("/" + src); src == "" { return os.ErrNotExist } @@ -31,9 +33,34 @@ func Copy(fs afero.Fs, src, dst string) error { return err } - if info.IsDir() { - return CopyDir(fs, src, dst) + switch info.Mode() & os.ModeType { + case os.ModeDir: + return CopyDir(fs, src, dst, scope) + case os.ModeSymlink: + return CopySymLink(fs, src, dst, scope) + default: + return CopyFile(fs, src, dst) } +} + +func CopySymLink(fs afero.Fs, source, dest, scope string) error { + if reader, ok := fs.(afero.LinkReader); ok { + link, err := reader.ReadlinkIfPossible(source) + if err != nil { + return err + } - return CopyFile(fs, src, dst) + if filepath.IsAbs(link) { + link = strings.TrimPrefix(link, scope) + link = filepath.Join(string(os.PathSeparator), link) + } else { + link = filepath.Clean(filepath.Join(filepath.Dir(source), link)) + } + + if linker, ok := fs.(afero.Linker); ok { + return linker.SymlinkIfPossible(link, dest) + } + return nil + } + return nil } diff --git a/fileutils/dir.go b/fileutils/dir.go index 609e0b6a3a..02e0198881 100644 --- a/fileutils/dir.go +++ b/fileutils/dir.go @@ -2,6 +2,7 @@ package fileutils import ( "errors" + "os" "path/filepath" "github.com/spf13/afero" @@ -10,7 +11,7 @@ import ( // CopyDir copies a directory from source to dest and all // of its sub-directories. It doesn't stop if it finds an error // during the copy. Returns an error if any. -func CopyDir(fs afero.Fs, source, dest string) error { +func CopyDir(fs afero.Fs, source, dest, scope string) error { // Get properties of source. srcinfo, err := fs.Stat(source) if err != nil { @@ -35,16 +36,19 @@ func CopyDir(fs afero.Fs, source, dest string) error { fsource := source + "/" + obj.Name() fdest := dest + "/" + obj.Name() - if obj.IsDir() { + switch obj.Mode() & os.ModeType { + case os.ModeDir: // Create sub-directories, recursively. - err = CopyDir(fs, fsource, fdest) - if err != nil { + if err := CopyDir(fs, fsource, fdest, scope); err != nil { errs = append(errs, err) } - } else { + case os.ModeSymlink: + if err := CopySymLink(fs, fsource, fdest, scope); err != nil { + return err + } + default: // Perform the file copy. - err = CopyFile(fs, fsource, fdest) - if err != nil { + if err := CopyFile(fs, fsource, fdest); err != nil { errs = append(errs, err) } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cbf1136bd6..a694218e14 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,7 @@ "name": "filebrowser-frontend", "version": "2.0.0", "dependencies": { - "ace-builds": "^1.4.7", + "ace-builds": "^1.5.1", "clipboard": "^2.0.4", "core-js": "^3.9.1", "css-vars-ponyfill": "^2.4.3", @@ -2397,9 +2397,9 @@ } }, "node_modules/ace-builds": { - "version": "1.4.12", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz", - "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg==" + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.15.3.tgz", + "integrity": "sha512-hq8+4DfQcUYcUyAF3vF7UoGFXwNxXST5A2IdarUOp9/Xg1thWTfxusPI2HAlTvXRTVjLDQOj9O34uPoTehEs0A==" }, "node_modules/acorn": { "version": "7.4.1", @@ -17408,9 +17408,9 @@ } }, "ace-builds": { - "version": "1.4.12", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz", - "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg==" + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.15.3.tgz", + "integrity": "sha512-hq8+4DfQcUYcUyAF3vF7UoGFXwNxXST5A2IdarUOp9/Xg1thWTfxusPI2HAlTvXRTVjLDQOj9O34uPoTehEs0A==" }, "acorn": { "version": "7.4.1", diff --git a/frontend/package.json b/frontend/package.json index 33ab2ff5d1..92eca16eb2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,7 @@ "watch": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --watch --no-clean" }, "dependencies": { - "ace-builds": "^1.4.7", + "ace-builds": "^1.5.1", "clipboard": "^2.0.4", "core-js": "^3.9.1", "css-vars-ponyfill": "^2.4.3", diff --git a/http/resource.go b/http/resource.go index 7c11a0308c..0721d5de2f 100644 --- a/http/resource.go +++ b/http/resource.go @@ -438,7 +438,7 @@ func patchAction(ctx context.Context, action, src, dst string, d *data, fileCach return errors.ErrPermissionDenied } - return fileutils.Copy(d.user.Fs, src, dst) + return fileutils.Copy(d.user.Fs, src, dst, d.server.Root) case "rename": if !d.user.Perm.Rename { return errors.ErrPermissionDenied