From f8bfda96a40dead708d18e0d42059fff86b60225 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 30 Dec 2018 08:55:45 +0000 Subject: [PATCH] feat: copy files again License: MIT Signed-off-by: Henrique Dias --- fileutils/copy.go | 39 +++++++++++++++++++++++++++++ fileutils/dir.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++ fileutils/file.go | 51 ++++++++++++++++++++++++++++++++++++++ http/resource.go | 4 +-- 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 fileutils/copy.go create mode 100644 fileutils/dir.go create mode 100644 fileutils/file.go diff --git a/fileutils/copy.go b/fileutils/copy.go new file mode 100644 index 00000000..57c961da --- /dev/null +++ b/fileutils/copy.go @@ -0,0 +1,39 @@ +package fileutils + +import ( + "os" + "path" + + "github.com/spf13/afero" +) + +// Copy copies a file or folder from one place to another. +func Copy(fs afero.Fs, src, dst string) error { + if src = path.Clean("/" + src); src == "" { + return os.ErrNotExist + } + + if dst = path.Clean("/" + dst); dst == "" { + return os.ErrNotExist + } + + if src == "/" || dst == "/" { + // Prohibit copying from or to the virtual root directory. + return os.ErrInvalid + } + + if dst == src { + return os.ErrInvalid + } + + info, err := fs.Stat(src) + if err != nil { + return err + } + + if info.IsDir() { + return CopyDir(fs, src, dst) + } + + return CopyFile(fs, src, dst) +} diff --git a/fileutils/dir.go b/fileutils/dir.go new file mode 100644 index 00000000..56d99645 --- /dev/null +++ b/fileutils/dir.go @@ -0,0 +1,62 @@ +package fileutils + +import ( + "errors" + + "github.com/spf13/afero" +) + +// 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 string, dest string) error { + // Get properties of source. + srcinfo, err := fs.Stat(source) + if err != nil { + return err + } + + // Create the destination directory. + err = fs.MkdirAll(dest, srcinfo.Mode()) + if err != nil { + return err + } + + dir, _ := fs.Open(source) + obs, err := dir.Readdir(-1) + if err != nil { + return err + } + + var errs []error + + for _, obj := range obs { + fsource := source + "/" + obj.Name() + fdest := dest + "/" + obj.Name() + + if obj.IsDir() { + // Create sub-directories, recursively. + err = CopyDir(fs, fsource, fdest) + if err != nil { + errs = append(errs, err) + } + } else { + // Perform the file copy. + err = CopyFile(fs, fsource, fdest) + if err != nil { + errs = append(errs, err) + } + } + } + + var errString string + for _, err := range errs { + errString += err.Error() + "\n" + } + + if errString != "" { + return errors.New(errString) + } + + return nil +} diff --git a/fileutils/file.go b/fileutils/file.go new file mode 100644 index 00000000..64919bbc --- /dev/null +++ b/fileutils/file.go @@ -0,0 +1,51 @@ +package fileutils + +import ( + "io" + "path/filepath" + + "github.com/spf13/afero" +) + +// CopyFile copies a file from source to dest and returns +// an error if any. +func CopyFile(fs afero.Fs, source string, dest string) error { + // Open the source file. + src, err := fs.Open(source) + if err != nil { + return err + } + defer src.Close() + + // Makes the directory needed to create the dst + // file. + err = fs.MkdirAll(filepath.Dir(dest), 0666) + if err != nil { + return err + } + + // Create the destination file. + dst, err := fs.Create(dest) + if err != nil { + return err + } + defer dst.Close() + + // Copy the contents of the file. + _, err = io.Copy(dst, src) + if err != nil { + return err + } + + // Copy the mode if the user can't + // open the file. + info, err := fs.Stat(source) + if err != nil { + err = fs.Chmod(dest, info.Mode()) + if err != nil { + return err + } + } + + return nil +} diff --git a/http/resource.go b/http/resource.go index c71fc8e1..4440bdae 100644 --- a/http/resource.go +++ b/http/resource.go @@ -9,6 +9,7 @@ import ( "os" "strings" + "github.com/filebrowser/filebrowser/fileutils" "github.com/filebrowser/filebrowser/types" ) @@ -223,8 +224,7 @@ func (e *Env) resourcePatchHandler(w http.ResponseWriter, r *http.Request) { err = e.Runner.Run(func() error { if action == "copy" { - // TODO: err = user.FileSystem.Copy(src, dst) - return nil + return fileutils.Copy(user.Fs, src, dst) } return user.Fs.Rename(src, dst)