func (t *tsetattr) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	if err := ref.safelyWrite(func() error {
		if ref.isDeleted() {
			return linux.EINVAL
		}
		return ref.file.SetAttr(t.Valid, t.SetAttr)
	}); err != nil {
		return newErr(err)
	}
	return &rsetattr{}
}
handle implements handler.handle.
package p9
import (
	"fmt"
	"io"
	"path"
	"strings"
	"sync/atomic"
	"github.com/hugelgupf/p9/internal"
	"github.com/hugelgupf/p9/internal/linux"
)
func newErr(err error) *rlerror {
	return &rlerror{Error: uint32(internal.ExtractErrno(err))}
}
type handler interface {
	handle(cs *connState) message
}
func (t *tversion) handle(cs *connState) message {
	unknown := &rversion{
		MSize:   0,
		Version: "unknown",
	}
	if t.MSize == 0 {
		return unknown
	}
	msize := t.MSize
	if t.MSize > maximumLength {
		msize = maximumLength
	}
	reqBaseVersion, reqVersion, ok := parseVersion(t.Version)
	if !ok {
		return unknown
	}
	var baseVersion baseVersion
	var version uint32
	switch reqBaseVersion {
	case version9P2000, version9P2000U:
		return unknown
	case version9P2000L:
		baseVersion = reqBaseVersion
		if reqVersion > highestSupportedVersion {
			version = highestSupportedVersion
		} else {
			version = reqVersion
		}
	}
	atomic.StoreUint32(&cs.messageSize, msize)
	atomic.StoreUint32(&cs.version, version)
	cs.baseVersion = baseVersion
	return &rversion{
		MSize:   msize,
		Version: versionString(baseVersion, version),
	}
}
func (t *tflush) handle(cs *connState) message {
	cs.WaitTag(t.OldTag)
	return &rflush{}
}
func checkSafeName(name string) error {
	if name != "" && !strings.Contains(name, "/") && name != "." && name != ".." {
		return nil
	}
	return linux.EINVAL
}
func (t *tclunk) handle(cs *connState) message {
	if !cs.DeleteFID(t.fid) {
		return newErr(linux.EBADF)
	}
	return &rclunk{}
}
func (t *tremove) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	err := ref.safelyGlobal(func() error {
		if ref.isRoot() {
			return linux.EINVAL
		}
		if ref.isDeleted() {
			return linux.EINVAL
		}
		name := ref.parent.pathNode.nameFor(ref)
		if err := ref.parent.file.UnlinkAt(name, 0); err != nil {
			return err
		}
		ref.parent.markChildDeleted(name)
		return nil
	})
	if !cs.DeleteFID(t.fid) {
		return newErr(linux.EBADF)
	}
	if err != nil {
		return newErr(err)
	}
	return &rremove{}
}
func (t *tauth) handle(cs *connState) message {
	return newErr(linux.ENOSYS)
}
func (t *tattach) handle(cs *connState) message {
	if t.Auth.Authenticationfid != noFID {
		return newErr(linux.EINVAL)
	}
	if path.IsAbs(t.Auth.AttachName) {
		t.Auth.AttachName = t.Auth.AttachName[1:]
	}
	sf, err := cs.server.attacher.Attach()
	if err != nil {
		return newErr(err)
	}
	qid, valid, attr, err := sf.GetAttr(AttrMaskAll)
	if err != nil {
		sf.Close()  
		return newErr(err)
	}
	if !valid.Mode {
		sf.Close()  
		return newErr(linux.EINVAL)
	}
	root := &fidRef{
		server:   cs.server,
		parent:   nil,
		file:     sf,
		refs:     1,
		mode:     attr.Mode.FileType(),
		pathNode: cs.server.pathTree,
	}
	defer root.DecRef()
	if len(t.Auth.AttachName) == 0 {
		cs.InsertFID(t.fid, root)
		return &rattach{QID: qid}
	}
	names := strings.Split(t.Auth.AttachName, "/")
	_, newRef, _, _, err := doWalk(cs, root, names, false)
	if err != nil {
		return newErr(err)
	}
	defer newRef.DecRef()
	cs.InsertFID(t.fid, newRef)
	return &rattach{QID: qid}
}
func CanOpen(mode FileMode) bool {
	return mode.IsRegular() || mode.IsDir() || mode.IsNamedPipe() || mode.IsBlockDevice() || mode.IsCharacterDevice()
}
func (t *tlopen) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	ref.openedMu.Lock()
	defer ref.openedMu.Unlock()
	if ref.opened || !CanOpen(ref.mode) {
		return newErr(linux.EINVAL)
	}
	if ref.mode.IsDir() && t.Flags.Mode() != ReadOnly {
		return newErr(linux.EINVAL)
	}
	var (
		qid    QID
		ioUnit uint32
	)
	if err := ref.safelyRead(func() (err error) {
		if ref.isDeleted() {
			return linux.EINVAL
		}
		qid, ioUnit, err = ref.file.Open(t.Flags)
		return err
	}); err != nil {
		return newErr(err)
	}
	ref.opened = true
	ref.openFlags = t.Flags
	return &rlopen{QID: qid, IoUnit: ioUnit}
}
func (t *tlcreate) do(cs *connState, uid UID) (*rlcreate, error) {
	if err := checkSafeName(t.Name); err != nil {
		return nil, err
	}
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return nil, linux.EBADF
	}
	defer ref.DecRef()
	var (
		nsf    File
		qid    QID
		ioUnit uint32
		newRef *fidRef
	)
	if err := ref.safelyWrite(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		nsf, qid, ioUnit, err = ref.file.Create(t.Name, t.OpenFlags, t.Permissions, uid, t.GID)
		if err != nil {
			return err
		}
		newRef = &fidRef{
			server:    cs.server,
			parent:    ref,
			file:      nsf,
			opened:    true,
			openFlags: t.OpenFlags,
			mode:      ModeRegular,
			pathNode:  ref.pathNode.pathNodeFor(t.Name),
		}
		ref.pathNode.addChild(newRef, t.Name)
		ref.IncRef()  
		return nil
	}); err != nil {
		return nil, err
	}
	cs.InsertFID(t.fid, newRef)
	return &rlcreate{rlopen: rlopen{QID: qid, IoUnit: ioUnit}}, nil
}
func (t *tlcreate) handle(cs *connState) message {
	rlcreate, err := t.do(cs, NoUID)
	if err != nil {
		return newErr(err)
	}
	return rlcreate
}
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) {
	if err := checkSafeName(t.Name); err != nil {
		return nil, err
	}
	ref, ok := cs.LookupFID(t.Directory)
	if !ok {
		return nil, linux.EBADF
	}
	defer ref.DecRef()
	var qid QID
	if err := ref.safelyWrite(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		qid, err = ref.file.Symlink(t.Target, t.Name, uid, t.GID)
		return err
	}); err != nil {
		return nil, err
	}
	return &rsymlink{QID: qid}, nil
}
func (t *tlink) handle(cs *connState) message {
	if err := checkSafeName(t.Name); err != nil {
		return newErr(err)
	}
	ref, ok := cs.LookupFID(t.Directory)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	refTarget, ok := cs.LookupFID(t.Target)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer refTarget.DecRef()
	if err := ref.safelyWrite(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		return ref.file.Link(refTarget.file, t.Name)
	}); err != nil {
		return newErr(err)
	}
	return &rlink{}
}
func (t *trenameat) handle(cs *connState) message {
	if err := checkSafeName(t.OldName); err != nil {
		return newErr(err)
	}
	if err := checkSafeName(t.NewName); err != nil {
		return newErr(err)
	}
	ref, ok := cs.LookupFID(t.OldDirectory)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	refTarget, ok := cs.LookupFID(t.NewDirectory)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer refTarget.DecRef()
	if err := ref.safelyGlobal(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() || refTarget.isDeleted() || !refTarget.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		if ref.pathNode == refTarget.pathNode && t.OldName == t.NewName {
			return nil
		}
		if err := ref.file.RenameAt(t.OldName, refTarget.file, t.NewName); err != nil {
			return err
		}
		ref.renameChildTo(t.OldName, refTarget, t.NewName)
		return nil
	}); err != nil {
		return newErr(err)
	}
	return &rrenameat{}
}
func (t *tunlinkat) handle(cs *connState) message {
	if err := checkSafeName(t.Name); err != nil {
		return newErr(err)
	}
	ref, ok := cs.LookupFID(t.Directory)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	if err := ref.safelyWrite(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		childPathNode := ref.pathNode.pathNodeFor(t.Name)
		childPathNode.opMu.Lock()
		defer childPathNode.opMu.Unlock()
		err = ref.file.UnlinkAt(t.Name, t.Flags)
		if err != nil {
			return err
		}
		ref.markChildDeleted(t.Name)
		return nil
	}); err != nil {
		return newErr(err)
	}
	return &runlinkat{}
}
func (t *trename) handle(cs *connState) message {
	if err := checkSafeName(t.Name); err != nil {
		return newErr(err)
	}
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	refTarget, ok := cs.LookupFID(t.Directory)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer refTarget.DecRef()
	if err := ref.safelyGlobal(func() (err error) {
		if ref.isRoot() {
			return linux.EINVAL
		}
		if ref.isDeleted() || refTarget.isDeleted() || !refTarget.mode.IsDir() {
			return linux.EINVAL
		}
		if ref.parent.isDeleted() {
			panic(fmt.Sprintf("parent %+v deleted, child %+v is not", ref.parent, ref))
		}
		oldName := ref.parent.pathNode.nameFor(ref)
		if ref.parent.pathNode == refTarget.pathNode && oldName == t.Name {
			return nil
		}
		if err := ref.parent.file.RenameAt(oldName, refTarget.file, t.Name); err != nil {
			return err
		}
		ref.parent.renameChildTo(oldName, refTarget, t.Name)
		return nil
	}); err != nil {
		return newErr(err)
	}
	return &rrename{}
}
func (t *treadlink) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	var target string
	if err := ref.safelyRead(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsSymlink() {
			return linux.EINVAL
		}
		target, err = ref.file.Readlink()
		return err
	}); err != nil {
		return newErr(err)
	}
	return &rreadlink{target}
}
func (t *tread) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	if int(t.Count) > int(maximumLength) {
		return newErr(linux.ENOBUFS)
	}
	var (
		data = make([]byte, t.Count)
		n    int
	)
	if err := ref.safelyRead(func() (err error) {
		openFlags, opened := ref.OpenFlags()
		if !opened {
			return linux.EINVAL
		}
		if openFlags&OpenFlagsModeMask == WriteOnly {
			return linux.EPERM
		}
		n, err = ref.file.ReadAt(data, int64(t.Offset))
		return err
	}); err != nil && err != io.EOF {
		return newErr(err)
	}
	return &rread{Data: data[:n]}
}
func (t *twrite) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	var n int
	if err := ref.safelyRead(func() (err error) {
		openFlags, opened := ref.OpenFlags()
		if !opened {
			return linux.EINVAL
		}
		if openFlags&OpenFlagsModeMask == ReadOnly {
			return linux.EPERM
		}
		n, err = ref.file.WriteAt(t.Data, int64(t.Offset))
		return err
	}); err != nil {
		return newErr(err)
	}
	return &rwrite{Count: uint32(n)}
}
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) {
	if err := checkSafeName(t.Name); err != nil {
		return nil, err
	}
	ref, ok := cs.LookupFID(t.Directory)
	if !ok {
		return nil, linux.EBADF
	}
	defer ref.DecRef()
	var qid QID
	if err := ref.safelyWrite(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		qid, err = ref.file.Mknod(t.Name, t.Mode, t.Major, t.Minor, uid, t.GID)
		return err
	}); err != nil {
		return nil, err
	}
	return &rmknod{QID: qid}, nil
}
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) {
	if err := checkSafeName(t.Name); err != nil {
		return nil, err
	}
	ref, ok := cs.LookupFID(t.Directory)
	if !ok {
		return nil, linux.EBADF
	}
	defer ref.DecRef()
	var qid QID
	if err := ref.safelyWrite(func() (err error) {
		if ref.isDeleted() || !ref.mode.IsDir() {
			return linux.EINVAL
		}
		if _, opened := ref.OpenFlags(); opened {
			return linux.EINVAL
		}
		qid, err = ref.file.Mkdir(t.Name, t.Permissions, uid, t.GID)
		return err
	}); err != nil {
		return nil, err
	}
	return &rmkdir{QID: qid}, nil
}
func (t *tgetattr) handle(cs *connState) message {
	ref, ok := cs.LookupFID(t.fid)
	if !ok {
		return newErr(linux.EBADF)
	}
	defer ref.DecRef()
	var (
		qid   QID
		valid AttrMask
		attr  Attr
	)
	if err := ref.safelyRead(func() (err error) {
		qid, valid, attr, err = ref.file.GetAttr(t.AttrMask)
		return err
	}); err != nil {
		return newErr(err)
	}
	return &rgetattr{QID: qid, Valid: valid, Attr: attr}
}