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

     1  package plan9
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  )
     7  
     8  const (
     9  	IOHDRSIZE = 24
    10  )
    11  
    12  type Fcall struct {
    13  	Type    uint8
    14  	Fid     uint32
    15  	Tag     uint16
    16  	Msize   uint32
    17  	Version string   // Tversion, Rversion
    18  	Oldtag  uint16   // Tflush
    19  	Ename   string   // Rerror
    20  	Qid     Qid      // Rattach, Ropen, Rcreate
    21  	Iounit  uint32   // Ropen, Rcreate
    22  	Aqid    Qid      // Rauth
    23  	Afid    uint32   // Tauth, Tattach
    24  	Uname   string   // Tauth, Tattach
    25  	Aname   string   // Tauth, Tattach
    26  	Perm    Perm     // Tcreate
    27  	Name    string   // Tcreate
    28  	Mode    uint8    // Tcreate, Topen
    29  	Newfid  uint32   // Twalk
    30  	Wname   []string // Twalk
    31  	Wqid    []Qid    // Rwalk
    32  	Offset  uint64   // Tread, Twrite
    33  	Count   uint32   // Tread, Rwrite
    34  	Data    []byte   // Twrite, Rread
    35  	Stat    []byte   // Twstat, Rstat
    36  
    37  	// 9P2000.u extensions
    38  	Errno     uint32 // Rerror
    39  	Uid       uint32 // Tattach, Tauth
    40  	Extension string // Tcreate
    41  }
    42  
    43  const (
    44  	Tversion = 100 + iota
    45  	Rversion
    46  	Tauth
    47  	Rauth
    48  	Tattach
    49  	Rattach
    50  	Terror // illegal
    51  	Rerror
    52  	Tflush
    53  	Rflush
    54  	Twalk
    55  	Rwalk
    56  	Topen
    57  	Ropen
    58  	Tcreate
    59  	Rcreate
    60  	Tread
    61  	Rread
    62  	Twrite
    63  	Rwrite
    64  	Tclunk
    65  	Rclunk
    66  	Tremove
    67  	Rremove
    68  	Tstat
    69  	Rstat
    70  	Twstat
    71  	Rwstat
    72  	Tmax
    73  )
    74  
    75  func (f *Fcall) Bytes() ([]byte, error) {
    76  	b := pbit32(nil, 0) // length: fill in later
    77  	b = pbit8(b, f.Type)
    78  	b = pbit16(b, f.Tag)
    79  	switch f.Type {
    80  	default:
    81  		return nil, ProtocolError("invalid type")
    82  
    83  	case Tversion:
    84  		b = pbit32(b, f.Msize)
    85  		b = pstring(b, f.Version)
    86  
    87  	case Tflush:
    88  		b = pbit16(b, f.Oldtag)
    89  
    90  	case Tauth:
    91  		b = pbit32(b, f.Afid)
    92  		b = pstring(b, f.Uname)
    93  		b = pstring(b, f.Aname)
    94  
    95  	case Tattach:
    96  		b = pbit32(b, f.Fid)
    97  		b = pbit32(b, f.Afid)
    98  		b = pstring(b, f.Uname)
    99  		b = pstring(b, f.Aname)
   100  
   101  	case Twalk:
   102  		b = pbit32(b, f.Fid)
   103  		b = pbit32(b, f.Newfid)
   104  		if len(f.Wname) > MAXWELEM {
   105  			return nil, ProtocolError("too many names in walk")
   106  		}
   107  		b = pbit16(b, uint16(len(f.Wname)))
   108  		for i := range f.Wname {
   109  			b = pstring(b, f.Wname[i])
   110  		}
   111  
   112  	case Topen:
   113  		b = pbit32(b, f.Fid)
   114  		b = pbit8(b, f.Mode)
   115  
   116  	case Tcreate:
   117  		b = pbit32(b, f.Fid)
   118  		b = pstring(b, f.Name)
   119  		b = pperm(b, f.Perm)
   120  		b = pbit8(b, f.Mode)
   121  
   122  	case Tread:
   123  		b = pbit32(b, f.Fid)
   124  		b = pbit64(b, f.Offset)
   125  		b = pbit32(b, f.Count)
   126  
   127  	case Twrite:
   128  		b = pbit32(b, f.Fid)
   129  		b = pbit64(b, f.Offset)
   130  		b = pbit32(b, uint32(len(f.Data)))
   131  		b = append(b, f.Data...)
   132  
   133  	case Tclunk, Tremove, Tstat:
   134  		b = pbit32(b, f.Fid)
   135  
   136  	case Twstat:
   137  		b = pbit32(b, f.Fid)
   138  		b = pbit16(b, uint16(len(f.Stat)))
   139  		b = append(b, f.Stat...)
   140  
   141  	case Rversion:
   142  		b = pbit32(b, f.Msize)
   143  		b = pstring(b, f.Version)
   144  
   145  	case Rerror:
   146  		b = pstring(b, f.Ename)
   147  
   148  	case Rflush, Rclunk, Rremove, Rwstat:
   149  		// nothing
   150  
   151  	case Rauth:
   152  		b = pqid(b, f.Aqid)
   153  
   154  	case Rattach:
   155  		b = pqid(b, f.Qid)
   156  
   157  	case Rwalk:
   158  		if len(f.Wqid) > MAXWELEM {
   159  			return nil, ProtocolError("too many qid in walk")
   160  		}
   161  		b = pbit16(b, uint16(len(f.Wqid)))
   162  		for i := range f.Wqid {
   163  			b = pqid(b, f.Wqid[i])
   164  		}
   165  
   166  	case Ropen, Rcreate:
   167  		b = pqid(b, f.Qid)
   168  		b = pbit32(b, f.Iounit)
   169  
   170  	case Rread:
   171  		b = pbit32(b, uint32(len(f.Data)))
   172  		b = append(b, f.Data...)
   173  
   174  	case Rwrite:
   175  		b = pbit32(b, f.Count)
   176  
   177  	case Rstat:
   178  		b = pbit16(b, uint16(len(f.Stat)))
   179  		b = append(b, f.Stat...)
   180  	}
   181  
   182  	pbit32(b[0:0], uint32(len(b)))
   183  	return b, nil
   184  }
   185  
   186  func UnmarshalFcall(b []byte) (f *Fcall, err error) {
   187  	defer func() {
   188  		if recover() != nil {
   189  			println("bad fcall at ", b)
   190  			f = nil
   191  			err = ProtocolError("malformed Fcall")
   192  		}
   193  	}()
   194  
   195  	n, b := gbit32(b)
   196  	if len(b) != int(n)-4 {
   197  		panic(1)
   198  	}
   199  
   200  	f = new(Fcall)
   201  	f.Type, b = gbit8(b)
   202  	f.Tag, b = gbit16(b)
   203  
   204  	switch f.Type {
   205  	default:
   206  		panic(1)
   207  
   208  	case Tversion:
   209  		f.Msize, b = gbit32(b)
   210  		f.Version, b = gstring(b)
   211  
   212  	case Tflush:
   213  		f.Oldtag, b = gbit16(b)
   214  
   215  	case Tauth:
   216  		f.Afid, b = gbit32(b)
   217  		f.Uname, b = gstring(b)
   218  		f.Aname, b = gstring(b)
   219  
   220  	case Tattach:
   221  		f.Fid, b = gbit32(b)
   222  		f.Afid, b = gbit32(b)
   223  		f.Uname, b = gstring(b)
   224  		f.Aname, b = gstring(b)
   225  
   226  	case Twalk:
   227  		f.Fid, b = gbit32(b)
   228  		f.Newfid, b = gbit32(b)
   229  		var n uint16
   230  		n, b = gbit16(b)
   231  		if n > MAXWELEM {
   232  			panic(1)
   233  		}
   234  		f.Wname = make([]string, n)
   235  		for i := range f.Wname {
   236  			f.Wname[i], b = gstring(b)
   237  		}
   238  
   239  	case Topen:
   240  		f.Fid, b = gbit32(b)
   241  		f.Mode, b = gbit8(b)
   242  
   243  	case Tcreate:
   244  		f.Fid, b = gbit32(b)
   245  		f.Name, b = gstring(b)
   246  		f.Perm, b = gperm(b)
   247  		f.Mode, b = gbit8(b)
   248  
   249  	case Tread:
   250  		f.Fid, b = gbit32(b)
   251  		f.Offset, b = gbit64(b)
   252  		f.Count, b = gbit32(b)
   253  
   254  	case Twrite:
   255  		f.Fid, b = gbit32(b)
   256  		f.Offset, b = gbit64(b)
   257  		n, b = gbit32(b)
   258  		if len(b) != int(n) {
   259  			panic(1)
   260  		}
   261  		f.Data = b
   262  		b = nil
   263  
   264  	case Tclunk, Tremove, Tstat:
   265  		f.Fid, b = gbit32(b)
   266  
   267  	case Twstat:
   268  		f.Fid, b = gbit32(b)
   269  		var n uint16
   270  		n, b = gbit16(b)
   271  		if len(b) != int(n) {
   272  			panic(1)
   273  		}
   274  		f.Stat = b
   275  		b = nil
   276  
   277  	case Rversion:
   278  		f.Msize, b = gbit32(b)
   279  		f.Version, b = gstring(b)
   280  
   281  	case Rerror:
   282  		f.Ename, b = gstring(b)
   283  
   284  	case Rflush, Rclunk, Rremove, Rwstat:
   285  		// nothing
   286  
   287  	case Rauth:
   288  		f.Aqid, b = gqid(b)
   289  
   290  	case Rattach:
   291  		f.Qid, b = gqid(b)
   292  
   293  	case Rwalk:
   294  		var n uint16
   295  		n, b = gbit16(b)
   296  		if n > MAXWELEM {
   297  			panic(1)
   298  		}
   299  		f.Wqid = make([]Qid, n)
   300  		for i := range f.Wqid {
   301  			f.Wqid[i], b = gqid(b)
   302  		}
   303  
   304  	case Ropen, Rcreate:
   305  		f.Qid, b = gqid(b)
   306  		f.Iounit, b = gbit32(b)
   307  
   308  	case Rread:
   309  		n, b = gbit32(b)
   310  		if len(b) != int(n) {
   311  			panic(1)
   312  		}
   313  		f.Data = b
   314  		b = nil
   315  
   316  	case Rwrite:
   317  		f.Count, b = gbit32(b)
   318  
   319  	case Rstat:
   320  		var n uint16
   321  		n, b = gbit16(b)
   322  		if len(b) != int(n) {
   323  			panic(1)
   324  		}
   325  		f.Stat = b
   326  		b = nil
   327  	}
   328  
   329  	if len(b) != 0 {
   330  		panic(1)
   331  	}
   332  
   333  	return f, nil
   334  }
   335  
   336  func (f *Fcall) String() string {
   337  	if f == nil {
   338  		return "<nil>"
   339  	}
   340  	switch f.Type {
   341  	case Tversion:
   342  		return fmt.Sprintf("Tversion tag %d msize %d version '%s'",
   343  			f.Tag, f.Msize, f.Version)
   344  	case Rversion:
   345  		return fmt.Sprintf("Rversion tag %d msize %d version '%s'",
   346  			f.Tag, f.Msize, f.Version)
   347  	case Tauth:
   348  		return fmt.Sprintf("Tauth tag %d afid %d uname %s aname %s",
   349  			f.Tag, f.Afid, f.Uname, f.Aname)
   350  	case Rauth:
   351  		return fmt.Sprintf("Rauth tag %d qid %v", f.Tag, f.Qid)
   352  	case Tattach:
   353  		return fmt.Sprintf("Tattach tag %d fid %d afid %d uname %s aname %s",
   354  			f.Tag, f.Fid, f.Afid, f.Uname, f.Aname)
   355  	case Rattach:
   356  		return fmt.Sprintf("Rattach tag %d qid %v", f.Tag, f.Qid)
   357  	case Rerror:
   358  		return fmt.Sprintf("Rerror tag %d ename %s", f.Tag, f.Ename)
   359  	case Tflush:
   360  		return fmt.Sprintf("Tflush tag %d oldtag %d", f.Tag, f.Oldtag)
   361  	case Rflush:
   362  		return fmt.Sprintf("Rflush tag %d", f.Tag)
   363  	case Twalk:
   364  		return fmt.Sprintf("Twalk tag %d fid %d newfid %d wname %v",
   365  			f.Tag, f.Fid, f.Newfid, f.Wname)
   366  	case Rwalk:
   367  		return fmt.Sprintf("Rwalk tag %d wqid %v", f.Tag, f.Wqid)
   368  	case Topen:
   369  		return fmt.Sprintf("Topen tag %d fid %d mode %d", f.Tag, f.Fid, f.Mode)
   370  	case Ropen:
   371  		return fmt.Sprintf("Ropen tag %d qid %v iouint %d", f.Tag, f.Qid, f.Iounit)
   372  	case Tcreate:
   373  		return fmt.Sprintf("Tcreate tag %d fid %d name %s perm %v mode %d",
   374  			f.Tag, f.Fid, f.Name, f.Perm, f.Mode)
   375  	case Rcreate:
   376  		return fmt.Sprintf("Rcreate tag %d qid %v iouint %d", f.Tag, f.Qid, f.Iounit)
   377  	case Tread:
   378  		return fmt.Sprintf("Tread tag %d fid %d offset %d count %d",
   379  			f.Tag, f.Fid, f.Offset, f.Count)
   380  	case Rread:
   381  		return fmt.Sprintf("Rread tag %d count %d %s",
   382  			f.Tag, len(f.Data), dumpsome(f.Data))
   383  	case Twrite:
   384  		return fmt.Sprintf("Twrite tag %d fid %d offset %d count %d %s",
   385  			f.Tag, f.Fid, f.Offset, len(f.Data), dumpsome(f.Data))
   386  	case Rwrite:
   387  		return fmt.Sprintf("Rwrite tag %d count %d", f.Tag, f.Count)
   388  	case Tclunk:
   389  		return fmt.Sprintf("Tclunk tag %d fid %d", f.Tag, f.Fid)
   390  	case Rclunk:
   391  		return fmt.Sprintf("Rclunk tag %d", f.Tag)
   392  	case Tremove:
   393  		return fmt.Sprintf("Tremove tag %d fid %d", f.Tag, f.Fid)
   394  	case Rremove:
   395  		return fmt.Sprintf("Rremove tag %d", f.Tag)
   396  	case Tstat:
   397  		return fmt.Sprintf("Tstat tag %d fid %d", f.Tag, f.Fid)
   398  	case Rstat:
   399  		d, err := UnmarshalDir(f.Stat)
   400  		if err == nil {
   401  			return fmt.Sprintf("Rstat tag %d stat(%d bytes)",
   402  				f.Tag, len(f.Stat))
   403  		}
   404  		return fmt.Sprintf("Rstat tag %d stat %v", f.Tag, d)
   405  	case Twstat:
   406  		d, err := UnmarshalDir(f.Stat)
   407  		if err == nil {
   408  			return fmt.Sprintf("Twstat tag %d fid %d stat(%d bytes)",
   409  				f.Tag, f.Fid, len(f.Stat))
   410  		}
   411  		return fmt.Sprintf("Twstat tag %d fid %d stat %v", f.Tag, f.Fid, d)
   412  	case Rwstat:
   413  		return fmt.Sprintf("FidRwstat tag %d", f.Tag)
   414  	}
   415  	return fmt.Sprintf("unknown type %d", f.Type)
   416  }
   417  
   418  func ReadFcall(r io.Reader) (*Fcall, error) {
   419  	// 128 bytes should be enough for most messages
   420  	buf := make([]byte, 128)
   421  	_, err := io.ReadFull(r, buf[0:4])
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  
   426  	// read 4-byte header, make room for remainder
   427  	n, _ := gbit32(buf)
   428  	if n < 4 {
   429  		return nil, ProtocolError("invalid length")
   430  	}
   431  	if int(n) <= len(buf) {
   432  		buf = buf[0:n]
   433  	} else {
   434  		buf = make([]byte, n)
   435  		pbit32(buf[0:0], n)
   436  	}
   437  
   438  	// read remainder and unpack
   439  	_, err = io.ReadFull(r, buf[4:])
   440  	if err != nil {
   441  		return nil, err
   442  	}
   443  	return UnmarshalFcall(buf)
   444  }
   445  
   446  func WriteFcall(w io.Writer, f *Fcall) error {
   447  	b, err := f.Bytes()
   448  	if err != nil {
   449  		return err
   450  	}
   451  	_, err = w.Write(b)
   452  	return err
   453  }