gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

iofs.go (6545B)


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