Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/finder/fs/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 21 kB image not shown  

Quelle  fs.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fs

import (
 "bytes"
 "errors"
 "fmt"
 "io"
 "io/ioutil"
 "os"
 "os/user"
 "path/filepath"
 "sync"
 "time"
)

var OsFs FileSystem = osFs{}

func NewMockFs(files map[string][]byte) *MockFs {
 workDir := "/cwd"
 fs := &MockFs{
  Clock:   NewClock(time.Unix(22)),
  workDir: workDir,
 }
 fs.root = *fs.newDir()
 fs.MkDirs(workDir)

 for path, bytes := range files {
  dir := filepath.Dir(path)
  fs.MkDirs(dir)
  fs.WriteFile(path, bytes, 0777)
 }

 return fs
}

type FileSystem interface {
 // getting information about files
 Open(name string) (file io.ReadCloser, err error)
 Lstat(path string) (stats os.FileInfo, err error)
 Stat(path string) (stats os.FileInfo, err error)
 ReadDir(path string) (contents []DirEntryInfo, err error)

 InodeNumber(info os.FileInfo) (number uint64, err error)
 DeviceNumber(info os.FileInfo) (number uint64, err error)
 PermTime(info os.FileInfo) (time time.Time, err error)

 // changing contents of the filesystem
 Rename(oldPath string, newPath string) (err error)
 WriteFile(path string, data []byte, perm os.FileMode) (err error)
 Remove(path string) (err error)
 RemoveAll(path string) (err error)

 // metadata about the filesystem
 ViewId() (id string) // Some unique id of the user accessing the filesystem
}

// DentryInfo is a subset of the functionality available through os.FileInfo that might be able
// to be gleaned through only a syscall.Getdents without requiring a syscall.Lstat of every file.
type DirEntryInfo interface {
 Name() string
 Mode() os.FileMode // the file type encoded as an os.FileMode
 IsDir() bool
}

type dirEntryInfo struct {
 name       string
 mode       os.FileMode
 modeExists bool
}

var _ DirEntryInfo = os.FileInfo(nil)

func (d *dirEntryInfo) Name() string      { return d.name }
func (d *dirEntryInfo) Mode() os.FileMode { return d.mode }
func (d *dirEntryInfo) IsDir() bool       { return d.mode.IsDir() }
func (d *dirEntryInfo) String() string    { return d.name + ": " + d.mode.String() }

// osFs implements FileSystem using the local disk.
type osFs struct{}

var _ FileSystem = (*osFs)(nil)

func (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) }

func (osFs) Lstat(path string) (stats os.FileInfo, err error) {
 return os.Lstat(path)
}

func (osFs) Stat(path string) (stats os.FileInfo, err error) {
 return os.Stat(path)
}

func (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
 entries, err := readdir(path)
 if err != nil {
  return nil, err
 }
 for _, entry := range entries {
  contents = append(contents, entry)
 }

 return contents, nil
}

func (osFs) Rename(oldPath string, newPath string) error {
 return os.Rename(oldPath, newPath)
}

func (osFs) WriteFile(path string, data []byte, perm os.FileMode) error {
 return ioutil.WriteFile(path, data, perm)
}

func (osFs) Remove(path string) error {
 return os.Remove(path)
}

func (osFs) RemoveAll(path string) error {
 return os.RemoveAll(path)
}

func (osFs) ViewId() (id string) {
 user, err := user.Current()
 if err != nil {
  return ""
 }
 username := user.Username

 hostname, err := os.Hostname()
 if err != nil {
  return ""
 }

 return username + "@" + hostname
}

type Clock struct {
 time time.Time
}

func NewClock(startTime time.Time) *Clock {
 return &Clock{time: startTime}

}

func (c *Clock) Tick() {
 c.time = c.time.Add(time.Microsecond)
}

func (c *Clock) Time() time.Time {
 return c.time
}

// given "/a/b/c/d", pathSplit returns ("/a/b/c", "d")
func pathSplit(path string) (dir string, leaf string) {
 dir, leaf = filepath.Split(path)
 if dir != "/" && len(dir) > 0 {
  dir = dir[:len(dir)-1]
 }
 return dir, leaf
}

