client2.go (2932B)
1 package lib9p 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "io/fs" 8 "path" 9 "strings" 10 ) 11 12 type ClientFS struct { 13 c *Client 14 tPool *tagPool 15 } 16 17 func (fsys *ClientFS) Open(name string) (File, error) { 18 return fsys.OpenFile(name, OREAD, 0) 19 } 20 21 func (fsys *ClientFS) OpenFile(name string, omode OpenMode, perm fs.FileMode) (File, error) { 22 var ( 23 qid Qid 24 iounit uint32 25 ) 26 f, err := fsys.walkFile(name) 27 if err != nil { 28 // File not found. Create. 29 f, err = fsys.walkFile(path.Dir(name)) 30 if err != nil { 31 return nil, fmt.Errorf("walk to %s: %v", name, err) 32 } 33 tag, err := fsys.tPool.add() 34 if err != nil { 35 return nil, err 36 } 37 qid, iounit, err = fsys.c.Create(context.TODO(), tag, f.fid.fid, path.Base(name), perm, omode) 38 fsys.tPool.delete(tag) 39 if err != nil { 40 f.Close() 41 return nil, fmt.Errorf("create: %v", err) 42 } 43 } else { 44 // File exists. Open it. 45 tag, err := fsys.tPool.add() 46 if err != nil { 47 return nil, err 48 } 49 qid, iounit, err = fsys.c.Open(context.TODO(), tag, f.fid.fid, omode) 50 fsys.tPool.delete(tag) 51 if err != nil { 52 f.Close() 53 return nil, fmt.Errorf("open: %v", err) 54 } 55 } 56 f.fid.omode = omode 57 f.qid = qid 58 f.iounit = iounit 59 return f, nil 60 } 61 62 func (fsys *ClientFS) walkFile(name string) (*ClientFile, error) { 63 fid, err := fsys.c.fPool.add() 64 if err != nil { 65 return nil, fmt.Errorf("add fid: %v", err) 66 } 67 var wname []string 68 if name != "." { 69 wname = strings.Split(path.Clean(name), "/") 70 } 71 tag, err := fsys.tPool.add() 72 if err != nil { 73 return nil, err 74 } 75 wqid, err := fsys.c.Walk(context.TODO(), tag, fsys.c.rootFid.fid, fid.fid, wname) 76 fsys.tPool.delete(tag) 77 if err != nil { 78 return nil, fmt.Errorf("walk: %v", err) 79 } 80 var qid Qid 81 if name == "." { 82 qid = Qid{} 83 } else if len(wqid) > 0 { 84 qid = wqid[len(wqid)-1] 85 } else { 86 return nil, fmt.Errorf("invalid wqid: %v", wqid) 87 } 88 f := &ClientFile{ 89 name: path.Base(name), 90 path: name, 91 fid: fid, 92 qid: qid, 93 fs: fsys, 94 } 95 fid.file = f 96 return f, nil 97 } 98 99 func Mount(r io.Reader, w io.Writer, uname, aname string) (fs *ClientFS, err error) { 100 var ( 101 mSize uint32 = 8192 102 version = "9P2000" 103 ctx = context.TODO() 104 ) 105 cfs := &ClientFS{ 106 c: NewClient(mSize, uname, r, w), 107 tPool: newTagPool(), 108 } 109 defer func() { 110 if err != nil { 111 cfs.c.Stop() 112 } 113 }() 114 rmSize, rver, err := cfs.c.Version(ctx, NOTAG, mSize, version) 115 if err != nil { 116 return nil, fmt.Errorf("version: %v", err) 117 } 118 if rver != version { 119 return nil, fmt.Errorf("incompatible version %s", rver) 120 } 121 if rmSize < mSize { 122 cfs.c.setMSize(rmSize) 123 } 124 // TODO: auth 125 fid, err := cfs.c.fPool.add() 126 if err != nil { 127 return nil, fmt.Errorf("add fid: %v", err) 128 } 129 tag, err := cfs.tPool.add() 130 if err != nil { 131 return nil, err 132 } 133 _, err = cfs.c.Attach(ctx, tag, fid.fid, NOFID, uname, aname) 134 cfs.tPool.delete(tag) 135 if err != nil { 136 return nil, fmt.Errorf("attach: %v", err) 137 } 138 cfs.c.rootFid = fid 139 return cfs, nil 140 }