123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- //go:build go1.16
- // +build go1.16
- package afero
- import (
- "io"
- "io/fs"
- "os"
- "path"
- "sort"
- "time"
- "github.com/spf13/afero/internal/common"
- )
- // IOFS adopts afero.Fs to stdlib io/fs.FS
- type IOFS struct {
- Fs
- }
- func NewIOFS(fs Fs) IOFS {
- return IOFS{Fs: fs}
- }
- var (
- _ fs.FS = IOFS{}
- _ fs.GlobFS = IOFS{}
- _ fs.ReadDirFS = IOFS{}
- _ fs.ReadFileFS = IOFS{}
- _ fs.StatFS = IOFS{}
- _ fs.SubFS = IOFS{}
- )
- func (iofs IOFS) Open(name string) (fs.File, error) {
- const op = "open"
- // by convention for fs.FS implementations we should perform this check
- if !fs.ValidPath(name) {
- return nil, iofs.wrapError(op, name, fs.ErrInvalid)
- }
- file, err := iofs.Fs.Open(name)
- if err != nil {
- return nil, iofs.wrapError(op, name, err)
- }
- // file should implement fs.ReadDirFile
- if _, ok := file.(fs.ReadDirFile); !ok {
- file = readDirFile{file}
- }
- return file, nil
- }
- func (iofs IOFS) Glob(pattern string) ([]string, error) {
- const op = "glob"
- // afero.Glob does not perform this check but it's required for implementations
- if _, err := path.Match(pattern, ""); err != nil {
- return nil, iofs.wrapError(op, pattern, err)
- }
- items, err := Glob(iofs.Fs, pattern)
- if err != nil {
- return nil, iofs.wrapError(op, pattern, err)
- }
- return items, nil
- }
- func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) {
- f, err := iofs.Fs.Open(name)
- if err != nil {
- return nil, iofs.wrapError("readdir", name, err)
- }
- defer f.Close()
- if rdf, ok := f.(fs.ReadDirFile); ok {
- items, err := rdf.ReadDir(-1)
- if err != nil {
- return nil, iofs.wrapError("readdir", name, err)
- }
- sort.Slice(items, func(i, j int) bool { return items[i].Name() < items[j].Name() })
- return items, nil
- }
- items, err := f.Readdir(-1)
- if err != nil {
- return nil, iofs.wrapError("readdir", name, err)
- }
- sort.Sort(byName(items))
- ret := make([]fs.DirEntry, len(items))
- for i := range items {
- ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
- }
- return ret, nil
- }
- func (iofs IOFS) ReadFile(name string) ([]byte, error) {
- const op = "readfile"
- if !fs.ValidPath(name) {
- return nil, iofs.wrapError(op, name, fs.ErrInvalid)
- }
- bytes, err := ReadFile(iofs.Fs, name)
- if err != nil {
- return nil, iofs.wrapError(op, name, err)
- }
- return bytes, nil
- }
- func (iofs IOFS) Sub(dir string) (fs.FS, error) { return IOFS{NewBasePathFs(iofs.Fs, dir)}, nil }
- func (IOFS) wrapError(op, path string, err error) error {
- if _, ok := err.(*fs.PathError); ok {
- return err // don't need to wrap again
- }
- return &fs.PathError{
- Op: op,
- Path: path,
- Err: err,
- }
- }
- // readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
- type readDirFile struct {
- File
- }
- var _ fs.ReadDirFile = readDirFile{}
- func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
- items, err := r.File.Readdir(n)
- if err != nil {
- return nil, err
- }
- ret := make([]fs.DirEntry, len(items))
- for i := range items {
- ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
- }
- return ret, nil
- }
- // FromIOFS adopts io/fs.FS to use it as afero.Fs
- // Note that io/fs.FS is read-only so all mutating methods will return fs.PathError with fs.ErrPermission
- // To store modifications you may use afero.CopyOnWriteFs
- type FromIOFS struct {
- fs.FS
- }
- var _ Fs = FromIOFS{}
- func (f FromIOFS) Create(name string) (File, error) { return nil, notImplemented("create", name) }
- func (f FromIOFS) Mkdir(name string, perm os.FileMode) error { return notImplemented("mkdir", name) }
- func (f FromIOFS) MkdirAll(path string, perm os.FileMode) error {
- return notImplemented("mkdirall", path)
- }
- func (f FromIOFS) Open(name string) (File, error) {
- file, err := f.FS.Open(name)
- if err != nil {
- return nil, err
- }
- return fromIOFSFile{File: file, name: name}, nil
- }
- func (f FromIOFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
- return f.Open(name)
- }
- func (f FromIOFS) Remove(name string) error {
- return notImplemented("remove", name)
- }
- func (f FromIOFS) RemoveAll(path string) error {
- return notImplemented("removeall", path)
- }
- func (f FromIOFS) Rename(oldname, newname string) error {
- return notImplemented("rename", oldname)
- }
- func (f FromIOFS) Stat(name string) (os.FileInfo, error) { return fs.Stat(f.FS, name) }
- func (f FromIOFS) Name() string { return "fromiofs" }
- func (f FromIOFS) Chmod(name string, mode os.FileMode) error {
- return notImplemented("chmod", name)
- }
- func (f FromIOFS) Chown(name string, uid, gid int) error {
- return notImplemented("chown", name)
- }
- func (f FromIOFS) Chtimes(name string, atime time.Time, mtime time.Time) error {
- return notImplemented("chtimes", name)
- }
- type fromIOFSFile struct {
- fs.File
- name string
- }
- func (f fromIOFSFile) ReadAt(p []byte, off int64) (n int, err error) {
- readerAt, ok := f.File.(io.ReaderAt)
- if !ok {
- return -1, notImplemented("readat", f.name)
- }
- return readerAt.ReadAt(p, off)
- }
- func (f fromIOFSFile) Seek(offset int64, whence int) (int64, error) {
- seeker, ok := f.File.(io.Seeker)
- if !ok {
- return -1, notImplemented("seek", f.name)
- }
- return seeker.Seek(offset, whence)
- }
- func (f fromIOFSFile) Write(p []byte) (n int, err error) {
- return -1, notImplemented("write", f.name)
- }
- func (f fromIOFSFile) WriteAt(p []byte, off int64) (n int, err error) {
- return -1, notImplemented("writeat", f.name)
- }
- func (f fromIOFSFile) Name() string { return f.name }
- func (f fromIOFSFile) Readdir(count int) ([]os.FileInfo, error) {
- rdfile, ok := f.File.(fs.ReadDirFile)
- if !ok {
- return nil, notImplemented("readdir", f.name)
- }
- entries, err := rdfile.ReadDir(count)
- if err != nil {
- return nil, err
- }
- ret := make([]os.FileInfo, len(entries))
- for i := range entries {
- ret[i], err = entries[i].Info()
- if err != nil {
- return nil, err
- }
- }
- return ret, nil
- }
- func (f fromIOFSFile) Readdirnames(n int) ([]string, error) {
- rdfile, ok := f.File.(fs.ReadDirFile)
- if !ok {
- return nil, notImplemented("readdir", f.name)
- }
- entries, err := rdfile.ReadDir(n)
- if err != nil {
- return nil, err
- }
- ret := make([]string, len(entries))
- for i := range entries {
- ret[i] = entries[i].Name()
- }
- return ret, nil
- }
- func (f fromIOFSFile) Sync() error { return nil }
- func (f fromIOFSFile) Truncate(size int64) error {
- return notImplemented("truncate", f.name)
- }
- func (f fromIOFSFile) WriteString(s string) (ret int, err error) {
- return -1, notImplemented("writestring", f.name)
- }
- func notImplemented(op, path string) error {
- return &fs.PathError{Op: op, Path: path, Err: fs.ErrPermission}
- }
|