diff --git a/internal/sandbox/tarfs/dir.go b/internal/sandbox/tarfs/dir.go index fbd6fbbf..c2176d37 100644 --- a/internal/sandbox/tarfs/dir.go +++ b/internal/sandbox/tarfs/dir.go @@ -13,7 +13,6 @@ import ( ) type dir struct { - name string ents []dirEntry info sandbox.FileInfo } @@ -23,8 +22,8 @@ type dirEntry struct { file fileEntry } -func (d *dir) open(fsys *FileSystem) (sandbox.File, error) { - open := &openDir{fsys: fsys} +func (d *dir) open(fsys *FileSystem, name string) (sandbox.File, error) { + open := &openDir{fsys: fsys, name: name} open.dir.Store(d) return open, nil } @@ -37,15 +36,12 @@ func (d *dir) mode() fs.FileMode { return d.info.Mode } -func (d *dir) memsize() (size uintptr) { - size += unsafe.Sizeof(dir{}) - size += uintptr(len(d.name)) - +func (d *dir) memsize() uintptr { + size := unsafe.Sizeof(dir{}) for _, ent := range d.ents { size += unsafe.Sizeof(ent) size += uintptr(len(ent.name)) } - return size } @@ -59,12 +55,14 @@ func (d *dir) find(name string) fileEntry { return d.ents[i].file } -func resolve[R any](fsys *FileSystem, cwd *dir, name string, flags int, do func(fileEntry) (R, error)) (R, error) { +func resolve[R any](fsys *FileSystem, cwd *dir, cwdName, name string, flags int, do func(fileEntry, []string) (R, error)) (R, error) { var zero R + pathElems := make([]string, 1, 8) + pathElems[0] = cwdName for loop := 0; loop < sandbox.MaxFollowSymlink; loop++ { if name == "" { - return do(cwd) + return do(cwd, pathElems) } var elem string @@ -72,6 +70,7 @@ func resolve[R any](fsys *FileSystem, cwd *dir, name string, flags int, do func( if elem == "/" { cwd = &fsys.root + pathElems = append(pathElems[:0], "/") continue } @@ -80,6 +79,8 @@ func resolve[R any](fsys *FileSystem, cwd *dir, name string, flags int, do func( return zero, sandbox.ENOENT } + pathElems = append(pathElems, elem) + if name != "" { switch c := f.(type) { case *symlink: @@ -105,7 +106,7 @@ func resolve[R any](fsys *FileSystem, cwd *dir, name string, flags int, do func( } } - return do(f) + return do(f, pathElems) } return zero, sandbox.ELOOP @@ -114,6 +115,7 @@ func resolve[R any](fsys *FileSystem, cwd *dir, name string, flags int, do func( type openDir struct { readOnlyFile fsys *FileSystem + name string dir atomic.Pointer[dir] mu sync.Mutex index int @@ -121,10 +123,7 @@ type openDir struct { } func (d *openDir) Name() string { - if dir := d.dir.Load(); dir != nil { - return dir.name - } - return "" + return d.name } func (d *openDir) Close() error { @@ -151,11 +150,11 @@ func (d *openDir) Open(name string, flags int, mode fs.FileMode) (sandbox.File, flags |= sandbox.O_DIRECTORY } - return resolve(d.fsys, dir, name, flags, func(f fileEntry) (sandbox.File, error) { + return resolve(d.fsys, dir, d.name, name, flags, func(f fileEntry, pathElems []string) (sandbox.File, error) { if _, ok := f.(*symlink); ok { return nil, sandbox.ELOOP } - return f.open(d.fsys) + return f.open(d.fsys, path.Join(pathElems...)) }) } @@ -168,7 +167,7 @@ func (d *openDir) Stat(name string, flags int) (sandbox.FileInfo, error) { if (flags & sandbox.AT_SYMLINK_NOFOLLOW) != 0 { openFlags |= sandbox.O_NOFOLLOW } - return resolve(d.fsys, dir, name, openFlags, func(f fileEntry) (sandbox.FileInfo, error) { + return resolve(d.fsys, dir, d.name, name, openFlags, func(f fileEntry, _ []string) (sandbox.FileInfo, error) { return f.stat(), nil }) } @@ -178,7 +177,7 @@ func (d *openDir) Readlink(name string, buf []byte) (int, error) { if dir == nil { return 0, sandbox.EBADF } - return resolve(d.fsys, dir, name, sandbox.O_NOFOLLOW, func(f fileEntry) (int, error) { + return resolve(d.fsys, dir, d.name, name, sandbox.O_NOFOLLOW, func(f fileEntry, _ []string) (int, error) { if s, ok := f.(*symlink); ok { return copy(buf, s.link), nil } else { diff --git a/internal/sandbox/tarfs/file.go b/internal/sandbox/tarfs/file.go index 66d44b4e..b086031b 100644 --- a/internal/sandbox/tarfs/file.go +++ b/internal/sandbox/tarfs/file.go @@ -11,13 +11,12 @@ import ( ) type file struct { - name string info sandbox.FileInfo offset int64 } -func (f *file) open(fsys *FileSystem) (sandbox.File, error) { - open := new(openFile) +func (f *file) open(fsys *FileSystem, name string) (sandbox.File, error) { + open := &openFile{name: name} open.file.Store(f) open.data = *io.NewSectionReader(fsys.data, f.offset, f.info.Size) return open, nil @@ -32,21 +31,19 @@ func (f *file) mode() fs.FileMode { } func (f *file) memsize() uintptr { - return unsafe.Sizeof(file{}) + uintptr(len(f.name)) + return unsafe.Sizeof(file{}) } type openFile struct { leafFile + name string file atomic.Pointer[file] seek sync.Mutex data io.SectionReader } func (f *openFile) Name() string { - if file := f.file.Load(); file != nil { - return file.name - } - return "" + return f.name } func (f *openFile) Close() error { diff --git a/internal/sandbox/tarfs/placeholder.go b/internal/sandbox/tarfs/placeholder.go index 0d4e8124..6d238fde 100644 --- a/internal/sandbox/tarfs/placeholder.go +++ b/internal/sandbox/tarfs/placeholder.go @@ -14,7 +14,7 @@ type placeholder struct { info sandbox.FileInfo } -func (p *placeholder) open(fsys *FileSystem) (sandbox.File, error) { +func (p *placeholder) open(fsys *FileSystem, name string) (sandbox.File, error) { return nil, syscall.EPERM } diff --git a/internal/sandbox/tarfs/symlink.go b/internal/sandbox/tarfs/symlink.go index 67321d62..a539dc8c 100644 --- a/internal/sandbox/tarfs/symlink.go +++ b/internal/sandbox/tarfs/symlink.go @@ -8,12 +8,11 @@ import ( ) type symlink struct { - name string link string info sandbox.FileInfo } -func (s *symlink) open(fsys *FileSystem) (sandbox.File, error) { +func (s *symlink) open(fsys *FileSystem, name string) (sandbox.File, error) { return nil, sandbox.ELOOP } @@ -26,5 +25,5 @@ func (s *symlink) mode() fs.FileMode { } func (s *symlink) memsize() uintptr { - return unsafe.Sizeof(symlink{}) + uintptr(len(s.name)) + uintptr(len(s.link)) + return unsafe.Sizeof(symlink{}) + uintptr(len(s.link)) } diff --git a/internal/sandbox/tarfs/tarfs.go b/internal/sandbox/tarfs/tarfs.go index c53c7614..4ec2fcd9 100644 --- a/internal/sandbox/tarfs/tarfs.go +++ b/internal/sandbox/tarfs/tarfs.go @@ -25,7 +25,7 @@ type FileSystem struct { // Open satisfies sandbox.FileSystem. func (fsys *FileSystem) Open(name string, flags int, mode fs.FileMode) (sandbox.File, error) { - f, err := fsys.root.open(fsys) + f, err := fsys.root.open(fsys, "/") if err != nil { return nil, err } @@ -64,7 +64,6 @@ func Open(data io.ReaderAt, size int64) (*FileSystem, error) { data: data, size: size, root: dir{ - name: "/", info: makeDirInfo(modTime), }, } @@ -93,11 +92,11 @@ func Open(data io.ReaderAt, size int64) (*FileSystem, error) { switch header.Typeflag { case tar.TypeReg: offset, _ := section.Seek(0, io.SeekCurrent) - entry = &file{name: name, info: info, offset: offset} + entry = &file{info: info, offset: offset} case tar.TypeDir: - entry = &dir{name: name, info: info} + entry = &dir{info: info} case tar.TypeSymlink: - entry = &symlink{name: name, info: info, link: header.Linkname} + entry = &symlink{info: info, link: header.Linkname} case tar.TypeLink: if _, exists := links[name]; exists { return nil, fmt.Errorf("%s: duplicate link entry in tar archive", name) @@ -172,7 +171,7 @@ func OpenFile(f *os.File) (*FileSystem, error) { } type fileEntry interface { - open(fsys *FileSystem) (sandbox.File, error) + open(fsys *FileSystem, name string) (sandbox.File, error) stat() sandbox.FileInfo @@ -223,7 +222,6 @@ func makePath(files map[string]fileEntry, name string, modTime time.Time, file f return err } d = &dir{ - name: name, info: makeDirInfo(modTime), } files[dirname] = d