...

Source file src/github.com/spf13/afero/iofs.go

Documentation: github.com/spf13/afero

     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  }
   299  

View as plain text