Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
func (c *serveConn) serve(r fuse.Request) {
	intr := make(Intr)
	req := &serveRequest{Request: r, Intr: intr}

	dprintf("%v\n", 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()
			dprintf("%v\n", 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
		}
		dprintf("%v\n", msg)

		c.meta.Lock()
		delete(c.req, hdr.ID)
		c.meta.Unlock()
	}

Req:
	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:
		uid = r.Header.Uid
		gid = r.Header.Gid
		s := &fuse.InitResponse{
			MaxWrite: 16*1024,
		}
		done(s)
		r.Respond(s)

	case *fuse.StatfsRequest:
		// fake it so the other end always thinks we have resources
		s := &fuse.StatfsResponse{}
		done(s)
		r.Respond(s)

	// Node operations.
	case *fuse.GetattrRequest:
		s := &fuse.GetattrResponse{}
		s.AttrValid = attrValidTime
		a, err := snode.attr()
		if err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		s.Attr = a
		done(s)
		r.Respond(s)

	case *fuse.SetattrRequest:
		s := &fuse.SetattrResponse{}
		n, ok := node.(NodeSetAttrer)
		if !ok {
			done(fuse.EPERM)
			r.RespondError(fuse.EPERM)
			break
		}
		if err := n.SetAttr(r, intr); err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		if s.AttrValid == 0 {
			s.AttrValid = attrValidTime
		}
		a, err := snode.attr()
		if err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		s.Attr = a
		done(s)
		r.Respond(s)

	case *fuse.GetxattrRequest:
		s := &fuse.GetxattrResponse{}
		n, ok := node.(NodeXAttrer)
		if !ok || r.Position>0 {
			done(fuse.ENODATA)
			r.RespondError(fuse.ENODATA)
			break
		}
		v, err := n.Xattr(r.Name)
		if err != nil {
			done(fuse.ENODATA)
			r.RespondError(fuse.ENODATA)
			break
		}
		s.Xattr = v
		done(s)
		r.Respond(s)

	case *fuse.ListxattrRequest:
		s := &fuse.ListxattrResponse{}
		if n, ok := node.(NodeXAttrer); ok && r.Position==0 {
			v := n.Xattrs()
			if len(v) > 0 {
				s.Append(v...)
			}
		}
		done(s)
		r.Respond(s)

	case *fuse.SetxattrRequest:
		n, ok := node.(NodeXAttrer)
		if !ok || r.Position>0 {
			done(fuse.EPERM)
			r.RespondError(fuse.EPERM)
			break
		}
		err := n.Wxattr(r.Name, r.Xattr)
		if err != nil {
			done(fuse.EPERM)
			r.RespondError(fuse.EPERM)
			break
		}
		done(nil)
		r.Respond()

	case *fuse.RemovexattrRequest:
		n, ok := node.(NodeXAttrer)
		if !ok {
			done(fuse.ENOTSUP)
			r.RespondError(fuse.ENOTSUP)
			break
		}
		err := n.Wxattr(r.Name, nil)
		if err != nil {
			done(fuse.EPERM)
			r.RespondError(fuse.EPERM)
			break
		}
		done(nil)
		r.Respond()

	case *fuse.SymlinkRequest:
		done(fuse.EPERM)
		r.RespondError(fuse.EPERM)

	case *fuse.ReadlinkRequest:
		done(fuse.EPERM)
		r.RespondError(fuse.EPERM)

	case *fuse.LinkRequest:
		done(fuse.EPERM)
		r.RespondError(fuse.EPERM)

	case *fuse.RemoveRequest:
		n, ok := node.(NodeRemover)
		if !ok {
			done(fuse.EIO) /// XXX or EPERM?
			r.RespondError(fuse.EIO)
			break
		}
		err := n.Remove(r.Name, intr)
		if err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		done(nil)
		r.Respond()

	case *fuse.AccessRequest:
		done(nil)
		r.Respond()

	case *fuse.LookupRequest:
		var n2 Node
		var err fuse.Error
		s := &fuse.LookupResponse{}
		if n, ok := node.(NodeLookuper); ok {
			n2, err = n.Lookup(r.Name, 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.Name, r.Mode, 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:

		var h2 Handle
		n := node
		hh, err := n.Open(r.Flags, intr)
		if err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		h2 = hh
		// Using DirectIO requires buffers to be page aligned for exec
		// to work on served files.
		// But not using DirectIO means that UNIX stats the file and
		// then reads the data, which means we can't use it for Ctl files.
		flags := fuse.OpenPurgeAttr | fuse.OpenPurgeUBC
		if xh, ok := hh.(HandleIsCtler); ok && xh.IsCtl() {
			flags = fuse.OpenDirectIO
		}
		if r.Flags&3==fuse.OpenFlags(os.O_WRONLY) &&
			runtime.GOOS=="darwin" {
			/*
				This is required for append on osx
			*/
			flags = fuse.OpenPurgeAttr | fuse.OpenPurgeUBC
		}
		s := &fuse.OpenResponse{Flags: flags}
		s.Handle = c.saveHandle(h2, hdr.Node)
		done(s)
		r.Respond(s)

	case *fuse.CreateRequest:
		n, ok := node.(NodeCreater)
		if !ok {
			done(fuse.EPERM)
			r.RespondError(fuse.EPERM)
			break
		}
		flags := fuse.OpenPurgeAttr | fuse.OpenPurgeUBC
		// flags := fuse.OpenDirectIO
		s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{Flags: flags}}
		n2, h2, err := n.Create(r.Name, r.Flags, r.Mode, 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.ForgetRequest:
		forget := c.dropNode(hdr.Node, r.N)
		if forget {
			n, ok := node.(NodePuter)
			if ok {
				n.PutNode()
			}
		}
		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 {
			h := handle
			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 {
						err := errors.New("bad inode")
						done(err)
						r.RespondError(err)
						break Req
					}
					data = fuse.AppendDirent(data, dir)
				}
				shandle.readData = data
			}
			fuseutil.HandleRead(r, s, shandle.readData)
			done(s)
			r.Respond(s)
			break
		}
		h := handle
		rdata, err := h.Read(r.Offset, r.Size, intr)
		if err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		s.Data = rdata
		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 {
			n, err := h.Write(r.Data, r.Offset, intr)
			if err != nil {
				done(err)
				r.RespondError(err)
				break
			}
			s.Size = n
			done(s)
			r.Respond(s)
			break
		}
		done(fuse.EPERM)
		r.RespondError(fuse.EPERM)

	case *fuse.FlushRequest:
		shandle := c.getHandle(r.Handle)
		if shandle == nil {
			done(fuse.ESTALE)
			r.RespondError(fuse.ESTALE)
			return
		}
		handle := shandle.handle
		h := handle
		if err := h.Close(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.(HandlePuter); ok {
			h.PutHandle()
		}
		done(nil)
		r.Respond()

	case *fuse.DestroyRequest:
		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 {
			dprintf("%v\n", renameNewDirNodeNotFound{
				Request: r.Hdr(),
				In:      r,
			})
			done(fuse.EIO)
			r.RespondError(fuse.EIO)
			break
		}
		n, ok := node.(NodeRenamer)
		if !ok {
			done(fuse.EPERM)
			r.RespondError(fuse.EPERM)
			break
		}
		err := n.Rename(r.OldName, r.NewName, newDirNode.node, intr)
		if err != nil {
			done(err)
			r.RespondError(err)
			break
		}
		done(nil)
		r.Respond()

	case *fuse.MknodRequest:
		done(fuse.EIO)
		r.RespondError(fuse.EIO)

	case *fuse.FsyncRequest:
		n, ok := node.(NodeFsyncer)
		if !ok {
			// if there's no implementation, we pretend it's done.
			done(nil)
			r.Respond()
			break
		}
		err := n.Fsync(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)
		*/
	}
}