github.com/avfs/avfs@v0.33.1-0.20240303173310-c6ba67c33eb7/vfs/memfs/memfs_internal.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
    18  
    19  import (
    20  	"bytes"
    21  	"io/fs"
    22  	"sort"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	"github.com/avfs/avfs"
    27  )
    28  
    29  // searchNode search a node from the root of the file system
    30  // where path is the absolute or relative path of the node
    31  // and slMode the behavior of searchNode function relatively to symlinks.
    32  // It returns :
    33  // parent, the parent node of the node if found, the last found node otherwise
    34  // child, the node corresponding to the path or nil if not found
    35  // absPath, the absolute path of the input path
    36  // start and end, the beginning and ending position of the last found segment of absPath
    37  // err, one of the following errors :
    38  //
    39  //	ErrNoSuchFileOrDir when the node is not found
    40  //	ErrFileExists when the node is a file or directory
    41  //	ErrPermDenied when the current user doesn't have permissions on one of the nodes on the path
    42  //	ErrNotADirectory when a file node is found while the path segmentation is not finished
    43  //	ErrTooManySymlinks when more than slCountMax symbolic link resolutions have been performed.
    44  func (vfs *MemFS) searchNode(path string, slMode slMode) (
    45  	parent *dirNode, child node, pi *avfs.PathIterator[*MemFS], err error,
    46  ) {
    47  	slCount := 0
    48  	slResolved := false
    49  
    50  	absPath, _ := vfs.Abs(path)
    51  	pi = avfs.NewPathIterator[*MemFS](vfs, absPath)
    52  
    53  	volNode := vfs.rootNode
    54  
    55  	if pi.VolumeNameLen() > 0 {
    56  		nd, ok := vfs.volumes[pi.VolumeName()]
    57  		if !ok {
    58  			err = vfs.err.NoSuchDir
    59  
    60  			return
    61  		}
    62  
    63  		volNode = nd
    64  	}
    65  
    66  	parent = volNode
    67  
    68  	for pi.Next() {
    69  		name := pi.Part()
    70  
    71  		parent.mu.RLock()
    72  		child = parent.children[name]
    73  		parent.mu.RUnlock()
    74  
    75  		if child == nil {
    76  			err = vfs.err.NoSuchDir
    77  			if pi.IsLast() {
    78  				err = vfs.err.NoSuchFile
    79  			}
    80  
    81  			return
    82  		}
    83  
    84  		switch c := child.(type) {
    85  		case *dirNode:
    86  			if pi.IsLast() {
    87  				err = vfs.err.FileExists
    88  
    89  				return
    90  			}
    91  
    92  			c.mu.RLock()
    93  			ok := c.checkPermission(avfs.OpenLookup, vfs.User())
    94  			c.mu.RUnlock()
    95  
    96  			if !ok {
    97  				err = vfs.err.PermDenied
    98  
    99  				return
   100  			}
   101  
   102  			parent = c
   103  
   104  		case *fileNode:
   105  			// File permissions are checked by the calling function.
   106  			if pi.IsLast() {
   107  				err = vfs.err.FileExists
   108  
   109  				return
   110  			}
   111  
   112  			err = vfs.err.NotADirectory
   113  
   114  			return
   115  
   116  		case *symlinkNode:
   117  			// Symlinks mode is always 0o777, no need to check permissions.
   118  			slCount++
   119  			if slCount > slCountMax {
   120  				err = vfs.err.TooManySymlinks
   121  
   122  				return
   123  			}
   124  
   125  			if pi.IsLast() {
   126  				if slMode == slmLstat {
   127  					err = vfs.err.FileExists
   128  
   129  					return
   130  				}
   131  
   132  				// if the last part of the path is a symbolic link
   133  				// Stat should return the initial path of the symbolic link
   134  				// and the parent and child nodes of the resolved symbolic link.
   135  				if slMode == slmStat && !slResolved {
   136  					slResolved = true
   137  
   138  					defer func(piSymLink avfs.PathIterator[*MemFS]) { //nolint:gocritic // Possible resource leak
   139  						pi = &piSymLink
   140  					}(*pi)
   141  				}
   142  			}
   143  
   144  			if pi.ReplacePart(c.link) {
   145  				parent = volNode
   146  			}
   147  		}
   148  	}
   149  
   150  	return parent, parent, pi, vfs.err.FileExists
   151  }
   152  
   153  // createRootNode creates a root node for a file system.
   154  func (vfs *MemFS) createRootNode() *dirNode {
   155  	u := vfs.User()
   156  	dn := &dirNode{
   157  		baseNode: baseNode{
   158  			mtime: time.Now().UnixNano(),
   159  			mode:  fs.ModeDir | 0o755,
   160  			uid:   u.Uid(),
   161  			gid:   u.Gid(),
   162  		},
   163  	}
   164  
   165  	return dn
   166  }
   167  
   168  // createDir creates a new directory.
   169  func (vfs *MemFS) createDir(parent *dirNode, name string, perm fs.FileMode) *dirNode {
   170  	child := &dirNode{
   171  		baseNode: baseNode{
   172  			mtime: time.Now().UnixNano(),
   173  			mode:  vfs.dirMode | (perm & avfs.FileModeMask &^ vfs.UMask()),
   174  			uid:   vfs.User().Uid(),
   175  			gid:   vfs.User().Gid(),
   176  		},
   177  		children: nil,
   178  	}
   179  
   180  	parent.addChild(name, child)
   181  
   182  	return child
   183  }
   184  
   185  // createFile creates a new file.
   186  func (vfs *MemFS) createFile(parent *dirNode, name string, perm fs.FileMode) *fileNode {
   187  	child := &fileNode{
   188  		baseNode: baseNode{
   189  			mtime: time.Now().UnixNano(),
   190  			mode:  vfs.fileMode | (perm & avfs.FileModeMask &^ vfs.UMask()),
   191  			uid:   vfs.User().Uid(),
   192  			gid:   vfs.User().Gid(),
   193  		},
   194  		id:    atomic.AddUint64(vfs.lastId, 1),
   195  		nlink: 1,
   196  	}
   197  
   198  	parent.addChild(name, child)
   199  
   200  	return child
   201  }
   202  
   203  // createSymlink creates a new symlink.
   204  func (vfs *MemFS) createSymlink(parent *dirNode, name, link string) *symlinkNode {
   205  	child := &symlinkNode{
   206  		baseNode: baseNode{
   207  			mtime: time.Now().UnixNano(),
   208  			mode:  fs.ModeSymlink | fs.ModePerm,
   209  			uid:   vfs.User().Uid(),
   210  			gid:   vfs.User().Gid(),
   211  		},
   212  		link: link,
   213  	}
   214  
   215  	parent.addChild(name, child)
   216  
   217  	return child
   218  }
   219  
   220  // isNotExist is IsNotExist without unwrapping.
   221  func (vfs *MemFS) isNotExist(err error) bool {
   222  	return err == vfs.err.NoSuchDir || err == vfs.err.NoSuchFile
   223  }
   224  
   225  // checkPermission checks if the current user has the desired permissions (perm) on the node.
   226  func (bn *baseNode) checkPermission(perm avfs.OpenMode, u avfs.UserReader) bool {
   227  	const PermRWX = 0o007 // filter all permissions bits.
   228  
   229  	if u.IsAdmin() {
   230  		return true
   231  	}
   232  
   233  	mode := avfs.OpenMode(bn.mode)
   234  
   235  	switch {
   236  	case bn.uid == u.Uid():
   237  		mode >>= 6
   238  	case bn.gid == u.Gid():
   239  		mode >>= 3
   240  	}
   241  
   242  	perm &= PermRWX
   243  
   244  	return mode&perm == perm
   245  }
   246  
   247  // Lock locks the node.
   248  func (bn *baseNode) Lock() {
   249  	bn.mu.Lock()
   250  }
   251  
   252  // setModTime sets the modification time of the node.
   253  func (bn *baseNode) setModTime(mtime time.Time, u avfs.UserReader) bool {
   254  	if bn.uid != u.Uid() && !u.IsAdmin() {
   255  		return false
   256  	}
   257  
   258  	bn.mtime = mtime.UnixNano()
   259  
   260  	return true
   261  }
   262  
   263  // setOwner sets the owner of the node.
   264  func (bn *baseNode) setOwner(uid, gid int) {
   265  	bn.uid = uid
   266  	bn.gid = gid
   267  }
   268  
   269  // Unlock unlocks the node.
   270  func (bn *baseNode) Unlock() {
   271  	bn.mu.Unlock()
   272  }
   273  
   274  // dirNode
   275  
   276  // addChild adds a child to a dirNode.
   277  func (dn *dirNode) addChild(name string, child node) {
   278  	if dn.children == nil {
   279  		dn.children = make(children)
   280  	}
   281  
   282  	dn.children[name] = child
   283  }
   284  
   285  // removeChild removes the child from the parent dirNode.
   286  func (dn *dirNode) removeChild(name string) {
   287  	delete(dn.children, name)
   288  }
   289  
   290  // delete removes all information from the node.
   291  func (dn *dirNode) delete() {
   292  	dn.children = nil
   293  }
   294  
   295  // fillStatFrom returns a MemInfo (implementation of fs.FileInfo) from a dirNode dn named name.
   296  func (dn *dirNode) fillStatFrom(name string) *MemInfo {
   297  	dn.mu.RLock()
   298  
   299  	fst := &MemInfo{
   300  		name:  name,
   301  		size:  dn.size(),
   302  		mode:  dn.mode,
   303  		mtime: dn.mtime,
   304  		uid:   dn.uid,
   305  		gid:   dn.gid,
   306  		nlink: 0,
   307  	}
   308  
   309  	dn.mu.RUnlock()
   310  
   311  	return fst
   312  }
   313  
   314  // dirEntries returns a slice of fs.DirEntry from a directory ordered by name.
   315  func (dn *dirNode) dirEntries() []fs.DirEntry {
   316  	l := len(dn.children)
   317  	if l == 0 {
   318  		return nil
   319  	}
   320  
   321  	entries := make([]fs.DirEntry, l)
   322  	i := 0
   323  
   324  	for name, nd := range dn.children {
   325  		entries[i] = nd.fillStatFrom(name)
   326  		i++
   327  	}
   328  
   329  	sort.Slice(entries, func(i, j int) bool { return entries[i].Name() < entries[j].Name() })
   330  
   331  	return entries
   332  }
   333  
   334  // dirNames returns a slice of file names from a directory ordered by name.
   335  func (dn *dirNode) dirNames() []string {
   336  	l := len(dn.children)
   337  	if l == 0 {
   338  		return nil
   339  	}
   340  
   341  	names := make([]string, l)
   342  	i := 0
   343  
   344  	for name := range dn.children {
   345  		names[i] = name
   346  		i++
   347  	}
   348  
   349  	sort.Strings(names)
   350  
   351  	return names
   352  }
   353  
   354  // setMode sets the permissions of the directory node.
   355  func (dn *dirNode) setMode(mode fs.FileMode, u avfs.UserReader) bool {
   356  	if dn.uid != u.Uid() && !u.IsAdmin() {
   357  		return false
   358  	}
   359  
   360  	dn.mode &^= avfs.FileModeMask
   361  	dn.mode |= mode & avfs.FileModeMask
   362  
   363  	return true
   364  }
   365  
   366  // size returns the size of the dirNode : number of children.
   367  func (dn *dirNode) size() int64 {
   368  	return int64(len(dn.children))
   369  }
   370  
   371  // fileNode
   372  
   373  // delete removes all information from the node, decrements the reference counter of the fileNode.
   374  // If there is no more references, the data is deleted.
   375  func (fn *fileNode) delete() {
   376  	fn.nlink--
   377  	if fn.nlink == 0 {
   378  		fn.data = nil
   379  	}
   380  }
   381  
   382  // fillStatFrom returns a MemInfo (implementation of fs.FileInfo) from a fileNode fn named name.
   383  func (fn *fileNode) fillStatFrom(name string) *MemInfo {
   384  	fn.mu.RLock()
   385  
   386  	fst := &MemInfo{
   387  		id:    fn.id,
   388  		name:  name,
   389  		size:  fn.size(),
   390  		mode:  fn.mode,
   391  		mtime: fn.mtime,
   392  		uid:   fn.uid,
   393  		gid:   fn.gid,
   394  		nlink: fn.nlink,
   395  	}
   396  
   397  	fn.mu.RUnlock()
   398  
   399  	return fst
   400  }
   401  
   402  // setMode sets the permissions of the file node.
   403  func (fn *fileNode) setMode(mode fs.FileMode, u avfs.UserReader) bool {
   404  	if fn.uid != u.Uid() && !u.IsAdmin() {
   405  		return false
   406  	}
   407  
   408  	fn.mode &^= avfs.FileModeMask
   409  	fn.mode |= mode & avfs.FileModeMask
   410  
   411  	return true
   412  }
   413  
   414  // size returns the size of the file.
   415  func (fn *fileNode) size() int64 {
   416  	return int64(len(fn.data))
   417  }
   418  
   419  // truncate truncates the file.
   420  func (fn *fileNode) truncate(size int64) {
   421  	if size == 0 {
   422  		fn.data = nil
   423  
   424  		return
   425  	}
   426  
   427  	diff := int(size) - len(fn.data)
   428  	if diff > 0 {
   429  		fn.data = append(fn.data, bytes.Repeat([]byte{0}, diff)...)
   430  
   431  		return
   432  	}
   433  
   434  	fn.data = fn.data[:size]
   435  }
   436  
   437  // symlinkNode
   438  
   439  // delete removes all information from the node.
   440  func (sn *symlinkNode) delete() {
   441  	sn.link = ""
   442  }
   443  
   444  // fillStatFrom returns a MemInfo (implementation of fs.FileInfo) from a symlinkNode named name.
   445  func (sn *symlinkNode) fillStatFrom(name string) *MemInfo {
   446  	sn.mu.RLock()
   447  
   448  	fst := &MemInfo{
   449  		name:  name,
   450  		size:  sn.size(),
   451  		mode:  sn.mode,
   452  		mtime: sn.mtime,
   453  		uid:   sn.uid,
   454  		gid:   sn.gid,
   455  		nlink: 0,
   456  	}
   457  
   458  	sn.mu.RUnlock()
   459  
   460  	return fst
   461  }
   462  
   463  // setMode sets the permissions of the symlink node.
   464  func (sn *symlinkNode) setMode(mode fs.FileMode, u avfs.UserReader) bool {
   465  	return false
   466  }
   467  
   468  func (sn *symlinkNode) size() int64 {
   469  	return 1
   470  }