Skip to content

Commit 3835d56

Browse files
committed
plan9/srv9p: add Go port of lib9p, with examples
1 parent 7ad7123 commit 3835d56

File tree

21 files changed

+3375
-10
lines changed

21 files changed

+3375
-10
lines changed

‎go.mod‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
module 9fans.net/go
22

3-
go 1.13
3+
go 1.23.0
44

55
require (
66
golang.org/x/exp v0.0.0-20210405174845-4513512abef3
77
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08
88
golang.org/x/sys v0.0.0-20210415045647-66c3f260301c
99
)
10+
11+
require (
12+
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037 // indirect
13+
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 // indirect
14+
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 // indirect
15+
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
16+
)

‎plan9/const.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,6 @@ const (
5555
MREPL = 0x0000
5656
MBEFORE = 0x0001
5757
MAFTER = 0x0002
58+
MCREATE = 0x0004
59+
MCACHE = 0x0010
5860
)

‎plan9/dir.go‎

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package plan9
22

33
import (
4+
"bytes"
45
"fmt"
56
"strconv"
7+
"strings"
68
)
79

810
type ProtocolError string
@@ -43,6 +45,10 @@ var nullDir = Dir{
4345
"",
4446
}
4547

48+
func (d *Dir) IsNull() bool {
49+
return *d == nullDir
50+
}
51+
4652
func (d *Dir) Null() {
4753
*d = nullDir
4854
}
@@ -102,12 +108,96 @@ func UnmarshalDir(b []byte) (d *Dir, err error) {
102108
}
103109

