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 }