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

     1  //
     2  //  Copyright 2022 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 mountfs implements a file system composed of different file systems.
    18  package mountfs
    19  
    20  import (
    21  	"io/fs"
    22  	"os"
    23  	"time"
    24  
    25  	"github.com/avfs/avfs"
    26  )
    27  
    28  // Abs returns an absolute representation of path.
    29  // If the path is not absolute it will be joined with the current
    30  // working directory to turn it into an absolute path. The absolute
    31  // path name for a given file is not guaranteed to be unique.
    32  // Abs calls [Clean] on the result.
    33  func (vfs *MountFS) Abs(path string) (string, error) {
    34  	if vfs.IsAbs(path) {
    35  		return vfs.Clean(path), nil
    36  	}
    37  
    38  	return vfs.Join(vfs.CurDir(), path), nil
    39  }
    40  
    41  // Base returns the last element of path.
    42  // Trailing path separators are removed before extracting the last element.
    43  // If the path is empty, Base returns ".".
    44  // If the path consists entirely of separators, Base returns a single separator.
    45  func (vfs *MountFS) Base(path string) string {
    46  	return avfs.Base(vfs, path)
    47  }
    48  
    49  // Chdir changes the current working directory to the named directory.
    50  // If there is an error, it will be of type *PathError.
    51  func (vfs *MountFS) Chdir(dir string) error {
    52  	mnt, vfsPath := vfs.pathToMount(dir)
    53  
    54  	err := mnt.vfs.Chdir(vfsPath)
    55  	if err != nil {
    56  		return mnt.restoreError(err)
    57  	}
    58  
    59  	vfs.curMnt = mnt
    60  	_ = vfs.SetCurDir(vfsPath)
    61  
    62  	return nil
    63  }
    64  
    65  // Chmod changes the mode of the named file to mode.
    66  // If the file is a symbolic link, it changes the mode of the link's target.
    67  // If there is an error, it will be of type *PathError.
    68  //
    69  // A different subset of the mode bits are used, depending on the
    70  // operating system.
    71  //
    72  // On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
    73  // ModeSticky are used.
    74  //
    75  // On Windows, only the 0200 bit (owner writable) of mode is used; it
    76  // controls whether the file's read-only attribute is set or cleared.
    77  // The other bits are currently unused. For compatibility with Go 1.12
    78  // and earlier, use a non-zero mode. Use mode 0400 for a read-only
    79  // file and 0600 for a readable+writable file.
    80  //
    81  // On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive,
    82  // and ModeTemporary are used.
    83  func (vfs *MountFS) Chmod(name string, mode fs.FileMode) error {
    84  	mnt, vfsPath := vfs.pathToMount(name)
    85  	err := mnt.vfs.Chmod(vfsPath, mode)
    86  
    87  	return mnt.restoreError(err)
    88  }
    89  
    90  // Chown changes the numeric uid and gid of the named file.
    91  // If the file is a symbolic link, it changes the uid and gid of the link's target.
    92  // A uid or gid of -1 means to not change that value.
    93  // If there is an error, it will be of type *PathError.
    94  //
    95  // On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
    96  // EPLAN9 error, wrapped in *PathError.
    97  func (vfs *MountFS) Chown(name string, uid, gid int) error {
    98  	mnt, vfsPath := vfs.pathToMount(name)
    99  	err := mnt.vfs.Chown(vfsPath, uid, gid)
   100  
   101  	return mnt.restoreError(err)
   102  }
   103  
   104  // Chtimes changes the access and modification times of the named
   105  // file, similar to the Unix utime() or utimes() functions.
   106  //
   107  // The underlying file system may truncate or round the values to a
   108  // less precise time unit.
   109  // If there is an error, it will be of type *PathError.
   110  func (vfs *MountFS) Chtimes(name string, atime, mtime time.Time) error {
   111  	mnt, vfsPath := vfs.pathToMount(name)
   112  	err := mnt.vfs.Chtimes(vfsPath, atime, mtime)
   113  
   114  	return mnt.restoreError(err)
   115  }
   116  
   117  // Clean returns the shortest path name equivalent to path
   118  // by purely lexical processing. It applies the following rules
   119  // iteratively until no further processing can be done:
   120  //
   121  //  1. Replace multiple Separator elements with a single one.
   122  //  2. Eliminate each . path name element (the current directory).
   123  //  3. Eliminate each inner .. path name element (the parent directory)
   124  //     along with the non-.. element that precedes it.
   125  //  4. Eliminate .. elements that begin a rooted path:
   126  //     that is, replace "/.." by "/" at the beginning of a path,
   127  //     assuming Separator is '/'.
   128  //
   129  // The returned path ends in a slash only if it represents a root directory,
   130  // such as "/" on Unix or `C:\` on Windows.
   131  //
   132  // Finally, any occurrences of slash are replaced by Separator.
   133  //
   134  // If the result of this process is an empty string, Clean
   135  // returns the string ".".
   136  //
   137  // See also Rob Pike, “Lexical File Names in Plan 9 or
   138  // Getting Dot-Dot Right,”
   139  // https://9p.io/sys/doc/lexnames.html
   140  func (vfs *MountFS) Clean(path string) string {
   141  	return avfs.Clean(vfs, path)
   142  }
   143  
   144  // Create creates or truncates the named file. If the file already exists,
   145  // it is truncated. If the file does not exist, it is created with mode 0666
   146  // (before umask). If successful, methods on the returned DummyFile can
   147  // be used for I/O; the associated file descriptor has mode O_RDWR.
   148  // If there is an error, it will be of type *PathError.
   149  func (vfs *MountFS) Create(name string) (avfs.File, error) {
   150  	return avfs.Create(vfs, name)
   151  }
   152  
   153  // CreateTemp creates a new temporary file in the directory dir,
   154  // opens the file for reading and writing, and returns the resulting file.
   155  // The filename is generated by taking pattern and adding a random string to the end.
   156  // If pattern includes a "*", the random string replaces the last "*".
   157  // If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir.
   158  // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
   159  // The caller can use the file's Name method to find the pathname of the file.
   160  // It is the caller's responsibility to remove the file when it is no longer needed.
   161  func (vfs *MountFS) CreateTemp(dir, pattern string) (avfs.File, error) {
   162  	return avfs.CreateTemp(vfs, dir, pattern)
   163  }
   164  
   165  // Dir returns all but the last element of path, typically the path's directory.
   166  // After dropping the final element, Dir calls Clean on the path and trailing
   167  // slashes are removed.
   168  // If the path is empty, Dir returns ".".
   169  // If the path consists entirely of separators, Dir returns a single separator.
   170  // The returned path does not end in a separator unless it is the root directory.
   171  func (vfs *MountFS) Dir(path string) string {
   172  	return avfs.Dir(vfs, path)
   173  }
   174  
   175  // EvalSymlinks returns the path name after the evaluation of any symbolic
   176  // links.
   177  // If path is relative the result will be relative to the current directory,
   178  // unless one of the components is an absolute symbolic link.
   179  // EvalSymlinks calls Clean on the result.
   180  func (vfs *MountFS) EvalSymlinks(path string) (string, error) {
   181  	op := "lstat"
   182  	err := error(avfs.ErrPermDenied)
   183  
   184  	if vfs.OSType() == avfs.OsWindows {
   185  		op = "CreateFile"
   186  		err = avfs.ErrWinAccessDenied
   187  	}
   188  
   189  	return "", &fs.PathError{Op: op, Path: path, Err: err}
   190  }
   191  
   192  // FromSlash returns the result of replacing each slash ('/') character
   193  // in path with a separator character. Multiple slashes are replaced
   194  // by multiple separators.
   195  func (vfs *MountFS) FromSlash(path string) string {
   196  	return avfs.FromSlash(vfs, path)
   197  }
   198  
   199  // Getwd returns a rooted name link corresponding to the
   200  // current directory. If the current directory can be
   201  // reached via multiple paths (due to symbolic links),
   202  // Getwd may return any one of them.
   203  func (vfs *MountFS) Getwd() (dir string, err error) {
   204  	cd := vfs.curMnt.toAbsPath(vfs.CurDir())
   205  
   206  	return cd, nil
   207  }
   208  
   209  // IsAbs reports whether the path is absolute.
   210  func (vfs *MountFS) IsAbs(path string) bool {
   211  	return avfs.IsAbs(vfs, path)
   212  }
   213  
   214  // IsPathSeparator reports whether c is a directory separator character.
   215  func (vfs *MountFS) IsPathSeparator(c uint8) bool {
   216  	return avfs.IsPathSeparator(vfs, c)
   217  }
   218  
   219  // Join joins any number of path elements into a single path,
   220  // separating them with an OS specific Separator. Empty elements
   221  // are ignored. The result is Cleaned. However, if the argument
   222  // list is empty or all its elements are empty, Join returns
   223  // an empty string.
   224  // On Windows, the result will only be a UNC path if the first
   225  // non-empty element is a UNC path.
   226  func (vfs *MountFS) Join(elem ...string) string {
   227  	return avfs.Join(vfs, elem...)
   228  }
   229  
   230  // Glob returns the names of all files matching pattern or nil
   231  // if there is no matching file. The syntax of patterns is the same
   232  // as in Match. The pattern may describe hierarchical names such as
   233  // /usr/*/bin/ed (assuming the Separator is '/').
   234  //
   235  // Glob ignores file system errors such as I/O errors reading directories.
   236  // The only possible returned error is ErrBadPattern, when pattern
   237  // is malformed.
   238  func (vfs *MountFS) Glob(pattern string) (matches []string, err error) {
   239  	matches, err = avfs.Glob(vfs, pattern)
   240  
   241  	/*
   242  		TODO : restore path if possible or disable function
   243  		for i, m := range matches {
   244  			matches[i] = vfs.fromBasePath(m)
   245  		}
   246  	*/
   247  
   248  	return matches, err
   249  }
   250  
   251  // Idm returns the identity manager of the file system.
   252  // If the file system does not have an identity manager, avfs.DummyIdm is returned.
   253  func (vfs *MountFS) Idm() avfs.IdentityMgr {
   254  	return vfs.rootFS.Idm()
   255  }
   256  
   257  // Lchown changes the numeric uid and gid of the named file.
   258  // If the file is a symbolic link, it changes the uid and gid of the link itself.
   259  // If there is an error, it will be of type *PathError.
   260  //
   261  // On Windows, it always returns the syscall.EWINDOWS error, wrapped
   262  // in *PathError.
   263  func (vfs *MountFS) Lchown(name string, uid, gid int) error {
   264  	mnt, vfsPath := vfs.pathToMount(name)
   265  	err := mnt.vfs.Lchown(vfsPath, uid, gid)
   266  
   267  	return mnt.restoreError(err)
   268  }
   269  
   270  // Link creates newname as a hard link to the oldname file.
   271  // If there is an error, it will be of type *LinkError.
   272  func (vfs *MountFS) Link(oldname, newname string) error {
   273  	const op = ""
   274  
   275  	oldMnt, oldVfsPath := vfs.pathToMount(oldname)
   276  	newMnt, newVfsPath := vfs.pathToMount(newname)
   277  
   278  	if oldMnt != newMnt {
   279  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: avfs.ErrCrossDevLink}
   280  	}
   281  
   282  	err := oldMnt.vfs.Link(oldVfsPath, newVfsPath)
   283  
   284  	return oldMnt.restoreError(err)
   285  }
   286  
   287  // Lstat returns a FileInfo describing the named file.
   288  // If the file is a symbolic link, the returned FileInfo
   289  // describes the symbolic link. Lstat makes no attempt to follow the link.
   290  // If there is an error, it will be of type *PathError.
   291  func (vfs *MountFS) Lstat(path string) (fs.FileInfo, error) {
   292  	mnt, vfsPath := vfs.pathToMount(path)
   293  	info, err := mnt.vfs.Lstat(vfsPath)
   294  
   295  	return info, mnt.restoreError(err)
   296  }
   297  
   298  // Match reports whether name matches the shell file name pattern.
   299  // The pattern syntax is:
   300  //
   301  //	pattern:
   302  //		{ term }
   303  //	term:
   304  //		'*'         matches any sequence of non-Separator characters
   305  //		'?'         matches any single non-Separator character
   306  //		'[' [ '^' ] { character-range } ']'
   307  //		            character class (must be non-empty)
   308  //		c           matches character c (c != '*', '?', '\\', '[')
   309  //		'\\' c      matches character c
   310  //
   311  //	character-range:
   312  //		c           matches character c (c != '\\', '-', ']')
   313  //		'\\' c      matches character c
   314  //		lo '-' hi   matches character c for lo <= c <= hi
   315  //
   316  // Match requires pattern to match all of name, not just a substring.
   317  // The only possible returned error is ErrBadPattern, when pattern
   318  // is malformed.
   319  //
   320  // On Windows, escaping is disabled. Instead, '\\' is treated as
   321  // path separator.
   322  func (vfs *MountFS) Match(pattern, name string) (matched bool, err error) {
   323  	return avfs.Match(vfs, pattern, name)
   324  }
   325  
   326  // Mkdir creates a new directory with the specified name and permission
   327  // bits (before umask).
   328  // If there is an error, it will be of type *PathError.
   329  func (vfs *MountFS) Mkdir(name string, perm fs.FileMode) error {
   330  	if name == "" {
   331  		err := error(avfs.ErrNoSuchFileOrDir)
   332  		if vfs.OSType() == avfs.OsWindows {
   333  			err = avfs.ErrWinPathNotFound
   334  		}
   335  
   336  		return &fs.PathError{Op: "mkdir", Path: "", Err: err}
   337  	}
   338  
   339  	mnt, vfsPath := vfs.pathToMount(name)
   340  	err := mnt.vfs.Mkdir(vfsPath, perm)
   341  
   342  	return mnt.restoreError(err)
   343  }
   344  
   345  // MkdirAll creates a directory named name,
   346  // along with any necessary parents, and returns nil,
   347  // or else returns an error.
   348  // The permission bits perm (before umask) are used for all
   349  // directories that MkdirAll creates.
   350  // If name is already a directory, MkdirAll does nothing
   351  // and returns nil.
   352  func (vfs *MountFS) MkdirAll(path string, perm fs.FileMode) error {
   353  	absPath, _ := vfs.rootFS.Abs(path)
   354  	mnt := vfs.rootMnt
   355  	mntPos := 0
   356  
   357  	pi := avfs.NewPathIterator(vfs, absPath)
   358  	for pi.Next() {
   359  		m, ok := vfs.mounts[pi.LeftPart()]
   360  		if ok {
   361  			vfsPath := absPath[mntPos:pi.End()]
   362  
   363  			err := mnt.vfs.MkdirAll(vfsPath, perm)
   364  			if err != nil {
   365  				return mnt.restoreError(err)
   366  			}
   367  
   368  			mnt = m
   369  			mntPos = pi.End()
   370  		}
   371  	}
   372  
   373  	err := mnt.vfs.MkdirAll(absPath[mntPos:], perm)
   374  
   375  	return mnt.restoreError(err)
   376  }
   377  
   378  // MkdirTemp creates a new temporary directory in the directory dir
   379  // and returns the pathname of the new directory.
   380  // The new directory's name is generated by adding a random string to the end of pattern.
   381  // If pattern includes a "*", the random string replaces the last "*" instead.
   382  // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
   383  // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
   384  // It is the caller's responsibility to remove the directory when it is no longer needed.
   385  func (vfs *MountFS) MkdirTemp(dir, pattern string) (string, error) {
   386  	return avfs.MkdirTemp(vfs, dir, pattern)
   387  }
   388  
   389  // Open opens the named file for reading. If successful, methods on
   390  // the returned file can be used for reading; the associated file
   391  // descriptor has mode O_RDONLY.
   392  // If there is an error, it will be of type *PathError.
   393  func (vfs *MountFS) Open(name string) (avfs.File, error) {
   394  	return vfs.OpenFile(name, os.O_RDONLY, 0)
   395  }
   396  
   397  // OpenFile is the generalized open call; most users will use Open
   398  // or Create instead. It opens the named file with specified flag
   399  // (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag
   400  // is passed, it is created with mode perm (before umask). If successful,
   401  // methods on the returned File can be used for I/O.
   402  // If there is an error, it will be of type *PathError.
   403  func (vfs *MountFS) OpenFile(name string, flag int, perm fs.FileMode) (avfs.File, error) {
   404  	mnt, vfsPath := vfs.pathToMount(name)
   405  
   406  	f, err := mnt.vfs.OpenFile(vfsPath, flag, perm)
   407  	if err != nil {
   408  		return f, mnt.restoreError(err)
   409  	}
   410  
   411  	mf := &MountFile{
   412  		vfs:   vfs,
   413  		mount: mnt,
   414  		file:  f,
   415  	}
   416  
   417  	return mf, nil
   418  }
   419  
   420  // ReadDir reads the named directory,
   421  // returning all its directory entries sorted by filename.
   422  // If an error occurs reading the directory,
   423  // ReadDir returns the entries it was able to read before the error,
   424  // along with the error.
   425  func (vfs *MountFS) ReadDir(name string) ([]fs.DirEntry, error) {
   426  	return avfs.ReadDir(vfs, name)
   427  }
   428  
   429  // ReadFile reads the named file and returns the contents.
   430  // A successful call returns err == nil, not err == EOF.
   431  // Because ReadFile reads the whole file, it does not treat an EOF from Read
   432  // as an error to be reported.
   433  func (vfs *MountFS) ReadFile(name string) ([]byte, error) {
   434  	return avfs.ReadFile(vfs, name)
   435  }
   436  
   437  // Readlink returns the destination of the named symbolic link.
   438  // If there is an error, it will be of type *PathError.
   439  func (vfs *MountFS) Readlink(name string) (string, error) {
   440  	const op = "readlink"
   441  
   442  	if vfs.OSType() == avfs.OsWindows {
   443  		return "", &fs.PathError{Op: op, Path: name, Err: avfs.ErrWinNotReparsePoint}
   444  	}
   445  
   446  	return "", &fs.PathError{Op: op, Path: name, Err: avfs.ErrPermDenied}
   447  }
   448  
   449  // Rel returns a relative path that is lexically equivalent to targpath when
   450  // joined to basepath with an intervening separator. That is,
   451  // Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
   452  // On success, the returned path will always be relative to basepath,
   453  // even if basepath and targpath share no elements.
   454  // An error is returned if targpath can't be made relative to basepath or if
   455  // knowing the current working directory would be necessary to compute it.
   456  // Rel calls Clean on the result.
   457  func (vfs *MountFS) Rel(basepath, targpath string) (string, error) {
   458  	return avfs.Rel(vfs, basepath, targpath)
   459  }
   460  
   461  // Remove removes the named file or (empty) directory.
   462  // If there is an error, it will be of type *PathError.
   463  func (vfs *MountFS) Remove(name string) error {
   464  	mnt, vfsPath := vfs.pathToMount(name)
   465  	err := mnt.vfs.Remove(vfsPath)
   466  
   467  	return mnt.restoreError(err)
   468  }
   469  
   470  // RemoveAll removes path and any children it contains.
   471  // It removes everything it can but returns the first error
   472  // it encounters. If the path does not exist, RemoveAll
   473  // returns nil (no error).
   474  // If there is an error, it will be of type *PathError.
   475  func (vfs *MountFS) RemoveAll(path string) error {
   476  	if path == "" {
   477  		// fail silently to retain compatibility with previous behavior of RemoveAll.
   478  		return nil
   479  	}
   480  
   481  	mnt, vfsPath := vfs.pathToMount(path)
   482  	err := mnt.vfs.RemoveAll(vfsPath)
   483  
   484  	return mnt.restoreError(err)
   485  }
   486  
   487  // Rename renames (moves) oldpath to newpath.
   488  // If newpath already exists and is not a directory, Rename replaces it.
   489  // OS-specific restrictions may apply when oldpath and newpath are in different directories.
   490  // If there is an error, it will be of type *LinkError.
   491  func (vfs *MountFS) Rename(oldname, newname string) error {
   492  	const op = "rename"
   493  
   494  	oldMnt, oldVfsPath := vfs.pathToMount(oldname)
   495  	newMnt, newVfsPath := vfs.pathToMount(newname)
   496  
   497  	if oldMnt != newMnt {
   498  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: avfs.ErrCrossDevLink}
   499  	}
   500  
   501  	err := oldMnt.vfs.Rename(oldVfsPath, newVfsPath)
   502  
   503  	return oldMnt.restoreError(err)
   504  }
   505  
   506  // SameFile reports whether fi1 and fi2 describe the same file.
   507  // For example, on Unix this means that the device and inode fields
   508  // of the two underlying structures are identical; on other systems
   509  // the decision may be based on the path names.
   510  // SameFile only applies to results returned by this package's Stat.
   511  // It returns false in other cases.
   512  func (vfs *MountFS) SameFile(fi1, fi2 fs.FileInfo) bool {
   513  	return vfs.rootFS.SameFile(fi1, fi2)
   514  }
   515  
   516  // SetUMask sets the file mode creation mask.
   517  func (vfs *MountFS) SetUMask(mask fs.FileMode) error {
   518  	return vfs.rootFS.SetUMask(mask)
   519  }
   520  
   521  // SetUserByName sets the current user by name.
   522  // If the user is not found, the returned error is of type UnknownUserError.
   523  func (vfs *MountFS) SetUserByName(name string) error {
   524  	return avfs.SetUserByName(vfs, name)
   525  }
   526  
   527  // Split splits path immediately following the final Separator,
   528  // separating it into a directory and file name component.
   529  // If there is no Separator in path, Split returns an empty dir
   530  // and file set to path.
   531  // The returned values have the property that path = dir+file.
   532  func (vfs *MountFS) Split(path string) (dir, file string) {
   533  	return avfs.Split(vfs, path)
   534  }
   535  
   536  // Stat returns a FileInfo describing the named file.
   537  // If there is an error, it will be of type *PathError.
   538  func (vfs *MountFS) Stat(path string) (fs.FileInfo, error) {
   539  	mnt, vfsPath := vfs.pathToMount(path)
   540  	info, err := mnt.vfs.Stat(vfsPath)
   541  
   542  	return info, mnt.restoreError(err)
   543  }
   544  
   545  // Sub returns an FS corresponding to the subtree rooted at dir.
   546  func (vfs *MountFS) Sub(dir string) (avfs.VFS, error) {
   547  	mnt, vfsPath := vfs.pathToMount(dir)
   548  	info, err := mnt.vfs.Sub(vfsPath)
   549  
   550  	return info, mnt.restoreError(err)
   551  }
   552  
   553  // Symlink creates newname as a symbolic link to oldname.
   554  // If there is an error, it will be of type *LinkError.
   555  func (vfs *MountFS) Symlink(oldname, newname string) error {
   556  	const op = "symlink"
   557  
   558  	if vfs.OSType() == avfs.OsWindows {
   559  		return &os.LinkError{Op: op, Old: oldname, New: newname, Err: avfs.ErrWinPrivilegeNotHeld}
   560  	}
   561  
   562  	return &os.LinkError{Op: op, Old: oldname, New: newname, Err: avfs.ErrPermDenied}
   563  }
   564  
   565  // TempDir returns the default directory to use for temporary files.
   566  //
   567  // On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
   568  // On Windows, it uses GetTempPath, returning the first non-empty
   569  // value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
   570  // On Plan 9, it returns /tmp.
   571  //
   572  // The directory is neither guaranteed to exist nor have accessible
   573  // permissions.
   574  func (vfs *MountFS) TempDir() string {
   575  	return avfs.TempDir(vfs)
   576  }
   577  
   578  // ToSlash returns the result of replacing each separator character
   579  // in path with a slash ('/') character. Multiple separators are
   580  // replaced by multiple slashes.
   581  func (vfs *MountFS) ToSlash(path string) string {
   582  	return avfs.ToSlash(vfs, path)
   583  }
   584  
   585  // ToSysStat takes a value from fs.FileInfo.Sys() and returns a value that implements interface avfs.SysStater.
   586  func (vfs *MountFS) ToSysStat(info fs.FileInfo) avfs.SysStater {
   587  	return vfs.rootFS.ToSysStat(info)
   588  }
   589  
   590  // Truncate changes the size of the named file.
   591  // If the file is a symbolic link, it changes the size of the link's target.
   592  // If there is an error, it will be of type *PathError.
   593  func (vfs *MountFS) Truncate(name string, size int64) error {
   594  	mnt, vfsPath := vfs.pathToMount(name)
   595  	err := mnt.vfs.Truncate(vfsPath, size)
   596  
   597  	return mnt.restoreError(err)
   598  }
   599  
   600  // UMask returns the file mode creation mask.
   601  func (vfs *MountFS) UMask() fs.FileMode {
   602  	return vfs.rootFS.UMask()
   603  }
   604  
   605  // User returns the current user.
   606  func (vfs *MountFS) User() avfs.UserReader {
   607  	return vfs.rootFS.User()
   608  }
   609  
   610  // WalkDir walks the file tree rooted at root, calling fn for each file or
   611  // directory in the tree, including root.
   612  //
   613  // All errors that arise visiting files and directories are filtered by fn:
   614  // see the fs.WalkDirFunc documentation for details.
   615  //
   616  // The files are walked in lexical order, which makes the output deterministic
   617  // but requires WalkDir to read an entire directory into memory before proceeding
   618  // to walk that directory.
   619  //
   620  // WalkDir does not follow symbolic links.
   621  func (vfs *MountFS) WalkDir(root string, fn fs.WalkDirFunc) error {
   622  	err := avfs.WalkDir(vfs, root, fn)
   623  
   624  	return vfs.rootMnt.restoreError(err)
   625  }
   626  
   627  // WriteFile writes data to a file named by filename.
   628  // If the file does not exist, WriteFile creates it with permissions perm;
   629  // otherwise WriteFile truncates it before writing.
   630  func (vfs *MountFS) WriteFile(filename string, data []byte, perm fs.FileMode) error {
   631  	err := avfs.WriteFile(vfs, filename, data, perm)
   632  
   633  	return vfs.rootMnt.restoreError(err)
   634  }