104110
func (d *Dir) String() string {
105-
return fmt.Sprintf("'%s' '%s' '%s' '%s' q %v m %#o at %d mt %d l %d t %d d %d",
111+
return fmt.Sprintf("name '%s' uid '%s' gid '%s' muid '%s' qid %v mode %v atime %d mtime %d length %d type %d dev %d",
106112
d.Name, d.Uid, d.Gid, d.Muid, d.Qid, d.Mode,
107113
d.Atime, d.Mtime, d.Length, d.Type, d.Dev)
108114
}
109115

116+
func parseDir(s string) (*Dir, error) {
117+
d := new(Dir)
118+
d.Null()
119+
for s != "" {
120+
s = strings.TrimSpace(s)
121+
if s == "" {
122+
break
123+
}
124+
var name string
125+
name, s, _ = strings.Cut(s, " ")
126+
s = strings.TrimSpace(s)
127+
var arg string
128+
if strings.HasPrefix(s, "'") {
129+
i := strings.Index(s[1:], "'")
130+
if i < 0 {
131+
return nil, fmt.Errorf("missing closing quote")
132+
}
133+
arg, s = s[1:1+i], s[1+i+1:]
134+
} else {
135+
arg, s, _ = strings.Cut(s, " ")
136+
}
137+
switch name {
138+
default:
139+
return nil, fmt.Errorf("unknown field %q", name)
140+
case "type":
141+
n, err := strconv.ParseUint(arg, 0, 16)
142+
if err != nil {
143+
return nil, fmt.Errorf("invalid type: %v", err)
144+
}
145+
d.Type = uint16(n)
146+
case "dev":
147+
n, err := strconv.ParseUint(arg, 0, 32)
148+
if err != nil {
149+
return nil, fmt.Errorf("invalid dev: %v", err)
150+
}
151+
d.Dev = uint32(n)
152+
case "qid":
153+
q, err := parseQid(arg)
154+
if err != nil {
155+
return nil, fmt.Errorf("invalid qid: %v", err)
156+
}
157+
d.Qid = q
158+
case "mode":
159+
m, err := parsePerm(arg)
160+
if err != nil {
161+
return nil, fmt.Errorf("invalid mode: %v", err)
162+
}
163+
d.Mode = m
164+
case "atime":
165+
n, err := strconv.ParseUint(arg, 0, 32)
166+
if err != nil {
167+
return nil, fmt.Errorf("invalid atime: %v", err)
168+
}
169+
d.Atime = uint32(n)
170+
case "mtime":
171+
n, err := strconv.ParseUint(arg, 0, 32)
172+
if err != nil {
173+
return nil, fmt.Errorf("invalid mtime: %v", err)
174+
}
175+
d.Mtime = uint32(n)
176+
case "length":
177+
n, err := strconv.ParseUint(arg, 0, 64)
178+
if err != nil {
179+
return nil, fmt.Errorf("invalid length: %v", err)
180+
}
181+
d.Length = n
182+
case "name":
183+
d.Name = arg
184+
case "uid":
185+
d.Uid = arg
186+
case "gid":
187+
d.Gid = arg
188+
case "muid":
189+
d.Muid = arg
190+
}
191+
}
192+
return d, nil
193+
}
194+
110195
func dumpsome(b []byte) string {
196+
// Is this all directories?
197+
if s, ok := dumpDirs(b); ok {
198+
return s
199+
}
200+
111201
if len(b) > 64 {
112202
b = b[0:64]
113203
}
@@ -126,6 +216,38 @@ func dumpsome(b []byte) string {
126216
return fmt.Sprintf("%x", b)
127217
}
128218

219+
func dumpDirs(b []byte) (string, bool) {
220+
var dirs []*Dir
221+
for len(b) > 0 {
222+
if len(b) < 2 {
223+
return "", false
224+
}
225+
n, _ := gbit16(b)
226+
m := int(n) + 2
227+
if len(b) < m {
228+
return "", false
229+
}
230+
d, err := UnmarshalDir(b[:m])
231+
if err != nil {
232+
return "", false
233+
}
234+
dirs = append(dirs, d)
235+
b = b[m:]
236+
}
237+
var out bytes.Buffer
238+
out.WriteString("[")
239+
for i, d := range dirs {
240+
if i > 0 {
241+
out.WriteString(" ")
242+
}
243+
out.WriteString("(")
244+
out.WriteString(d.String())
245+
out.WriteString(")")
246+
}
247+
out.WriteString("]")
248+
return out.String(), true
249+
}
250+
129251
type Perm uint32
130252

131253
type permChar struct {
@@ -164,6 +286,32 @@ var permChars = []permChar{
164286
permChar{0, '-'},
165287
}
166288

289+
func parsePerm(s string) (Perm, error) {
290+
orig := s
291+
did := false
292+
var p Perm
293+
for _, pc := range permChars {
294+
if pc.bit == 0 && did {
295+
did = false
296+
continue
297+
}
298+
if s == "" {
299+
return Perm(0), fmt.Errorf("perm too short: %q", orig)
300+
}
301+
if s[0] == byte(pc.c) {
302+
s = s[1:]
303+
p |= pc.bit
304+
if pc.bit != 0 {
305+
did = true
306+
}
307+
}
308+
}
309+
if s != "" {
310+
return Perm(0), fmt.Errorf("perm too long: %q", orig)
311+
}
312+
return p, nil
313+
}
314+
167315
func (p Perm) String() string {
168316
s := ""
169317
did := false
@@ -211,7 +359,39 @@ func (q Qid) String() string {
211359
if q.Type&QTAUTH != 0 {
212360
t += "A"
213361
}
214-
return fmt.Sprintf("(%.16x %d %s)", q.Path, q.Vers, t)
362+
if t != "" {
363+
t = "." + t
364+
}
365+
return fmt.Sprintf("%#x.%d%s", q.Path, q.Vers, t)
366+
}
367+
368+
func parseQid(s string) (Qid, error) {
369+
orig := s
370+
var q Qid
371+
var ok bool
372+
ps, vs, _ := strings.Cut(s, ".")
373+
vs, ts, _ := strings.Cut(vs, ".")
374+
pn, err1 := strconv.ParseUint(ps, 0, 64)
375+
vn, err2 := strconv.ParseUint(vs, 0, 32)
376+
if ts, ok = strings.CutPrefix(ts, "d"); ok {
377+
q.Type |= QTDIR
378+
}
379+
if ts, ok = strings.CutPrefix(ts, "a"); ok {
380+
q.Type |= QTAPPEND
381+
}
382+
if ts, ok = strings.CutPrefix(ts, "l"); ok {
383+
q.Type |= QTEXCL
384+
}
385+
if ts, ok = strings.CutPrefix(ts, "A"); ok {
386+
q.Type |= QTAUTH
387+
}
388+
if err1 != nil || err2 != nil || ts != "" {
389+
return Qid{}, fmt.Errorf("invalid qid %q", orig)
390+
}
391+
q.Path = pn
392+
q.Vers = uint32(vn)
393+
394+
return q, nil
215395
}
216396

217397
func gqid(b []byte) (Qid, []byte) {

0 commit comments

Comments
 (0)