706 lines
15 KiB
Go
706 lines
15 KiB
Go
|
// Copyright 2018 Google Inc.
|
|||
|
//
|
|||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
// you may not use this file except in compliance with the License.
|
|||
|
// You may obtain a copy of the License at
|
|||
|
//
|
|||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
//
|
|||
|
// Unless required by applicable law or agreed to in writing, software
|
|||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
// See the License for the specific language governing permissions and
|
|||
|
// limitations under the License.
|
|||
|
|
|||
|
package p9
|
|||
|
|
|||
|
import (
|
|||
|
"io"
|
|||
|
"os"
|
|||
|
"sync/atomic"
|
|||
|
"syscall"
|
|||
|
|
|||
|
"gvisor.googlesource.com/gvisor/pkg/log"
|
|||
|
)
|
|||
|
|
|||
|
// newErr returns a new error message from an error.
|
|||
|
func newErr(err error) *Rlerror {
|
|||
|
switch e := err.(type) {
|
|||
|
case syscall.Errno:
|
|||
|
return &Rlerror{Error: uint32(e)}
|
|||
|
case *os.PathError:
|
|||
|
return newErr(e.Err)
|
|||
|
case *os.SyscallError:
|
|||
|
return newErr(e.Err)
|
|||
|
default:
|
|||
|
log.Warningf("unknown error: %v", err)
|
|||
|
return &Rlerror{Error: uint32(syscall.EIO)}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// handler is implemented for server-handled messages.
|
|||
|
//
|
|||
|
// See server.go for call information.
|
|||
|
type handler interface {
|
|||
|
// Handle handles the given message.
|
|||
|
//
|
|||
|
// This may modify the server state. The handle function must return a
|
|||
|
// message which will be sent back to the client. It may be useful to
|
|||
|
// use newErr to automatically extract an error message.
|
|||
|
handle(cs *connState) message
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tversion) handle(cs *connState) message {
|
|||
|
if t.MSize == 0 {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
if t.MSize > maximumLength {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
atomic.StoreUint32(&cs.messageSize, t.MSize)
|
|||
|
requested, ok := parseVersion(t.Version)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
// The server cannot support newer versions that it doesn't know about. In this
|
|||
|
// case we return EAGAIN to tell the client to try again with a lower version.
|
|||
|
if requested > highestSupportedVersion {
|
|||
|
return newErr(syscall.EAGAIN)
|
|||
|
}
|
|||
|
// From Tversion(9P): "The server may respond with the client’s version
|
|||
|
// string, or a version string identifying an earlier defined protocol version".
|
|||
|
atomic.StoreUint32(&cs.version, requested)
|
|||
|
return &Rversion{
|
|||
|
MSize: t.MSize,
|
|||
|
Version: t.Version,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tflush) handle(cs *connState) message {
|
|||
|
cs.WaitTag(t.OldTag)
|
|||
|
return &Rflush{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Twalk) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
if _, opened := ref.OpenFlags(); opened {
|
|||
|
return newErr(syscall.EBUSY)
|
|||
|
}
|
|||
|
|
|||
|
// Do the walk.
|
|||
|
qids, sf, err := ref.file.Walk(t.Names)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
// Install the new FID.
|
|||
|
cs.InsertFID(t.NewFID, &fidRef{file: sf})
|
|||
|
|
|||
|
return &Rwalk{QIDs: qids}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tclunk) handle(cs *connState) message {
|
|||
|
if !cs.DeleteFID(t.FID) {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
return &Rclunk{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tremove) handle(cs *connState) message {
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// "The remove request asks the file server both to remove the file
|
|||
|
// represented by fid and to clunk the fid, even if the remove fails."
|
|||
|
//
|
|||
|
// "It is correct to consider remove to be a clunk with the side effect
|
|||
|
// of removing the file if permissions allow."
|
|||
|
// https://swtch.com/plan9port/man/man9/remove.html
|
|||
|
err := ref.file.Remove()
|
|||
|
|
|||
|
// Clunk the FID regardless of Remove error.
|
|||
|
if !cs.DeleteFID(t.FID) {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return &Rremove{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
//
|
|||
|
// We don't support authentication, so this just returns ENOSYS.
|
|||
|
func (t *Tauth) handle(cs *connState) message {
|
|||
|
return newErr(syscall.ENOSYS)
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tattach) handle(cs *connState) message {
|
|||
|
// Ensure no authentication FID is provided.
|
|||
|
if t.Auth.AuthenticationFID != NoFID {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
|
|||
|
// Do the attach.
|
|||
|
sf, err := cs.server.attacher.Attach(t.Auth.AttachName)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
cs.InsertFID(t.FID, &fidRef{file: sf})
|
|||
|
|
|||
|
// Return an empty QID.
|
|||
|
return &Rattach{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tlopen) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
ref.openedMu.Lock()
|
|||
|
defer ref.openedMu.Unlock()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
if ref.opened {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
|
|||
|
// Do the open.
|
|||
|
osFile, qid, ioUnit, err := ref.file.Open(t.Flags)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
// Mark file as opened and set open mode.
|
|||
|
ref.opened = true
|
|||
|
ref.openFlags = t.Flags
|
|||
|
|
|||
|
return &Rlopen{QID: qid, IoUnit: ioUnit, File: osFile}
|
|||
|
}
|
|||
|
|
|||
|
func (t *Tlcreate) do(cs *connState, uid UID) (*Rlcreate, error) {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return nil, syscall.EBADF
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the create.
|
|||
|
osFile, nsf, qid, ioUnit, err := ref.file.Create(t.Name, t.OpenFlags, t.Permissions, uid, t.GID)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
// Replace the FID reference.
|
|||
|
//
|
|||
|
// The new file will be opened already.
|
|||
|
cs.InsertFID(t.FID, &fidRef{file: nsf, opened: true, openFlags: t.OpenFlags})
|
|||
|
|
|||
|
return &Rlcreate{Rlopen: Rlopen{QID: qid, IoUnit: ioUnit, File: osFile}}, nil
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tlcreate) handle(cs *connState) message {
|
|||
|
rlcreate, err := t.do(cs, NoUID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return rlcreate
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tsymlink) handle(cs *connState) message {
|
|||
|
rsymlink, err := t.do(cs, NoUID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return rsymlink
|
|||
|
}
|
|||
|
|
|||
|
func (t *Tsymlink) do(cs *connState, uid UID) (*Rsymlink, error) {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return nil, syscall.EBADF
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the symlink.
|
|||
|
qid, err := ref.file.Symlink(t.Target, t.Name, uid, t.GID)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
return &Rsymlink{QID: qid}, nil
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tlink) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Lookup the other FID.
|
|||
|
refTarget, ok := cs.LookupFID(t.Target)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer refTarget.DecRef()
|
|||
|
|
|||
|
// Do the link.
|
|||
|
if err := ref.file.Link(refTarget.file, t.Name); err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rlink{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Trenameat) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.OldDirectory)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Lookup the other FID.
|
|||
|
refTarget, ok := cs.LookupFID(t.NewDirectory)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer refTarget.DecRef()
|
|||
|
|
|||
|
// Do the rename.
|
|||
|
if err := ref.file.RenameAt(t.OldName, refTarget.file, t.NewName); err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rrenameat{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tunlinkat) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the unlink.
|
|||
|
if err := ref.file.UnlinkAt(t.Name, t.Flags); err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Runlinkat{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Trename) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Lookup the target.
|
|||
|
refTarget, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer refTarget.DecRef()
|
|||
|
|
|||
|
// Call the rename method.
|
|||
|
if err := ref.file.Rename(refTarget.file, t.Name); err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rrename{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Treadlink) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the read.
|
|||
|
target, err := ref.file.Readlink()
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rreadlink{target}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tread) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
openFlags, opened := ref.OpenFlags()
|
|||
|
if !opened {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
|
|||
|
// Can it be read? Check permissions.
|
|||
|
if openFlags&OpenFlagsModeMask == WriteOnly {
|
|||
|
return newErr(syscall.EPERM)
|
|||
|
}
|
|||
|
|
|||
|
// Constrain the size of the read buffer.
|
|||
|
if int(t.Count) > int(maximumLength) {
|
|||
|
return newErr(syscall.ENOBUFS)
|
|||
|
}
|
|||
|
|
|||
|
// Do the read.
|
|||
|
data := make([]byte, t.Count)
|
|||
|
n, err := ref.file.ReadAt(data, t.Offset)
|
|||
|
if err != nil && err != io.EOF {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rread{Data: data[:n]}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Twrite) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
openFlags, opened := ref.OpenFlags()
|
|||
|
if !opened {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
|
|||
|
// Can it be write? Check permissions.
|
|||
|
if openFlags&OpenFlagsModeMask == ReadOnly {
|
|||
|
return newErr(syscall.EPERM)
|
|||
|
}
|
|||
|
|
|||
|
// Do the write.
|
|||
|
n, err := ref.file.WriteAt(t.Data, t.Offset)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rwrite{Count: uint32(n)}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tmknod) handle(cs *connState) message {
|
|||
|
rmknod, err := t.do(cs, NoUID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return rmknod
|
|||
|
}
|
|||
|
|
|||
|
func (t *Tmknod) do(cs *connState, uid UID) (*Rmknod, error) {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return nil, syscall.EBADF
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the mknod.
|
|||
|
qid, err := ref.file.Mknod(t.Name, t.Permissions, t.Major, t.Minor, uid, t.GID)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
return &Rmknod{QID: qid}, nil
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tmkdir) handle(cs *connState) message {
|
|||
|
rmkdir, err := t.do(cs, NoUID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return rmkdir
|
|||
|
}
|
|||
|
|
|||
|
func (t *Tmkdir) do(cs *connState, uid UID) (*Rmkdir, error) {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return nil, syscall.EBADF
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the mkdir.
|
|||
|
qid, err := ref.file.Mkdir(t.Name, t.Permissions, uid, t.GID)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
return &Rmkdir{QID: qid}, nil
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tgetattr) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Get attributes.
|
|||
|
qid, valid, attr, err := ref.file.GetAttr(t.AttrMask)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rgetattr{QID: qid, Valid: valid, Attr: attr}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tsetattr) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Set attributes.
|
|||
|
if err := ref.file.SetAttr(t.Valid, t.SetAttr); err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rsetattr{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Txattrwalk) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// We don't support extended attributes.
|
|||
|
return newErr(syscall.ENODATA)
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Txattrcreate) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// We don't support extended attributes.
|
|||
|
return newErr(syscall.ENOSYS)
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Treaddir) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.Directory)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
if _, opened := ref.OpenFlags(); !opened {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
|
|||
|
// Read the entries.
|
|||
|
entries, err := ref.file.Readdir(t.Offset, t.Count)
|
|||
|
if err != nil && err != io.EOF {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rreaddir{Count: t.Count, Entries: entries}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tfsync) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
if _, opened := ref.OpenFlags(); !opened {
|
|||
|
return newErr(syscall.EINVAL)
|
|||
|
}
|
|||
|
|
|||
|
err := ref.file.FSync()
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rfsync{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tstatfs) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
st, err := ref.file.StatFS()
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rstatfs{st}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tflushf) handle(cs *connState) message {
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
if err := ref.file.Flush(); err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rflushf{}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Twalkgetattr) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Has it been opened already?
|
|||
|
if _, opened := ref.OpenFlags(); opened {
|
|||
|
return newErr(syscall.EBUSY)
|
|||
|
}
|
|||
|
|
|||
|
// Do the walk.
|
|||
|
qids, sf, valid, attr, err := ref.file.WalkGetAttr(t.Names)
|
|||
|
if err == syscall.ENOSYS {
|
|||
|
qids, sf, err = ref.file.Walk(t.Names)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
_, valid, attr, err = sf.GetAttr(AttrMaskAll())
|
|||
|
}
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
// Install the new FID.
|
|||
|
cs.InsertFID(t.NewFID, &fidRef{file: sf})
|
|||
|
|
|||
|
return &Rwalkgetattr{QIDs: qids, Valid: valid, Attr: attr}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tucreate) handle(cs *connState) message {
|
|||
|
rlcreate, err := t.Tlcreate.do(cs, t.UID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return &Rucreate{*rlcreate}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tumkdir) handle(cs *connState) message {
|
|||
|
rmkdir, err := t.Tmkdir.do(cs, t.UID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return &Rumkdir{*rmkdir}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tusymlink) handle(cs *connState) message {
|
|||
|
rsymlink, err := t.Tsymlink.do(cs, t.UID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return &Rusymlink{*rsymlink}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tumknod) handle(cs *connState) message {
|
|||
|
rmknod, err := t.Tmknod.do(cs, t.UID)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
return &Rumknod{*rmknod}
|
|||
|
}
|
|||
|
|
|||
|
// handle implements handler.handle.
|
|||
|
func (t *Tlconnect) handle(cs *connState) message {
|
|||
|
// Lookup the FID.
|
|||
|
ref, ok := cs.LookupFID(t.FID)
|
|||
|
if !ok {
|
|||
|
return newErr(syscall.EBADF)
|
|||
|
}
|
|||
|
defer ref.DecRef()
|
|||
|
|
|||
|
// Do the connect.
|
|||
|
osFile, err := ref.file.Connect(t.Flags)
|
|||
|
if err != nil {
|
|||
|
return newErr(err)
|
|||
|
}
|
|||
|
|
|||
|
return &Rlconnect{File: osFile}
|
|||
|
}
|