vendor/github.com/spf13/afero/iofs.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
       
     1 // +build go1.16
       
     2 
       
     3 package afero
       
     4 
       
     5 import (
       
     6 	"io"
       
     7 	"io/fs"
       
     8 	"os"
       
     9 	"path"
       
    10 	"time"
       
    11 )
       
    12 
       
    13 // IOFS adopts afero.Fs to stdlib io/fs.FS
       
    14 type IOFS struct {
       
    15 	Fs
       
    16 }
       
    17 
       
    18 func NewIOFS(fs Fs) IOFS {
       
    19 	return IOFS{Fs: fs}
       
    20 }
       
    21 
       
    22 var (
       
    23 	_ fs.FS         = IOFS{}
       
    24 	_ fs.GlobFS     = IOFS{}
       
    25 	_ fs.ReadDirFS  = IOFS{}
       
    26 	_ fs.ReadFileFS = IOFS{}
       
    27 	_ fs.StatFS     = IOFS{}
       
    28 	_ fs.SubFS      = IOFS{}
       
    29 )
       
    30 
       
    31 func (iofs IOFS) Open(name string) (fs.File, error) {
       
    32 	const op = "open"
       
    33 
       
    34 	// by convention for fs.FS implementations we should perform this check
       
    35 	if !fs.ValidPath(name) {
       
    36 		return nil, iofs.wrapError(op, name, fs.ErrInvalid)
       
    37 	}
       
    38 
       
    39 	file, err := iofs.Fs.Open(name)
       
    40 	if err != nil {
       
    41 		return nil, iofs.wrapError(op, name, err)
       
    42 	}
       
    43 
       
    44 	// file should implement fs.ReadDirFile
       
    45 	if _, ok := file.(fs.ReadDirFile); !ok {
       
    46 		file = readDirFile{file}
       
    47 	}
       
    48 
       
    49 	return file, nil
       
    50 }
       
    51 
       
    52 func (iofs IOFS) Glob(pattern string) ([]string, error) {
       
    53 	const op = "glob"
       
    54 
       
    55 	// afero.Glob does not perform this check but it's required for implementations
       
    56 	if _, err := path.Match(pattern, ""); err != nil {
       
    57 		return nil, iofs.wrapError(op, pattern, err)
       
    58 	}
       
    59 
       
    60 	items, err := Glob(iofs.Fs, pattern)
       
    61 	if err != nil {
       
    62 		return nil, iofs.wrapError(op, pattern, err)
       
    63 	}
       
    64 
       
    65 	return items, nil
       
    66 }
       
    67 
       
    68 func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) {
       
    69 	items, err := ReadDir(iofs.Fs, name)
       
    70 	if err != nil {
       
    71 		return nil, iofs.wrapError("readdir", name, err)
       
    72 	}
       
    73 
       
    74 	ret := make([]fs.DirEntry, len(items))
       
    75 	for i := range items {
       
    76 		ret[i] = dirEntry{items[i]}
       
    77 	}
       
    78 
       
    79 	return ret, nil
       
    80 }
       
    81 
       
    82 func (iofs IOFS) ReadFile(name string) ([]byte, error) {
       
    83 	const op = "readfile"
       
    84 
       
    85 	if !fs.ValidPath(name) {
       
    86 		return nil, iofs.wrapError(op, name, fs.ErrInvalid)
       
    87 	}
       
    88 
       
    89 	bytes, err := ReadFile(iofs.Fs, name)
       
    90 	if err != nil {
       
    91 		return nil, iofs.wrapError(op, name, err)
       
    92 	}
       
    93 
       
    94 	return bytes, nil
       
    95 }
       
    96 
       
    97 func (iofs IOFS) Sub(dir string) (fs.FS, error) { return IOFS{NewBasePathFs(iofs.Fs, dir)}, nil }
       
    98 
       
    99 func (IOFS) wrapError(op, path string, err error) error {
       
   100 	if _, ok := err.(*fs.PathError); ok {
       
   101 		return err // don't need to wrap again
       
   102 	}
       
   103 
       
   104 	return &fs.PathError{
       
   105 		Op:   op,
       
   106 		Path: path,
       
   107 		Err:  err,
       
   108 	}
       
   109 }
       
   110 
       
   111 // dirEntry provides adapter from os.FileInfo to fs.DirEntry
       
   112 type dirEntry struct {
       
   113 	fs.FileInfo
       
   114 }
       
   115 
       
   116 var _ fs.DirEntry = dirEntry{}
       
   117 
       
   118 func (d dirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
       
   119 
       
   120 func (d dirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
       
   121 
       
   122 // readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
       
   123 type readDirFile struct {
       
   124 	File
       
   125 }
       
   126 
       
   127 var _ fs.ReadDirFile = readDirFile{}
       
   128 
       
   129 func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
       
   130 	items, err := r.File.Readdir(n)
       
   131 	if err != nil {
       
   132 		return nil, err
       
   133 	}
       
   134 
       
   135 	ret := make([]fs.DirEntry, len(items))
       
   136 	for i := range items {
       
   137 		ret[i] = dirEntry{items[i]}
       
   138 	}
       
   139 
       
   140 	return ret, nil
       
   141 }
       
   142 
       
   143 // FromIOFS adopts io/fs.FS to use it as afero.Fs
       
   144 // Note that io/fs.FS is read-only so all mutating methods will return fs.PathError with fs.ErrPermission
       
   145 // To store modifications you may use afero.CopyOnWriteFs
       
   146 type FromIOFS struct {
       
   147 	fs.FS
       
   148 }
       
   149 
       
   150 var _ Fs = FromIOFS{}
       
   151 
       
   152 func (f FromIOFS) Create(name string) (File, error) { return nil, notImplemented("create", name) }
       
   153 
       
   154 func (f FromIOFS) Mkdir(name string, perm os.FileMode) error { return notImplemented("mkdir", name) }
       
   155 
       
   156 func (f FromIOFS) MkdirAll(path string, perm os.FileMode) error {
       
   157 	return notImplemented("mkdirall", path)
       
   158 }
       
   159 
       
   160 func (f FromIOFS) Open(name string) (File, error) {
       
   161 	file, err := f.FS.Open(name)
       
   162 	if err != nil {
       
   163 		return nil, err
       
   164 	}
       
   165 
       
   166 	return fromIOFSFile{File: file, name: name}, nil
       
   167 }
       
   168 
       
   169 func (f FromIOFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
       
   170 	return f.Open(name)
       
   171 }
       
   172 
       
   173 func (f FromIOFS) Remove(name string) error {
       
   174 	return notImplemented("remove", name)
       
   175 }
       
   176 
       
   177 func (f FromIOFS) RemoveAll(path string) error {
       
   178 	return notImplemented("removeall", path)
       
   179 }
       
   180 
       
   181 func (f FromIOFS) Rename(oldname, newname string) error {
       
   182 	return notImplemented("rename", oldname)
       
   183 }
       
   184 
       
   185 func (f FromIOFS) Stat(name string) (os.FileInfo, error) { return fs.Stat(f.FS, name) }
       
   186 
       
   187 func (f FromIOFS) Name() string { return "fromiofs" }
       
   188 
       
   189 func (f FromIOFS) Chmod(name string, mode os.FileMode) error {
       
   190 	return notImplemented("chmod", name)
       
   191 }
       
   192 
       
   193 func (f FromIOFS) Chown(name string, uid, gid int) error {
       
   194 	return notImplemented("chown", name)
       
   195 }
       
   196 
       
   197 func (f FromIOFS) Chtimes(name string, atime time.Time, mtime time.Time) error {
       
   198 	return notImplemented("chtimes", name)
       
   199 }
       
   200 
       
   201 type fromIOFSFile struct {
       
   202 	fs.File
       
   203 	name string
       
   204 }
       
   205 
       
   206 func (f fromIOFSFile) ReadAt(p []byte, off int64) (n int, err error) {
       
   207 	readerAt, ok := f.File.(io.ReaderAt)
       
   208 	if !ok {
       
   209 		return -1, notImplemented("readat", f.name)
       
   210 	}
       
   211 
       
   212 	return readerAt.ReadAt(p, off)
       
   213 }
       
   214 
       
   215 func (f fromIOFSFile) Seek(offset int64, whence int) (int64, error) {
       
   216 	seeker, ok := f.File.(io.Seeker)
       
   217 	if !ok {
       
   218 		return -1, notImplemented("seek", f.name)
       
   219 	}
       
   220 
       
   221 	return seeker.Seek(offset, whence)
       
   222 }
       
   223 
       
   224 func (f fromIOFSFile) Write(p []byte) (n int, err error) {
       
   225 	return -1, notImplemented("write", f.name)
       
   226 }
       
   227 
       
   228 func (f fromIOFSFile) WriteAt(p []byte, off int64) (n int, err error) {
       
   229 	return -1, notImplemented("writeat", f.name)
       
   230 }
       
   231 
       
   232 func (f fromIOFSFile) Name() string { return f.name }
       
   233 
       
   234 func (f fromIOFSFile) Readdir(count int) ([]os.FileInfo, error) {
       
   235 	rdfile, ok := f.File.(fs.ReadDirFile)
       
   236 	if !ok {
       
   237 		return nil, notImplemented("readdir", f.name)
       
   238 	}
       
   239 
       
   240 	entries, err := rdfile.ReadDir(count)
       
   241 	if err != nil {
       
   242 		return nil, err
       
   243 	}
       
   244 
       
   245 	ret := make([]os.FileInfo, len(entries))
       
   246 	for i := range entries {
       
   247 		ret[i], err = entries[i].Info()
       
   248 
       
   249 		if err != nil {
       
   250 			return nil, err
       
   251 		}
       
   252 	}
       
   253 
       
   254 	return ret, nil
       
   255 }
       
   256 
       
   257 func (f fromIOFSFile) Readdirnames(n int) ([]string, error) {
       
   258 	rdfile, ok := f.File.(fs.ReadDirFile)
       
   259 	if !ok {
       
   260 		return nil, notImplemented("readdir", f.name)
       
   261 	}
       
   262 
       
   263 	entries, err := rdfile.ReadDir(n)
       
   264 	if err != nil {
       
   265 		return nil, err
       
   266 	}
       
   267 
       
   268 	ret := make([]string, len(entries))
       
   269 	for i := range entries {
       
   270 		ret[i] = entries[i].Name()
       
   271 	}
       
   272 
       
   273 	return ret, nil
       
   274 }
       
   275 
       
   276 func (f fromIOFSFile) Sync() error { return nil }
       
   277 
       
   278 func (f fromIOFSFile) Truncate(size int64) error {
       
   279 	return notImplemented("truncate", f.name)
       
   280 }
       
   281 
       
   282 func (f fromIOFSFile) WriteString(s string) (ret int, err error) {
       
   283 	return -1, notImplemented("writestring", f.name)
       
   284 }
       
   285 
       
   286 func notImplemented(op, path string) error {
       
   287 	return &fs.PathError{Op: op, Path: path, Err: fs.ErrPermission}
       
   288 }