diff --git a/fs/serve.go b/fs/serve.go index e9fc5659..e4a84b40 100644 --- a/fs/serve.go +++ b/fs/serve.go @@ -217,7 +217,7 @@ type NodeMknoder interface { Mknod(ctx context.Context, req *fuse.MknodRequest) (Node, error) } -// TODO this should be on Handle not Node +// NodeFsyncer is deprecated. Use HandleFsyncer instead. type NodeFsyncer interface { Fsync(ctx context.Context, req *fuse.FsyncRequest) error } @@ -282,6 +282,32 @@ type HandleFlusher interface { Flush(ctx context.Context, req *fuse.FlushRequest) error } +type HandleFsyncer interface { + Fsync(ctx context.Context, req *fuse.FsyncRequest) error +} + +type HandleGetattrer interface { + // Getattr obtains the standard metadata related to an open file handle. + // It should store that metadata in resp. + // + // If this method is not implemented, it will defer to NodeGetattrer. + Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error +} + +type HandleSetattrer interface { + // Setattr sets the standard metadata related to an open file handle. + // + // If this method is not implemented, it will defer to NodeSetattrer. + // + // Note, this is also used to communicate changes in the size of + // the file, outside of Writes. + // + // req.Valid is a bitmask of what fields are actually being set. + // For example, the method should not change the mode of the file + // unless req.Valid.Mode() is true. + Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error +} + type HandleReadAller interface { ReadAll(ctx context.Context) ([]byte, error) } @@ -926,6 +952,19 @@ func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, // Node operations. case *fuse.GetattrRequest: s := &fuse.GetattrResponse{} + + // Try Getattr on the handle (if set) before falling back to node attributes. + if shandle := c.getHandle(r.Handle); shandle != nil { + if h, ok := shandle.handle.(HandleGetattrer); ok { + if err := h.Getattr(ctx, r, s); err != nil { + return err + } + done(s) + r.Respond(s) + return nil + } + } + if n, ok := node.(NodeGetattrer); ok { if err := n.Getattr(ctx, r, s); err != nil { return err @@ -941,7 +980,19 @@ func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, case *fuse.SetattrRequest: s := &fuse.SetattrResponse{} - if n, ok := node.(NodeSetattrer); ok { + var set bool + + // Try Setattr on the handle (if set) before falling back to node attributes. + if shandle := c.getHandle(r.Handle); shandle != nil { + if h, ok := shandle.handle.(HandleSetattrer); ok { + if err := h.Setattr(ctx, r, s); err != nil { + return err + } + set = true + } + } + + if n, ok := node.(NodeSetattrer); ok && !set { if err := n.Setattr(ctx, r, s); err != nil { return err } @@ -1359,14 +1410,25 @@ func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, return nil case *fuse.FsyncRequest: - n, ok := node.(NodeFsyncer) - if !ok { + shandle := c.getHandle(r.Handle) + if shandle == nil { + return fuse.ESTALE + } + handle := shandle.handle + + var err error + if h, ok := handle.(HandleFsyncer); ok { + err = h.Fsync(ctx, r) + } else if n, ok := node.(NodeFsyncer); ok { + err = n.Fsync(ctx, r) + } else { return fuse.EIO } - err := n.Fsync(ctx, r) + if err != nil { return err } + done(nil) r.Respond() return nil