// MockFs supports singlethreaded writes and multithreaded reads
type MockFs struct {
 // configuration
 viewId       string //
 deviceNumber uint64

 // implementation
 root            mockDir
 Clock           *Clock
 workDir         string
 nextInodeNumber uint64

 // history of requests, for tests to check
 StatCalls      []string
 ReadDirCalls   []string
 aggregatesLock sync.Mutex
}

var _ FileSystem = (*MockFs)(nil)

type mockInode struct {
 modTime     time.Time
 permTime    time.Time
 sys         interface{}
 inodeNumber uint64
 readErr     error
}

func (m mockInode) ModTime() time.Time {
 return m.modTime
}

func (m mockInode) Sys() interface{} {
 return m.sys
}

type mockFile struct {
 bytes []byte

 mockInode
}

type mockLink struct {
 target string

 mockInode
}

type mockDir struct {
 mockInode

 subdirs  map[string]*mockDir
 files    map[string]*mockFile
 symlinks map[string]*mockLink
}

func (m *MockFs) resolve(path string, followLastLink bool) (result string, err error) {
 if !filepath.IsAbs(path) {
  path = filepath.Join(m.workDir, path)
 }
 path = filepath.Clean(path)

 return m.followLinks(path, followLastLink, 10)
}

// note that followLinks can return a file path that doesn't exist
func (m *MockFs) followLinks(path string, followLastLink bool, count int) (canonicalPath string, err error) {
 if path == "/" {
  return path, nil
 }

 parentPath, leaf := pathSplit(path)
 if parentPath == path {
  err = fmt.Errorf("Internal error: %v yields itself as a parent", path)
  panic(err.Error())
 }

 parentPath, err = m.followLinks(parentPath, true, count)
 if err != nil {
  return "", err
 }

 parentNode, err := m.getDir(parentPath, false)
 if err != nil {
  return "", err
 }
 if parentNode.readErr != nil {
  return "", &os.PathError{
   Op:   "read",
   Path: path,
   Err:  parentNode.readErr,
  }
 }

 link, isLink := parentNode.symlinks[leaf]
 if isLink && followLastLink {
  if count <= 0 {
   // probably a loop
   return "", &os.PathError{
    Op:   "read",
    Path: path,
    Err:  fmt.Errorf("too many levels of symbolic links"),
   }
  }

  if link.readErr != nil {
   return "", &os.PathError{
    Op:   "read",
    Path: path,
    Err:  link.readErr,
   }
  }

  target := m.followLink(link, parentPath)
  return m.followLinks(target, followLastLink, count-1)
 }
 return path, nil
}

func (m *MockFs) followLink(link *mockLink, parentPath string) (result string) {
 return filepath.Clean(filepath.Join(parentPath, link.target))
}

func (m *MockFs) getFile(parentDir *mockDir, fileName string) (file *mockFile, err error) {
 file, isFile := parentDir.files[fileName]
 if !isFile {
  _, isDir := parentDir.subdirs[fileName]
  _, isLink := parentDir.symlinks[fileName]
  if isDir || isLink {
   return nil, &os.PathError{
    Op:   "open",
    Path: fileName,
    Err:  os.ErrInvalid,
   }
  }

  return nil, &os.PathError{
   Op:   "open",
   Path: fileName,
   Err:  os.ErrNotExist,
  }
 }
 if file.readErr != nil {
  return nil, &os.PathError{
   Op:   "open",
   Path: fileName,
   Err:  file.readErr,
  }
 }
 return file, nil
}

func (m *MockFs) getInode(parentDir *mockDir, name string) (inode *mockInode, err error) {
 file, isFile := parentDir.files[name]
 if isFile {
  return &file.mockInode, nil
 }
 link, isLink := parentDir.symlinks[name]
 if isLink {
  return &link.mockInode, nil
 }
 dir, isDir := parentDir.subdirs[name]
 if isDir {
  return &dir.mockInode, nil
 }
 return nil, &os.PathError{
  Op:   "stat",
  Path: name,
  Err:  os.ErrNotExist,
 }

}

