69 lines
1.6 KiB
Go
69 lines
1.6 KiB
Go
package vfscopy
|
|
|
|
import (
|
|
"os"
|
|
"io"
|
|
"path/filepath"
|
|
"path"
|
|
"strings"
|
|
"errors"
|
|
)
|
|
|
|
// FileSystem is copied from http.FileSystem
|
|
type FileSystem interface {
|
|
Open(name string) (File, error)
|
|
}
|
|
|
|
// File is copied from http.File
|
|
type File interface {
|
|
io.Closer
|
|
io.Reader
|
|
io.Seeker
|
|
Readdir(count int) ([]os.FileInfo, error)
|
|
Stat() (os.FileInfo, error)
|
|
}
|
|
|
|
// Dir is an implementation of a Virtual FileSystem
|
|
type Dir string
|
|
|
|
// mapDirOpenError maps the provided non-nil error from opening name
|
|
// to a possibly better non-nil error. In particular, it turns OS-specific errors
|
|
// about opening files in non-directories into os.ErrNotExist. See Issue 18984.
|
|
func mapDirOpenError(originalErr error, name string) error {
|
|
if os.IsNotExist(originalErr) || os.IsPermission(originalErr) {
|
|
return originalErr
|
|
}
|
|
|
|
parts := strings.Split(name, string(filepath.Separator))
|
|
for i := range parts {
|
|
if parts[i] == "" {
|
|
continue
|
|
}
|
|
fi, err := os.Stat(strings.Join(parts[:i+1], string(filepath.Separator)))
|
|
if err != nil {
|
|
return originalErr
|
|
}
|
|
if !fi.IsDir() {
|
|
return os.ErrNotExist
|
|
}
|
|
}
|
|
return originalErr
|
|
}
|
|
|
|
// Open opens a file relative to a virtual filesystem
|
|
func (d Dir) Open(name string) (File, error) {
|
|
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
|
|
return nil, errors.New("http: invalid character in file path")
|
|
}
|
|
dir := string(d)
|
|
if dir == "" {
|
|
dir = "."
|
|
}
|
|
fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
|
|
f, err := os.Open(fullName)
|
|
if err != nil {
|
|
return nil, mapDirOpenError(err, fullName)
|
|
}
|
|
return f, nil
|
|
}
|