87 lines
1.7 KiB
Go
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
|
|
}
|