func (m *MockFs) Open(path string) (io.ReadCloser, error) {
 path, err := m.resolve(path, true)
 if err != nil {
  return nil, err
 }

 if err != nil {
  return nil, err
 }

 parentPath, base := pathSplit(path)
 parentDir, err := m.getDir(parentPath, false)
 if err != nil {
  return nil, err
 }
 file, err := m.getFile(parentDir, base)
 if err != nil {
  return nil, err
 }
 return struct {
  io.Closer
  *bytes.Reader
 }{
  ioutil.NopCloser(nil),
  bytes.NewReader(file.bytes),
 }, nil

}

// a mockFileInfo is for exporting file stats in a way that satisfies the FileInfo interface
type mockFileInfo struct {
 path         string
 size         int64
 modTime      time.Time // time at which the inode's contents were modified
 permTime     time.Time // time at which the inode's permissions were modified
 mode         os.FileMode
 inodeNumber  uint64
 deviceNumber uint64
}

func (m *mockFileInfo) Name() string {
 return m.path
}

func (m *mockFileInfo) Size() int64 {
 return m.size
}

func (m *mockFileInfo) Mode() os.FileMode {
 return m.mode
}

func (m *mockFileInfo) ModTime() time.Time {
 return m.modTime
}

func (m *mockFileInfo) IsDir() bool {
 return m.mode&os.ModeDir != 0
}

func (m *mockFileInfo) Sys() interface{} {
 return nil
}

func (m *MockFs) dirToFileInfo(d *mockDir, path string) (info *mockFileInfo) {
 return &mockFileInfo{
  path:         filepath.Base(path),
  size:         1,
  modTime:      d.modTime,
  permTime:     d.permTime,
  mode:         os.ModeDir,
  inodeNumber:  d.inodeNumber,
  deviceNumber: m.deviceNumber,
 }

}

func (m *MockFs) fileToFileInfo(f *mockFile, path string) (info *mockFileInfo) {
 return &mockFileInfo{
  path:         filepath.Base(path),
  size:         1,
  modTime:      f.modTime,
  permTime:     f.permTime,
  mode:         0,
  inodeNumber:  f.inodeNumber,
  deviceNumber: m.deviceNumber,
 }
}

func (m *MockFs) linkToFileInfo(l *mockLink, path string) (info *mockFileInfo) {
 return &mockFileInfo{
  path:         filepath.Base(path),
  size:         1,
  modTime:      l.modTime,
  permTime:     l.permTime,
  mode:         os.ModeSymlink,
  inodeNumber:  l.inodeNumber,
  deviceNumber: m.deviceNumber,
 }
}

func (m *MockFs) Lstat(path string) (stats os.FileInfo, err error) {
 // update aggregates
 m.aggregatesLock.Lock()
 m.StatCalls = append(m.StatCalls, path)
 m.aggregatesLock.Unlock()

 // resolve symlinks
 path, err = m.resolve(path, false)
 if err != nil {
  return nil, err
 }

 // special case for root dir
 if path == "/" {
  return m.dirToFileInfo(&m.root, "/"), nil
 }

 // determine type and handle appropriately
 parentPath, baseName := pathSplit(path)
 dir, err := m.getDir(parentPath, false)
 if err != nil {
  return nil, err
 }
 subdir, subdirExists := dir.subdirs[baseName]
 if subdirExists {
  return m.dirToFileInfo(subdir, path), nil
 }
 file, fileExists := dir.files[baseName]
 if fileExists {
  return m.fileToFileInfo(file, path), nil
 }
 link, linkExists := dir.symlinks[baseName]
 if linkExists {
  return m.linkToFileInfo(link, path), nil
 }
 // not found
 return nil, &os.PathError{
  Op:   "stat",
  Path: path,
  Err:  os.ErrNotExist,
 }
}

func (m *MockFs) Stat(path string) (stats os.FileInfo, err error) {
 // resolve symlinks
 path, err = m.resolve(path, true)
 if err != nil {
  return nil, err
 }

 return m.Lstat(path)
}

func (m *MockFs) InodeNumber(info os.FileInfo) (number uint64, err error) {
 mockInfo, ok := info.(*mockFileInfo)
 if ok {
  return mockInfo.inodeNumber, nil
 }
 return 0, fmt.Errorf("%v is not a mockFileInfo", info)
}
func (m *MockFs) DeviceNumber(info os.FileInfo) (number uint64, err error) {
 mockInfo, ok := info.(*mockFileInfo)
 if ok {
  return mockInfo.deviceNumber, nil
 }
 return 0, fmt.Errorf("%v is not a mockFileInfo", info)
}
func (m *MockFs) PermTime(info os.FileInfo) (when time.Time, err error) {
 mockInfo, ok := info.(*mockFileInfo)
 if ok {
  return mockInfo.permTime, nil
 }
 return time.Date(0000000, nil),
  fmt.Errorf("%v is not a mockFileInfo", info)
}

