98 lines
1.9 KiB
Go
98 lines
1.9 KiB
Go
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 {
|
|
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)
|
|
}
|
|
|
|
// Same as Copy, but checks scope in symlinks
|
|
func CopyScoped(fs afero.Fs, src, dst, scope 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
|
|
}
|
|
|
|
switch info.Mode() & os.ModeType {
|
|
case os.ModeDir:
|
|
return CopyDirScoped(fs, src, dst, scope)
|
|
case os.ModeSymlink:
|
|
return CopySymLinkScoped(fs, src, dst, scope)
|
|
default:
|
|
return CopyFile(fs, src, dst)
|
|
}
|
|
}
|
|
|
|
func CopySymLinkScoped(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
|
|
}
|
|
|
|
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
|
|
}
|