lib9p

Go 9P library.
Log | Files | Refs | LICENSE

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 }