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.
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
}