Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #211 from stealthrocket/sandbox-fs-fix-python-tests
Browse files Browse the repository at this point in the history
sandbox: fix python tests
  • Loading branch information
achille-roussel authored Aug 10, 2023
2 parents 4a5fa20 + 0edf1e2 commit 7c1c1bc
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 104 deletions.
68 changes: 32 additions & 36 deletions internal/sandbox/dirfs_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type dirFS struct {
root string
}

func (fsys *dirFS) Open(name string, flags int, mode fs.FileMode) (File, error) {
func (fsys *dirFS) Open(name string, flags OpenFlags, mode fs.FileMode) (File, error) {
f, err := fsys.openRoot()
if err != nil {
return nil, err
Expand All @@ -26,7 +26,7 @@ func (fsys *dirFS) Open(name string, flags int, mode fs.FileMode) (File, error)
}

func (fsys *dirFS) openRoot() (File, error) {
dirfd, err := openat(unix.AT_FDCWD, fsys.root, O_DIRECTORY, 0)
dirfd, err := openat(unix.AT_FDCWD, fsys.root, O_DIRECTORY.sysFlags(), 0)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -100,15 +100,15 @@ func (f *dirFile) openRoot() (File, error) {
return f.openSelf()
}

func (f *dirFile) openFile(name string, flags int, mode fs.FileMode) (File, error) {
fd, err := openat(f.fd, name, flags|O_NOFOLLOW, uint32(mode.Perm()))
func (f *dirFile) openFile(name string, flags OpenFlags, mode fs.FileMode) (File, error) {
fd, err := openat(f.fd, name, (flags | O_NOFOLLOW).sysFlags(), uint32(mode.Perm()))
if err != nil {
return nil, err
}
return newFile(f, fd), nil
}

func (f *dirFile) open(name string, flags int, mode fs.FileMode) (File, error) {
func (f *dirFile) open(name string, flags OpenFlags, mode fs.FileMode) (File, error) {
switch name {
case ".":
return f.openSelf()
Expand All @@ -119,11 +119,14 @@ func (f *dirFile) open(name string, flags int, mode fs.FileMode) (File, error) {
}
}

func (f *dirFile) Open(name string, flags int, mode fs.FileMode) (File, error) {
func (f *dirFile) Open(name string, flags OpenFlags, mode fs.FileMode) (File, error) {
if fspath.IsRoot(name) {
return f.openRoot()
}
return ResolvePath(f, name, flags, func(d *dirFile, name string) (File, error) {
if fspath.HasTrailingSlash(name) {
flags |= O_DIRECTORY
}
return ResolvePath(f, name, flags.LookupFlags(), func(d *dirFile, name string) (File, error) {
return d.open(name, flags, mode)
})
}
Expand Down Expand Up @@ -164,28 +167,29 @@ func (f *dirFile) Datasync() error {
return fdatasync(f.fd)
}

func (f *dirFile) Flags() (int, error) {
return unix.FcntlInt(uintptr(f.fd), unix.F_GETFL, 0)
func (f *dirFile) Flags() (OpenFlags, error) {
flags, err := unix.FcntlInt(uintptr(f.fd), unix.F_GETFL, 0)
return makeOpenFlags(flags), err
}

func (f *dirFile) SetFlags(flags int) error {
_, err := unix.FcntlInt(uintptr(f.fd), unix.F_SETFL, flags)
func (f *dirFile) SetFlags(flags OpenFlags) error {
_, err := unix.FcntlInt(uintptr(f.fd), unix.F_SETFL, flags.sysFlags())
return err
}

func (f *dirFile) ReadDirent(buf []byte) (int, error) {
return ignoreEINTR2(func() (int, error) { return unix.ReadDirent(f.fd, buf) })
}

func (f *dirFile) Stat(name string, flags int) (FileInfo, error) {
return ResolvePath(f, name, openFlags(flags), func(d *dirFile, name string) (FileInfo, error) {
func (f *dirFile) Stat(name string, flags LookupFlags) (FileInfo, error) {
return ResolvePath(f, name, flags, func(d *dirFile, name string) (FileInfo, error) {
var stat unix.Stat_t
var err error

if name == "" {
err = fstat(d.fd, &stat)
} else {
err = fstatat(d.fd, name, &stat, AT_SYMLINK_NOFOLLOW)
err = fstatat(d.fd, name, &stat, AT_SYMLINK_NOFOLLOW.sysFlags())
}
if err != nil {
return FileInfo{}, err
Expand Down Expand Up @@ -231,7 +235,7 @@ func (f *dirFile) Stat(name string, flags int) (FileInfo, error) {
}

func (f *dirFile) Readlink(name string, buf []byte) (int, error) {
return ResolvePath(f, name, O_NOFOLLOW, func(d *dirFile, name string) (int, error) {
return ResolvePath(f, name, AT_SYMLINK_NOFOLLOW, func(d *dirFile, name string) (int, error) {
if name == "" {
return freadlink(d.fd, buf)
} else {
Expand All @@ -240,24 +244,24 @@ func (f *dirFile) Readlink(name string, buf []byte) (int, error) {
})
}

func (f *dirFile) Chtimes(name string, times [2]Timespec, flags int) error {
return resolvePath1(f, name, openFlags(flags), func(d *dirFile, name string) error {
func (f *dirFile) Chtimes(name string, times [2]Timespec, flags LookupFlags) error {
return resolvePath1(f, name, flags, func(d *dirFile, name string) error {
if name == "" {
return futimens(d.fd, &times)
} else {
return utimensat(d.fd, name, &times, AT_SYMLINK_NOFOLLOW)
return utimensat(d.fd, name, &times, AT_SYMLINK_NOFOLLOW.sysFlags())
}
})
}

func (f *dirFile) Mkdir(name string, mode fs.FileMode) error {
return resolvePath1(f, name, O_NOFOLLOW, func(d *dirFile, name string) error {
return resolvePath1(f, name, AT_SYMLINK_NOFOLLOW, func(d *dirFile, name string) error {
return mkdirat(d.fd, name, uint32(mode.Perm()))
})
}

func (f *dirFile) Rmdir(name string) error {
return resolvePath1(f, name, O_NOFOLLOW, func(d *dirFile, name string) error {
return resolvePath1(f, name, AT_SYMLINK_NOFOLLOW, func(d *dirFile, name string) error {
return unlinkat(d.fd, name, unix.AT_REMOVEDIR)
})
}
Expand All @@ -267,46 +271,38 @@ func (f1 *dirFile) Rename(oldName string, newDir File, newName string) error {
if !ok {
return EXDEV
}
return resolvePath1(f1, oldName, O_NOFOLLOW, func(d1 *dirFile, name1 string) error {
return resolvePath1(f2, newName, O_NOFOLLOW, func(d2 *dirFile, name2 string) error {
return resolvePath1(f1, oldName, AT_SYMLINK_NOFOLLOW, func(d1 *dirFile, name1 string) error {
return resolvePath1(f2, newName, AT_SYMLINK_NOFOLLOW, func(d2 *dirFile, name2 string) error {
return renameat(d1.fd, name1, d2.fd, name2)
})
})
}

func (f1 *dirFile) Link(oldName string, newDir File, newName string, flags int) error {
func (f1 *dirFile) Link(oldName string, newDir File, newName string, flags LookupFlags) error {
f2, ok := newDir.(*dirFile)
if !ok {
return EXDEV
}
oflags := openFlags(flags)
return resolvePath1(f1, oldName, oflags, func(d1 *dirFile, name1 string) error {
return resolvePath1(f2, newName, oflags, func(d2 *dirFile, name2 string) error {
return resolvePath1(f1, oldName, flags, func(d1 *dirFile, name1 string) error {
return resolvePath1(f2, newName, flags, func(d2 *dirFile, name2 string) error {
return linkat(d1.fd, name1, d2.fd, name2, 0)
})
})
}

func (f *dirFile) Symlink(oldName string, newName string) error {
return resolvePath1(f, newName, O_NOFOLLOW, func(d *dirFile, name string) error {
return resolvePath1(f, newName, AT_SYMLINK_NOFOLLOW, func(d *dirFile, name string) error {
return symlinkat(oldName, d.fd, name)
})
}

func (f *dirFile) Unlink(name string) error {
return resolvePath1(f, name, O_NOFOLLOW, func(d *dirFile, name string) error {
return resolvePath1(f, name, AT_SYMLINK_NOFOLLOW, func(d *dirFile, name string) error {
return unlinkat(d.fd, name, 0)
})
}

func openFlags(flags int) int {
if (flags & AT_SYMLINK_NOFOLLOW) != 0 {
return O_NOFOLLOW
}
return 0
}

func resolvePath1(d *dirFile, name string, flags int, do func(*dirFile, string) error) error {
func resolvePath1(d *dirFile, name string, flags LookupFlags, do func(*dirFile, string) error) error {
_, err := ResolvePath(d, name, flags, func(d *dirFile, name string) (_ struct{}, err error) {
err = do(d, name)
return
Expand Down
86 changes: 86 additions & 0 deletions internal/sandbox/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package sandbox

import (
"sort"
"strings"
)

// OpenFlags is a bitset of flags that can be passed to the Open method of
// File and FileSystem values.
type OpenFlags int

func makeOpenFlags(sysFlags int) OpenFlags {
return OpenFlags(sysFlags)
}

func (openFlags OpenFlags) String() string {
var names []string

switch openFlags & (O_RDWR | O_WRONLY | O_RDONLY) {
case O_RDWR:
names = append(names, "O_RDWR")
case O_WRONLY:
names = append(names, "O_WRONLY")
}

for _, f := range [...]struct {
flag OpenFlags
name string
}{
{O_APPEND, "O_APPEND"},
{O_CREAT, "O_CREAT"},
{O_EXCL, "O_EXCL"},
{O_SYNC, "O_SYNC"},
{O_TRUNC, "O_TRUNC"},
{O_DIRECTORY, "O_DIRECTORY"},
{O_NOFOLLOW, "O_NOFOLLOW"},
{O_NONBLOCK, "O_NONBLOCK"},
} {
if (openFlags & f.flag) != 0 {
names = append(names, f.name)
}
}

if len(names) == 0 {
names = append(names, "O_RDONLY")
}

sort.Strings(names)
return strings.Join(names, "|")
}

func (openFlags OpenFlags) LookupFlags() LookupFlags {
if (openFlags & O_NOFOLLOW) != 0 {
return AT_SYMLINK_NOFOLLOW
} else {
return 0
}
}

func (openFlags OpenFlags) sysFlags() int {
return int(openFlags)
}

// LookupFlags is a bitset of flags that can be passed to methods of File and
// FileSystem values to customize the behavior of file name lookups.
type LookupFlags int

func (lookupFlags LookupFlags) String() string {
if (lookupFlags & AT_SYMLINK_NOFOLLOW) != 0 {
return "AT_SYMLINK_NOFOLLOW"
} else {
return "AT_SYMLINK_FOLLOW"
}
}

func (lookupFlags LookupFlags) OpenFlags() OpenFlags {
if (lookupFlags & AT_SYMLINK_NOFOLLOW) != 0 {
return O_NOFOLLOW
} else {
return 0
}
}

func (lookupFlags LookupFlags) sysFlags() int {
return int(lookupFlags)
}
28 changes: 12 additions & 16 deletions internal/sandbox/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const (
// root directory and use the methods of the returned File instance to access
// the rest of the directory tree.
type FileSystem interface {
Open(name string, flags int, mode fs.FileMode) (File, error)
Open(name string, flags OpenFlags, mode fs.FileMode) (File, error)
}

// Create creates and opens a file on a file system. The name is the location
Expand Down Expand Up @@ -102,8 +102,8 @@ func Stat(fsys FileSystem, name string) (FileInfo, error) {
// the location where the file is recorded on the file system. The flags are
// passed to configure how the file is opened (e.g. passing O_NOFOLLOW will
// fail if a symbolic link exists at that location).
func ReadFile(fsys FileSystem, name string, flags int) ([]byte, error) {
f, err := fsys.Open(name, flags|O_RDONLY, 0)
func ReadFile(fsys FileSystem, name string, flags LookupFlags) ([]byte, error) {
f, err := fsys.Open(name, flags.OpenFlags()|O_RDONLY, 0)
if err != nil {
return nil, &fs.PathError{Op: "read", Path: name, Err: err}
}
Expand Down Expand Up @@ -310,7 +310,7 @@ type File interface {
// file system.
//
// The file must point to a directory or the method errors with ENOTDIR.
Open(name string, flags int, mode fs.FileMode) (File, error)
Open(name string, flags OpenFlags, mode fs.FileMode) (File, error)

// Readv reads data from the current seek offset of the file into the list
// of vectors passed as arguments.
Expand Down Expand Up @@ -378,13 +378,13 @@ type File interface {
// combination of O_* flags such as those that can be passed to Open.
//
// The set of flags supported by the file depends on the underlying type.
Flags() (int, error)
Flags() (OpenFlags, error)

// Changes the bitset of flags set on the file. The flags are a combination
// of O_* flags such as those that can be passed to Open.
//
// The set of flags supported by the file depends on the underlying type.
SetFlags(flags int) error
SetFlags(flags OpenFlags) error

// Read directory entries into the given buffer. The caller must be aware of
// the way directory entries are laid out by the underlying file system to
Expand All @@ -402,7 +402,7 @@ type File interface {
//
// If the name is empty, flags are ignored and the method returns metdata
// for the receiver.
Stat(name string, flags int) (FileInfo, error)
Stat(name string, flags LookupFlags) (FileInfo, error)

// Reads the target of a symbolic link into buf.
//
Expand All @@ -425,7 +425,7 @@ type File interface {
//
// If the name is empty, flags are ignored and the method changes times of
// the receiver.
Chtimes(name string, times [2]Timespec, flags int) error
Chtimes(name string, times [2]Timespec, flags LookupFlags) error

// Creates a directory at the named location.
//
Expand Down Expand Up @@ -462,7 +462,7 @@ type File interface {
//
// The flags may be AT_SYMLINK_NOFOLLOW to create a link to a symbolic link
// instead of its target.
Link(oldName string, newDir File, newName string, flags int) error
Link(oldName string, newDir File, newName string, flags LookupFlags) error

// Creates a symbolic link to a named location.
//
Expand Down Expand Up @@ -734,13 +734,10 @@ func (dirent *fsDirEntry) Info() (fs.FileInfo, error) {
// was encountered and must be followed, in which case ResolvePath continues
// walking the path at the link target. Any other value or error returned by the
// do function will be returned immediately.
func ResolvePath[F File, R any](dir F, name string, flags int, do func(F, string) (R, error)) (ret R, err error) {
func ResolvePath[F File, R any](dir F, name string, flags LookupFlags, do func(F, string) (R, error)) (ret R, err error) {
if name == "" {
return do(dir, "")
}
if fspath.HasTrailingSlash(name) {
flags |= O_DIRECTORY
}

var lastOpenDir File
defer func() { closeFileIfNotNil(lastOpenDir) }()
Expand Down Expand Up @@ -795,7 +792,7 @@ func ResolvePath[F File, R any](dir F, name string, flags int, do func(F, string
doFile:
ret, err = do(dir, elem)
if err != nil {
if !errors.Is(err, ELOOP) || ((flags & O_NOFOLLOW) != 0) {
if !errors.Is(err, ELOOP) || ((flags & AT_SYMLINK_NOFOLLOW) != 0) {
return ret, err
}
switch err := followSymlink(elem, ""); {
Expand All @@ -816,7 +813,6 @@ func ResolvePath[F File, R any](dir F, name string, flags int, do func(F, string
continue
}

openPath:
d, err := dir.Open(elem, openPathFlags, 0)
if err != nil {
if !errors.Is(err, ENOTDIR) {
Expand All @@ -826,7 +822,7 @@ func ResolvePath[F File, R any](dir F, name string, flags int, do func(F, string
case errors.Is(err, nil):
continue
case errors.Is(err, EINVAL):
goto openPath
return ret, ENOTDIR
default:
return ret, err
}
Expand Down
Loading

0 comments on commit 7c1c1bc

Please sign in to comment.