func (m *MockFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
 // update aggregates
 m.aggregatesLock.Lock()
 m.ReadDirCalls = append(m.ReadDirCalls, path)
 m.aggregatesLock.Unlock()

 // locate directory
 path, err = m.resolve(path, true)
 if err != nil {
  return nil, err
 }
 results := []DirEntryInfo{}
 dir, err := m.getDir(path, false)
 if err != nil {
  return nil, err
 }
 if dir.readErr != nil {
  return nil, &os.PathError{
   Op:   "read",
   Path: path,
   Err:  dir.readErr,
  }
 }
 // describe its contents
 for name, subdir := range dir.subdirs {
  dirInfo := m.dirToFileInfo(subdir, name)
  results = append(results, dirInfo)
 }
 for name, file := range dir.files {
  info := m.fileToFileInfo(file, name)
  results = append(results, info)
 }
 for name, link := range dir.symlinks {
  info := m.linkToFileInfo(link, name)
  results = append(results, info)
 }
 return results, nil
}

func (m *MockFs) Rename(sourcePath string, destPath string) error {
 // validate source parent exists
 sourcePath, err := m.resolve(sourcePath, false)
 if err != nil {
  return err
 }
 sourceParentPath := filepath.Dir(sourcePath)
 sourceParentDir, err := m.getDir(sourceParentPath, false)
 if err != nil {
  return err
 }
 if sourceParentDir == nil {
  return &os.PathError{
   Op:   "move",
   Path: sourcePath,
   Err:  os.ErrNotExist,
  }
 }
 if sourceParentDir.readErr != nil {
  return &os.PathError{
   Op:   "move",
   Path: sourcePath,
   Err:  sourceParentDir.readErr,
  }
 }

 // validate dest parent exists
 destPath, err = m.resolve(destPath, false)
 destParentPath := filepath.Dir(destPath)
 destParentDir, err := m.getDir(destParentPath, false)
 if err != nil {
  return err
 }
 if destParentDir == nil {
  return &os.PathError{
   Op:   "move",
   Path: destParentPath,
   Err:  os.ErrNotExist,
  }
 }
 if destParentDir.readErr != nil {
  return &os.PathError{
   Op:   "move",
   Path: destParentPath,
   Err:  destParentDir.readErr,
  }
 }
 // check the source and dest themselves
 sourceBase := filepath.Base(sourcePath)
 destBase := filepath.Base(destPath)

 file, sourceIsFile := sourceParentDir.files[sourceBase]
 dir, sourceIsDir := sourceParentDir.subdirs[sourceBase]
 link, sourceIsLink := sourceParentDir.symlinks[sourceBase]

 // validate that the source exists
 if !sourceIsFile && !sourceIsDir && !sourceIsLink {
  return &os.PathError{
   Op:   "move",
   Path: sourcePath,
   Err:  os.ErrNotExist,
  }

 }

 // validate the destination doesn't already exist as an incompatible type
 _, destWasFile := destParentDir.files[destBase]
 _, destWasDir := destParentDir.subdirs[destBase]
 _, destWasLink := destParentDir.symlinks[destBase]

 if destWasDir {
  return &os.PathError{
   Op:   "move",
   Path: destPath,
   Err:  errors.New("destination exists as a directory"),
  }
 }

 if sourceIsDir && (destWasFile || destWasLink) {
  return &os.PathError{
   Op:   "move",
   Path: destPath,
   Err:  errors.New("destination exists as a file"),
  }
 }

 if destWasFile {
  delete(destParentDir.files, destBase)
 }
 if destWasDir {
  delete(destParentDir.subdirs, destBase)
 }
 if destWasLink {
  delete(destParentDir.symlinks, destBase)
 }

 if sourceIsFile {
  destParentDir.files[destBase] = file
  delete(sourceParentDir.files, sourceBase)
 }
 if sourceIsDir {
  destParentDir.subdirs[destBase] = dir
  delete(sourceParentDir.subdirs, sourceBase)
 }
 if sourceIsLink {
  destParentDir.symlinks[destBase] = link
  delete(destParentDir.symlinks, sourceBase)
 }

 destParentDir.modTime = m.Clock.Time()
 sourceParentDir.modTime = m.Clock.Time()
 return nil
}

