github.com/avfs/avfs@v0.33.1-0.20240303173310-c6ba67c33eb7/vfs/memfs/memfs.go (about)

     1  //
     2  //  Copyright 2020 The AVFS authors
     3  //
     4  //  Licensed under the Apache License, Version 2.0 (the "License");
     5  //  you may not use this file except in compliance with the License.
     6  //  You may obtain a copy of the License at
     7  //
     8  //  	http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  //  Unless required by applicable law or agreed to in writing, software
    11  //  distributed under the License is distributed on an "AS IS" BASIS,
    12  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  //  See the License for the specific language governing permissions and
    14  //  limitations under the License.
    15  //
    16  
    17  // Package memfs implements an in memory file system.
    18  //
    19  // it supports several features :
    20  //   - can emulate Linux or Windows systems regardless of the host system
    21  //   - checks files permissions
    22  //   - supports different Identity managers
    23  //   - supports multiple concurrent users
    24  //   - supports Hard links
    25  //   - supports symbolic links
    26  package memfs
    27  
    28  import (
    29  	"io/fs"
    30  	"os"
    31  	"time"
    32  
    33  	"github.com/avfs/avfs"
    34  )
    35  
    36  // Abs returns an absolute representation of path.
    37  // If the path is not absolute it will be joined with the current
    38  // working directory to turn it into an absolute path. The absolute
    39  // path name for a given file is not guaranteed to be unique.
    40  // Abs calls [Clean] on the result.
    41  func (vfs *MemFS) Abs(path string) (string, error) {
    42  	if vfs.IsAbs(path) {
    43  		return vfs.Clean(path), nil
    44  	}
    45  
    46  	return vfs.Join(vfs.CurDir(), path), nil
    47  }
    48  
    49  // Base returns the last element of path.
    50  // Trailing path separators are removed before extracting the last element.
    51  // If the path is empty, Base returns ".".
    52  // If the path consists entirely of separators, Base returns a single separator.
    53  func (vfs *MemFS) Base(path string) string {
    54  	return avfs.Base(vfs, path)
    55  }
    56  
    57  // Chdir changes the current working directory to the named directory.
    58  // If there is an error, it will be of type *PathError.
    59  func (vfs *MemFS) Chdir(dir string) error {
    60  	const op = "chdir"
    61  
    62  	_, child, pi, err := vfs.searchNode(dir, slmLstat)
    63  	if err != vfs.err.FileExists {
    64  		return &fs.PathError{Op: op, Path: dir, Err: err}
    65  	}
    66  
    67  	c, ok := child.(*dirNode)
    68  	if !ok {
    69  		err = vfs.err.NotADirectory
    70  		if vfs.OSType() == avfs.OsWindows {
    71  			err = avfs.ErrWinDirNameInvalid
    72  		}
    73  
    74  		return &fs.PathError{Op: op, Path: dir, Err: err}
    75  	}
    76  
    77  	c.mu.RLock()
    78  	defer c.mu.RUnlock()
    79  
    80  	if !c.checkPermission(avfs.OpenLookup, vfs.User()) {
    81  		return &fs.PathError{Op: op, Path: dir, Err: vfs.err.PermDenied}
    82  	}
    83  
    84  	_ = vfs.SetCurDir(pi.Path())
    85  
    86  	return nil
    87  }
    88  
    89  // Chmod changes the mode of the named file to mode.
    90  // If the file is a symbolic link, it changes the mode of the link's target.
    91  // If there is an error, it will be of type *PathError.
    92  //
    93  // A different subset of the mode bits are used, depending on the
    94  // operating system.
    95  //
    96  // On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
    97  // ModeSticky are used.
    98  //
    99  // On Windows, only the 0200 bit (owner writable) of mode is used; it
   100  // controls whether the file's read-only attribute is set or cleared.
   101  // The other bits are currently unused. For compatibility with Go 1.12
   102  // and earlier, use a non-zero mode. Use mode 0400 for a read-only
   103  // file and 0600 for a readable+writable file.
   104  //
   105  // On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive,
   106  // and ModeTemporary are used.
   107  func (vfs *MemFS) Chmod(name string, mode fs.FileMode) error {
   108  	const op = "chmod"
   109  
   110  	_, child, _, err := vfs.searchNode(name, slmEval)
   111  	if err != vfs.err.FileExists || child == nil {
   112  		return &fs.PathError{Op: op, Path: name, Err: err}
   113  	}
   114  
   115  	child.Lock()
   116  	defer child.Unlock()
   117  
   118  	if !child.setMode(mode, vfs.User()) {
   119  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.OpNotPermitted}
   120  	}
   121  
   122  	return nil
   123  }
   124  
   125  // Chown changes the numeric uid and gid of the named file.
   126  // If the file is a symbolic link, it changes the uid and gid of the link's target.
   127  // A uid or gid of -1 means to not change that value.
   128  // If there is an error, it will be of type *PathError.
   129  //
   130  // On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
   131  // EPLAN9 error, wrapped in *PathError.
   132  func (vfs *MemFS) Chown(name string, uid, gid int) error {
   133  	const op = "chown"
   134  
   135  	if (vfs.HasFeature(avfs.FeatIdentityMgr) && !vfs.User().IsAdmin()) || vfs.OSType() == avfs.OsWindows {
   136  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.OpNotPermitted}
   137  	}
   138  
   139  	_, child, _, err := vfs.searchNode(name, slmEval)
   140  	if err != vfs.err.FileExists || child == nil {
   141  		return &fs.PathError{Op: op, Path: name, Err: err}
   142  	}
   143  
   144  	child.Lock()
   145  	child.setOwner(uid, gid)
   146  	child.Unlock()
   147  
   148  	return nil
   149  }
   150  
   151  // Chtimes changes the access and modification times of the named
   152  // file, similar to the Unix utime() or utimes() functions.
   153  //
   154  // The underlying file system may truncate or round the values to a
   155  // less precise time unit.
   156  // If there is an error, it will be of type *PathError.
   157  func (vfs *MemFS) Chtimes(name string, _, mtime time.Time) error {
   158  	const op = "chtimes"
   159  
   160  	_, child, _, err := vfs.searchNode(name, slmLstat)
   161  	if err != vfs.err.FileExists || child == nil {
   162  		return &fs.PathError{Op: op, Path: name, Err: err}
   163  	}
   164  
   165  	child.Lock()
   166  	defer child.Unlock()
   167  
   168  	if !child.setModTime(mtime, vfs.User()) {
   169  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.OpNotPermitted}
   170  	}
   171  
   172  	return nil
   173  }
   174  
   175  // Clean returns the shortest path name equivalent to path
   176  // by purely lexical processing. It applies the following rules
   177  // iteratively until no further processing can be done:
   178  //
   179  //  1. Replace multiple Separator elements with a single one.
   180  //  2. Eliminate each . path name element (the current directory).
   181  //  3. Eliminate each inner .. path name element (the parent directory)
   182  //     along with the non-.. element that precedes it.
   183  //  4. Eliminate .. elements that begin a rooted path:
   184  //     that is, replace "/.." by "/" at the beginning of a path,
   185  //     assuming Separator is '/'.
   186  //
   187  // The returned path ends in a slash only if it represents a root directory,
   188  // such as "/" on Unix or `C:\` on Windows.
   189  //
   190  // Finally, any occurrences of slash are replaced by Separator.
   191  //
   192  // If the result of this process is an empty string, Clean
   193  // returns the string ".".
   194  //
   195  // See also Rob Pike, “Lexical File Names in Plan 9 or
   196  // Getting Dot-Dot Right,”
   197  // https://9p.io/sys/doc/lexnames.html
   198  func (vfs *MemFS) Clean(path string) string {
   199  	return avfs.Clean(vfs, path)
   200  }
   201  
   202  // Create creates or truncates the named file. If the file already exists,
   203  // it is truncated. If the file does not exist, it is created with mode 0666
   204  // (before umask). If successful, methods on the returned DummyFile can
   205  // be used for I/O; the associated file descriptor has mode O_RDWR.
   206  // If there is an error, it will be of type *PathError.
   207  func (vfs *MemFS) Create(name string) (avfs.File, error) {
   208  	return avfs.Create(vfs, name)
   209  }
   210  
   211  // CreateTemp creates a new temporary file in the directory dir,
   212  // opens the file for reading and writing, and returns the resulting file.
   213  // The filename is generated by taking pattern and adding a random string to the end.
   214  // If pattern includes a "*", the random string replaces the last "*".
   215  // If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir.
   216  // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
   217  // The caller can use the file's Name method to find the pathname of the file.
   218  // It is the caller's responsibility to remove the file when it is no longer needed.
   219  func (vfs *MemFS) CreateTemp(dir, pattern string) (avfs.File, error) {
   220  	return avfs.CreateTemp(vfs, dir, pattern)
   221  }
   222  
   223  // Dir returns all but the last element of path, typically the path's directory.
   224  // After dropping the final element, Dir calls Clean on the path and trailing
   225  // slashes are removed.
   226  // If the path is empty, Dir returns ".".
   227  // If the path consists entirely of separators, Dir returns a single separator.
   228  // The returned path does not end in a separator unless it is the root directory.
   229  func (vfs *MemFS) Dir(path string) string {
   230  	return avfs.Dir(vfs, path)
   231  }
   232  
   233  // EvalSymlinks returns the path name after the evaluation of any symbolic
   234  // links.
   235  // If path is relative the result will be relative to the current directory,
   236  // unless one of the components is an absolute symbolic link.
   237  // EvalSymlinks calls Clean on the result.
   238  func (vfs *MemFS) EvalSymlinks(path string) (string, error) {
   239  	const op = "lstat"
   240  
   241  	_, _, pi, err := vfs.searchNode(path, slmEval)
   242  	if err != vfs.err.FileExists {
   243  		return "", &fs.PathError{Op: op, Path: pi.LeftPart(), Err: err}
   244  	}
   245  
   246  	return pi.Path(), nil
   247  }
   248  
   249  // FromSlash returns the result of replacing each slash ('/') character
   250  // in path with a separator character. Multiple slashes are replaced
   251  // by multiple separators.
   252  func (vfs *MemFS) FromSlash(path string) string {
   253  	return avfs.FromSlash(vfs, path)
   254  }
   255  
   256  // Getwd returns a rooted name link corresponding to the
   257  // current directory. If the current directory can be
   258  // reached via multiple paths (due to symbolic links),
   259  // Getwd may return any one of them.
   260  func (vfs *MemFS) Getwd() (dir string, err error) {
   261  	return vfs.CurDir(), nil
   262  }
   263  
   264  // Glob returns the names of all files matching pattern or nil
   265  // if there is no matching file. The syntax of patterns is the same
   266  // as in Match. The pattern may describe hierarchical names such as
   267  // /usr/*/bin/ed (assuming the Separator is '/').
   268  //
   269  // Glob ignores file system errors such as I/O errors reading directories.
   270  // The only possible returned error is ErrBadPattern, when pattern
   271  // is malformed.
   272  func (vfs *MemFS) Glob(pattern string) (matches []string, err error) {
   273  	return avfs.Glob(vfs, pattern)
   274  }
   275  
   276  // IsAbs reports whether the path is absolute.
   277  func (vfs *MemFS) IsAbs(path string) bool {
   278  	return avfs.IsAbs(vfs, path)
   279  }
   280  
   281  // IsPathSeparator reports whether c is a directory separator character.
   282  func (vfs *MemFS) IsPathSeparator(c uint8) bool {
   283  	return avfs.IsPathSeparator(vfs, c)
   284  }
   285  
   286  // Join joins any number of path elements into a single path,
   287  // separating them with an OS specific Separator. Empty elements
   288  // are ignored. The result is Cleaned. However, if the argument
   289  // list is empty or all its elements are empty, Join returns
   290  // an empty string.
   291  // On Windows, the result will only be a UNC path if the first
   292  // non-empty element is a UNC path.
   293  func (vfs *MemFS) Join(elem ...string) string {
   294  	return avfs.Join(vfs, elem...)
   295  }
   296  
   297  // Lchown changes the numeric uid and gid of the named file.
   298  // If the file is a symbolic link, it changes the uid and gid of the link itself.
   299  // If there is an error, it will be of type *PathError.
   300  //
   301  // On Windows, it always returns the syscall.EWINDOWS error, wrapped
   302  // in *PathError.
   303  func (vfs *MemFS) Lchown(name string, uid, gid int) error {
   304  	const op = "lchown"
   305  
   306  	if (vfs.HasFeature(avfs.FeatIdentityMgr) && !vfs.User().IsAdmin()) || vfs.OSType() == avfs.OsWindows {
   307  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.OpNotPermitted}
   308  	}
   309  
   310  	_, child, _, err := vfs.searchNode(name, slmLstat)
   311  	if err != vfs.err.FileExists || child == nil {
   312  		return &fs.PathError{Op: op, Path: name, Err: err}
   313  	}
   314  
   315  	child.Lock()
   316  	child.setOwner(uid, gid)
   317  	child.Unlock()
   318  
   319  	return nil
   320  }
   321  
   322  // Link creates newname as a hard link to the oldname file.
   323  // If there is an error, it will be of type *LinkError.
   324  func (vfs *MemFS) Link(oldname, newname string) error {
   325  	const op = "link"
   326  
   327  	_, oChild, _, oerr := vfs.searchNode(oldname, slmLstat)
   328  	if oerr != vfs.err.FileExists || oChild == nil {
   329  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: oerr}
   330  	}
   331  
   332  	nParent, _, pi, nerr := vfs.searchNode(newname, slmLstat)
   333  	if !vfs.isNotExist(nerr) {
   334  		if vfs.OSType() == avfs.OsWindows {
   335  			nerr = avfs.ErrWinAlreadyExists
   336  		}
   337  
   338  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: nerr}
   339  	}
   340  
   341  	nParent.mu.Lock()
   342  	defer nParent.mu.Unlock()
   343  
   344  	if !nParent.checkPermission(avfs.OpenWrite, vfs.User()) {
   345  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: vfs.err.PermDenied}
   346  	}
   347  
   348  	c, ok := oChild.(*fileNode)
   349  	if !ok {
   350  		err := error(avfs.ErrOpNotPermitted)
   351  		if vfs.OSType() == avfs.OsWindows {
   352  			err = avfs.ErrWinAccessDenied
   353  		}
   354  
   355  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: err}
   356  	}
   357  
   358  	c.mu.Lock()
   359  	nParent.addChild(pi.Part(), c)
   360  
   361  	c.nlink++
   362  	c.mu.Unlock()
   363  
   364  	return nil
   365  }
   366  
   367  // Lstat returns a FileInfo describing the named file.
   368  // If the file is a symbolic link, the returned FileInfo
   369  // describes the symbolic link. Lstat makes no attempt to follow the link.
   370  // If there is an error, it will be of type *PathError.
   371  func (vfs *MemFS) Lstat(path string) (fs.FileInfo, error) {
   372  	op := "lstat"
   373  	if vfs.OSType() == avfs.OsWindows {
   374  		op = "CreateFile"
   375  	}
   376  
   377  	_, child, pi, err := vfs.searchNode(path, slmLstat)
   378  	if err != vfs.err.FileExists || child == nil {
   379  		return nil, &fs.PathError{Op: op, Path: path, Err: err}
   380  	}
   381  
   382  	fst := child.fillStatFrom(pi.Part())
   383  
   384  	return fst, nil
   385  }
   386  
   387  // Match reports whether name matches the shell file name pattern.
   388  // The pattern syntax is:
   389  //
   390  //	pattern:
   391  //		{ term }
   392  //	term:
   393  //		'*'         matches any sequence of non-Separator characters
   394  //		'?'         matches any single non-Separator character
   395  //		'[' [ '^' ] { character-range } ']'
   396  //		            character class (must be non-empty)
   397  //		c           matches character c (c != '*', '?', '\\', '[')
   398  //		'\\' c      matches character c
   399  //
   400  //	character-range:
   401  //		c           matches character c (c != '\\', '-', ']')
   402  //		'\\' c      matches character c
   403  //		lo '-' hi   matches character c for lo <= c <= hi
   404  //
   405  // Match requires pattern to match all of name, not just a substring.
   406  // The only possible returned error is ErrBadPattern, when pattern
   407  // is malformed.
   408  //
   409  // On Windows, escaping is disabled. Instead, '\\' is treated as
   410  // path separator.
   411  func (vfs *MemFS) Match(pattern, name string) (matched bool, err error) {
   412  	return avfs.Match(vfs, pattern, name)
   413  }
   414  
   415  // Mkdir creates a new directory with the specified name and permission
   416  // bits (before umask).
   417  // If there is an error, it will be of type *PathError.
   418  func (vfs *MemFS) Mkdir(name string, perm fs.FileMode) error {
   419  	const op = "mkdir"
   420  
   421  	if name == "" {
   422  		return &fs.PathError{Op: op, Path: "", Err: vfs.err.NoSuchDir}
   423  	}
   424  
   425  	parent, _, pi, err := vfs.searchNode(name, slmEval)
   426  	if !vfs.isNotExist(err) || !pi.IsLast() {
   427  		return &fs.PathError{Op: op, Path: name, Err: err}
   428  	}
   429  
   430  	parent.mu.Lock()
   431  	defer parent.mu.Unlock()
   432  
   433  	if !parent.checkPermission(avfs.OpenWrite|avfs.OpenLookup, vfs.User()) {
   434  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.PermDenied}
   435  	}
   436  
   437  	part := pi.Part()
   438  	if parent.children[part] != nil {
   439  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.FileExists}
   440  	}
   441  
   442  	_ = vfs.createDir(parent, part, perm)
   443  
   444  	return nil
   445  }
   446  
   447  // MkdirAll creates a directory named name,
   448  // along with any necessary parents, and returns nil,
   449  // or else returns an error.
   450  // The permission bits perm (before umask) are used for all
   451  // directories that MkdirAll creates.
   452  // If name is already a directory, MkdirAll does nothing
   453  // and returns nil.
   454  func (vfs *MemFS) MkdirAll(path string, perm fs.FileMode) error {
   455  	const op = "mkdir"
   456  
   457  	parent, child, pi, err := vfs.searchNode(path, slmEval)
   458  	switch child.(type) {
   459  	case *dirNode:
   460  		if err != vfs.err.FileExists {
   461  			return &fs.PathError{Op: op, Path: path, Err: err}
   462  		}
   463  
   464  		return nil
   465  	case *fileNode:
   466  		return &fs.PathError{Op: op, Path: pi.LeftPart(), Err: vfs.err.NotADirectory}
   467  	}
   468  
   469  	parent.mu.Lock()
   470  	defer parent.mu.Unlock()
   471  
   472  	if !parent.checkPermission(avfs.OpenWrite|avfs.OpenLookup, vfs.User()) {
   473  		return &fs.PathError{Op: op, Path: path, Err: vfs.err.PermDenied}
   474  	}
   475  
   476  	dn := parent
   477  
   478  	for {
   479  		part := pi.Part()
   480  		if dn.children[part] != nil {
   481  			break
   482  		}
   483  
   484  		dn = vfs.createDir(dn, part, perm)
   485  
   486  		if !pi.Next() {
   487  			break
   488  		}
   489  	}
   490  
   491  	return nil
   492  }
   493  
   494  // MkdirTemp creates a new temporary directory in the directory dir
   495  // and returns the pathname of the new directory.
   496  // The new directory's name is generated by adding a random string to the end of pattern.
   497  // If pattern includes a "*", the random string replaces the last "*" instead.
   498  // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
   499  // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
   500  // It is the caller's responsibility to remove the directory when it is no longer needed.
   501  func (vfs *MemFS) MkdirTemp(dir, pattern string) (string, error) {
   502  	return avfs.MkdirTemp(vfs, dir, pattern)
   503  }
   504  
   505  // Open opens the named file for reading. If successful, methods on
   506  // the returned file can be used for reading; the associated file
   507  // descriptor has mode O_RDONLY.
   508  // If there is an error, it will be of type *PathError.
   509  func (vfs *MemFS) Open(name string) (avfs.File, error) {
   510  	return vfs.OpenFile(name, os.O_RDONLY, 0)
   511  }
   512  
   513  // OpenFile is the generalized open call; most users will use Open
   514  // or Create instead. It opens the named file with specified flag
   515  // (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag
   516  // is passed, it is created with mode perm (before umask). If successful,
   517  // methods on the returned File can be used for I/O.
   518  // If there is an error, it will be of type *PathError.
   519  func (vfs *MemFS) OpenFile(name string, flag int, perm fs.FileMode) (avfs.File, error) {
   520  	const op = "open"
   521  
   522  	at := int64(0)
   523  	om := avfs.ToOpenMode(flag)
   524  
   525  	parent, child, pi, err := vfs.searchNode(name, slmEval)
   526  	if err != vfs.err.FileExists && !vfs.isNotExist(err) || !pi.IsLast() {
   527  		return &MemFile{}, &fs.PathError{Op: op, Path: name, Err: err}
   528  	}
   529  
   530  	if vfs.isNotExist(err) {
   531  		if om&avfs.OpenCreate == 0 {
   532  			return &MemFile{}, &fs.PathError{Op: op, Path: name, Err: err}
   533  		}
   534  
   535  		parent.mu.Lock()
   536  		defer parent.mu.Unlock()
   537  
   538  		if om&avfs.OpenWrite == 0 || !parent.checkPermission(avfs.OpenWrite|avfs.OpenLookup, vfs.User()) {
   539  			return &MemFile{}, &fs.PathError{Op: op, Path: name, Err: vfs.err.PermDenied}
   540  		}
   541  
   542  		part := pi.Part()
   543  
   544  		child = parent.children[part]
   545  		if child == nil {
   546  			child = vfs.createFile(parent, part, perm)
   547  			f := &MemFile{
   548  				nd:       child,
   549  				vfs:      vfs,
   550  				name:     name,
   551  				at:       at,
   552  				openMode: om,
   553  			}
   554  
   555  			return f, nil
   556  		}
   557  	}
   558  
   559  	switch c := child.(type) {
   560  	case *fileNode:
   561  		c.mu.Lock()
   562  		defer c.mu.Unlock()
   563  
   564  		if !c.checkPermission(om, vfs.User()) {
   565  			return &MemFile{}, &fs.PathError{Op: op, Path: name, Err: vfs.err.PermDenied}
   566  		}
   567  
   568  		if om&avfs.OpenCreateExcl != 0 {
   569  			return &MemFile{}, &fs.PathError{Op: op, Path: name, Err: vfs.err.FileExists}
   570  		}
   571  
   572  		if om&avfs.OpenTruncate != 0 {
   573  			c.truncate(0)
   574  		}
   575  
   576  		if om&avfs.OpenAppend != 0 {
   577  			at = c.size()
   578  		}
   579  
   580  	case *dirNode:
   581  		c.mu.Lock()
   582  		defer c.mu.Unlock()
   583  
   584  		if om&avfs.OpenWrite != 0 {
   585  			return (*MemFile)(nil), &fs.PathError{Op: op, Path: name, Err: vfs.err.IsADirectory}
   586  		}
   587  
   588  		if !c.checkPermission(om, vfs.User()) {
   589  			return &MemFile{}, &fs.PathError{Op: op, Path: name, Err: vfs.err.PermDenied}
   590  		}
   591  	}
   592  
   593  	f := &MemFile{
   594  		nd:       child,
   595  		vfs:      vfs,
   596  		name:     name,
   597  		at:       at,
   598  		openMode: om,
   599  	}
   600  
   601  	return f, nil
   602  }
   603  
   604  // ReadDir reads the named directory,
   605  // returning all its directory entries sorted by filename.
   606  // If an error occurs reading the directory,
   607  // ReadDir returns the entries it was able to read before the error,
   608  // along with the error.
   609  func (vfs *MemFS) ReadDir(name string) ([]fs.DirEntry, error) {
   610  	return avfs.ReadDir(vfs, name)
   611  }
   612  
   613  // ReadFile reads the named file and returns the contents.
   614  // A successful call returns err == nil, not err == EOF.
   615  // Because ReadFile reads the whole file, it does not treat an EOF from Read
   616  // as an error to be reported.
   617  func (vfs *MemFS) ReadFile(name string) ([]byte, error) {
   618  	return avfs.ReadFile(vfs, name)
   619  }
   620  
   621  // Readlink returns the destination of the named symbolic link.
   622  // If there is an error, it will be of type *PathError.
   623  func (vfs *MemFS) Readlink(name string) (string, error) {
   624  	const op = "readlink"
   625  
   626  	_, child, _, err := vfs.searchNode(name, slmLstat)
   627  	if err != vfs.err.FileExists {
   628  		return "", &fs.PathError{Op: op, Path: name, Err: err}
   629  	}
   630  
   631  	sl, ok := child.(*symlinkNode)
   632  	if !ok {
   633  		err = avfs.ErrInvalidArgument
   634  		if vfs.OSType() == avfs.OsWindows {
   635  			err = avfs.ErrWinNotReparsePoint
   636  		}
   637  
   638  		return "", &fs.PathError{Op: op, Path: name, Err: err}
   639  	}
   640  
   641  	return sl.link, nil
   642  }
   643  
   644  // Rel returns a relative path that is lexically equivalent to targpath when
   645  // joined to basepath with an intervening separator. That is,
   646  // Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
   647  // On success, the returned path will always be relative to basepath,
   648  // even if basepath and targpath share no elements.
   649  // An error is returned if targpath can't be made relative to basepath or if
   650  // knowing the current working directory would be necessary to compute it.
   651  // Rel calls Clean on the result.
   652  func (vfs *MemFS) Rel(basepath, targpath string) (string, error) {
   653  	return avfs.Rel(vfs, basepath, targpath)
   654  }
   655  
   656  // Remove removes the named file or (empty) directory.
   657  // If there is an error, it will be of type *PathError.
   658  func (vfs *MemFS) Remove(name string) error {
   659  	const op = "remove"
   660  
   661  	parent, child, pi, err := vfs.searchNode(name, slmLstat)
   662  	if err != vfs.err.FileExists || child == nil {
   663  		return &fs.PathError{Op: op, Path: name, Err: err}
   664  	}
   665  
   666  	parent.mu.Lock()
   667  	defer parent.mu.Unlock()
   668  
   669  	if !parent.checkPermission(avfs.OpenWrite, vfs.User()) {
   670  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.PermDenied}
   671  	}
   672  
   673  	child.Lock()
   674  	defer child.Unlock()
   675  
   676  	if c, ok := child.(*dirNode); ok {
   677  		if len(c.children) != 0 {
   678  			return &fs.PathError{Op: op, Path: name, Err: vfs.err.DirNotEmpty}
   679  		}
   680  	}
   681  
   682  	part := pi.Part()
   683  	if parent.children[part] == nil {
   684  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.NoSuchDir}
   685  	}
   686  
   687  	parent.removeChild(part)
   688  	child.delete()
   689  
   690  	return nil
   691  }
   692  
   693  // RemoveAll removes path and any children it contains.
   694  // It removes everything it can but returns the first error
   695  // it encounters. If the path does not exist, RemoveAll
   696  // returns nil (no error).
   697  // If there is an error, it will be of type *PathError.
   698  func (vfs *MemFS) RemoveAll(path string) error {
   699  	const op = "unlinkat"
   700  
   701  	if path == "" {
   702  		// fail silently to retain compatibility with previous behavior of RemoveAll.
   703  		return nil
   704  	}
   705  
   706  	parent, child, pi, err := vfs.searchNode(path, slmLstat)
   707  	if vfs.isNotExist(err) {
   708  		return nil
   709  	}
   710  
   711  	if err != vfs.err.FileExists {
   712  		return &fs.PathError{Op: op, Path: path, Err: err}
   713  	}
   714  
   715  	parent.mu.Lock()
   716  	defer parent.mu.Unlock()
   717  
   718  	if c, ok := child.(*dirNode); ok && len(c.children) != 0 {
   719  		err = vfs.removeAll(c)
   720  		if err != nil {
   721  			return &fs.PathError{Op: op, Path: path, Err: err}
   722  		}
   723  	}
   724  
   725  	if ok := parent.checkPermission(avfs.OpenWrite, vfs.User()); !ok {
   726  		return &fs.PathError{Op: op, Path: path, Err: vfs.err.PermDenied}
   727  	}
   728  
   729  	parent.removeChild(pi.Part())
   730  	child.delete()
   731  
   732  	return nil
   733  }
   734  
   735  func (vfs *MemFS) removeAll(parent *dirNode) error {
   736  	parent.mu.Lock()
   737  	defer parent.mu.Unlock()
   738  
   739  	if ok := parent.checkPermission(avfs.OpenWrite, vfs.User()); !ok {
   740  		return vfs.err.PermDenied
   741  	}
   742  
   743  	for _, child := range parent.children {
   744  		if c, ok := child.(*dirNode); ok {
   745  			err := vfs.removeAll(c)
   746  			if err != nil {
   747  				return err
   748  			}
   749  		}
   750  
   751  		child.delete()
   752  	}
   753  
   754  	return nil
   755  }
   756  
   757  // Rename renames (moves) oldpath to newpath.
   758  // If newpath already exists and is not a directory, Rename replaces it.
   759  // OS-specific restrictions may apply when oldpath and newpath are in different directories.
   760  // If there is an error, it will be of type *LinkError.
   761  func (vfs *MemFS) Rename(oldpath, newpath string) error {
   762  	const op = "rename"
   763  
   764  	oParent, oChild, oPI, oErr := vfs.searchNode(oldpath, slmLstat)
   765  	if oErr != vfs.err.FileExists {
   766  		return &os.LinkError{Op: op, Old: oldpath, New: newpath, Err: oErr}
   767  	}
   768  
   769  	nParent, nChild, nPI, nErr := vfs.searchNode(newpath, slmLstat)
   770  	if nErr != vfs.err.FileExists && !vfs.isNotExist(nErr) {
   771  		return &os.LinkError{Op: op, Old: oldpath, New: newpath, Err: nErr}
   772  	}
   773  
   774  	oParent.mu.Lock()
   775  	defer oParent.mu.Unlock()
   776  
   777  	if !oParent.checkPermission(avfs.OpenWrite, vfs.User()) {
   778  		return &os.LinkError{Op: op, Old: oldpath, New: newpath, Err: vfs.err.PermDenied}
   779  	}
   780  
   781  	if nParent != oParent {
   782  		nParent.mu.Lock()
   783  		defer nParent.mu.Unlock()
   784  
   785  		if !nParent.checkPermission(avfs.OpenWrite, vfs.User()) {
   786  			return &os.LinkError{Op: op, Old: oldpath, New: newpath, Err: vfs.err.PermDenied}
   787  		}
   788  	}
   789  
   790  	if oPI.Path() == nPI.Path() {
   791  		return nil
   792  	}
   793  
   794  	switch oChild.(type) {
   795  	case *dirNode:
   796  		if !vfs.isNotExist(nErr) {
   797  			if vfs.OSType() == avfs.OsWindows {
   798  				nErr = avfs.ErrWinAccessDenied
   799  			}
   800  
   801  			return &os.LinkError{Op: op, Old: oldpath, New: newpath, Err: nErr}
   802  		}
   803  
   804  	case *fileNode:
   805  		if nChild == nil {
   806  			break
   807  		}
   808  
   809  		switch nc := nChild.(type) {
   810  		case *fileNode:
   811  			nc.delete()
   812  		default:
   813  			err := error(avfs.ErrFileExists)
   814  			if vfs.OSType() == avfs.OsWindows {
   815  				err = avfs.ErrWinAccessDenied
   816  			}
   817  
   818  			return &os.LinkError{Op: op, Old: oldpath, New: newpath, Err: err}
   819  		}
   820  	}
   821  
   822  	nParent.addChild(nPI.Part(), oChild)
   823  	oParent.removeChild(oPI.Part())
   824  
   825  	return nil
   826  }
   827  
   828  // SameFile reports whether fi1 and fi2 describe the same file.
   829  // For example, on Unix this means that the device and inode fields
   830  // of the two underlying structures are identical; on other systems
   831  // the decision may be based on the path names.
   832  // SameFile only applies to results returned by this package's Stat.
   833  // It returns false in other cases.
   834  func (*MemFS) SameFile(fi1, fi2 fs.FileInfo) bool {
   835  	fs1, ok1 := fi1.(*MemInfo)
   836  	if !ok1 {
   837  		return false
   838  	}
   839  
   840  	fs2, ok2 := fi2.(*MemInfo)
   841  	if !ok2 {
   842  		return false
   843  	}
   844  
   845  	return fs1.id == fs2.id
   846  }
   847  
   848  // SetUserByName sets the current user by name.
   849  // If the user is not found, the returned error is of type UnknownUserError.
   850  func (vfs *MemFS) SetUserByName(name string) error {
   851  	return avfs.SetUserByName(vfs, name)
   852  }
   853  
   854  // Split splits path immediately following the final Separator,
   855  // separating it into a directory and file name component.
   856  // If there is no Separator in path, Split returns an empty dir
   857  // and file set to path.
   858  // The returned values have the property that path = dir+file.
   859  func (vfs *MemFS) Split(path string) (dir, file string) {
   860  	return avfs.Split(vfs, path)
   861  }
   862  
   863  // Stat returns a FileInfo describing the named file.
   864  // If there is an error, it will be of type *PathError.
   865  func (vfs *MemFS) Stat(path string) (fs.FileInfo, error) {
   866  	op := "stat"
   867  	if vfs.OSType() == avfs.OsWindows {
   868  		op = "CreateFile"
   869  	}
   870  
   871  	_, child, pi, err := vfs.searchNode(path, slmStat)
   872  	if err != vfs.err.FileExists || child == nil {
   873  		return nil, &fs.PathError{Op: op, Path: path, Err: err}
   874  	}
   875  
   876  	fst := child.fillStatFrom(pi.Part())
   877  
   878  	return fst, nil
   879  }
   880  
   881  // Sub returns an FS corresponding to the subtree rooted at dir.
   882  func (vfs *MemFS) Sub(dir string) (avfs.VFS, error) {
   883  	const op = "sub"
   884  
   885  	_, child, _, err := vfs.searchNode(dir, slmEval)
   886  	if err != vfs.err.FileExists || child == nil {
   887  		return nil, &fs.PathError{Op: op, Path: dir, Err: err}
   888  	}
   889  
   890  	c, ok := child.(*dirNode)
   891  	if !ok {
   892  		return nil, &fs.PathError{Op: op, Path: dir, Err: vfs.err.NotADirectory}
   893  	}
   894  
   895  	subFS := *vfs
   896  	subFS.rootNode = c
   897  
   898  	return &subFS, nil
   899  }
   900  
   901  // Symlink creates newname as a symbolic link to oldname.
   902  // If there is an error, it will be of type *LinkError.
   903  func (vfs *MemFS) Symlink(oldname, newname string) error {
   904  	const op = "symlink"
   905  
   906  	parent, _, pi, nerr := vfs.searchNode(newname, slmLstat)
   907  	if !vfs.isNotExist(nerr) {
   908  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: nerr}
   909  	}
   910  
   911  	parent.mu.Lock()
   912  	defer parent.mu.Unlock()
   913  
   914  	if !parent.checkPermission(avfs.OpenWrite, vfs.User()) {
   915  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: vfs.err.PermDenied}
   916  	}
   917  
   918  	link := vfs.Clean(oldname)
   919  
   920  	vfs.createSymlink(parent, pi.Part(), link)
   921  
   922  	return nil
   923  }
   924  
   925  // TempDir returns the default directory to use for temporary files.
   926  //
   927  // On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
   928  // On Windows, it uses GetTempPath, returning the first non-empty
   929  // value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
   930  // On Plan 9, it returns /tmp.
   931  //
   932  // The directory is neither guaranteed to exist nor have accessible
   933  // permissions.
   934  func (vfs *MemFS) TempDir() string {
   935  	return avfs.TempDir(vfs)
   936  }
   937  
   938  // ToSlash returns the result of replacing each separator character
   939  // in path with a slash ('/') character. Multiple separators are
   940  // replaced by multiple slashes.
   941  func (vfs *MemFS) ToSlash(path string) string {
   942  	return avfs.ToSlash(vfs, path)
   943  }
   944  
   945  // ToSysStat takes a value from fs.FileInfo.Sys() and returns a value that implements interface avfs.SysStater.
   946  func (*MemFS) ToSysStat(info fs.FileInfo) avfs.SysStater {
   947  	return info.Sys().(avfs.SysStater) //nolint:forcetypeassert // type assertion must be checked
   948  }
   949  
   950  // Truncate changes the size of the named file.
   951  // If the file is a symbolic link, it changes the size of the link's target.
   952  // If there is an error, it will be of type *PathError.
   953  func (vfs *MemFS) Truncate(name string, size int64) error {
   954  	op := "truncate"
   955  
   956  	_, child, _, err := vfs.searchNode(name, slmEval)
   957  	if err != vfs.err.FileExists {
   958  		if vfs.OSType() == avfs.OsWindows {
   959  			op = "open"
   960  		}
   961  
   962  		return &fs.PathError{Op: op, Path: name, Err: err}
   963  	}
   964  
   965  	c, ok := child.(*fileNode)
   966  	if !ok {
   967  		if vfs.OSType() == avfs.OsWindows {
   968  			op = "open"
   969  		}
   970  
   971  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.IsADirectory}
   972  	}
   973  
   974  	if size < 0 {
   975  		return &fs.PathError{Op: op, Path: name, Err: vfs.err.InvalidArgument}
   976  	}
   977  
   978  	c.mu.Lock()
   979  	c.truncate(size)
   980  	c.mu.Unlock()
   981  
   982  	return nil
   983  }
   984  
   985  // WalkDir walks the file tree rooted at root, calling fn for each file or
   986  // directory in the tree, including root.
   987  //
   988  // All errors that arise visiting files and directories are filtered by fn:
   989  // see the fs.WalkDirFunc documentation for details.
   990  //
   991  // The files are walked in lexical order, which makes the output deterministic
   992  // but requires WalkDir to read an entire directory into memory before proceeding
   993  // to walk that directory.
   994  //
   995  // WalkDir does not follow symbolic links.
   996  func (vfs *MemFS) WalkDir(root string, fn fs.WalkDirFunc) error {
   997  	return avfs.WalkDir(vfs, root, fn)
   998  }
   999  
  1000  // WriteFile writes data to the named file, creating it if necessary.
  1001  // If the file does not exist, WriteFile creates it with permissions perm (before umask);
  1002  // otherwise WriteFile truncates it before writing, without changing permissions.
  1003  func (vfs *MemFS) WriteFile(name string, data []byte, perm fs.FileMode) error {
  1004  	return avfs.WriteFile(vfs, name, data, perm)
  1005  }