lib9p

Go 9P library.
Log | Files | Refs

commit 0020dcd0a0e379bad363ac2aee9a8535fdde00f5
parent 09bdb46c6034b5376d33de023267317df0671dfc
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Mon, 17 Jul 2023 11:35:00 +0900

split file

Diffstat:
Mfcall.go | 78+++++-------------------------------------------------------------------------
Afid.go | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afile.go | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mserver.go | 48++----------------------------------------------
4 files changed, 148 insertions(+), 119 deletions(-)

diff --git a/fcall.go b/fcall.go @@ -39,20 +39,6 @@ const ( Tmax = 128 ) -// QidType represents the type of Qid. the 'QT' prefix may be redundant. -type QidType uint8 - -const ( - QTDIR QidType = 0x80 /* type bit for directories */ - QTAPPEND = 0x40 /* type bit for append only files */ - QTEXCL = 0x20 /* type bit for exclusive use files */ - QTMOUNT = 0x10 /* type bit for mounted channel */ - QTAUTH = 0x08 /* type bit for authentication file */ - QTTMP = 0x04 /* type bit for non-backed-up file */ - QTSYMLINK = 0x02 /* type bit for symbolic link */ - QTFILE = 0x00 /* type bits for plain file */ -) - // Gbit16 reads b as 2-byte long little endian unsigned integer and // returns the result func gbit16(b []byte) uint16 { return binary.LittleEndian.Uint16(b[0:2]) } @@ -74,54 +60,6 @@ func pbit32(b []byte, n uint32) { binary.LittleEndian.PutUint32(b, n) } // Pbit64 puts into b an 8-byte long little endian unsigned integer n. func pbit64(b []byte, n uint64) { binary.LittleEndian.PutUint64(b, n) } -const ( - Topenfd = 98 - Ropenfd = 99 -) - -type Req struct { - srv *Srv - ifcall Msg - ofcall Msg -} - -type Fid []byte - -func (f Fid) String() string { - return fmt.Sprintf("%d", gbit32(f)) -} - -type Qid []byte - -func (q Qid) Type() QidType { return QidType(q[0]) } -func (q Qid) SetType(t QidType) { q[0] = uint8(t) } -func (q Qid) Vers() uint32 { return gbit32(q[1:5]) } -func (q Qid) SetVers(v uint32) { pbit32(q[1:5], v) } -func (q Qid) Path() uint64 { return gbit64(q[5:13]) } -func (q Qid) SetPath(p uint64) { pbit64(q[5:13], p) } -func (q Qid) String() string { - return fmt.Sprintf("(%016d %d %s)", q.Path(), q.Vers(), q.typeStr()) -} - -// TypeStr returns the q.Type() as string for debugging information. -func (q Qid) typeStr() string { - var s string - t := q.Type() - if t&QTDIR != 0 { - s += "d" - } - if t&QTAPPEND != 0 { - s += "a" - } - if t&QTEXCL != 0 { - s += "l" - } - if t&QTAUTH != 0 { - s += "A" - } - return s -} - // Msg represents any kind of message of 9P. // It defines methods for common fields. type Msg interface { @@ -192,7 +130,7 @@ type TAuth []byte func (msg TAuth) Size() uint32 { return gbit32(msg[0:4]) } func (msg TAuth) Type() MsgType { return MsgType(msg[4]) } func (msg TAuth) Tag() uint16 { return gbit16(msg[5:7]) } -func (msg TAuth) AFid() uint32 { return gbit32(msg[7:11]) } +func (msg TAuth) AFid() Fid { return Fid(msg[7:11]) } func (msg TAuth) UName() string { size := gbit16(msg[11:13]) return string(msg[13 : 13+size]) @@ -204,7 +142,7 @@ func (msg TAuth) AName() string { } func (msg TAuth) conv2M() []byte { return []byte(msg)[:msg.Size()] } func (msg TAuth) String() string { - return fmt.Sprintf("Tauth tag %d afid %d uname %s aname %s", + return fmt.Sprintf("Tauth tag %d afid %v uname %s aname %s", msg.Tag(), msg.AFid(), msg.UName(), msg.AName()) } @@ -226,7 +164,7 @@ func (msg TAttach) Size() uint32 { return gbit32(msg[0:4]) } func (msg TAttach) Type() MsgType { return MsgType(msg[4]) } func (msg TAttach) Tag() uint16 { return gbit16(msg[5:7]) } func (msg TAttach) Fid() Fid { return Fid(msg[7:11]) } -func (msg TAttach) AFid() uint32 { return gbit32(msg[11:15]) } +func (msg TAttach) AFid() Fid { return Fid(msg[11:15]) } func (msg TAttach) UName() string { usize := gbit16(msg[15:17]) return string(msg[17 : 17+usize]) @@ -238,14 +176,8 @@ func (msg TAttach) AName() string { } func (msg TAttach) conv2M() []byte { return []byte(msg)[:msg.Size()] } func (msg TAttach) String() string { - var afid int64 - if msg.AFid() == ^uint32(0) { - afid = -1 - } else { - afid = int64(msg.AFid()) - } - return fmt.Sprintf("Tattach tag %d fid %v afid %d uname %s aname %s", - msg.Tag(), msg.Fid(), afid, msg.UName(), msg.AName()) + return fmt.Sprintf("Tattach tag %d fid %v afid %v uname %s aname %s", + msg.Tag(), msg.Fid(), msg.AFid(), msg.UName(), msg.AName()) } type RAttach []byte diff --git a/fid.go b/fid.go @@ -0,0 +1,68 @@ +package lib9p + +import ( + "fmt" +) + +// QidType represents the type of Qid. the 'QT' prefix may be redundant. +type QidType uint8 + +const ( + QTDIR QidType = 0x80 /* type bit for directories */ + QTAPPEND = 0x40 /* type bit for append only files */ + QTEXCL = 0x20 /* type bit for exclusive use files */ + QTMOUNT = 0x10 /* type bit for mounted channel */ + QTAUTH = 0x08 /* type bit for authentication file */ + QTTMP = 0x04 /* type bit for non-backed-up file */ + QTSYMLINK = 0x02 /* type bit for symbolic link */ + QTFILE = 0x00 /* type bits for plain file */ +) + +type Req struct { + srv *Srv + ifcall Msg + ofcall Msg +} + +type Fid []byte + +const NOFID = ^uint32(0) + +func (f Fid) String() string { + fn := int64(gbit32(f)) + if uint32(fn) == NOFID { + fn = -1 + } + return fmt.Sprintf("%d", fn) +} + +type Qid []byte + +func (q Qid) Type() QidType { return QidType(q[0]) } +func (q Qid) SetType(t QidType) { q[0] = uint8(t) } +func (q Qid) Vers() uint32 { return gbit32(q[1:5]) } +func (q Qid) SetVers(v uint32) { pbit32(q[1:5], v) } +func (q Qid) Path() uint64 { return gbit64(q[5:13]) } +func (q Qid) SetPath(p uint64) { pbit64(q[5:13], p) } +func (q Qid) String() string { + return fmt.Sprintf("(%016d %d %s)", q.Path(), q.Vers(), q.typeStr()) +} + +// TypeStr returns the q.Type() as string for debugging information. +func (q Qid) typeStr() string { + var s string + t := q.Type() + if t&QTDIR != 0 { + s += "d" + } + if t&QTAPPEND != 0 { + s += "a" + } + if t&QTEXCL != 0 { + s += "l" + } + if t&QTAUTH != 0 { + s += "A" + } + return s +} diff --git a/file.go b/file.go @@ -0,0 +1,73 @@ +package lib9p + +import ( + "io/fs" + "time" +) + +const ( + DMDIR = 0x80000000 + DMAPPEND = 0x40000000 + DMEXCL = 0x20000000 + DMTMP = 0x04000000 +) + +type Stat []byte + +func (s Stat) Size() uint16 { return gbit16(s[0:2]) } +func (s Stat) Type() uint16 { return gbit16(s[2:4]) } +func (s Stat) Dev() uint32 { return gbit32(s[4:8]) } +func (s Stat) Qid() Qid { return Qid(s[8:21]) } +func (s Stat) Mode() uint32 { return gbit32(s[21:25]) } +func (s Stat) ATime() uint32 { return gbit32(s[25:29]) } +func (s Stat) MTime() uint32 { return gbit32(s[29:33]) } +func (s Stat) Length() uint64 { return gbit64(s[33:41]) } +func (s Stat) Name() string { + nlen := gbit16(s[41:43]) + return string(s[43 : 43+nlen]) +} +func (s Stat) Uid() string { + nlen := gbit16(s[41:43]) + ulen := gbit16(s[43+nlen : 43+nlen+2]) + return string(s[43+nlen+2 : 43+nlen+2+ulen]) +} +func (s Stat) Gid() string { + nlen := gbit16(s[41:43]) + ulen := gbit16(s[43+nlen : 43+nlen+2]) + glen := gbit16(s[43+nlen+2+ulen : 43+nlen+2+ulen+2]) + return string(s[43+nlen+2+ulen+2 : 43+nlen+2+ulen+2+glen]) +} +func (s Stat) MUid() string { + nlen := gbit16(s[41:43]) + ulen := gbit16(s[43+nlen : 43+nlen+2]) + glen := gbit16(s[43+nlen+2+ulen : 43+nlen+2+ulen+2]) + mlen := gbit16(s[43+nlen+2+ulen+2+glen : 43+nlen+2+ulen+2+glen+2]) + return string(s[43+nlen+2+ulen+2+glen+2 : 43+nlen+2+ulen+2+glen+2+mlen]) +} + +type FileInfo Stat + +func (fi FileInfo) Name() string { return Stat(fi).Name() } +func (fi FileInfo) Size() int64 { return int64(Stat(fi).Length()) } +func (fi FileInfo) Mode() fs.FileMode { + var mode fs.FileMode + smode := Stat(fi).Mode() + if smode&DMDIR != 0 { + mode |= fs.ModeDir + } + if smode&DMAPPEND != 0 { + mode |= fs.ModeAppend + } + if smode&DMEXCL != 0 { + mode |= fs.ModeExclusive + } + if smode&DMTMP != 0 { + mode |= fs.ModeTemporary + } + // Permission bits are fixed according to godoc of fs.FileMode + mode |= fs.FileMode(smode&0777) + return mode +} +func (fi FileInfo) ModTime() time.Time { return time.Unix(int64(Stat(fi).MTime()), 0) } +func (fi FileInfo) IsDir() bool { return Stat(fi).Mode()&DMDIR != 0 } +func (fi FileInfo) Sys() any { return Stat(fi) } diff --git a/server.go b/server.go @@ -7,7 +7,6 @@ import ( "log" "os" "strings" - "time" ) var chatty9P = false @@ -23,50 +22,6 @@ type Srv struct { io.Writer } -const ( - DMDIR = 0x80000000 - DMAPPEND = 0x40000000 - DMEXCL = 0x20000000 - DMTMP = 0x04000000 -) - -type FileInfo struct { - // type uint16 - dev uint32 - qid Qid - mode uint32 - aTime int32 - mTime int32 // also in fs.FileInfo - length int64 // also in fs.FileInfo - name string // also in fs.FileInfo - uid string - gid string - mUid string -} - -func (fi *FileInfo) Name() string { return fi.name } -func (fi *FileInfo) Size() int64 { return fi.length } -func (fi *FileInfo) Mode() fs.FileMode { - var mode fs.FileMode - if fi.mode&DMDIR != 0 { - mode |= fs.ModeDir - } - if fi.mode&DMAPPEND != 0 { - mode |= fs.ModeAppend - } - if fi.mode&DMEXCL != 0 { - mode |= fs.ModeExclusive - } - if fi.mode&DMTMP != 0 { - mode |= fs.ModeTemporary - } - mode |= fs.FileMode(fi.mode & 0777) - return mode -} -func (fi *FileInfo) ModTime() time.Time { return time.Unix(int64(fi.mTime), 0) } -func (fi *FileInfo) IsDir() bool { return fi.qid.Type()&QTDIR != 0 } -func (fi *FileInfo) Sys() any { return fi } - func getReq(s *Srv) (*Req, error) { var r Req @@ -146,7 +101,8 @@ func sAttach(s *Srv, r *Req) { respond(r, nil) } -func rAttach(r *Req, err error) {} +func rAttach(r *Req, err error) { +} func rError(r *Req, err error) { size := uint32(4 + 1 + 2 + 2 + len(err.Error()))