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