func (m *MockFs) newInodeNumber() uint64 {
 result := m.nextInodeNumber
 m.nextInodeNumber++
 return result
}

func (m *MockFs) WriteFile(filePath string, data []byte, perm os.FileMode) error {
 filePath, err := m.resolve(filePath, true)
 if err != nil {
  return err
 }
 parentPath := filepath.Dir(filePath)
 parentDir, err := m.getDir(parentPath, false)
 if err != nil || parentDir == nil {
  return &os.PathError{
   Op:   "write",
   Path: parentPath,
   Err:  os.ErrNotExist,
  }
 }
 if parentDir.readErr != nil {
  return &os.PathError{
   Op:   "write",
   Path: parentPath,
   Err:  parentDir.readErr,
  }
 }

 baseName := filepath.Base(filePath)
 _, exists := parentDir.files[baseName]
 if !exists {
  parentDir.modTime = m.Clock.Time()
  parentDir.files[baseName] = m.newFile()
 } else {
  readErr := parentDir.files[baseName].readErr
  if readErr != nil {
   return &os.PathError{
    Op:   "write",
    Path: filePath,
    Err:  readErr,
   }
  }
 }
 file := parentDir.files[baseName]
 file.bytes = data
 file.modTime = m.Clock.Time()
 return nil
}

func (m *MockFs) newFile() *mockFile {
 newFile := &mockFile{}
 newFile.inodeNumber = m.newInodeNumber()
 newFile.modTime = m.Clock.Time()
 newFile.permTime = newFile.modTime
 return newFile
}

func (m *MockFs) newDir() *mockDir {
 newDir := &mockDir{
  subdirs:  make(map[string]*mockDir, 0),
  files:    make(map[string]*mockFile, 0),
  symlinks: make(map[string]*mockLink, 0),
 }
 newDir.inodeNumber = m.newInodeNumber()
 newDir.modTime = m.Clock.Time()
 newDir.permTime = newDir.modTime
 return newDir
}

func (m *MockFs) newLink(target string) *mockLink {
 newLink := &mockLink{
  target: target,
 }
 newLink.inodeNumber = m.newInodeNumber()
 newLink.modTime = m.Clock.Time()
 newLink.permTime = newLink.modTime

 return newLink
}
func (m *MockFs) MkDirs(path string) error {
 _, err := m.getDir(path, true)
 return err
}

// getDir doesn't support symlinks
func (m *MockFs) getDir(path string, createIfMissing bool) (dir *mockDir, err error) {
 cleanedPath := filepath.Clean(path)
 if cleanedPath == "/" {
  return &m.root, nil
 }

 parentPath, leaf := pathSplit(cleanedPath)
 if len(parentPath) >= len(path) {
  return &m.root, nil
 }
 parent, err := m.getDir(parentPath, createIfMissing)
 if err != nil {
  return nil, err
 }
 if parent.readErr != nil {
  return nil, &os.PathError{
   Op:   "stat",
   Path: path,
   Err:  parent.readErr,
  }
 }
 childDir, dirExists := parent.subdirs[leaf]
 if !dirExists {
  if createIfMissing {
   // confirm that a file with the same name doesn't already exist
   _, fileExists := parent.files[leaf]
   if fileExists {
    return nil, &os.PathError{
     Op:   "mkdir",
     Path: path,
     Err:  os.ErrExist,
    }
   }
   // create this directory
   childDir = m.newDir()
   parent.subdirs[leaf] = childDir
   parent.modTime = m.Clock.Time()
  } else {
   return nil, &os.PathError{
    Op:   "stat",
    Path: path,
    Err:  os.ErrNotExist,
   }
  }
 }
 return childDir, nil

}

