func (c *clientFile) Mknod(name string, mode FileMode, major uint32, minor uint32, uid UID, gid GID) (QID, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return QID{}, linux.EBADF
	}
	msg := tmknod{
		Directory: c.fid,
		Name:      name,
		Mode:      mode,
		Major:     major,
		Minor:     minor,
		GID:       NoGID,
	}
	if versionSupportsTucreation(c.client.version) {
		msg.GID = gid
		rumknod := rumknod{}
		if err := c.client.sendRecv(&tumknod{tmknod: msg, UID: uid}, &rumknod); err != nil {
			return QID{}, err
		}
		return rumknod.QID, nil
	}
	rmknod := rmknod{}
	if err := c.client.sendRecv(&msg, &rmknod); err != nil {
		return QID{}, err
	}
	return rmknod.QID, nil
}
Mknod implements File.Mknod.
package p9
import (
	"fmt"
	"io"
	"log"
	"runtime"
	"sync/atomic"
	"github.com/hugelgupf/p9/internal/linux"
)
func (c *Client) Attach(name string) (File, error) {
	id, ok := c.fidPool.Get()
	if !ok {
		return nil, ErrOutOfFIDs
	}
	rattach := rattach{}
	if err := c.sendRecv(&tattach{fid: fid(id), Auth: tauth{AttachName: name, Authenticationfid: noFID, UID: NoUID}}, &rattach); err != nil {
		c.fidPool.Put(id)
		return nil, err
	}
	return c.newFile(fid(id)), nil
}
func (c *Client) newFile(fid fid) *clientFile {
	cf := &clientFile{
		client: c,
		fid:    fid,
	}
	runtime.SetFinalizer(cf, (*clientFile).Close)
	return cf
}
type clientFile struct {
	client *Client
	fid fid
	closed uint32
}
func (c *clientFile) Walk(names []string) ([]QID, File, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return nil, nil, linux.EBADF
	}
	id, ok := c.client.fidPool.Get()
	if !ok {
		return nil, nil, ErrOutOfFIDs
	}
	rwalk := rwalk{}
	if err := c.client.sendRecv(&twalk{fid: c.fid, newFID: fid(id), Names: names}, &rwalk); err != nil {
		c.client.fidPool.Put(id)
		return nil, nil, err
	}
	return rwalk.QIDs, c.client.newFile(fid(id)), nil
}
func (c *clientFile) WalkGetAttr(components []string) ([]QID, File, AttrMask, Attr, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return nil, nil, AttrMask{}, Attr{}, linux.EBADF
	}
	if !versionSupportsTwalkgetattr(c.client.version) {
		qids, file, err := c.Walk(components)
		if err != nil {
			return nil, nil, AttrMask{}, Attr{}, err
		}
		_, valid, attr, err := file.GetAttr(AttrMaskAll)
		if err != nil {
			file.Close()
			return nil, nil, AttrMask{}, Attr{}, err
		}
		return qids, file, valid, attr, nil
	}
	id, ok := c.client.fidPool.Get()
	if !ok {
		return nil, nil, AttrMask{}, Attr{}, ErrOutOfFIDs
	}
	rwalkgetattr := rwalkgetattr{}
	if err := c.client.sendRecv(&twalkgetattr{fid: c.fid, newFID: fid(id), Names: components}, &rwalkgetattr); err != nil {
		c.client.fidPool.Put(id)
		return nil, nil, AttrMask{}, Attr{}, err
	}
	return rwalkgetattr.QIDs, c.client.newFile(fid(id)), rwalkgetattr.Valid, rwalkgetattr.Attr, nil
}
func (c *clientFile) StatFS() (FSStat, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return FSStat{}, linux.EBADF
	}
	rstatfs := rstatfs{}
	if err := c.client.sendRecv(&tstatfs{fid: c.fid}, &rstatfs); err != nil {
		return FSStat{}, err
	}
	return rstatfs.FSStat, nil
}
func (c *clientFile) FSync() error {
	if atomic.LoadUint32(&c.closed) != 0 {
		return linux.EBADF
	}
	return c.client.sendRecv(&tfsync{fid: c.fid}, &rfsync{})
}
func (c *clientFile) GetAttr(req AttrMask) (QID, AttrMask, Attr, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return QID{}, AttrMask{}, Attr{}, linux.EBADF
	}
	rgetattr := rgetattr{}
	if err := c.client.sendRecv(&tgetattr{fid: c.fid, AttrMask: req}, &rgetattr); err != nil {
		return QID{}, AttrMask{}, Attr{}, err
	}
	return rgetattr.QID, rgetattr.Valid, rgetattr.Attr, nil
}
func (c *clientFile) SetAttr(valid SetAttrMask, attr SetAttr) error {
	if atomic.LoadUint32(&c.closed) != 0 {
		return linux.EBADF
	}
	return c.client.sendRecv(&tsetattr{fid: c.fid, Valid: valid, SetAttr: attr}, &rsetattr{})
}
func (c *clientFile) Remove() error {
	if !atomic.CompareAndSwapUint32(&c.closed, 0, 1) {
		return linux.EBADF
	}
	runtime.SetFinalizer(c, nil)
	if err := c.client.sendRecv(&tremove{fid: c.fid}, &rremove{}); err != nil {
		return err
	}
	c.client.fidPool.Put(uint64(c.fid))
	return nil
}
func (c *clientFile) Close() error {
	if !atomic.CompareAndSwapUint32(&c.closed, 0, 1) {
		return linux.EBADF
	}
	runtime.SetFinalizer(c, nil)
	if err := c.client.sendRecv(&tclunk{fid: c.fid}, &rclunk{}); err != nil {
		log.Printf("Tclunk failed, losing fid %v: %v", c.fid, err)
		return err
	}
	c.client.fidPool.Put(uint64(c.fid))
	return nil
}
func (c *clientFile) Open(flags OpenFlags) (QID, uint32, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return QID{}, 0, linux.EBADF
	}
	rlopen := rlopen{}
	if err := c.client.sendRecv(&tlopen{fid: c.fid, Flags: flags}, &rlopen); err != nil {
		return QID{}, 0, err
	}
	return rlopen.QID, rlopen.IoUnit, nil
}
func chunk(chunkSize uint32, fn func([]byte, int64) (int, error), p []byte, offset int64) (int, error) {
	if len(p) == 0 {
		return fn(p, offset)
	}
	var total int
	for {
		var n int
		var err error
		if total == len(p) {
			return total, nil
		}
		if len(p) < total+int(chunkSize) {
			n, err = fn(p[total:], offset)
		} else {
			n, err = fn(p[total:total+int(chunkSize)], offset)
		}
		total += n
		offset += int64(n)
		if err != nil {
			return total, err
		}
		if n < int(chunkSize) {
			return total, nil
		}
		if total > len(p) {
			panic(fmt.Sprintf("bytes completed (%d)) > requested (%d)", total, len(p)))
		}
	}
}
func (c *clientFile) ReadAt(p []byte, offset int64) (int, error) {
	return chunk(c.client.payloadSize, c.readAt, p, offset)
}
func (c *clientFile) readAt(p []byte, offset int64) (int, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return 0, linux.EBADF
	}
	rread := rread{Data: p}
	if err := c.client.sendRecv(&tread{fid: c.fid, Offset: uint64(offset), Count: uint32(len(p))}, &rread); err != nil {
		return 0, err
	}
	if len(p) > 0 && len(rread.Data) > 0 && &rread.Data[0] != &p[0] {
		copy(p, rread.Data)
	}
	if len(rread.Data) == 0 && len(p) > 0 {
		return 0, io.EOF
	}
	return len(rread.Data), nil
}
func (c *clientFile) WriteAt(p []byte, offset int64) (int, error) {
	return chunk(c.client.payloadSize, c.writeAt, p, offset)
}
func (c *clientFile) writeAt(p []byte, offset int64) (int, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return 0, linux.EBADF
	}
	rwrite := rwrite{}
	if err := c.client.sendRecv(&twrite{fid: c.fid, Offset: uint64(offset), Data: p}, &rwrite); err != nil {
		return 0, err
	}
	return int(rwrite.Count), nil
}
func (c *clientFile) Rename(dir File, name string) error {
	if atomic.LoadUint32(&c.closed) != 0 {
		return linux.EBADF
	}
	clientDir, ok := dir.(*clientFile)
	if !ok {
		return linux.EBADF
	}
	return c.client.sendRecv(&trename{fid: c.fid, Directory: clientDir.fid, Name: name}, &rrename{})
}
func (c *clientFile) Create(name string, openFlags OpenFlags, permissions FileMode, uid UID, gid GID) (File, QID, uint32, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return nil, QID{}, 0, linux.EBADF
	}
	msg := tlcreate{
		fid:         c.fid,
		Name:        name,
		OpenFlags:   openFlags,
		Permissions: permissions,
		GID:         NoGID,
	}
	if versionSupportsTucreation(c.client.version) {
		msg.GID = gid
		rucreate := rucreate{}
		if err := c.client.sendRecv(&tucreate{tlcreate: msg, UID: uid}, &rucreate); err != nil {
			return nil, QID{}, 0, err
		}
		return c, rucreate.QID, rucreate.IoUnit, nil
	}
	rlcreate := rlcreate{}
	if err := c.client.sendRecv(&msg, &rlcreate); err != nil {
		return nil, QID{}, 0, err
	}
	return c, rlcreate.QID, rlcreate.IoUnit, nil
}
func (c *clientFile) Mkdir(name string, permissions FileMode, uid UID, gid GID) (QID, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return QID{}, linux.EBADF
	}
	msg := tmkdir{
		Directory:   c.fid,
		Name:        name,
		Permissions: permissions,
		GID:         NoGID,
	}
	if versionSupportsTucreation(c.client.version) {
		msg.GID = gid
		rumkdir := rumkdir{}
		if err := c.client.sendRecv(&tumkdir{tmkdir: msg, UID: uid}, &rumkdir); err != nil {
			return QID{}, err
		}
		return rumkdir.QID, nil
	}
	rmkdir := rmkdir{}
	if err := c.client.sendRecv(&msg, &rmkdir); err != nil {
		return QID{}, err
	}
	return rmkdir.QID, nil
}
func (c *clientFile) Symlink(oldname string, newname string, uid UID, gid GID) (QID, error) {
	if atomic.LoadUint32(&c.closed) != 0 {
		return QID{}, linux.EBADF
	}
	msg := tsymlink{
		Directory: c.fid,
		Name:      newname,
		Target:    oldname,
		GID:       NoGID,
	}
	if versionSupportsTucreation(c.client.version) {
		msg.GID = gid
		rusymlink := rusymlink{}
		if err := c.client.sendRecv(&tusymlink{tsymlink: msg, UID: uid}, &rusymlink); err != nil {
			return QID{}, err
		}
		return rusymlink.QID, nil
	}
	rsymlink := rsymlink{}
	if err := c.client.sendRecv(&msg, &rsymlink); err != nil {
		return QID{}, err
	}
	return rsymlink.QID, nil
}
func (c *clientFile) Link(target File, newname string) error {
	if atomic.LoadUint32(&c.closed) != 0 {
		return linux.EBADF
	}
	targetFile, ok := target.(*clientFile)
	if !ok {
		return linux.EBADF
	}
	return c.client.sendRecv(&tlink{Directory: c.fid, Name: newname, Target: targetFile.fid}, &rlink{})
}