2022-04-25 12:23:57 -05:00

87 lines
1.7 KiB
Go

package httpfs
import (
"io"
"net/http"
"os"
"path/filepath"
)
// Copy copies the file src to dst from the filesystem fs. If src is
// a directory, then all contents in the directory will be copied into the
// directory dst. If src is a file, then it will be copied directly to dst.
func Copy(fs http.FileSystem, dst, src string) error {
f, err := fs.Open(src)
if err != nil {
return err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
// If this is a file, then copy the file as-is to the destination path
// and we're done.
if !fi.IsDir() {
dstF, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode(fi))
if err != nil {
return err
}
defer dstF.Close()
_, err = io.Copy(dstF, f)
return err
}
// Create this directory
if _, err := os.Stat(dst); err != nil {
if !os.IsNotExist(err) {
return err
}
if err := os.Mkdir(dst, mode(fi)); err != nil {
return err
}
}
// We want to copy all the files
fis, err := f.Readdir(-1)
if err != nil {
return err
}
for _, fi := range fis {
// fi.Name is in the format "src/filename" where src is the
// value of src. We need to get the relative path so that we can
// determine the proper target destination.
rel, err := filepath.Rel(src, fi.Name())
if err != nil {
return err
}
// Recurse!
if err := Copy(fs, filepath.Join(dst, rel), fi.Name()); err != nil {
return err
}
}
return nil
}
// mode returns the proper mode to use for creating files
func mode(fi os.FileInfo) os.FileMode {
if fi.IsDir() {
// We always return this. We don't use fi.Mode because go-bindata
// sets it to non-executable.
return 0755
}
mode := fi.Mode()
if mode > 0 {
return mode
}
return 0644
}