containerd/vendor/github.com/hanwen/go-fuse/v2/fs/dirstream_unix.go
Brad Davidson 63272c3b7a
Enable btrfs/fuse-overlayfs/stargz snapshotter plugins
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
2025-03-20 21:34:00 +00:00

129 lines
2.5 KiB
Go

//go:build !darwin
// Copyright 2019 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fs
import (
"context"
"sync"
"syscall"
"github.com/hanwen/go-fuse/v2/fuse"
"golang.org/x/sys/unix"
)
type loopbackDirStream struct {
buf []byte
// Protects mutable members
mu sync.Mutex
// mutable
todo []byte
todoErrno syscall.Errno
fd int
}
// NewLoopbackDirStream open a directory for reading as a DirStream
func NewLoopbackDirStream(name string) (DirStream, syscall.Errno) {
// TODO: should return concrete type.
fd, err := syscall.Open(name, syscall.O_DIRECTORY, 0755)
if err != nil {
return nil, ToErrno(err)
}
ds := &loopbackDirStream{
buf: make([]byte, 4096),
fd: fd,
}
ds.load()
return ds, OK
}
func (ds *loopbackDirStream) Close() {
ds.mu.Lock()
defer ds.mu.Unlock()
if ds.fd != -1 {
syscall.Close(ds.fd)
ds.fd = -1
}
}
var _ = (FileReleasedirer)((*loopbackDirStream)(nil))
func (ds *loopbackDirStream) Releasedir(ctx context.Context, flags uint32) {
ds.Close()
}
var _ = (FileSeekdirer)((*loopbackDirStream)(nil))
func (ds *loopbackDirStream) Seekdir(ctx context.Context, off uint64) syscall.Errno {
ds.mu.Lock()
defer ds.mu.Unlock()
_, errno := unix.Seek(ds.fd, int64(off), unix.SEEK_SET)
if errno != nil {
return ToErrno(errno)
}
ds.todo = nil
ds.todoErrno = 0
ds.load()
return 0
}
var _ = (FileFsyncdirer)((*loopbackDirStream)(nil))
func (ds *loopbackDirStream) Fsyncdir(ctx context.Context, flags uint32) syscall.Errno {
ds.mu.Lock()
defer ds.mu.Unlock()
return ToErrno(syscall.Fsync(ds.fd))
}
func (ds *loopbackDirStream) HasNext() bool {
ds.mu.Lock()
defer ds.mu.Unlock()
return len(ds.todo) > 0 || ds.todoErrno != 0
}
var _ = (FileReaddirenter)((*loopbackDirStream)(nil))
func (ds *loopbackDirStream) Readdirent(ctx context.Context) (*fuse.DirEntry, syscall.Errno) {
if !ds.HasNext() {
return nil, 0
}
de, errno := ds.Next()
return &de, errno
}
func (ds *loopbackDirStream) Next() (fuse.DirEntry, syscall.Errno) {
ds.mu.Lock()
defer ds.mu.Unlock()
if ds.todoErrno != 0 {
return fuse.DirEntry{}, ds.todoErrno
}
var res fuse.DirEntry
n := res.Parse(ds.todo)
ds.todo = ds.todo[n:]
if len(ds.todo) == 0 {
ds.load()
}
return res, 0
}
func (ds *loopbackDirStream) load() {
if len(ds.todo) > 0 {
return
}
n, err := unix.Getdents(ds.fd, ds.buf)
if n < 0 {
n = 0
}
ds.todo = ds.buf[:n]
ds.todoErrno = ToErrno(err)
}