func (f *fs) handleLookup(r *fuse.LookupRequest) { log.Println("Inside handleLookup") log.Printf("Running Lookup for %s", r.Name) log.Println(r) resp := &fuse.LookupResponse{} l, err := f.rpc.api.Lookup(f.getContext(), &pb.LookupRequest{Name: r.Name, Parent: uint64(r.Node)}) if err != nil { log.Fatalf("Lookup failed(%s): %v", r.Name, err) } // If there is no name then it wasn't found if l.Name != r.Name { log.Printf("ENOENT Lookup(%s)", r.Name) r.RespondError(fuse.ENOENT) return } resp.Node = fuse.NodeID(l.Attr.Inode) copyAttr(&resp.Attr, l.Attr) // TODO: should we make these configureable? resp.Attr.Valid = 5 * time.Second resp.EntryValid = 5 * time.Second log.Println(resp) r.Respond(resp) }
func (c *serveConn) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) { c.meta.Lock() defer c.meta.Unlock() var ref *NodeRef if nodeRef, ok := node.(nodeRef); ok { ref = nodeRef.nodeRef() if ref.id != 0 { // dropNode guarantees that NodeRef is zeroed at the same // time as the NodeID is removed from serveConn.node, as // guarded by c.meta; this means sn cannot be nil here sn := c.node[ref.id] sn.refs++ return ref.id, ref.generation } } sn := &serveNode{inode: inode, node: node, refs: 1} if n := len(c.freeNode); n > 0 { id = c.freeNode[n-1] c.freeNode = c.freeNode[:n-1] c.node[id] = sn c.nodeGen++ } else { id = fuse.NodeID(len(c.node)) c.node = append(c.node, sn) } gen = c.nodeGen if ref != nil { ref.id = id ref.generation = gen } return }
// Return a Dirent for all children of an inode, or ENOENT func (sc *serveConn) lookup(req *fuse.LookupRequest) { inode := uint64(req.Header.Node) resp := &fuse.LookupResponse{} var err error file, err := sc.db.FileByInode(inode) if err != nil { fuse.Debug(fmt.Sprintf("FileByInode lookup failure for %d: %v", inode, err)) req.RespondError(fuse.ENOENT) return } for _, cInode := range file.Children { cf, err := sc.db.FileByInode(cInode) if err != nil { fuse.Debug(fmt.Sprintf("FileByInode(%v): %v", cInode, err)) req.RespondError(fuse.EIO) return } if cf.Title == req.Name { resp.Node = fuse.NodeID(cInode) resp.EntryValid = *driveMetadataLatency resp.Attr = sc.attrFromFile(*cf) fuse.Debug(fmt.Sprintf("Lookup(%v in %v): %v", req.Name, inode, cInode)) req.Respond(resp) return } } fuse.Debug(fmt.Sprintf("Lookup(%v in %v): ENOENT", req.Name, inode)) req.RespondError(fuse.ENOENT) }
func (d Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, res *fuse.LookupResponse) (fs.Node, error) { log.Debug("Lookup(%s,%d,%s)", d.GetPath(), req.Node, req.Name) lock.Lock() defer lock.Unlock() node, err := d.lookup(ctx, req.Name) if err != nil { return nil, err } res.Node = fuse.NodeID(d.Fs.GenerateInode(uint64(req.Node), req.Name)) return node, nil }
func (f *fs) handleSymlink(r *fuse.SymlinkRequest) { log.Println("Inside handleSymlink") log.Println(r) resp := &fuse.SymlinkResponse{} symlink, err := f.rpc.api.Symlink(f.getContext(), &pb.SymlinkRequest{Parent: uint64(r.Node), Name: r.NewName, Target: r.Target, Uid: r.Uid, Gid: r.Gid}) if err != nil { log.Fatalf("Symlink failed: %v", err) } resp.Node = fuse.NodeID(symlink.Attr.Inode) copyAttr(&resp.Attr, symlink.Attr) resp.Attr.Valid = 5 * time.Second resp.EntryValid = 5 * time.Second log.Println(resp) r.Respond(resp) }
func (c *serveConn) saveNode(name string, node Node) (id fuse.NodeID, gen uint64, sn *serveNode) { sn = &serveNode{name: name, node: node} c.meta.Lock() if n := len(c.freeNode); n > 0 { id = c.freeNode[n-1] c.freeNode = c.freeNode[:n-1] c.node[id] = sn c.nodeGen++ } else { id = fuse.NodeID(len(c.node)) c.node = append(c.node, sn) } gen = c.nodeGen c.meta.Unlock() return }
func (f *fs) handleCreate(r *fuse.CreateRequest) { log.Println("Inside handleCreate") log.Println(r) resp := &fuse.CreateResponse{} c, err := f.rpc.api.Create(f.getContext(), &pb.CreateRequest{Parent: uint64(r.Node), Name: r.Name, Attr: &pb.Attr{Uid: r.Uid, Gid: r.Gid, Mode: uint32(r.Mode)}}) if err != nil { log.Fatalf("Failed to create file: %v", err) } resp.Node = fuse.NodeID(c.Attr.Inode) copyAttr(&resp.Attr, c.Attr) resp.EntryValid = 5 * time.Second resp.Attr.Valid = 5 * time.Second copyAttr(&resp.LookupResponse.Attr, c.Attr) resp.LookupResponse.EntryValid = 5 * time.Second resp.LookupResponse.Attr.Valid = 5 * time.Second r.Respond(resp) }
// Creates a regular file in dir with the attributes supplied in req func (dir *Directory) Create(req *fuse.CreateRequest, resp *fuse.CreateResponse, intr fs.Intr) (fs.Node, fs.Handle, fuse.Error) { if strings.Contains(req.Name, "@") { return nil, nil, fuse.EPERM } filesystem.Lock(dir) defer filesystem.Unlock(dir) util.P_out(req.String()) rval := new(File) rval.InitFile(req.Name, req.Mode, dir) rval.Attrs.Gid = req.Gid rval.Attrs.Uid = req.Uid dir.setChild(rval) resp.Attr = rval.Attr() resp.Node = fuse.NodeID(rval.Attr().Inode) rval.dirty = true dir.dirty = true return rval, rval, nil }
func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fusefs.Node, error) { if skipDirEntry(req.Name) { return nil, fuse.ENOENT } path := filepath.Join(d.path, req.Name) isDir := false defer trace(NewLookupOp(req, path, isDir)) var st syscall.Stat_t if err := syscall.Lstat(path, &st); err != nil { return nil, fuse.ENOENT } resp.Attr = statToFuseAttr(st) resp.Node = fuse.NodeID(resp.Attr.Inode) // TODO: should we overwrite resp.EntryValid? // resp.EntryValid = time.Duration(500) * time.Millisecond if isDir = resp.Attr.Mode.IsDir(); isDir { return NewDir(d.path, req.Name, d.fs), nil } return NewFile(d.path, req.Name, d.fs), nil }
func (sc *serveConn) mkdir(req *fuse.MkdirRequest) { if *readOnly { req.RespondError(fuse.EPERM) return } // TODO: if allow_other, require uid == invoking uid to allow writes pInode := uint64(req.Header.Node) pId, err := sc.db.FileIdForInode(pInode) if err != nil { debug.Printf("failed to get parent fileid: %v", err) req.RespondError(fuse.EIO) return } p := []*drive.ParentReference{&drive.ParentReference{Id: pId}} file := &drive.File{Title: req.Name, MimeType: driveFolderMimeType, Parents: p} file, err = sc.service.Files.Insert(file).Do() if err != nil { debug.Printf("Insert failed: %v", err) req.RespondError(fuse.EIO) return } debug.Printf("Child of %v created in drive: %+v", file.Parents[0].Id, file) f, err := sc.db.UpdateFile(nil, file) if err != nil { debug.Printf("failed to update levelDB for %v: %v", f.Id, err) // The write has happened to drive, but we failed to update the kernel. // The Changes API will update Fuse, and when the kernel metadata for // the parent directory expires, the new dir will become visible. req.RespondError(fuse.EIO) return } sc.db.FlushCachedInode(pInode) resp := &fuse.MkdirResponse{} resp.Node = fuse.NodeID(f.Inode) resp.EntryValid = *driveMetadataLatency resp.Attr.Valid = *driveMetadataLatency resp.Attr = sc.attrFromFile(*f) fuse.Debug(fmt.Sprintf("Mkdir(%v): %+v", req.Name, f)) req.Respond(resp) }
func (f *fs) handleMkdir(r *fuse.MkdirRequest) { log.Println("Inside handleMkdir") log.Println(r) resp := &fuse.MkdirResponse{} m, err := f.rpc.api.MkDir(f.getContext(), &pb.MkDirRequest{Name: r.Name, Parent: uint64(r.Node), Attr: &pb.Attr{Uid: r.Uid, Gid: r.Gid, Mode: uint32(r.Mode)}}) if err != nil { log.Fatalf("Mkdir failed(%s): %v", r.Name, err) } // If the name is empty, then the dir already exists if m.Name != r.Name { log.Printf("EEXIST Mkdir(%s)", r.Name) r.RespondError(fuse.EEXIST) return } resp.Node = fuse.NodeID(m.Attr.Inode) copyAttr(&resp.Attr, m.Attr) resp.Attr.Valid = 5 * time.Second resp.EntryValid = 5 * time.Second log.Println(resp) r.Respond(resp) }
func (c *Server) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) { c.meta.Lock() defer c.meta.Unlock() if id, ok := c.nodeRef[node]; ok { sn := c.node[id] sn.refs++ return id, sn.generation } sn := &serveNode{inode: inode, node: node, refs: 1} if n := len(c.freeNode); n > 0 { id = c.freeNode[n-1] c.freeNode = c.freeNode[:n-1] c.node[id] = sn c.nodeGen++ } else { id = fuse.NodeID(len(c.node)) c.node = append(c.node, sn) } sn.generation = c.nodeGen c.nodeRef[node] = id return id, sn.generation }
func (d dir) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) { log.Printf("Lookup %q in Directory: %q\n%v\n", name, d.name, d) select { case <-intr: return nil, fuse.EINTR default: } newNodeID := fuse.NodeID(fs.GenerateDynamicInode(uint64(d.inode), name)) switch d.contentType { default: return nil, nil case "commit": node, CommitErr := d.LookupCommit(name, intr, newNodeID) return node, CommitErr case "list": node, listErr := d.LookupList(name, intr, newNodeID) return node, listErr case "tag": node, tagErr := d.LookupTag(name, intr, newNodeID) return node, tagErr } }
func generateInode(NodeID fuse.NodeID, name string) fuse.NodeID { return fuse.NodeID(fs.GenerateDynamicInode(uint64(NodeID), name)) }
// Create file in drive, allocate kernel filehandle for writes func (sc *serveConn) create(req *fuse.CreateRequest) { if *readOnly && !req.Flags.IsReadOnly() { req.RespondError(fuse.EPERM) return } pInode := uint64(req.Header.Node) parent, err := sc.db.FileByInode(pInode) if err != nil { debug.Printf("failed to get parent file: %v", err) req.RespondError(fuse.EIO) return } p := &drive.ParentReference{Id: parent.Id} f := &drive.File{Title: req.Name} f.Parents = []*drive.ParentReference{p} f, err = sc.service.Files.Insert(f).Do() if err != nil { debug.Printf("Files.Insert(f).Do(): %v", err) req.RespondError(fuse.EIO) return } inode, err := sc.db.InodeForFileId(f.Id) if err != nil { debug.Printf("failed creating inode for %v: %v", req.Name, err) req.RespondError(fuse.EIO) return } r, w := io.Pipe() // plumbing between WriteRequest and Drive h := sc.allocHandle(fuse.NodeID(inode), w) go sc.updateInDrive(f, r) // Tell fuse and the OS about the file df, err := sc.db.UpdateFile(nil, f) if err != nil { debug.Printf("failed to update levelDB for %v: %v", f.Id, err) // The write has happened to drive, but we failed to update the kernel. // The Changes API will update Fuse, and when the kernel metadata for // the parent directory expires, the new file will become visible. req.RespondError(fuse.EIO) return } resp := fuse.CreateResponse{ // describes the opened handle OpenResponse: fuse.OpenResponse{ Handle: fuse.HandleID(h), Flags: fuse.OpenNonSeekable, }, // describes the created file LookupResponse: fuse.LookupResponse{ Node: fuse.NodeID(inode), EntryValid: *driveMetadataLatency, Attr: sc.attrFromFile(*df), }, } fuse.Debug(fmt.Sprintf("Create(%v in %v): %+v", req.Name, parent.Title, resp)) req.Respond(&resp) }
func (c *serveConn) serve(fs FS, r fuse.Request) { intr := make(Intr) req := &serveRequest{Request: r, Intr: intr} fuse.Debugf("<- %s", req) var node Node var snode *serveNode c.meta.Lock() hdr := r.Hdr() if id := hdr.Node; id != 0 { if id < fuse.NodeID(len(c.node)) { snode = c.node[uint(id)] } if snode == nil { c.meta.Unlock() println("missing node", id, len(c.node), snode) fuse.Debugf("-> %#x %v", hdr.ID, fuse.ESTALE) r.RespondError(fuse.ESTALE) return } node = snode.node } if c.req[hdr.ID] != nil { // This happens with OSXFUSE. Assume it's okay and // that we'll never see an interrupt for this one. // Otherwise everything wedges. TODO: Report to OSXFUSE? intr = nil } else { c.req[hdr.ID] = req } c.meta.Unlock() // Call this before responding. // After responding is too late: we might get another request // with the same ID and be very confused. done := func(resp interface{}) { fuse.Debugf("-> %#x %v", hdr.ID, resp) c.meta.Lock() c.req[hdr.ID] = nil c.meta.Unlock() } switch r := r.(type) { default: // Note: To FUSE, ENOSYS means "this server never implements this request." // It would be inappropriate to return ENOSYS for other operations in this // switch that might only be unavailable in some contexts, not all. done(fuse.ENOSYS) r.RespondError(fuse.ENOSYS) // FS operations. case *fuse.InitRequest: s := &fuse.InitResponse{ MaxWrite: 4096, } if fs, ok := fs.(FSIniter); ok { if err := fs.Init(r, s, intr); err != nil { done(err) r.RespondError(err) break } } done(s) r.Respond(s) case *fuse.StatfsRequest: s := &fuse.StatfsResponse{} if fs, ok := fs.(FSStatfser); ok { if err := fs.Statfs(r, s, intr); err != nil { done(err) r.RespondError(err) break } } done(s) r.Respond(s) // Node operations. case *fuse.GetattrRequest: s := &fuse.GetattrResponse{} if n, ok := node.(NodeGetattrer); ok { if err := n.Getattr(r, s, intr); err != nil { done(err) r.RespondError(err) break } } else { s.AttrValid = 1 * time.Minute s.Attr = snode.attr() } done(s) r.Respond(s) case *fuse.SetattrRequest: s := &fuse.SetattrResponse{} // Special-case truncation, if no other bits are set // and the open Handles all have a WriteAll method. // // TODO WriteAll mishandles all kinds of cases, e.g. // truncating to non-zero size, noncontiguous writes, etc if r.Valid.Size() && r.Size == 0 { type writeAll interface { WriteAll([]byte, Intr) fuse.Error } switch r.Valid { case fuse.SetattrLockOwner | fuse.SetattrSize, fuse.SetattrSize: // Seen on Linux. Handle isn't set. c.meta.Lock() // it is not safe to assume any handles are open for // this node; calls to truncate(2) can happen at any // time if len(c.nodeHandles) > int(hdr.Node) { for hid := range c.nodeHandles[hdr.Node] { shandle := c.handle[hid] if _, ok := shandle.handle.(writeAll); ok { shandle.trunc = true } } } c.meta.Unlock() case fuse.SetattrHandle | fuse.SetattrSize: // Seen on OS X; the Handle is provided. shandle := c.getHandle(r.Handle) if shandle == nil { fuse.Debugf("-> %#x %v", hdr.ID, fuse.ESTALE) r.RespondError(fuse.ESTALE) return } if _, ok := shandle.handle.(writeAll); ok { shandle.trunc = true } } } log.Printf("setattr %v", r) if n, ok := node.(NodeSetattrer); ok { if err := n.Setattr(r, s, intr); err != nil { done(err) r.RespondError(err) break } done(s) r.Respond(s) break } if s.AttrValid == 0 { s.AttrValid = 1 * time.Minute } s.Attr = snode.attr() done(s) r.Respond(s) case *fuse.SymlinkRequest: s := &fuse.SymlinkResponse{} n, ok := node.(NodeSymlinker) if !ok { done(fuse.EIO) // XXX or EPERM like Mkdir? r.RespondError(fuse.EIO) break } n2, err := n.Symlink(r, intr) if err != nil { done(err) r.RespondError(err) break } c.saveLookup(&s.LookupResponse, snode, r.NewName, n2) done(s) r.Respond(s) case *fuse.ReadlinkRequest: n, ok := node.(NodeReadlinker) if !ok { done(fuse.EIO) /// XXX or EPERM? r.RespondError(fuse.EIO) break } target, err := n.Readlink(r, intr) if err != nil { done(err) r.RespondError(err) break } done(target) r.Respond(target) case *fuse.LinkRequest: n, ok := node.(NodeLinker) if !ok { log.Printf("Node %T doesn't implement fuse Link", node) done(fuse.EIO) /// XXX or EPERM? r.RespondError(fuse.EIO) break } c.meta.Lock() var oldNode *serveNode if int(r.OldNode) < len(c.node) { oldNode = c.node[r.OldNode] } c.meta.Unlock() if oldNode == nil { log.Printf("In LinkRequest, node %d not found", r.OldNode) done(fuse.EIO) r.RespondError(fuse.EIO) break } n2, err := n.Link(r, oldNode.node, intr) if err != nil { done(err) r.RespondError(err) break } s := &fuse.LookupResponse{} c.saveLookup(s, snode, r.NewName, n2) done(s) r.Respond(s) case *fuse.RemoveRequest: n, ok := node.(NodeRemover) if !ok { done(fuse.EIO) /// XXX or EPERM? r.RespondError(fuse.EIO) break } err := n.Remove(r, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.AccessRequest: if n, ok := node.(NodeAccesser); ok { if err := n.Access(r, intr); err != nil { done(err) r.RespondError(err) break } } done(r) r.Respond() case *fuse.LookupRequest: var n2 Node var err fuse.Error s := &fuse.LookupResponse{} if n, ok := node.(NodeStringLookuper); ok { n2, err = n.Lookup(r.Name, intr) } else if n, ok := node.(NodeRequestLookuper); ok { n2, err = n.Lookup(r, s, intr) } else { done(fuse.ENOENT) r.RespondError(fuse.ENOENT) break } if err != nil { done(err) r.RespondError(err) break } c.saveLookup(s, snode, r.Name, n2) done(s) r.Respond(s) case *fuse.MkdirRequest: s := &fuse.MkdirResponse{} n, ok := node.(NodeMkdirer) if !ok { done(fuse.EPERM) r.RespondError(fuse.EPERM) break } n2, err := n.Mkdir(r, intr) if err != nil { done(err) r.RespondError(err) break } c.saveLookup(&s.LookupResponse, snode, r.Name, n2) done(s) r.Respond(s) case *fuse.OpenRequest: s := &fuse.OpenResponse{Flags: fuse.OpenDirectIO} var h2 Handle if n, ok := node.(NodeOpener); ok { hh, err := n.Open(r, s, intr) if err != nil { done(err) r.RespondError(err) break } h2 = hh } else { h2 = node } s.Handle, _ = c.saveHandle(h2, hdr.Node) done(s) r.Respond(s) case *fuse.CreateRequest: n, ok := node.(NodeCreater) if !ok { // If we send back ENOSYS, FUSE will try mknod+open. done(fuse.EPERM) r.RespondError(fuse.EPERM) break } s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{Flags: fuse.OpenDirectIO}} n2, h2, err := n.Create(r, s, intr) if err != nil { done(err) r.RespondError(err) break } c.saveLookup(&s.LookupResponse, snode, r.Name, n2) h, shandle := c.saveHandle(h2, hdr.Node) s.Handle = h type writeAll interface { WriteAll([]byte, Intr) fuse.Error } if _, ok := shandle.handle.(writeAll); ok { shandle.trunc = true } done(s) r.Respond(s) case *fuse.GetxattrRequest, *fuse.SetxattrRequest, *fuse.ListxattrRequest, *fuse.RemovexattrRequest: // TODO: Use n. done(fuse.ENOSYS) r.RespondError(fuse.ENOSYS) case *fuse.ForgetRequest: n, ok := node.(NodeForgetter) if ok { n.Forget() } c.dropNode(hdr.Node) done(r) r.Respond() // Handle operations. case *fuse.ReadRequest: shandle := c.getHandle(r.Handle) if shandle == nil { fuse.Debugf("-> %#x %v", hdr.ID, fuse.ESTALE) r.RespondError(fuse.ESTALE) return } handle := shandle.handle s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)} if r.Dir { if h, ok := handle.(HandleReadDirer); ok { if shandle.readData == nil { dirs, err := h.ReadDir(intr) if err != nil { done(err) r.RespondError(err) break } var data []byte for _, dir := range dirs { if dir.Inode == 0 { dir.Inode = hash(path.Join(snode.name, dir.Name)) } data = fuse.AppendDirent(data, dir) } shandle.readData = data } fuseutil.HandleRead(r, s, shandle.readData) done(s) r.Respond(s) break } } else { if h, ok := handle.(HandleReadAller); ok { if shandle.readData == nil { data, err := h.ReadAll(intr) if err != nil { done(err) r.RespondError(err) break } if data == nil { data = []byte{} } shandle.readData = data } fuseutil.HandleRead(r, s, shandle.readData) done(s) r.Respond(s) break } h, ok := handle.(HandleReader) if !ok { fmt.Printf("NO READ FOR %T\n", handle) done(fuse.EIO) r.RespondError(fuse.EIO) break } if err := h.Read(r, s, intr); err != nil { done(err) r.RespondError(err) break } } done(s) r.Respond(s) case *fuse.WriteRequest: shandle := c.getHandle(r.Handle) if shandle == nil { fuse.Debugf("-> %#x %v", hdr.ID, fuse.ESTALE) r.RespondError(fuse.ESTALE) return } s := &fuse.WriteResponse{} if shandle.trunc && r.Offset == int64(len(shandle.writeData)) { shandle.writeData = append(shandle.writeData, r.Data...) s.Size = len(r.Data) done(s) r.Respond(s) break } if h, ok := shandle.handle.(HandleWriter); ok { if err := h.Write(r, s, intr); err != nil { done(err) r.RespondError(err) break } done(s) r.Respond(s) break } println("NO WRITE") done(fuse.EIO) r.RespondError(fuse.EIO) case *fuse.FlushRequest: shandle := c.getHandle(r.Handle) if shandle == nil { fuse.Debugf("-> %#x %v", hdr.ID, fuse.ESTALE) r.RespondError(fuse.ESTALE) return } handle := shandle.handle if shandle.trunc { h := handle.(HandleWriteAller) if err := h.WriteAll(shandle.writeData, intr); err != nil { done(err) r.RespondError(err) break } shandle.writeData = nil shandle.trunc = false } if h, ok := handle.(HandleFlusher); ok { if err := h.Flush(r, intr); err != nil { done(err) r.RespondError(err) break } } done(nil) r.Respond() case *fuse.ReleaseRequest: shandle := c.getHandle(r.Handle) if shandle == nil { fuse.Debugf("-> %#x %v", hdr.ID, fuse.ESTALE) r.RespondError(fuse.ESTALE) return } handle := shandle.handle // No matter what, release the handle. c.dropHandle(r.Handle) if h, ok := handle.(HandleReleaser); ok { if err := h.Release(r, intr); err != nil { done(err) r.RespondError(err) break } } done(nil) r.Respond() case *fuse.DestroyRequest: if fs, ok := fs.(FSDestroyer); ok { fs.Destroy() } done(nil) r.Respond() case *fuse.RenameRequest: c.meta.Lock() var newDirNode *serveNode if int(r.NewDir) < len(c.node) { newDirNode = c.node[r.NewDir] } c.meta.Unlock() if newDirNode == nil { println("RENAME NEW DIR NODE NOT FOUND") done(fuse.EIO) r.RespondError(fuse.EIO) break } n, ok := node.(NodeRenamer) if !ok { log.Printf("Node %T missing Rename method", node) done(fuse.EIO) // XXX or EPERM like Mkdir? r.RespondError(fuse.EIO) break } err := n.Rename(r, newDirNode.node, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.MknodRequest: n, ok := node.(NodeMknoder) if !ok { log.Printf("Node %T missing Mknod method", node) done(fuse.EIO) r.RespondError(fuse.EIO) break } n2, err := n.Mknod(r, intr) if err != nil { done(err) r.RespondError(err) break } s := &fuse.LookupResponse{} c.saveLookup(s, snode, r.Name, n2) done(s) r.Respond(s) case *fuse.FsyncRequest: n, ok := node.(NodeFsyncer) if !ok { log.Printf("Node %T missing Fsync method", node) done(fuse.EIO) r.RespondError(fuse.EIO) break } err := n.Fsync(r, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.InterruptRequest: c.meta.Lock() ireq := c.req[r.IntrID] if ireq != nil && ireq.Intr != nil { close(ireq.Intr) ireq.Intr = nil } c.meta.Unlock() done(nil) r.Respond() /* case *FsyncdirRequest: done(ENOSYS) r.RespondError(ENOSYS) case *GetlkRequest, *SetlkRequest, *SetlkwRequest: done(ENOSYS) r.RespondError(ENOSYS) case *BmapRequest: done(ENOSYS) r.RespondError(ENOSYS) case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest: done(ENOSYS) r.RespondError(ENOSYS) */ } }
func (c *Server) serve(r fuse.Request) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() parentCtx := ctx if c.context != nil { ctx = c.context(ctx, r) } req := &serveRequest{Request: r, cancel: cancel} c.debug(request{ Op: opName(r), Request: r.Hdr(), In: r, }) var node Node var snode *serveNode c.meta.Lock() hdr := r.Hdr() if id := hdr.Node; id != 0 { if id < fuse.NodeID(len(c.node)) { snode = c.node[uint(id)] } if snode == nil { c.meta.Unlock() c.debug(response{ Op: opName(r), Request: logResponseHeader{ID: hdr.ID}, Error: fuse.ESTALE.ErrnoName(), // this is the only place that sets both Error and // Out; not sure if i want to do that; might get rid // of len(c.node) things altogether Out: logMissingNode{ MaxNode: fuse.NodeID(len(c.node)), }, }) r.RespondError(fuse.ESTALE) return } node = snode.node } if c.req[hdr.ID] != nil { // This happens with OSXFUSE. Assume it's okay and // that we'll never see an interrupt for this one. // Otherwise everything wedges. TODO: Report to OSXFUSE? // // TODO this might have been because of missing done() calls } else { c.req[hdr.ID] = req } c.meta.Unlock() // Call this before responding. // After responding is too late: we might get another request // with the same ID and be very confused. done := func(resp interface{}) { msg := response{ Op: opName(r), Request: logResponseHeader{ID: hdr.ID}, } if err, ok := resp.(error); ok { msg.Error = err.Error() if ferr, ok := err.(fuse.ErrorNumber); ok { errno := ferr.Errno() msg.Errno = errno.ErrnoName() if errno == err { // it's just a fuse.Errno with no extra detail; // skip the textual message for log readability msg.Error = "" } } else { msg.Errno = fuse.DefaultErrno.ErrnoName() } } else { msg.Out = resp } c.debug(msg) c.meta.Lock() delete(c.req, hdr.ID) c.meta.Unlock() } var responded bool defer func() { if rec := recover(); rec != nil { const size = 1 << 16 buf := make([]byte, size) n := runtime.Stack(buf, false) buf = buf[:n] log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf) err := handlerPanickedError{ Request: r, Err: rec, } done(err) r.RespondError(err) return } if !responded { err := handlerTerminatedError{ Request: r, } done(err) r.RespondError(err) } }() if err := c.handleRequest(ctx, node, snode, r, done); err != nil { if err == context.Canceled { select { case <-parentCtx.Done(): // We canceled the parent context because of an // incoming interrupt request, so return EINTR // to trigger the right behavior in the client app. // // Only do this when it's the parent context that was // canceled, not a context controlled by the program // using this library, so we don't return EINTR too // eagerly -- it might cause busy loops. // // Decent write-up on role of EINTR: // http://250bpm.com/blog:12 err = fuse.EINTR default: // nothing } } done(err) r.RespondError(err) } // disarm runtime.Goexit protection responded = true }
func (c *serveConn) serve(r fuse.Request) { intr := make(Intr) req := &serveRequest{Request: r, Intr: intr} c.debug(request{ Op: opName(r), Request: r.Hdr(), In: r, }) var node Node var snode *serveNode c.meta.Lock() hdr := r.Hdr() if id := hdr.Node; id != 0 { if id < fuse.NodeID(len(c.node)) { snode = c.node[uint(id)] } if snode == nil { c.meta.Unlock() c.debug(response{ Op: opName(r), Request: logResponseHeader{ID: hdr.ID}, Error: fuse.ESTALE.ErrnoName(), // this is the only place that sets both Error and // Out; not sure if i want to do that; might get rid // of len(c.node) things altogether Out: logMissingNode{ MaxNode: fuse.NodeID(len(c.node)), }, }) r.RespondError(fuse.ESTALE) return } node = snode.node } if c.req[hdr.ID] != nil { // This happens with OSXFUSE. Assume it's okay and // that we'll never see an interrupt for this one. // Otherwise everything wedges. TODO: Report to OSXFUSE? // // TODO this might have been because of missing done() calls intr = nil } else { c.req[hdr.ID] = req } c.meta.Unlock() // Call this before responding. // After responding is too late: we might get another request // with the same ID and be very confused. done := func(resp interface{}) { msg := response{ Op: opName(r), Request: logResponseHeader{ID: hdr.ID}, } if err, ok := resp.(error); ok { msg.Error = err.Error() if ferr, ok := err.(fuse.ErrorNumber); ok { errno := ferr.Errno() msg.Errno = errno.ErrnoName() if errno == err { // it's just a fuse.Errno with no extra detail; // skip the textual message for log readability msg.Error = "" } } else { msg.Errno = fuse.DefaultErrno.ErrnoName() } } else { msg.Out = resp } c.debug(msg) c.meta.Lock() delete(c.req, hdr.ID) c.meta.Unlock() } switch r := r.(type) { default: // Note: To FUSE, ENOSYS means "this server never implements this request." // It would be inappropriate to return ENOSYS for other operations in this // switch that might only be unavailable in some contexts, not all. done(fuse.ENOSYS) r.RespondError(fuse.ENOSYS) // FS operations. case *fuse.InitRequest: s := &fuse.InitResponse{ MaxWrite: 128 * 1024, Flags: fuse.InitBigWrites, } if fs, ok := c.fs.(FSIniter); ok { if err := fs.Init(r, s, intr); err != nil { done(err) r.RespondError(err) break } } done(s) r.Respond(s) case *fuse.StatfsRequest: s := &fuse.StatfsResponse{} if fs, ok := c.fs.(FSStatfser); ok { if err := fs.Statfs(r, s, intr); err != nil { done(err) r.RespondError(err) break } } done(s) r.Respond(s) // Node operations. case *fuse.GetattrRequest: s := &fuse.GetattrResponse{} if n, ok := node.(NodeGetattrer); ok { if err := n.Getattr(r, s, intr); err != nil { done(err) r.RespondError(err) break } } else { s.AttrValid = attrValidTime s.Attr = snode.attr() } done(s) r.Respond(s) case *fuse.SetattrRequest: s := &fuse.SetattrResponse{} if n, ok := node.(NodeSetattrer); ok { if err := n.Setattr(r, s, intr); err != nil { done(err) r.RespondError(err) break } done(s) r.Respond(s) break } if s.AttrValid == 0 { s.AttrValid = attrValidTime } s.Attr = snode.attr() done(s) r.Respond(s) case *fuse.SymlinkRequest: s := &fuse.SymlinkResponse{} n, ok := node.(NodeSymlinker) if !ok { done(fuse.EIO) // XXX or EPERM like Mkdir? r.RespondError(fuse.EIO) break } n2, err := n.Symlink(r, intr) if err != nil { done(err) r.RespondError(err) break } c.saveLookup(&s.LookupResponse, snode, r.NewName, n2) done(s) r.Respond(s) case *fuse.ReadlinkRequest: n, ok := node.(NodeReadlinker) if !ok { done(fuse.EIO) /// XXX or EPERM? r.RespondError(fuse.EIO) break } target, err := n.Readlink(r, intr) if err != nil { done(err) r.RespondError(err) break } done(target) r.Respond(target) case *fuse.LinkRequest: n, ok := node.(NodeLinker) if !ok { done(fuse.EIO) /// XXX or EPERM? r.RespondError(fuse.EIO) break } c.meta.Lock() var oldNode *serveNode if int(r.OldNode) < len(c.node) { oldNode = c.node[r.OldNode] } c.meta.Unlock() if oldNode == nil { c.debug(logLinkRequestOldNodeNotFound{ Request: r.Hdr(), In: r, }) done(fuse.EIO) r.RespondError(fuse.EIO) break } n2, err := n.Link(r, oldNode.node, intr) if err != nil { done(err) r.RespondError(err) break } s := &fuse.LookupResponse{} c.saveLookup(s, snode, r.NewName, n2) done(s) r.Respond(s) case *fuse.RemoveRequest: n, ok := node.(NodeRemover) if !ok { done(fuse.EIO) /// XXX or EPERM? r.RespondError(fuse.EIO) break } err := n.Remove(r, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.AccessRequest: if n, ok := node.(NodeAccesser); ok { if err := n.Access(r, intr); err != nil { done(err) r.RespondError(err) break } } done(nil) r.Respond() case *fuse.LookupRequest: var n2 Node var err fuse.Error s := &fuse.LookupResponse{} if n, ok := node.(NodeStringLookuper); ok { n2, err = n.Lookup(r.Name, intr) } else if n, ok := node.(NodeRequestLookuper); ok { n2, err = n.Lookup(r, s, intr) } else { done(fuse.ENOENT) r.RespondError(fuse.ENOENT) break } if err != nil { done(err) r.RespondError(err) break } c.saveLookup(s, snode, r.Name, n2) done(s) r.Respond(s) case *fuse.MkdirRequest: s := &fuse.MkdirResponse{} n, ok := node.(NodeMkdirer) if !ok { done(fuse.EPERM) r.RespondError(fuse.EPERM) break } n2, err := n.Mkdir(r, intr) if err != nil { done(err) r.RespondError(err) break } c.saveLookup(&s.LookupResponse, snode, r.Name, n2) done(s) r.Respond(s) case *fuse.OpenRequest: s := &fuse.OpenResponse{} var h2 Handle if n, ok := node.(NodeOpener); ok { hh, err := n.Open(r, s, intr) if err != nil { done(err) r.RespondError(err) break } h2 = hh } else { h2 = node } s.Handle = c.saveHandle(h2, hdr.Node) done(s) r.Respond(s) case *fuse.CreateRequest: n, ok := node.(NodeCreater) if !ok { // If we send back ENOSYS, FUSE will try mknod+open. done(fuse.EPERM) r.RespondError(fuse.EPERM) break } s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}} n2, h2, err := n.Create(r, s, intr) if err != nil { done(err) r.RespondError(err) break } c.saveLookup(&s.LookupResponse, snode, r.Name, n2) s.Handle = c.saveHandle(h2, hdr.Node) done(s) r.Respond(s) case *fuse.GetxattrRequest: n, ok := node.(NodeGetxattrer) if !ok { done(fuse.ENOTSUP) r.RespondError(fuse.ENOTSUP) break } s := &fuse.GetxattrResponse{} err := n.Getxattr(r, s, intr) if err != nil { done(err) r.RespondError(err) break } if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) { done(fuse.ERANGE) r.RespondError(fuse.ERANGE) break } done(s) r.Respond(s) case *fuse.ListxattrRequest: n, ok := node.(NodeListxattrer) if !ok { done(fuse.ENOTSUP) r.RespondError(fuse.ENOTSUP) break } s := &fuse.ListxattrResponse{} err := n.Listxattr(r, s, intr) if err != nil { done(err) r.RespondError(err) break } if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) { done(fuse.ERANGE) r.RespondError(fuse.ERANGE) break } done(s) r.Respond(s) case *fuse.SetxattrRequest: n, ok := node.(NodeSetxattrer) if !ok { done(fuse.ENOTSUP) r.RespondError(fuse.ENOTSUP) break } err := n.Setxattr(r, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.RemovexattrRequest: n, ok := node.(NodeRemovexattrer) if !ok { done(fuse.ENOTSUP) r.RespondError(fuse.ENOTSUP) break } err := n.Removexattr(r, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.ForgetRequest: forget := c.dropNode(hdr.Node, r.N) if forget { n, ok := node.(NodeForgetter) if ok { n.Forget() } } done(nil) r.Respond() // Handle operations. case *fuse.ReadRequest: shandle := c.getHandle(r.Handle) if shandle == nil { done(fuse.ESTALE) r.RespondError(fuse.ESTALE) return } handle := shandle.handle s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)} if r.Dir { if h, ok := handle.(HandleReadDirer); ok { if shandle.readData == nil { dirs, err := h.ReadDir(intr) if err != nil { done(err) r.RespondError(err) break } var data []byte for _, dir := range dirs { if dir.Inode == 0 { dir.Inode = c.dynamicInode(snode.inode, dir.Name) } data = fuse.AppendDirent(data, dir) } shandle.readData = data } fuseutil.HandleRead(r, s, shandle.readData) done(s) r.Respond(s) break } } else { if h, ok := handle.(HandleReadAller); ok { if shandle.readData == nil { data, err := h.ReadAll(intr) if err != nil { done(err) r.RespondError(err) break } if data == nil { data = []byte{} } shandle.readData = data } fuseutil.HandleRead(r, s, shandle.readData) done(s) r.Respond(s) break } h, ok := handle.(HandleReader) if !ok { fmt.Printf("NO READ FOR %T\n", handle) done(fuse.EIO) r.RespondError(fuse.EIO) break } if err := h.Read(r, s, intr); err != nil { done(err) r.RespondError(err) break } } done(s) r.Respond(s) case *fuse.WriteRequest: shandle := c.getHandle(r.Handle) if shandle == nil { done(fuse.ESTALE) r.RespondError(fuse.ESTALE) return } s := &fuse.WriteResponse{} if h, ok := shandle.handle.(HandleWriter); ok { if err := h.Write(r, s, intr); err != nil { done(err) r.RespondError(err) break } done(s) r.Respond(s) break } done(fuse.EIO) r.RespondError(fuse.EIO) case *fuse.FlushRequest: shandle := c.getHandle(r.Handle) if shandle == nil { done(fuse.ESTALE) r.RespondError(fuse.ESTALE) return } handle := shandle.handle if h, ok := handle.(HandleFlusher); ok { if err := h.Flush(r, intr); err != nil { done(err) r.RespondError(err) break } } done(nil) r.Respond() case *fuse.ReleaseRequest: shandle := c.getHandle(r.Handle) if shandle == nil { done(fuse.ESTALE) r.RespondError(fuse.ESTALE) return } handle := shandle.handle // No matter what, release the handle. c.dropHandle(r.Handle) if h, ok := handle.(HandleReleaser); ok { if err := h.Release(r, intr); err != nil { done(err) r.RespondError(err) break } } done(nil) r.Respond() case *fuse.DestroyRequest: if fs, ok := c.fs.(FSDestroyer); ok { fs.Destroy() } done(nil) r.Respond() case *fuse.RenameRequest: c.meta.Lock() var newDirNode *serveNode if int(r.NewDir) < len(c.node) { newDirNode = c.node[r.NewDir] } c.meta.Unlock() if newDirNode == nil { c.debug(renameNewDirNodeNotFound{ Request: r.Hdr(), In: r, }) done(fuse.EIO) r.RespondError(fuse.EIO) break } n, ok := node.(NodeRenamer) if !ok { done(fuse.EIO) // XXX or EPERM like Mkdir? r.RespondError(fuse.EIO) break } err := n.Rename(r, newDirNode.node, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.MknodRequest: n, ok := node.(NodeMknoder) if !ok { done(fuse.EIO) r.RespondError(fuse.EIO) break } n2, err := n.Mknod(r, intr) if err != nil { done(err) r.RespondError(err) break } s := &fuse.LookupResponse{} c.saveLookup(s, snode, r.Name, n2) done(s) r.Respond(s) case *fuse.FsyncRequest: n, ok := node.(NodeFsyncer) if !ok { done(fuse.EIO) r.RespondError(fuse.EIO) break } err := n.Fsync(r, intr) if err != nil { done(err) r.RespondError(err) break } done(nil) r.Respond() case *fuse.InterruptRequest: c.meta.Lock() ireq := c.req[r.IntrID] if ireq != nil && ireq.Intr != nil { close(ireq.Intr) ireq.Intr = nil } c.meta.Unlock() done(nil) r.Respond() /* case *FsyncdirRequest: done(ENOSYS) r.RespondError(ENOSYS) case *GetlkRequest, *SetlkRequest, *SetlkwRequest: done(ENOSYS) r.RespondError(ENOSYS) case *BmapRequest: done(ENOSYS) r.RespondError(ENOSYS) case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest: done(ENOSYS) r.RespondError(ENOSYS) */ } }
func (d dir) LookupCommit(name string, intr fs.Intr, nodeID fuse.NodeID) (fs.Node, fuse.Error) { select { case <-intr: return nil, fuse.EINTR default: } ino := fuse.NodeID(1) if d.parent != nil { ino = generateInode(d.parent.inode, name) } c, CommitErr := services.GetCommit(d.leaf.(objects.HKID)) if CommitErr != nil { return nil, fuse.EIO /* log.Printf("commit %s:", CommitErr) _, err := services.GetKey(d.leaf.(objects.HKID)) perm := os.FileMode(0555) if err == nil { perm = 0777 } return dir{ permission: perm, contentType: "commit", leaf: d.leaf.(objects.HKID), parent: &d, name: name, openHandles: map[string]bool{}, inode: ino, }, nil */ } //get list hash l, listErr := services.GetList(c.ListHash) //l is the list object if listErr != nil { log.Printf("commit list retrieval error %s:", listErr) return nil, nil } listEntry, present := l[name] //go through list entries and is it maps to the string you passed in present == 1 if !present { return nil, fuse.ENOENT } //getKey to figure out permissions of the child _, keyErr := services.GetKey(c.Hkid) //perm := fuse.Attr{Mode: 0555}//default read permissions perm := os.FileMode(0777) if keyErr != nil { log.Printf("error not nil; change file Mode %s:", keyErr) //perm = fuse.Attr{Mode: 0755} perm = os.FileMode(0555) } if listEntry.TypeString == "blob" { b, blobErr := services.GetBlob(listEntry.Hash.(objects.HCID)) sizeBlob := 0 if blobErr == nil { sizeBlob = len(b) } return file{ contentHash: listEntry.Hash.(objects.HCID), permission: perm, name: name, parent: &d, inode: nodeID, size: uint64(sizeBlob), }, nil } ino = fuse.NodeID(1) if d.parent != nil { ino = generateInode(d.parent.inode, name) } return dir{ leaf: listEntry.Hash, permission: perm, contentType: listEntry.TypeString, parent: &d, name: name, openHandles: map[string]*openFileHandle{}, inode: ino, }, nil }