func (m *MockFs) Remove(path string) (err error) {
 path, err = m.resolve(path, false)
 parentPath, leaf := pathSplit(path)
 if len(leaf) == 0 {
  return fmt.Errorf("Cannot remove %v\n", path)
 }
 parentDir, err := m.getDir(parentPath, false)
 if err != nil {
  return err
 }
 if parentDir == nil {
  return &os.PathError{
   Op:   "remove",
   Path: path,
   Err:  os.ErrNotExist,
  }
 }
 if parentDir.readErr != nil {
  return &os.PathError{
   Op:   "remove",
   Path: path,
   Err:  parentDir.readErr,
  }
 }
 _, isDir := parentDir.subdirs[leaf]
 if isDir {
  return &os.PathError{
   Op:   "remove",
   Path: path,
   Err:  os.ErrInvalid,
  }
 }
 _, isLink := parentDir.symlinks[leaf]
 if isLink {
  delete(parentDir.symlinks, leaf)
 } else {
  _, isFile := parentDir.files[leaf]
  if !isFile {
   return &os.PathError{
    Op:   "remove",
    Path: path,
    Err:  os.ErrNotExist,
   }
  }
  delete(parentDir.files, leaf)
 }
 parentDir.modTime = m.Clock.Time()
 return nil
}

func (m *MockFs) Symlink(oldPath string, newPath string) (err error) {
 newPath, err = m.resolve(newPath, false)
 if err != nil {
  return err
 }

 newParentPath, leaf := pathSplit(newPath)
 newParentDir, err := m.getDir(newParentPath, false)
 if newParentDir.readErr != nil {
  return &os.PathError{
   Op:   "link",
   Path: newPath,
   Err:  newParentDir.readErr,
  }
 }
 if err != nil {
  return err
 }
 newParentDir.symlinks[leaf] = m.newLink(oldPath)
 return nil
}

func (m *MockFs) RemoveAll(path string) (err error) {
 path, err = m.resolve(path, false)
 if err != nil {
  return err
 }
 parentPath, leaf := pathSplit(path)
 if len(leaf) == 0 {
  return fmt.Errorf("Cannot remove %v\n", path)
 }
 parentDir, err := m.getDir(parentPath, false)
 if err != nil {
  return err
 }
 if parentDir == nil {
  return &os.PathError{
   Op:   "removeAll",
   Path: path,
   Err:  os.ErrNotExist,
  }
 }
 if parentDir.readErr != nil {
  return &os.PathError{
   Op:   "removeAll",
   Path: path,
   Err:  parentDir.readErr,
  }

 }
 _, isFile := parentDir.files[leaf]
 _, isLink := parentDir.symlinks[leaf]
 if isFile || isLink {
  return m.Remove(path)
 }
 _, isDir := parentDir.subdirs[leaf]
 if !isDir {
  if !isDir {
   return &os.PathError{
    Op:   "removeAll",
    Path: path,
    Err:  os.ErrNotExist,
   }
  }
 }

 delete(parentDir.subdirs, leaf)
 parentDir.modTime = m.Clock.Time()
 return nil
}

func (m *MockFs) SetReadable(path string, readable bool) error {
 var readErr error
 if !readable {
  readErr = os.ErrPermission
 }
 return m.SetReadErr(path, readErr)
}

func (m *MockFs) SetReadErr(path string, readErr error) error {
 path, err := m.resolve(path, false)
 if err != nil {
  return err
 }
 parentPath, leaf := filepath.Split(path)
 parentDir, err := m.getDir(parentPath, false)
 if err != nil {
  return err
 }
 if parentDir.readErr != nil {
  return &os.PathError{
   Op:   "chmod",
   Path: parentPath,
   Err:  parentDir.readErr,
  }
 }

 inode, err := m.getInode(parentDir, leaf)
 if err != nil {
  return err
 }
 inode.readErr = readErr
 inode.permTime = m.Clock.Time()
 return nil
}

func (m *MockFs) ClearMetrics() {
 m.ReadDirCalls = []string{}
 m.StatCalls = []string{}
}

func (m *MockFs) ViewId() (id string) {
 return m.viewId
}

func (m *MockFs) SetViewId(id string) {
 m.viewId = id
}
func (m *MockFs) SetDeviceNumber(deviceNumber uint64) {
 m.deviceNumber = deviceNumber
}

[Dauer der Verarbeitung: 0.24 Sekunden, vorverarbeitet 2026-06-28]