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