diff options
Diffstat (limited to 'pkg/sentry/fsimpl/memfs/directory.go')
-rw-r--r-- | pkg/sentry/fsimpl/memfs/directory.go | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/pkg/sentry/fsimpl/memfs/directory.go b/pkg/sentry/fsimpl/memfs/directory.go index b0c3ea39a..c52dc781c 100644 --- a/pkg/sentry/fsimpl/memfs/directory.go +++ b/pkg/sentry/fsimpl/memfs/directory.go @@ -23,23 +23,23 @@ import ( ) type directory struct { - inode Inode + inode inode // childList is a list containing (1) child Dentries and (2) fake Dentries // (with inode == nil) that represent the iteration position of // directoryFDs. childList is used to support directoryFD.IterDirents() - // efficiently. childList is protected by Filesystem.mu. + // efficiently. childList is protected by filesystem.mu. childList dentryList } -func (fs *Filesystem) newDirectory(creds *auth.Credentials, mode uint16) *Inode { +func (fs *filesystem) newDirectory(creds *auth.Credentials, mode uint16) *inode { dir := &directory{} dir.inode.init(dir, fs, creds, mode) dir.inode.nlink = 2 // from "." and parent directory or ".." for root return &dir.inode } -func (i *Inode) isDir() bool { +func (i *inode) isDir() bool { _, ok := i.impl.(*directory) return ok } @@ -48,8 +48,8 @@ type directoryFD struct { fileDescription vfs.DirectoryFileDescriptionDefaultImpl - // Protected by Filesystem.mu. - iter *Dentry + // Protected by filesystem.mu. + iter *dentry off int64 } @@ -68,7 +68,7 @@ func (fd *directoryFD) Release() { // IterDirents implements vfs.FileDescriptionImpl.IterDirents. func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback) error { fs := fd.filesystem() - d := fd.vfsfd.VirtualDentry().Dentry() + vfsd := fd.vfsfd.VirtualDentry().Dentry() fs.mu.Lock() defer fs.mu.Unlock() @@ -77,7 +77,7 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba if !cb.Handle(vfs.Dirent{ Name: ".", Type: linux.DT_DIR, - Ino: d.Impl().(*Dentry).inode.ino, + Ino: vfsd.Impl().(*dentry).inode.ino, Off: 0, }) { return nil @@ -85,7 +85,7 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba fd.off++ } if fd.off == 1 { - parentInode := d.ParentOrSelf().Impl().(*Dentry).inode + parentInode := vfsd.ParentOrSelf().Impl().(*dentry).inode if !cb.Handle(vfs.Dirent{ Name: "..", Type: parentInode.direntType(), @@ -97,12 +97,12 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba fd.off++ } - dir := d.Impl().(*Dentry).inode.impl.(*directory) - var child *Dentry + dir := vfsd.Impl().(*dentry).inode.impl.(*directory) + var child *dentry if fd.iter == nil { // Start iteration at the beginning of dir. child = dir.childList.Front() - fd.iter = &Dentry{} + fd.iter = &dentry{} } else { // Continue iteration from where we left off. child = fd.iter.Next() @@ -130,32 +130,41 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba // Seek implements vfs.FileDescriptionImpl.Seek. func (fd *directoryFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { - if whence != linux.SEEK_SET { - // TODO: Linux also allows SEEK_CUR. + fs := fd.filesystem() + fs.mu.Lock() + defer fs.mu.Unlock() + + switch whence { + case linux.SEEK_SET: + // Use offset as given. + case linux.SEEK_CUR: + offset += fd.off + default: return 0, syserror.EINVAL } if offset < 0 { return 0, syserror.EINVAL } + // If the offset isn't changing (e.g. due to lseek(0, SEEK_CUR)), don't + // seek even if doing so might reposition the iterator due to concurrent + // mutation of the directory. Compare fs/libfs.c:dcache_dir_lseek(). + if fd.off == offset { + return offset, nil + } + fd.off = offset // Compensate for "." and "..". - var remChildren int64 - if offset < 2 { - remChildren = 0 - } else { + remChildren := int64(0) + if offset >= 2 { remChildren = offset - 2 } - fs := fd.filesystem() dir := fd.inode().impl.(*directory) - fs.mu.Lock() - defer fs.mu.Unlock() - // Ensure that fd.iter exists and is not linked into dir.childList. if fd.iter == nil { - fd.iter = &Dentry{} + fd.iter = &dentry{} } else { dir.childList.Remove(fd.iter) } |