Commit 32016f39 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: documentation

parent 6d9ae31b
...@@ -84,5 +84,7 @@ or ...@@ -84,5 +84,7 @@ or
* Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.? * Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.?
* Merge Fsync/FsyncDir?
* Merge Release/ReleaseDir?
...@@ -104,8 +104,15 @@ type Operations interface { ...@@ -104,8 +104,15 @@ type Operations interface {
inode() *Inode inode() *Inode
setInode(*Inode) bool setInode(*Inode) bool
// StatFs implements statistics for the filesystem that holds
// this Inode. DefaultNode implements this, because OSX
// filesystem must have a valid StatFs implementation.
StatFs(ctx context.Context, out *fuse.StatfsOut) fuse.Status StatFs(ctx context.Context, out *fuse.StatfsOut) fuse.Status
// Access should return if the caller can access the file with
// the given mode. In this case, the context has data about
// the real UID. For example a root-SUID binary called by user
// `susan` gets the UID and GID for `susan` here.
Access(ctx context.Context, mask uint32) fuse.Status Access(ctx context.Context, mask uint32) fuse.Status
// File locking // File locking
...@@ -115,34 +122,77 @@ type Operations interface { ...@@ -115,34 +122,77 @@ type Operations interface {
// Extended attributes // Extended attributes
// GetXAttr should read data for the given attribute into
// `dest` and return the number of bytes. If `dest` is too
// small, it should return ERANGE and the size of the attribute.
GetXAttr(ctx context.Context, attr string, dest []byte) (uint32, fuse.Status) GetXAttr(ctx context.Context, attr string, dest []byte) (uint32, fuse.Status)
// SetXAttr should store data for the given attribute.
// XXX flags.
SetXAttr(ctx context.Context, attr string, data []byte, flags uint32) fuse.Status SetXAttr(ctx context.Context, attr string, data []byte, flags uint32) fuse.Status
// RemoveXAttr should delete the given attribute.
RemoveXAttr(ctx context.Context, attr string) fuse.Status RemoveXAttr(ctx context.Context, attr string) fuse.Status
// ListXAttr should read all attributes (null terminated) into
// `dest`. If the `dest` buffer is too small, it should return
// ERANGE and the correct size.
ListXAttr(ctx context.Context, dest []byte) (uint32, fuse.Status) ListXAttr(ctx context.Context, dest []byte) (uint32, fuse.Status)
// The methods below may be called on closed files, due to // The methods below may be called on closed files, due to
// concurrency. // concurrency.
GetAttr(ctx context.Context, f FileHandle, out *fuse.AttrOut) fuse.Status GetAttr(ctx context.Context, f FileHandle, out *fuse.AttrOut) fuse.Status
// Lookup should find a direct child of the node by child name. // Lookup should find a direct child of the node by child
// // name. If the entry does not exist, it should return ENOENT
// VFS makes sure to call Lookup only once for particular // and optionally set a NegativeTimeout in `out`. If it does
// (node, name) pair concurrently. // exist, it should return attribute data in `out` and return
// the Inode for the child. A new inode can be created using
// `Inode.NewInode`. The new Inode will be added to the FS
// tree automatically if the return status is OK.
Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, fuse.Status) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, fuse.Status)
// Mkdir is similar to Lookup, but must create a directory entry and Inode.
Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*Inode, fuse.Status) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (*Inode, fuse.Status)
// Mknod is similar to Lookup, but must create a device entry and Inode.
Mknod(ctx context.Context, name string, mode uint32, dev uint32, out *fuse.EntryOut) (*Inode, fuse.Status) Mknod(ctx context.Context, name string, mode uint32, dev uint32, out *fuse.EntryOut) (*Inode, fuse.Status)
Rmdir(ctx context.Context, name string) fuse.Status
Unlink(ctx context.Context, name string) fuse.Status // Link is similar to Lookup, but must create a new link to an existing Inode.
Rename(ctx context.Context, name string, newParent Operations, newName string, flags uint32) fuse.Status
Create(ctx context.Context, name string, flags uint32, mode uint32) (node *Inode, fh FileHandle, fuseFlags uint32, status fuse.Status)
Link(ctx context.Context, target Operations, name string, out *fuse.EntryOut) (node *Inode, status fuse.Status) Link(ctx context.Context, target Operations, name string, out *fuse.EntryOut) (node *Inode, status fuse.Status)
// Symlink is similar to Lookup, but must create a new symbolic link.
Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (node *Inode, status fuse.Status) Symlink(ctx context.Context, target, name string, out *fuse.EntryOut) (node *Inode, status fuse.Status)
// Create is similar to Lookup, but should create a new
// child. It typically also returns a FileHandle as a
// reference for future reads/writes
Create(ctx context.Context, name string, flags uint32, mode uint32) (node *Inode, fh FileHandle, fuseFlags uint32, status fuse.Status)
// Unlink should remove a child from this directory. If the
// return status is OK, the Inode is removed as child in the
// FS tree automatically.
Unlink(ctx context.Context, name string) fuse.Status
// Rmdir is like Unlink but for directories.
Rmdir(ctx context.Context, name string) fuse.Status
// Rename should move a child from one directory to a
// different one. The changes is effected in the FS tree if
// the return status is OK
Rename(ctx context.Context, name string, newParent Operations, newName string, flags uint32) fuse.Status
// Readlink reads the content of a symlink.
Readlink(ctx context.Context) (string, fuse.Status) Readlink(ctx context.Context) (string, fuse.Status)
// Open opens an Inode (of regular file type) for reading. It
// is optional but recommended to return a FileHandle.
Open(ctx context.Context, flags uint32) (fh FileHandle, fuseFlags uint32, status fuse.Status) Open(ctx context.Context, flags uint32) (fh FileHandle, fuseFlags uint32, status fuse.Status)
// OpenDir is called for sanity/permission checks on opening a // OpenDir opens a directory Inode for reading its
// directory. // contents. The actual reading is driven from ReadDir, so
// this method is just for performing sanity/permission
// checks.
OpenDir(ctx context.Context) fuse.Status OpenDir(ctx context.Context) fuse.Status
// ReadDir opens a stream of directory entries. // ReadDir opens a stream of directory entries.
...@@ -150,26 +200,33 @@ type Operations interface { ...@@ -150,26 +200,33 @@ type Operations interface {
// Reads data from a file. The data should be returned as // Reads data from a file. The data should be returned as
// ReadResult, which may be constructed from the incoming // ReadResult, which may be constructed from the incoming
// `dest` buffer. // `dest` buffer. If the file was opened without FileHandle,
// the FileHandle argument here is nil. The default
// implementation forwards to the FileHandle.
Read(ctx context.Context, f FileHandle, dest []byte, off int64) (fuse.ReadResult, fuse.Status) Read(ctx context.Context, f FileHandle, dest []byte, off int64) (fuse.ReadResult, fuse.Status)
// Writes the data into the file handle at given offset. After // Writes the data into the file handle at given offset. After
// returning, the data will be reused and may not referenced. // returning, the data will be reused and may not referenced.
// The default implementation forwards to the FileHandle.
Write(ctx context.Context, f FileHandle, data []byte, off int64) (written uint32, status fuse.Status) Write(ctx context.Context, f FileHandle, data []byte, off int64) (written uint32, status fuse.Status)
// Fsync is a signal to ensure writes to the Inode are flushed
// to stable storage. The default implementation forwards to the
// FileHandle.
Fsync(ctx context.Context, f FileHandle, flags uint32) (status fuse.Status) Fsync(ctx context.Context, f FileHandle, flags uint32) (status fuse.Status)
// Flush is called for close() call on a file descriptor. In // Flush is called for close() call on a file descriptor. In
// case of duplicated descriptor, it may be called more than // case of duplicated descriptor, it may be called more than
// once for a file. // once for a file. The default implementation forwards to the
// FileHandle.
Flush(ctx context.Context, f FileHandle) fuse.Status Flush(ctx context.Context, f FileHandle) fuse.Status
// This is called to before the file handle is forgotten. This // This is called to before the file handle is forgotten. The
// method has no return value, so nothing can synchronize on // kernel ingores the return value of this method is ignored,
// the call, and it cannot be canceled. Any cleanup that // so any cleanup that requires specific synchronization or
// requires specific synchronization or could fail with I/O // could fail with I/O errors should happen in Flush instead.
// errors should happen in Flush instead. // The default implementation forwards to the FileHandle.
Release(f FileHandle) Release(f FileHandle) fuse.Status
/* /*
NOSUBMIT - fold into a setattr method, or expand methods? NOSUBMIT - fold into a setattr method, or expand methods?
...@@ -178,13 +235,29 @@ type Operations interface { ...@@ -178,13 +235,29 @@ type Operations interface {
types as args, we can't take apart SetAttr for the caller types as args, we can't take apart SetAttr for the caller
*/ */
// Truncate sets the file length to the given size. The
// default implementation forwards to the FileHandle.
Truncate(ctx context.Context, f FileHandle, size uint64) fuse.Status Truncate(ctx context.Context, f FileHandle, size uint64) fuse.Status
// Chown changes the file owner . The default implementation
// forwards to the FileHandle.
Chown(ctx context.Context, f FileHandle, uid uint32, gid uint32) fuse.Status Chown(ctx context.Context, f FileHandle, uid uint32, gid uint32) fuse.Status
// Chmod changes the file permissions. The default
// implementation forwards to the FileHandle.
Chmod(ctx context.Context, f FileHandle, perms uint32) fuse.Status Chmod(ctx context.Context, f FileHandle, perms uint32) fuse.Status
// Utimens changes the files timestamps. The default
// implementation forwards to the FileHandle.
Utimens(ctx context.Context, f FileHandle, atime *time.Time, mtime *time.Time) fuse.Status Utimens(ctx context.Context, f FileHandle, atime *time.Time, mtime *time.Time) fuse.Status
// Allocate preallocates space for future writes, so they will
// never encounter ESPACE. The default implementation
// forwards to the FileHandle.
Allocate(ctx context.Context, f FileHandle, off uint64, size uint64, mode uint32) (status fuse.Status) Allocate(ctx context.Context, f FileHandle, off uint64, size uint64, mode uint32) (status fuse.Status)
} }
// FileHandle is a resource identifier for opened files.
type FileHandle interface { type FileHandle interface {
Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, fuse.Status) Read(ctx context.Context, dest []byte, off int64) (fuse.ReadResult, fuse.Status)
...@@ -209,7 +282,7 @@ type FileHandle interface { ...@@ -209,7 +282,7 @@ type FileHandle interface {
// the call, and it cannot be canceled. Any cleanup that // the call, and it cannot be canceled. Any cleanup that
// requires specific synchronization or could fail with I/O // requires specific synchronization or could fail with I/O
// errors should happen in Flush instead. // errors should happen in Flush instead.
Release() Release() fuse.Status
// The methods below may be called on closed files, due to // The methods below may be called on closed files, due to
// concurrency. // concurrency.
......
...@@ -43,8 +43,8 @@ type rawBridge struct { ...@@ -43,8 +43,8 @@ type rawBridge struct {
freeFiles []uint32 freeFiles []uint32
} }
// newInode creates creates new inode pointing to node. // newInode creates creates new inode pointing to ops.
func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent bool) *Inode { func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent bool) *Inode {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
...@@ -75,7 +75,7 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent ...@@ -75,7 +75,7 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent
mode = mode &^ 07777 mode = mode &^ 07777
inode := &Inode{ inode := &Inode{
mode: mode, mode: mode,
node: node, ops: ops,
nodeID: id, nodeID: id,
bridge: b, bridge: b,
persistent: persistent, persistent: persistent,
...@@ -86,10 +86,12 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent ...@@ -86,10 +86,12 @@ func (b *rawBridge) newInode(node Operations, mode uint32, id FileID, persistent
} }
b.nodes[id.Ino] = inode b.nodes[id.Ino] = inode
node.setInode(inode) ops.setInode(inode)
return node.inode() return ops.inode()
} }
// NewNodeFS creates a node based filesystem based on an Operations
// instance for the root.
func NewNodeFS(root Operations, opts *Options) fuse.RawFileSystem { func NewNodeFS(root Operations, opts *Options) fuse.RawFileSystem {
bridge := &rawBridge{ bridge := &rawBridge{
automaticIno: 1 << 63, automaticIno: 1 << 63,
...@@ -108,7 +110,7 @@ func NewNodeFS(root Operations, opts *Options) fuse.RawFileSystem { ...@@ -108,7 +110,7 @@ func NewNodeFS(root Operations, opts *Options) fuse.RawFileSystem {
mode: fuse.S_IFDIR, mode: fuse.S_IFDIR,
children: make(map[string]*Inode), children: make(map[string]*Inode),
parents: nil, parents: nil,
node: root, ops: root,
bridge: bridge, bridge: bridge,
} }
bridge.root.nodeID.Ino = 1 bridge.root.nodeID.Ino = 1
...@@ -139,7 +141,7 @@ func (b *rawBridge) inode(id uint64, fh uint64) (*Inode, *fileEntry) { ...@@ -139,7 +141,7 @@ func (b *rawBridge) inode(id uint64, fh uint64) (*Inode, *fileEntry) {
func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name string, out *fuse.EntryOut) (status fuse.Status) { func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name string, out *fuse.EntryOut) (status fuse.Status) {
parent, _ := b.inode(header.NodeId, 0) parent, _ := b.inode(header.NodeId, 0)
child, status := parent.node.Lookup(&fuse.Context{Caller: header.Caller, Cancel: cancel}, name, out) child, status := parent.ops.Lookup(&fuse.Context{Caller: header.Caller, Cancel: cancel}, name, out)
if !status.Ok() { if !status.Ok() {
if b.options.NegativeTimeout != nil { if b.options.NegativeTimeout != nil {
out.SetEntryTimeout(*b.options.NegativeTimeout) out.SetEntryTimeout(*b.options.NegativeTimeout)
...@@ -156,7 +158,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s ...@@ -156,7 +158,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s
func (b *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name string) fuse.Status { func (b *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name string) fuse.Status {
parent, _ := b.inode(header.NodeId, 0) parent, _ := b.inode(header.NodeId, 0)
status := parent.node.Rmdir(&fuse.Context{Caller: header.Caller, Cancel: cancel}, name) status := parent.ops.Rmdir(&fuse.Context{Caller: header.Caller, Cancel: cancel}, name)
if status.Ok() { if status.Ok() {
parent.RmChild(name) parent.RmChild(name)
} }
...@@ -166,7 +168,7 @@ func (b *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name st ...@@ -166,7 +168,7 @@ func (b *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name st
func (b *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name string) fuse.Status { func (b *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name string) fuse.Status {
parent, _ := b.inode(header.NodeId, 0) parent, _ := b.inode(header.NodeId, 0)
status := parent.node.Unlink(&fuse.Context{Caller: header.Caller, Cancel: cancel}, name) status := parent.ops.Unlink(&fuse.Context{Caller: header.Caller, Cancel: cancel}, name)
if status.Ok() { if status.Ok() {
parent.RmChild(name) parent.RmChild(name)
} }
...@@ -176,7 +178,7 @@ func (b *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name s ...@@ -176,7 +178,7 @@ func (b *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name s
func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name string, out *fuse.EntryOut) (status fuse.Status) { func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name string, out *fuse.EntryOut) (status fuse.Status) {
parent, _ := b.inode(input.NodeId, 0) parent, _ := b.inode(input.NodeId, 0)
child, status := parent.node.Mkdir(&fuse.Context{Caller: input.Caller, Cancel: cancel}, name, input.Mode, out) child, status := parent.ops.Mkdir(&fuse.Context{Caller: input.Caller, Cancel: cancel}, name, input.Mode, out)
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -193,7 +195,7 @@ func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name stri ...@@ -193,7 +195,7 @@ func (b *rawBridge) Mkdir(cancel <-chan struct{}, input *fuse.MkdirIn, name stri
func (b *rawBridge) Mknod(cancel <-chan struct{}, input *fuse.MknodIn, name string, out *fuse.EntryOut) (status fuse.Status) { func (b *rawBridge) Mknod(cancel <-chan struct{}, input *fuse.MknodIn, name string, out *fuse.EntryOut) (status fuse.Status) {
parent, _ := b.inode(input.NodeId, 0) parent, _ := b.inode(input.NodeId, 0)
child, status := parent.node.Mknod(&fuse.Context{Caller: input.Caller, Cancel: cancel}, name, input.Mode, input.Rdev, out) child, status := parent.ops.Mknod(&fuse.Context{Caller: input.Caller, Cancel: cancel}, name, input.Mode, input.Rdev, out)
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -237,7 +239,7 @@ func (b *rawBridge) setEntryOutTimeout(out *fuse.EntryOut) { ...@@ -237,7 +239,7 @@ func (b *rawBridge) setEntryOutTimeout(out *fuse.EntryOut) {
func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name string, out *fuse.CreateOut) (status fuse.Status) { func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name string, out *fuse.CreateOut) (status fuse.Status) {
ctx := &fuse.Context{Caller: input.Caller, Cancel: cancel} ctx := &fuse.Context{Caller: input.Caller, Cancel: cancel}
parent, _ := b.inode(input.NodeId, 0) parent, _ := b.inode(input.NodeId, 0)
child, f, flags, status := parent.node.Create(ctx, name, input.Flags, input.Mode) child, f, flags, status := parent.ops.Create(ctx, name, input.Flags, input.Mode)
if !status.Ok() { if !status.Ok() {
if b.options.NegativeTimeout != nil { if b.options.NegativeTimeout != nil {
out.SetEntryTimeout(*b.options.NegativeTimeout) out.SetEntryTimeout(*b.options.NegativeTimeout)
...@@ -288,7 +290,7 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out * ...@@ -288,7 +290,7 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *
b.mu.Unlock() b.mu.Unlock()
} }
status := n.node.GetAttr(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f, out) status := n.ops.GetAttr(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f, out)
b.setAttrTimeout(out) b.setAttrTimeout(out)
out.Ino = input.NodeId out.Ino = input.NodeId
out.Mode = (out.Attr.Mode & 07777) | n.mode out.Mode = (out.Attr.Mode & 07777) | n.mode
...@@ -312,7 +314,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out * ...@@ -312,7 +314,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
if input.Valid&fuse.FATTR_MODE != 0 { if input.Valid&fuse.FATTR_MODE != 0 {
permissions := uint32(07777) & input.Mode permissions := uint32(07777) & input.Mode
status = n.node.Chmod(ctx, f, permissions) status = n.ops.Chmod(ctx, f, permissions)
} }
if status.Ok() && (input.Valid&(fuse.FATTR_UID|fuse.FATTR_GID) != 0) { if status.Ok() && (input.Valid&(fuse.FATTR_UID|fuse.FATTR_GID) != 0) {
...@@ -324,11 +326,11 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out * ...@@ -324,11 +326,11 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
if input.Valid&fuse.FATTR_GID != 0 { if input.Valid&fuse.FATTR_GID != 0 {
gid = input.Gid gid = input.Gid
} }
status = n.node.Chown(ctx, f, uid, gid) status = n.ops.Chown(ctx, f, uid, gid)
} }
if status.Ok() && input.Valid&fuse.FATTR_SIZE != 0 { if status.Ok() && input.Valid&fuse.FATTR_SIZE != 0 {
status = n.node.Truncate(ctx, f, input.Size) status = n.ops.Truncate(ctx, f, input.Size)
} }
if status.Ok() && (input.Valid&(fuse.FATTR_ATIME|fuse.FATTR_MTIME|fuse.FATTR_ATIME_NOW|fuse.FATTR_MTIME_NOW) != 0) { if status.Ok() && (input.Valid&(fuse.FATTR_ATIME|fuse.FATTR_MTIME|fuse.FATTR_ATIME_NOW|fuse.FATTR_MTIME_NOW) != 0) {
...@@ -354,7 +356,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out * ...@@ -354,7 +356,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
} }
} }
status = n.node.Utimens(ctx, f, atime, mtime) status = n.ops.Utimens(ctx, f, atime, mtime)
} }
if !status.Ok() { if !status.Ok() {
...@@ -363,7 +365,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out * ...@@ -363,7 +365,7 @@ func (b *rawBridge) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *
// Must call GetAttr(); the filesystem may override some of // Must call GetAttr(); the filesystem may override some of
// the changes we effect here. // the changes we effect here.
status = n.node.GetAttr(ctx, f, out) status = n.ops.GetAttr(ctx, f, out)
b.setAttrTimeout(out) b.setAttrTimeout(out)
out.Ino = n.nodeID.Ino out.Ino = n.nodeID.Ino
out.Mode = n.mode | (out.Mode &^ 07777) out.Mode = n.mode | (out.Mode &^ 07777)
...@@ -374,7 +376,7 @@ func (b *rawBridge) Rename(cancel <-chan struct{}, input *fuse.RenameIn, oldName ...@@ -374,7 +376,7 @@ func (b *rawBridge) Rename(cancel <-chan struct{}, input *fuse.RenameIn, oldName
p1, _ := b.inode(input.NodeId, 0) p1, _ := b.inode(input.NodeId, 0)
p2, _ := b.inode(input.Newdir, 0) p2, _ := b.inode(input.Newdir, 0)
status := p1.node.Rename(&fuse.Context{Caller: input.Caller, Cancel: cancel}, oldName, p2.node, newName, input.Flags) status := p1.ops.Rename(&fuse.Context{Caller: input.Caller, Cancel: cancel}, oldName, p2.ops, newName, input.Flags)
if status.Ok() { if status.Ok() {
if input.Flags&unix.RENAME_EXCHANGE != 0 { if input.Flags&unix.RENAME_EXCHANGE != 0 {
p1.ExchangeChild(oldName, p2, newName) p1.ExchangeChild(oldName, p2, newName)
...@@ -389,7 +391,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string ...@@ -389,7 +391,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string
parent, _ := b.inode(input.NodeId, 0) parent, _ := b.inode(input.NodeId, 0)
target, _ := b.inode(input.Oldnodeid, 0) target, _ := b.inode(input.Oldnodeid, 0)
child, status := parent.node.Link(&fuse.Context{Caller: input.Caller, Cancel: cancel}, target.node, name, out) child, status := parent.ops.Link(&fuse.Context{Caller: input.Caller, Cancel: cancel}, target.ops, name, out)
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -401,7 +403,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string ...@@ -401,7 +403,7 @@ func (b *rawBridge) Link(cancel <-chan struct{}, input *fuse.LinkIn, name string
func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, target string, name string, out *fuse.EntryOut) (status fuse.Status) { func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, target string, name string, out *fuse.EntryOut) (status fuse.Status) {
parent, _ := b.inode(header.NodeId, 0) parent, _ := b.inode(header.NodeId, 0)
child, status := parent.node.Symlink(&fuse.Context{Caller: header.Caller, Cancel: cancel}, target, name, out) child, status := parent.ops.Symlink(&fuse.Context{Caller: header.Caller, Cancel: cancel}, target, name, out)
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -413,7 +415,7 @@ func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, targe ...@@ -413,7 +415,7 @@ func (b *rawBridge) Symlink(cancel <-chan struct{}, header *fuse.InHeader, targe
func (b *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out []byte, status fuse.Status) { func (b *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out []byte, status fuse.Status) {
n, _ := b.inode(header.NodeId, 0) n, _ := b.inode(header.NodeId, 0)
result, status := n.node.Readlink(&fuse.Context{Caller: header.Caller, Cancel: cancel}) result, status := n.ops.Readlink(&fuse.Context{Caller: header.Caller, Cancel: cancel})
if !status.Ok() { if !status.Ok() {
return nil, status return nil, status
} }
...@@ -423,7 +425,7 @@ func (b *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out ...@@ -423,7 +425,7 @@ func (b *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out
func (b *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (status fuse.Status) { func (b *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (status fuse.Status) {
n, _ := b.inode(input.NodeId, 0) n, _ := b.inode(input.NodeId, 0)
return n.node.Access(&fuse.Context{Caller: input.Caller, Cancel: cancel}, input.Mask) return n.ops.Access(&fuse.Context{Caller: input.Caller, Cancel: cancel}, input.Mask)
} }
// Extended attributes. // Extended attributes.
...@@ -431,28 +433,28 @@ func (b *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (status ...@@ -431,28 +433,28 @@ func (b *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (status
func (b *rawBridge) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, data []byte) (uint32, fuse.Status) { func (b *rawBridge) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, data []byte) (uint32, fuse.Status) {
n, _ := b.inode(header.NodeId, 0) n, _ := b.inode(header.NodeId, 0)
return n.node.GetXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}, attr, data) return n.ops.GetXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}, attr, data)
} }
func (b *rawBridge) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (sz uint32, status fuse.Status) { func (b *rawBridge) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (sz uint32, status fuse.Status) {
n, _ := b.inode(header.NodeId, 0) n, _ := b.inode(header.NodeId, 0)
return n.node.ListXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}, dest) return n.ops.ListXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}, dest)
} }
func (b *rawBridge) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status { func (b *rawBridge) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
n, _ := b.inode(input.NodeId, 0) n, _ := b.inode(input.NodeId, 0)
return n.node.SetXAttr(&fuse.Context{Caller: input.Caller, Cancel: cancel}, attr, data, input.Flags) return n.ops.SetXAttr(&fuse.Context{Caller: input.Caller, Cancel: cancel}, attr, data, input.Flags)
} }
func (b *rawBridge) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) (status fuse.Status) { func (b *rawBridge) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) (status fuse.Status) {
n, _ := b.inode(header.NodeId, 0) n, _ := b.inode(header.NodeId, 0)
return n.node.RemoveXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}, attr) return n.ops.RemoveXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}, attr)
} }
func (b *rawBridge) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) { func (b *rawBridge) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
n, _ := b.inode(input.NodeId, 0) n, _ := b.inode(input.NodeId, 0)
// NOSUBMIT: what about the mode argument? // NOSUBMIT: what about the mode argument?
f, flags, status := n.node.Open(&fuse.Context{Caller: input.Caller, Cancel: cancel}, input.Flags) f, flags, status := n.ops.Open(&fuse.Context{Caller: input.Caller, Cancel: cancel}, input.Flags)
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -486,28 +488,28 @@ func (b *rawBridge) registerFile(n *Inode, f FileHandle, flags uint32) uint32 { ...@@ -486,28 +488,28 @@ func (b *rawBridge) registerFile(n *Inode, f FileHandle, flags uint32) uint32 {
func (b *rawBridge) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) { func (b *rawBridge) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.Read(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, buf, int64(input.Offset)) return n.ops.Read(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, buf, int64(input.Offset))
} }
func (b *rawBridge) GetLk(cancel <-chan struct{}, input *fuse.LkIn, out *fuse.LkOut) (status fuse.Status) { func (b *rawBridge) GetLk(cancel <-chan struct{}, input *fuse.LkIn, out *fuse.LkOut) (status fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.GetLk(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Owner, &input.Lk, input.LkFlags, &out.Lk) return n.ops.GetLk(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Owner, &input.Lk, input.LkFlags, &out.Lk)
} }
func (b *rawBridge) SetLk(cancel <-chan struct{}, input *fuse.LkIn) (status fuse.Status) { func (b *rawBridge) SetLk(cancel <-chan struct{}, input *fuse.LkIn) (status fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.SetLk(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Owner, &input.Lk, input.LkFlags) return n.ops.SetLk(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Owner, &input.Lk, input.LkFlags)
} }
func (b *rawBridge) SetLkw(cancel <-chan struct{}, input *fuse.LkIn) (status fuse.Status) { func (b *rawBridge) SetLkw(cancel <-chan struct{}, input *fuse.LkIn) (status fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.SetLkw(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Owner, &input.Lk, input.LkFlags) return n.ops.SetLkw(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Owner, &input.Lk, input.LkFlags)
} }
func (b *rawBridge) Release(input *fuse.ReleaseIn) { func (b *rawBridge) Release(input *fuse.ReleaseIn) {
n, f := b.releaseFileEntry(input.NodeId, input.Fh) n, f := b.releaseFileEntry(input.NodeId, input.Fh)
f.wg.Wait() f.wg.Wait()
n.node.Release(f.file) n.ops.Release(f.file)
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
...@@ -547,27 +549,27 @@ func (b *rawBridge) releaseFileEntry(nid uint64, fh uint64) (*Inode, *fileEntry) ...@@ -547,27 +549,27 @@ func (b *rawBridge) releaseFileEntry(nid uint64, fh uint64) (*Inode, *fileEntry)
func (b *rawBridge) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, status fuse.Status) { func (b *rawBridge) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, status fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.Write(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, data, int64(input.Offset)) return n.ops.Write(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, data, int64(input.Offset))
} }
func (b *rawBridge) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status { func (b *rawBridge) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.Flush(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file) return n.ops.Flush(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file)
} }
func (b *rawBridge) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) (status fuse.Status) { func (b *rawBridge) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) (status fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.Fsync(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.FsyncFlags) return n.ops.Fsync(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.FsyncFlags)
} }
func (b *rawBridge) Fallocate(cancel <-chan struct{}, input *fuse.FallocateIn) (status fuse.Status) { func (b *rawBridge) Fallocate(cancel <-chan struct{}, input *fuse.FallocateIn) (status fuse.Status) {
n, f := b.inode(input.NodeId, input.Fh) n, f := b.inode(input.NodeId, input.Fh)
return n.node.Allocate(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Offset, input.Length, input.Mode) return n.ops.Allocate(&fuse.Context{Caller: input.Caller, Cancel: cancel}, f.file, input.Offset, input.Length, input.Mode)
} }
func (b *rawBridge) OpenDir(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) fuse.Status { func (b *rawBridge) OpenDir(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) fuse.Status {
n, _ := b.inode(input.NodeId, 0) n, _ := b.inode(input.NodeId, 0)
status := n.node.OpenDir(&fuse.Context{Caller: input.Caller, Cancel: cancel}) status := n.ops.OpenDir(&fuse.Context{Caller: input.Caller, Cancel: cancel})
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -583,7 +585,7 @@ func (b *rawBridge) getStream(cancel <-chan struct{}, input *fuse.ReadIn, inode ...@@ -583,7 +585,7 @@ func (b *rawBridge) getStream(cancel <-chan struct{}, input *fuse.ReadIn, inode
f.dirStream.Close() f.dirStream.Close()
f.dirStream = nil f.dirStream = nil
} }
str, status := inode.node.ReadDir(&fuse.Context{Caller: input.Caller, Cancel: cancel}) str, status := inode.ops.ReadDir(&fuse.Context{Caller: input.Caller, Cancel: cancel})
if !status.Ok() { if !status.Ok() {
return status return status
} }
...@@ -652,7 +654,7 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out ...@@ -652,7 +654,7 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
return fuse.OK return fuse.OK
} }
child, status := n.node.Lookup(&fuse.Context{Caller: input.Caller, Cancel: cancel}, e.Name, entryOut) child, status := n.ops.Lookup(&fuse.Context{Caller: input.Caller, Cancel: cancel}, e.Name, entryOut)
if !status.Ok() { if !status.Ok() {
if b.options.NegativeTimeout != nil { if b.options.NegativeTimeout != nil {
entryOut.SetEntryTimeout(*b.options.NegativeTimeout) entryOut.SetEntryTimeout(*b.options.NegativeTimeout)
...@@ -674,12 +676,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out ...@@ -674,12 +676,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
func (b *rawBridge) FsyncDir(cancel <-chan struct{}, input *fuse.FsyncIn) (status fuse.Status) { func (b *rawBridge) FsyncDir(cancel <-chan struct{}, input *fuse.FsyncIn) (status fuse.Status) {
n, _ := b.inode(input.NodeId, input.Fh) n, _ := b.inode(input.NodeId, input.Fh)
return n.node.Fsync(&fuse.Context{Caller: input.Caller, Cancel: cancel}, nil, input.FsyncFlags) return n.ops.Fsync(&fuse.Context{Caller: input.Caller, Cancel: cancel}, nil, input.FsyncFlags)
} }
func (b *rawBridge) StatFs(cancel <-chan struct{}, input *fuse.InHeader, out *fuse.StatfsOut) (status fuse.Status) { func (b *rawBridge) StatFs(cancel <-chan struct{}, input *fuse.InHeader, out *fuse.StatfsOut) (status fuse.Status) {
n, _ := b.inode(input.NodeId, 0) n, _ := b.inode(input.NodeId, 0)
return n.node.StatFs(&fuse.Context{Caller: input.Caller, Cancel: cancel}, out) return n.ops.StatFs(&fuse.Context{Caller: input.Caller, Cancel: cancel}, out)
} }
func (b *rawBridge) Init(s *fuse.Server) { func (b *rawBridge) Init(s *fuse.Server) {
......
...@@ -150,10 +150,11 @@ func (n *DefaultOperations) Flush(ctx context.Context, f FileHandle) fuse.Status ...@@ -150,10 +150,11 @@ func (n *DefaultOperations) Flush(ctx context.Context, f FileHandle) fuse.Status
return fuse.ENOSYS return fuse.ENOSYS
} }
func (n *DefaultOperations) Release(f FileHandle) { func (n *DefaultOperations) Release(f FileHandle) fuse.Status {
if f != nil { if f != nil {
f.Release() return f.Release()
} }
return fuse.ENOSYS
} }
func (n *DefaultOperations) Allocate(ctx context.Context, f FileHandle, off uint64, size uint64, mode uint32) (status fuse.Status) { func (n *DefaultOperations) Allocate(ctx context.Context, f FileHandle, off uint64, size uint64, mode uint32) (status fuse.Status) {
...@@ -264,8 +265,8 @@ func (f *DefaultFile) Flush(ctx context.Context) fuse.Status { ...@@ -264,8 +265,8 @@ func (f *DefaultFile) Flush(ctx context.Context) fuse.Status {
return fuse.ENOSYS return fuse.ENOSYS
} }
func (f *DefaultFile) Release() { func (f *DefaultFile) Release() fuse.Status {
return fuse.ENOSYS
} }
func (f *DefaultFile) GetAttr(ctx context.Context, out *fuse.AttrOut) fuse.Status { func (f *DefaultFile) GetAttr(ctx context.Context, out *fuse.AttrOut) fuse.Status {
......
...@@ -46,10 +46,11 @@ func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint3 ...@@ -46,10 +46,11 @@ func (f *loopbackFile) Write(ctx context.Context, data []byte, off int64) (uint3
return uint32(n), fuse.ToStatus(err) return uint32(n), fuse.ToStatus(err)
} }
func (f *loopbackFile) Release() { func (f *loopbackFile) Release() fuse.Status {
f.mu.Lock() f.mu.Lock()
syscall.Close(f.fd) err := syscall.Close(f.fd)
f.mu.Unlock() f.mu.Unlock()
return fuse.ToStatus(err)
} }
func (f *loopbackFile) Flush(ctx context.Context) fuse.Status { func (f *loopbackFile) Flush(ctx context.Context) fuse.Status {
......
...@@ -15,8 +15,6 @@ import ( ...@@ -15,8 +15,6 @@ import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
) )
var _ = log.Println
type parentData struct { type parentData struct {
name string name string
parent *Inode parent *Inode
...@@ -54,7 +52,7 @@ type Inode struct { ...@@ -54,7 +52,7 @@ type Inode struct {
nodeID FileID nodeID FileID
node Operations ops Operations
bridge *rawBridge bridge *rawBridge
// Following data is mutable. // Following data is mutable.
...@@ -90,10 +88,12 @@ type Inode struct { ...@@ -90,10 +88,12 @@ type Inode struct {
parents map[parentData]struct{} parents map[parentData]struct{}
} }
// FileID returns the (Ino, Gen) tuple for this node.
func (n *Inode) FileID() FileID { func (n *Inode) FileID() FileID {
return n.nodeID return n.nodeID
} }
// IsRoot returns true if this is the root of the FUSE mount.
func (n *Inode) IsRoot() bool { func (n *Inode) IsRoot() bool {
return n.nodeID.Ino == fuse.FUSE_ROOT_ID return n.nodeID.Ino == fuse.FUSE_ROOT_ID
} }
...@@ -195,7 +195,7 @@ func (n *Inode) Forgotten() bool { ...@@ -195,7 +195,7 @@ func (n *Inode) Forgotten() bool {
// Node returns the Node object implementing the file system operations. // Node returns the Node object implementing the file system operations.
func (n *Inode) Operations() Operations { func (n *Inode) Operations() Operations {
return n.node return n.ops
} }
// Path returns a path string to the inode relative to the root. // Path returns a path string to the inode relative to the root.
...@@ -238,23 +238,6 @@ func (n *Inode) Path(root *Inode) string { ...@@ -238,23 +238,6 @@ func (n *Inode) Path(root *Inode) string {
return path return path
} }
// Finds a child with the given name and filetype. Returns nil if not
// found.
func (n *Inode) FindChildByMode(name string, mode uint32) *Inode {
mode ^= 07777
n.mu.Lock()
defer n.mu.Unlock()
ch := n.children[name]
if ch != nil && ch.mode == mode {
return ch
}
return nil
}
// setEntry does `iparent[name] = ichild` linking. // setEntry does `iparent[name] = ichild` linking.
// //
// setEntry must not be called simultaneously for any of iparent or ichild. // setEntry must not be called simultaneously for any of iparent or ichild.
...@@ -420,7 +403,7 @@ retry: ...@@ -420,7 +403,7 @@ retry:
} }
// MvChild executes a rename. If overwrite is set, a child at the // MvChild executes a rename. If overwrite is set, a child at the
// destination will be overwritten. // destination will be overwritten, should it exist.
func (n *Inode) MvChild(old string, newParent *Inode, newName string, overwrite bool) bool { func (n *Inode) MvChild(old string, newParent *Inode, newName string, overwrite bool) bool {
retry: retry:
for { for {
...@@ -475,6 +458,8 @@ retry: ...@@ -475,6 +458,8 @@ retry:
} }
} }
// ExchangeChild swaps the entries at (n, oldName) and (newParent,
// newName).
func (n *Inode) ExchangeChild(oldName string, newParent *Inode, newName string) { func (n *Inode) ExchangeChild(oldName string, newParent *Inode, newName string) {
oldParent := n oldParent := n
retry: retry:
...@@ -487,9 +472,6 @@ retry: ...@@ -487,9 +472,6 @@ retry:
destChild := newParent.children[newName] destChild := newParent.children[newName]
unlockNode2(oldParent, newParent) unlockNode2(oldParent, newParent)
if destChild == nil && oldChild == nil {
return
}
if destChild == oldChild { if destChild == oldChild {
return return
} }
...@@ -536,26 +518,36 @@ retry: ...@@ -536,26 +518,36 @@ retry:
} }
} }
// NotifyEntry notifies the kernel that data for a (directory, name)
// tuple should be invalidated. On next access, a LOOKUP operation
// will be started.
func (n *Inode) NotifyEntry(name string) fuse.Status { func (n *Inode) NotifyEntry(name string) fuse.Status {
return n.bridge.server.EntryNotify(n.nodeID.Ino, name) return n.bridge.server.EntryNotify(n.nodeID.Ino, name)
} }
// XXX naming: DeleteNotify ? // NotifyDelete notifies the kernel that the given inode was removed
// from this directory as entry under the given name. It is equivalent
// to NotifyEntry, but also sends an event to inotify watchers.
func (n *Inode) NotifyDelete(name string, child *Inode) fuse.Status { func (n *Inode) NotifyDelete(name string, child *Inode) fuse.Status {
// XXX arg ordering? // XXX arg ordering?
return n.bridge.server.DeleteNotify(n.nodeID.Ino, child.nodeID.Ino, name) return n.bridge.server.DeleteNotify(n.nodeID.Ino, child.nodeID.Ino, name)
} }
// NotifyContent notifies the kernel that content under the given
// inode should be flushed from buffers.
func (n *Inode) NotifyContent(off, sz int64) fuse.Status { func (n *Inode) NotifyContent(off, sz int64) fuse.Status {
// XXX how does this work for directories?
return n.bridge.server.InodeNotify(n.nodeID.Ino, off, sz) return n.bridge.server.InodeNotify(n.nodeID.Ino, off, sz)
} }
// WriteCache stores data in the kernel cache.
func (n *Inode) WriteCache(offset int64, data []byte) fuse.Status { func (n *Inode) WriteCache(offset int64, data []byte) fuse.Status {
return n.bridge.server.InodeNotifyStoreCache(n.nodeID.Ino, offset, data) return n.bridge.server.InodeNotifyStoreCache(n.nodeID.Ino, offset, data)
} }
// ReadCache reads data from the kernel cache.
func (n *Inode) ReadCache(offset int64, dest []byte) (count int, status fuse.Status) { func (n *Inode) ReadCache(offset int64, dest []byte) (count int, status fuse.Status) {
return n.bridge.server.InodeRetrieveCache(n.nodeID.Ino, offset, dest) return n.bridge.server.InodeRetrieveCache(n.nodeID.Ino, offset, dest)
} }
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