lib9p

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

parse.go (3584B)


      1 package lib9p
      2 
      3 import (
      4 	"encoding/binary"
      5 	"fmt"
      6 	"io"
      7 )
      8 
      9 // Read9PMsg reads a 9P message from r and saves it in a byte slice.
     10 // It returns the byte slice read and error if any.
     11 func readMsg(r io.Reader) ([]byte, error) {
     12 	buf := make([]byte, 4)
     13 	read, err := r.Read(buf)
     14 	if err != nil {
     15 		if err == io.EOF {
     16 			return nil, err
     17 		}
     18 		return nil, fmt.Errorf("read size: %v", err)
     19 	}
     20 	if read != len(buf) {
     21 		return buf, fmt.Errorf("read size: invalid message.")
     22 	}
     23 	size := bufMsg(buf).Size()
     24 	mbuf := make([]byte, size-4)
     25 	for read = 0; read < int(size)-4; {
     26 		n, err := r.Read(mbuf[read:])
     27 		if err != nil {
     28 			return buf, fmt.Errorf("read body: %v", err)
     29 		}
     30 		read += n
     31 	}
     32 	buf = append(buf, mbuf...)
     33 	if uint32(read+4) != size {
     34 		return buf, fmt.Errorf("read body: size mismatch: %d != %d", read+4, size)
     35 	}
     36 	return buf, nil
     37 }
     38 
     39 // unmarshal converts a byte array of 9P message into the corresponding
     40 // Msg struct.
     41 func unmarshal(buf []byte) (Msg, error) {
     42 	switch t := bufMsg(buf).Type(); t {
     43 	case Tversion:
     44 		return newTVersion(buf), nil
     45 	case Rversion:
     46 		return newRVersion(buf), nil
     47 	case Tauth:
     48 		return newTAuth(buf), nil
     49 	case Rauth:
     50 		return newRAuth(buf), nil
     51 	case Tattach:
     52 		return newTAttach(buf), nil
     53 	case Rattach:
     54 		return newRAttach(buf), nil
     55 	case Rerror:
     56 		return newRError(buf), nil
     57 	case Tflush:
     58 		return newTFlush(buf), nil
     59 	case Rflush:
     60 		return newRFlush(buf), nil
     61 	case Twalk:
     62 		return newTWalk(buf), nil
     63 	case Rwalk:
     64 		return newRWalk(buf), nil
     65 	case Topen:
     66 		return newTOpen(buf), nil
     67 	case Ropen:
     68 		return newROpen(buf), nil
     69 	case Tcreate:
     70 		return newTCreate(buf), nil
     71 	case Rcreate:
     72 		return newRCreate(buf), nil
     73 	case Tread:
     74 		return newTRead(buf), nil
     75 	case Rread:
     76 		return newRRead(buf), nil
     77 	case Twrite:
     78 		return newTWrite(buf), nil
     79 	case Rwrite:
     80 		return newRWrite(buf), nil
     81 	case Tclunk:
     82 		return newTClunk(buf), nil
     83 	case Rclunk:
     84 		return newRClunk(buf), nil
     85 	case Tremove:
     86 		return newTRemove(buf), nil
     87 	case Rremove:
     88 		return newRRemove(buf), nil
     89 	case Tstat:
     90 		return newTStat(buf), nil
     91 	case Rstat:
     92 		return newRStat(buf), nil
     93 	case Twstat:
     94 		return newTWstat(buf), nil
     95 	case Rwstat:
     96 		return newRWstat(buf), nil
     97 	default:
     98 		return nil, fmt.Errorf("unknown message type %v", t)
     99 	}
    100 }
    101 
    102 // SendMsg send a 9P message to w
    103 func SendMsg(msg Msg, w io.Writer) error {
    104 	if _, err := w.Write(msg.marshal()); err != nil {
    105 		return fmt.Errorf("write: %v", err)
    106 	}
    107 	return nil
    108 }
    109 
    110 // RecvMsg recievs a 9P message from r.
    111 func RecvMsg(r io.Reader) (Msg, error) {
    112 	b, err := readMsg(r)
    113 	if err == io.EOF {
    114 		return nil, err
    115 	} else if err != nil {
    116 		return nil, fmt.Errorf("readMsg: %v", err)
    117 	}
    118 	return unmarshal(b)
    119 }
    120 
    121 // Gbit16 reads b as 2-byte long little endian unsigned integer and
    122 // returns the result
    123 func gbit16(b []byte) uint16 { return binary.LittleEndian.Uint16(b[0:2]) }
    124 
    125 // Gbit32 reads b as 4-byte long little endian unsigned integer and
    126 // returns the result
    127 func gbit32(b []byte) uint32 { return binary.LittleEndian.Uint32(b[0:4]) }
    128 
    129 // Gbit64 reads b as 8-byte long little endian unsigned integer and
    130 // returns the result
    131 func gbit64(b []byte) uint64 { return binary.LittleEndian.Uint64(b[0:8]) }
    132 
    133 // Pbit16 puts into b an 2-byte long little endian unsigned integer n.
    134 func pbit16(b []byte, n uint16) { binary.LittleEndian.PutUint16(b, n) }
    135 
    136 // Pbit32 puts into b an 4-byte long little endian unsigned integer n.
    137 func pbit32(b []byte, n uint32) { binary.LittleEndian.PutUint32(b, n) }
    138 
    139 // Pbit64 puts into b an 8-byte long little endian unsigned integer n.
    140 func pbit64(b []byte, n uint64) { binary.LittleEndian.PutUint64(b, n) }