9fans.net/go@v0.0.5/plan9/client/fid_p9p.go (about)

     1  //go:build !plan9
     2  // +build !plan9
     3  
     4  package client
     5  
     6  import (
     7  	"io"
     8  	"os"
     9  	"strings"
    10  	"sync"
    11  
    12  	"9fans.net/go/plan9"
    13  )
    14  
    15  func getuser() string { return os.Getenv("USER") }
    16  
    17  type Fid struct {
    18  	qid  plan9.Qid
    19  	fid  uint32
    20  	mode uint8
    21  	// f guards offset and c.
    22  	f sync.Mutex
    23  	// c holds the underlying connection.
    24  	// It's nil after the Fid has been closed.
    25  	_c     *conn
    26  	offset int64
    27  }
    28  
    29  func (fid *Fid) conn() (*conn, error) {
    30  	fid.f.Lock()
    31  	c := fid._c
    32  	fid.f.Unlock()
    33  	if c == nil {
    34  		return nil, errClosed
    35  	}
    36  	return c, nil
    37  }
    38  
    39  func (fid *Fid) Close() error {
    40  	if fid == nil {
    41  		// TODO why is Close allowed on a nil fid but no other operations?
    42  		return nil
    43  	}
    44  	conn, err := fid.conn()
    45  	if err != nil {
    46  		return err
    47  	}
    48  	tx := &plan9.Fcall{Type: plan9.Tclunk, Fid: fid.fid}
    49  	_, err = conn.rpc(tx, fid)
    50  	return err
    51  }
    52  
    53  // clunked marks the fid as clunked and closes it. This is called
    54  // just before sending a message that will clunk it.
    55  func (fid *Fid) clunked() error {
    56  	fid.f.Lock()
    57  	defer fid.f.Unlock()
    58  	if fid._c == nil {
    59  		return errClosed
    60  	}
    61  	fid._c.putfidnum(fid.fid)
    62  	fid._c.release()
    63  	fid._c = nil
    64  	return nil
    65  }
    66  
    67  func (fid *Fid) Create(name string, mode uint8, perm plan9.Perm) error {
    68  	conn, err := fid.conn()
    69  	if err != nil {
    70  		return err
    71  	}
    72  	tx := &plan9.Fcall{Type: plan9.Tcreate, Fid: fid.fid, Name: name, Mode: mode, Perm: perm}
    73  	rx, err := conn.rpc(tx, nil)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	fid.mode = mode
    78  	fid.qid = rx.Qid
    79  	return nil
    80  }
    81  
    82  func (fid *Fid) Open(mode uint8) error {
    83  	conn, err := fid.conn()
    84  	if err != nil {
    85  		return err
    86  	}
    87  	tx := &plan9.Fcall{Type: plan9.Topen, Fid: fid.fid, Mode: mode}
    88  	if _, err := conn.rpc(tx, nil); err != nil {
    89  		return err
    90  	}
    91  	fid.mode = mode
    92  	return nil
    93  }
    94  
    95  func (fid *Fid) Qid() plan9.Qid {
    96  	return fid.qid
    97  }
    98  
    99  func (fid *Fid) Read(b []byte) (n int, err error) {
   100  	return fid.ReadAt(b, -1)
   101  }
   102  
   103  func (fid *Fid) ReadAt(b []byte, offset int64) (n int, err error) {
   104  	for len(b) > 0 {
   105  		m, err := fid.readAt(b, offset)
   106  		if err != nil {
   107  			return n, err
   108  		}
   109  		n += m
   110  		b = b[m:]
   111  		if offset != -1 {
   112  			offset += int64(m)
   113  		}
   114  	}
   115  	return n, nil
   116  }
   117  
   118  func (fid *Fid) readAt(b []byte, offset int64) (n int, err error) {
   119  	conn, err := fid.conn()
   120  	if err != nil {
   121  		return 0, err
   122  	}
   123  	msize := conn.msize - plan9.IOHDRSZ
   124  	n = len(b)
   125  	if uint32(n) > msize {
   126  		n = int(msize)
   127  	}
   128  	o := offset
   129  	if o == -1 {
   130  		fid.f.Lock()
   131  		o = fid.offset
   132  		fid.f.Unlock()
   133  	}
   134  	tx := &plan9.Fcall{Type: plan9.Tread, Fid: fid.fid, Offset: uint64(o), Count: uint32(n)}
   135  	rx, err := conn.rpc(tx, nil)
   136  	if err != nil {
   137  		return 0, err
   138  	}
   139  	if len(rx.Data) == 0 {
   140  		return 0, io.EOF
   141  	}
   142  	copy(b, rx.Data)
   143  	if offset == -1 {
   144  		fid.f.Lock()
   145  		fid.offset += int64(len(rx.Data))
   146  		fid.f.Unlock()
   147  	}
   148  	return len(rx.Data), nil
   149  }
   150  
   151  func (fid *Fid) Remove() error {
   152  	conn, err := fid.conn()
   153  	if err != nil {
   154  		return err
   155  	}
   156  	tx := &plan9.Fcall{Type: plan9.Tremove, Fid: fid.fid}
   157  	_, err = conn.rpc(tx, fid)
   158  	return err
   159  }
   160  
   161  func (fid *Fid) Seek(n int64, whence int) (int64, error) {
   162  	switch whence {
   163  	case 0:
   164  		fid.f.Lock()
   165  		fid.offset = n
   166  		fid.f.Unlock()
   167  
   168  	case 1:
   169  		fid.f.Lock()
   170  		n += fid.offset
   171  		if n < 0 {
   172  			fid.f.Unlock()
   173  			return 0, Error("negative offset")
   174  		}
   175  		fid.offset = n
   176  		fid.f.Unlock()
   177  
   178  	case 2:
   179  		d, err := fid.Stat()
   180  		if err != nil {
   181  			return 0, err
   182  		}
   183  		n += int64(d.Length)
   184  		if n < 0 {
   185  			return 0, Error("negative offset")
   186  		}
   187  		fid.f.Lock()
   188  		fid.offset = n
   189  		fid.f.Unlock()
   190  
   191  	default:
   192  		return 0, Error("bad whence in seek")
   193  	}
   194  
   195  	return n, nil
   196  }
   197  
   198  func (fid *Fid) Stat() (*plan9.Dir, error) {
   199  	conn, err := fid.conn()
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	tx := &plan9.Fcall{Type: plan9.Tstat, Fid: fid.fid}
   204  	rx, err := conn.rpc(tx, nil)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	return plan9.UnmarshalDir(rx.Stat)
   209  }
   210  
   211  // TODO(rsc): Could use ...string instead?
   212  func (fid *Fid) Walk(name string) (*Fid, error) {
   213  	conn, err := fid.conn()
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	wfidnum, err := conn.newfidnum()
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	// Split, delete empty strings and dot.
   223  	elem := strings.Split(name, "/")
   224  	j := 0
   225  	for _, e := range elem {
   226  		if e != "" && e != "." {
   227  			elem[j] = e
   228  			j++
   229  		}
   230  	}
   231  	elem = elem[0:j]
   232  
   233  	var wfid *Fid
   234  	fromfidnum := fid.fid
   235  	for nwalk := 0; ; nwalk++ {
   236  		n := len(elem)
   237  		if n > plan9.MAXWELEM {
   238  			n = plan9.MAXWELEM
   239  		}
   240  		tx := &plan9.Fcall{Type: plan9.Twalk, Fid: fromfidnum, Newfid: wfidnum, Wname: elem[0:n]}
   241  		rx, err := conn.rpc(tx, nil)
   242  		if err == nil && len(rx.Wqid) != n {
   243  			err = Error("file '" + name + "' not found")
   244  		}
   245  		if err != nil {
   246  			if wfid != nil {
   247  				wfid.Close()
   248  			}
   249  			return nil, err
   250  		}
   251  		if n == 0 {
   252  			wfid = conn.newFid(wfidnum, fid.qid)
   253  		} else {
   254  			wfid = conn.newFid(wfidnum, rx.Wqid[n-1])
   255  		}
   256  		elem = elem[n:]
   257  		if len(elem) == 0 {
   258  			break
   259  		}
   260  		fromfidnum = wfid.fid
   261  	}
   262  	return wfid, nil
   263  }
   264  
   265  func (fid *Fid) Write(b []byte) (n int, err error) {
   266  	return fid.WriteAt(b, -1)
   267  }
   268  
   269  func (fid *Fid) WriteAt(b []byte, offset int64) (n int, err error) {
   270  	conn, err := fid.conn()
   271  	if err != nil {
   272  		return 0, err
   273  	}
   274  	msize := conn.msize - plan9.IOHDRSIZE
   275  	tot := 0
   276  	n = len(b)
   277  	first := true
   278  	for tot < n || first {
   279  		want := n - tot
   280  		if uint32(want) > msize {
   281  			want = int(msize)
   282  		}
   283  		got, err := fid.writeAt(b[tot:tot+want], offset)
   284  		tot += got
   285  		if err != nil {
   286  			return tot, err
   287  		}
   288  		if offset != -1 {
   289  			offset += int64(got)
   290  		}
   291  		first = false
   292  	}
   293  	return tot, nil
   294  }
   295  
   296  func (fid *Fid) writeAt(b []byte, offset int64) (n int, err error) {
   297  	conn, err := fid.conn()
   298  	if err != nil {
   299  		return 0, err
   300  	}
   301  	o := offset
   302  	if o == -1 {
   303  		fid.f.Lock()
   304  		o = fid.offset
   305  		fid.f.Unlock()
   306  	}
   307  	tx := &plan9.Fcall{Type: plan9.Twrite, Fid: fid.fid, Offset: uint64(o), Data: b}
   308  	rx, err := conn.rpc(tx, nil)
   309  	if err != nil {
   310  		return 0, err
   311  	}
   312  	if offset == -1 && rx.Count > 0 {
   313  		fid.f.Lock()
   314  		fid.offset += int64(rx.Count)
   315  		fid.f.Unlock()
   316  	}
   317  	return int(rx.Count), nil
   318  }
   319  
   320  func (fid *Fid) Wstat(d *plan9.Dir) error {
   321  	conn, err := fid.conn()
   322  	if err != nil {
   323  		return err
   324  	}
   325  	b, err := d.Bytes()
   326  	if err != nil {
   327  		return err
   328  	}
   329  	tx := &plan9.Fcall{Type: plan9.Twstat, Fid: fid.fid, Stat: b}
   330  	_, err = conn.rpc(tx, nil)
   331  	return err
   332  }