Commit eb033a6d authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Hide LoopbackFile, DefaultFile, DevNullFile, DataFile types to reduce

API clutter.

To replace these in declarations, callers should embed a fuse.File,
and initialize it with NewDefaultFile, NewLoopbackFile, etc.
parent c0387f23
......@@ -97,8 +97,8 @@ type FsNode interface {
}
// A File object should be returned from FileSystem.Open and
// FileSystem.Create. Include DefaultFile into the struct to inherit
// a default null implementation.
// FileSystem.Create. Include the NewDefaultFile return value into
// the struct to inherit a default null implementation.
//
// TODO - should File be thread safe?
// TODO - should we pass a *Context argument?
......@@ -216,9 +216,6 @@ type MountOptions struct {
Name string
}
// DefaultFile returns ENOSYS for every operation.
type DefaultFile struct{}
// RawFileSystem is an interface close to the FUSE wire protocol.
//
// Unless you really know what you are doing, you should not implement
......
......@@ -9,63 +9,70 @@ import (
var _ = log.Println
var _ = (File)((*DefaultFile)(nil))
var _ = (File)((*defaultFile)(nil))
func (f *DefaultFile) SetInode(*Inode) {
type defaultFile struct{}
// DefaultFile returns ENOSYS for every operation.
func NewDefaultFile() File {
return &defaultFile{}
}
func (f *defaultFile) SetInode(*Inode) {
}
func (f *DefaultFile) InnerFile() File {
func (f *defaultFile) InnerFile() File {
return nil
}
func (f *DefaultFile) String() string {
return "DefaultFile"
func (f *defaultFile) String() string {
return "defaultFile"
}
func (f *DefaultFile) Read(buf []byte, off int64) (ReadResult, Status) {
func (f *defaultFile) Read(buf []byte, off int64) (ReadResult, Status) {
return nil, ENOSYS
}
func (f *DefaultFile) Write(data []byte, off int64) (uint32, Status) {
func (f *defaultFile) Write(data []byte, off int64) (uint32, Status) {
return 0, ENOSYS
}
func (f *DefaultFile) Flush() Status {
func (f *defaultFile) Flush() Status {
return OK
}
func (f *DefaultFile) Release() {
func (f *defaultFile) Release() {
}
func (f *DefaultFile) GetAttr(*Attr) Status {
func (f *defaultFile) GetAttr(*Attr) Status {
return ENOSYS
}
func (f *DefaultFile) Fsync(flags int) (code Status) {
func (f *defaultFile) Fsync(flags int) (code Status) {
return ENOSYS
}
func (f *DefaultFile) Utimens(atime *time.Time, mtime *time.Time) Status {
func (f *defaultFile) Utimens(atime *time.Time, mtime *time.Time) Status {
return ENOSYS
}
func (f *DefaultFile) Truncate(size uint64) Status {
func (f *defaultFile) Truncate(size uint64) Status {
return ENOSYS
}
func (f *DefaultFile) Chown(uid uint32, gid uint32) Status {
func (f *defaultFile) Chown(uid uint32, gid uint32) Status {
return ENOSYS
}
func (f *DefaultFile) Chmod(perms uint32) Status {
func (f *defaultFile) Chmod(perms uint32) Status {
return ENOSYS
}
func (f *DefaultFile) Ioctl(input *raw.IoctlIn) (output *raw.IoctlOut, data []byte, code Status) {
func (f *defaultFile) Ioctl(input *raw.IoctlIn) (output *raw.IoctlOut, data []byte, code Status) {
return nil, nil, ENOSYS
}
func (f *DefaultFile) Allocate(off uint64, size uint64, mode uint32) (code Status) {
func (f *defaultFile) Allocate(off uint64, size uint64, mode uint32) (code Status) {
return ENOSYS
}
......@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"sync"
"time"
"syscall"
)
......@@ -11,36 +12,37 @@ var _ = fmt.Println
// DataFile is for implementing read-only filesystems. This
// assumes we already have the data in memory.
type DataFile struct {
type dataFile struct {
data []byte
DefaultFile
File
}
var _ = (File)((*DataFile)(nil))
var _ = (File)((*dataFile)(nil))
func (f *DataFile) String() string {
func (f *dataFile) String() string {
l := len(f.data)
if l > 10 {
l = 10
}
return fmt.Sprintf("DataFile(%x)", f.data[:l])
return fmt.Sprintf("dataFile(%x)", f.data[:l])
}
func (f *DataFile) GetAttr(out *Attr) Status {
func (f *dataFile) GetAttr(out *Attr) Status {
out.Mode = S_IFREG | 0644
out.Size = uint64(len(f.data))
return OK
}
func NewDataFile(data []byte) *DataFile {
f := new(DataFile)
func NewDataFile(data []byte) *dataFile {
f := new(dataFile)
f.data = data
f.File = NewDefaultFile()
return f
}
func (f *DataFile) Read(buf []byte, off int64) (res ReadResult, code Status) {
func (f *dataFile) Read(buf []byte, off int64) (res ReadResult, code Status) {
end := int(off) + int(len(buf))
if end > len(f.data) {
end = len(f.data)
......@@ -51,62 +53,81 @@ func (f *DataFile) Read(buf []byte, off int64) (res ReadResult, code Status) {
////////////////
// DevNullFile accepts any write, and always returns EOF.
type DevNullFile struct {
DefaultFile
type devNullFile struct {
File
}
var _ = (File)((*DevNullFile)(nil))
var _ = (File)((*devNullFile)(nil))
// NewDevNullFile returns a file that accepts any write, and always
// returns EOF for reads.
func NewDevNullFile() *devNullFile {
return &devNullFile{
File: NewDefaultFile(),
}
}
func NewDevNullFile() *DevNullFile {
return new(DevNullFile)
func (f *devNullFile) Allocate(off uint64, size uint64, mode uint32) (code Status) {
return OK
}
func (f *DevNullFile) String() string {
return "DevNullFile"
func (f *devNullFile) String() string {
return "devNullFile"
}
func (f *DevNullFile) Read(buf []byte, off int64) (ReadResult, Status) {
func (f *devNullFile) Read(buf []byte, off int64) (ReadResult, Status) {
return &ReadResultData{}, OK
}
func (f *DevNullFile) Write(content []byte, off int64) (uint32, Status) {
func (f *devNullFile) Write(content []byte, off int64) (uint32, Status) {
return uint32(len(content)), OK
}
func (f *DevNullFile) Flush() Status {
func (f *devNullFile) Flush() Status {
return OK
}
func (f *DevNullFile) Fsync(flags int) (code Status) {
func (f *devNullFile) Fsync(flags int) (code Status) {
return OK
}
func (f *DevNullFile) Truncate(size uint64) (code Status) {
func (f *devNullFile) Truncate(size uint64) (code Status) {
return OK
}
////////////////
// LoopbackFile delegates all operations back to an underlying os.File.
type LoopbackFile struct {
func NewLoopbackFile(f *os.File) File {
return &loopbackFile{File: f}
}
type loopbackFile struct {
File *os.File
// os.File is not threadsafe. Although fd themselves are
// constant during the lifetime of an open file, the OS may
// reuse the fd number after it is closed. When combined with
// threads,
// reuse the fd number after it is closed. When open races
// with another close, they may lead to confusion as which
// file gets written in the end.
lock sync.Mutex
DefaultFile
}
var _ = (File)((*LoopbackFile)(nil))
func (f *LoopbackFile) String() string {
return fmt.Sprintf("LoopbackFile(%s)", f.File.Name())
var _ = (File)((*loopbackFile)(nil))
func (f *loopbackFile) InnerFile() File {
return nil
}
func (f *loopbackFile) SetInode(n *Inode) {
}
func (f *loopbackFile) String() string {
return fmt.Sprintf("loopbackFile(%s)", f.File.Name())
}
func (f *LoopbackFile) Read(buf []byte, off int64) (res ReadResult, code Status) {
func (f *loopbackFile) Read(buf []byte, off int64) (res ReadResult, code Status) {
f.lock.Lock()
r := &ReadResultFd{
Fd: f.File.Fd(),
......@@ -117,20 +138,20 @@ func (f *LoopbackFile) Read(buf []byte, off int64) (res ReadResult, code Status)
return r, OK
}
func (f *LoopbackFile) Write(data []byte, off int64) (uint32, Status) {
func (f *loopbackFile) Write(data []byte, off int64) (uint32, Status) {
f.lock.Lock()
n, err := f.File.WriteAt(data, off)
f.lock.Unlock()
return uint32(n), ToStatus(err)
}
func (f *LoopbackFile) Release() {
func (f *loopbackFile) Release() {
f.lock.Lock()
f.File.Close()
f.lock.Unlock()
}
func (f *LoopbackFile) Flush() Status {
func (f *loopbackFile) Flush() Status {
f.lock.Lock()
// Since Flush() may be called for each dup'd fd, we don't
......@@ -146,7 +167,7 @@ func (f *LoopbackFile) Flush() Status {
return ToStatus(err)
}
func (f *LoopbackFile) Fsync(flags int) (code Status) {
func (f *loopbackFile) Fsync(flags int) (code Status) {
f.lock.Lock()
r := ToStatus(syscall.Fsync(int(f.File.Fd())))
f.lock.Unlock()
......@@ -154,7 +175,7 @@ func (f *LoopbackFile) Fsync(flags int) (code Status) {
return r
}
func (f *LoopbackFile) Truncate(size uint64) Status {
func (f *loopbackFile) Truncate(size uint64) Status {
f.lock.Lock()
r := ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size)))
f.lock.Unlock()
......@@ -162,9 +183,7 @@ func (f *LoopbackFile) Truncate(size uint64) Status {
return r
}
// futimens missing from 6g runtime.
func (f *LoopbackFile) Chmod(mode uint32) Status {
func (f *loopbackFile) Chmod(mode uint32) Status {
f.lock.Lock()
r := ToStatus(f.File.Chmod(os.FileMode(mode)))
f.lock.Unlock()
......@@ -172,7 +191,7 @@ func (f *LoopbackFile) Chmod(mode uint32) Status {
return r
}
func (f *LoopbackFile) Chown(uid uint32, gid uint32) Status {
func (f *loopbackFile) Chown(uid uint32, gid uint32) Status {
f.lock.Lock()
r := ToStatus(f.File.Chown(int(uid), int(gid)))
f.lock.Unlock()
......@@ -180,7 +199,7 @@ func (f *LoopbackFile) Chown(uid uint32, gid uint32) Status {
return r
}
func (f *LoopbackFile) GetAttr(a *Attr) Status {
func (f *loopbackFile) GetAttr(a *Attr) Status {
st := syscall.Stat_t{}
f.lock.Lock()
err := syscall.Fstat(int(f.File.Fd()), &st)
......@@ -193,6 +212,12 @@ func (f *LoopbackFile) GetAttr(a *Attr) Status {
return OK
}
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) Status {
return ENOSYS
}
// Allocate implemented in files_linux.go
////////////////////////////////////////////////////////////////
// ReadOnlyFile is a wrapper that denies writable operations
......
......@@ -4,7 +4,7 @@ import (
"syscall"
)
func (f *LoopbackFile) Allocate(off uint64, sz uint64, mode uint32) Status {
func (f *loopbackFile) Allocate(off uint64, sz uint64, mode uint32) Status {
f.lock.Lock()
err := syscall.Fallocate(int(f.File.Fd()), mode, int64(off), int64(sz))
f.lock.Unlock()
......
......@@ -21,6 +21,8 @@ func (c *FileSystemConnector) RawFS() RawFileSystem {
}
type rawBridge FileSystemConnector
var _ = (RawFileSystem)((*rawBridge)(nil))
func (c *rawBridge) Fsync(context *Context, input *raw.FsyncIn) Status {
return ENOSYS
......
......@@ -134,20 +134,20 @@ func (n *memNode) Create(name string, flags uint32, mode uint32, context *Contex
}
type memNodeFile struct {
LoopbackFile
File
node *memNode
}
func (n *memNodeFile) String() string {
return fmt.Sprintf("memNodeFile(%s)", n.LoopbackFile.String())
return fmt.Sprintf("memNodeFile(%s)", n.File.String())
}
func (n *memNodeFile) InnerFile() File {
return &n.LoopbackFile
return n.File
}
func (n *memNodeFile) Flush() Status {
code := n.LoopbackFile.Flush()
code := n.File.Flush()
if !code.Ok() {
return code
......@@ -162,7 +162,7 @@ func (n *memNodeFile) Flush() Status {
func (n *memNode) newFile(f *os.File) File {
return &memNodeFile{
LoopbackFile: LoopbackFile{File: f},
File: NewLoopbackFile(f),
node: n,
}
}
......
......@@ -97,7 +97,7 @@ func (fs *loopbackFileSystem) Open(name string, flags uint32, context *fuse.Cont
if err != nil {
return nil, fuse.ToStatus(err)
}
return &fuse.LoopbackFile{File: f}, fuse.OK
return fuse.NewLoopbackFile(f), fuse.OK
}
func (fs *loopbackFileSystem) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
......@@ -166,5 +166,5 @@ func (fs *loopbackFileSystem) Access(name string, mode uint32, context *fuse.Con
func (fs *loopbackFileSystem) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile fuse.File, code fuse.Status) {
f, err := os.OpenFile(fs.GetPath(path), int(flags)|os.O_CREATE, os.FileMode(mode))
return &fuse.LoopbackFile{File: f}, fuse.ToStatus(err)
return fuse.NewLoopbackFile(f), fuse.ToStatus(err)
}
......@@ -29,7 +29,7 @@ func (fs *DefaultReadFS) GetAttr(name string, context *fuse.Context) (*fuse.Attr
}
func (fs *DefaultReadFS) Open(name string, f uint32, context *fuse.Context) (fuse.File, fuse.Status) {
return &fuse.DefaultFile{}, fuse.OK
return fuse.NewDefaultFile(), fuse.OK
}
func defaultReadTest(t *testing.T) (root string, cleanup func()) {
......
......@@ -13,7 +13,7 @@ import (
)
type MutableDataFile struct {
fuse.DefaultFile
fuse.File
data []byte
fuse.Attr
......@@ -129,7 +129,7 @@ func (fs *FSetAttrFs) Create(name string, flags uint32, mode uint32, context *fu
}
func NewFile() *MutableDataFile {
return &MutableDataFile{}
return &MutableDataFile{File: fuse.NewDefaultFile()}
}
func setupFAttrTest(t *testing.T, fs pathfs.FileSystem) (dir string, clean func(), sync func()) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment