123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // Copyright 2012 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- // Plan 9 directory marshalling. See intro(5).
-
- package plan9
-
- import "errors"
-
- var (
- ErrShortStat = errors.New("stat buffer too short")
- ErrBadStat = errors.New("malformed stat buffer")
- ErrBadName = errors.New("bad character in file name")
- )
-
- // A Qid represents a 9P server's unique identification for a file.
- type Qid struct {
- Path uint64 // the file server's unique identification for the file
- Vers uint32 // version number for given Path
- Type uint8 // the type of the file (plan9.QTDIR for example)
- }
-
- // A Dir contains the metadata for a file.
- type Dir struct {
- // system-modified data
- Type uint16 // server type
- Dev uint32 // server subtype
-
- // file data
- Qid Qid // unique id from server
- Mode uint32 // permissions
- Atime uint32 // last read time
- Mtime uint32 // last write time
- Length int64 // file length
- Name string // last element of path
- Uid string // owner name
- Gid string // group name
- Muid string // last modifier name
- }
-
- var nullDir = Dir{
- Type: ^uint16(0),
- Dev: ^uint32(0),
- Qid: Qid{
- Path: ^uint64(0),
- Vers: ^uint32(0),
- Type: ^uint8(0),
- },
- Mode: ^uint32(0),
- Atime: ^uint32(0),
- Mtime: ^uint32(0),
- Length: ^int64(0),
- }
-
- // Null assigns special "don't touch" values to members of d to
- // avoid modifying them during plan9.Wstat.
- func (d *Dir) Null() { *d = nullDir }
-
- // Marshal encodes a 9P stat message corresponding to d into b
- //
- // If there isn't enough space in b for a stat message, ErrShortStat is returned.
- func (d *Dir) Marshal(b []byte) (n int, err error) {
- n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
- if n > len(b) {
- return n, ErrShortStat
- }
-
- for _, c := range d.Name {
- if c == '/' {
- return n, ErrBadName
- }
- }
-
- b = pbit16(b, uint16(n)-2)
- b = pbit16(b, d.Type)
- b = pbit32(b, d.Dev)
- b = pbit8(b, d.Qid.Type)
- b = pbit32(b, d.Qid.Vers)
- b = pbit64(b, d.Qid.Path)
- b = pbit32(b, d.Mode)
- b = pbit32(b, d.Atime)
- b = pbit32(b, d.Mtime)
- b = pbit64(b, uint64(d.Length))
- b = pstring(b, d.Name)
- b = pstring(b, d.Uid)
- b = pstring(b, d.Gid)
- b = pstring(b, d.Muid)
-
- return n, nil
- }
-
- // UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
- //
- // If b is too small to hold a valid stat message, ErrShortStat is returned.
- //
- // If the stat message itself is invalid, ErrBadStat is returned.
- func UnmarshalDir(b []byte) (*Dir, error) {
- if len(b) < STATFIXLEN {
- return nil, ErrShortStat
- }
- size, buf := gbit16(b)
- if len(b) != int(size)+2 {
- return nil, ErrBadStat
- }
- b = buf
-
- var d Dir
- d.Type, b = gbit16(b)
- d.Dev, b = gbit32(b)
- d.Qid.Type, b = gbit8(b)
- d.Qid.Vers, b = gbit32(b)
- d.Qid.Path, b = gbit64(b)
- d.Mode, b = gbit32(b)
- d.Atime, b = gbit32(b)
- d.Mtime, b = gbit32(b)
-
- n, b := gbit64(b)
- d.Length = int64(n)
-
- var ok bool
- if d.Name, b, ok = gstring(b); !ok {
- return nil, ErrBadStat
- }
- if d.Uid, b, ok = gstring(b); !ok {
- return nil, ErrBadStat
- }
- if d.Gid, b, ok = gstring(b); !ok {
- return nil, ErrBadStat
- }
- if d.Muid, b, ok = gstring(b); !ok {
- return nil, ErrBadStat
- }
-
- return &d, nil
- }
-
- // pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
- func pbit8(b []byte, v uint8) []byte {
- b[0] = byte(v)
- return b[1:]
- }
-
- // pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
- func pbit16(b []byte, v uint16) []byte {
- b[0] = byte(v)
- b[1] = byte(v >> 8)
- return b[2:]
- }
-
- // pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
- func pbit32(b []byte, v uint32) []byte {
- b[0] = byte(v)
- b[1] = byte(v >> 8)
- b[2] = byte(v >> 16)
- b[3] = byte(v >> 24)
- return b[4:]
- }
-
- // pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
- func pbit64(b []byte, v uint64) []byte {
- b[0] = byte(v)
- b[1] = byte(v >> 8)
- b[2] = byte(v >> 16)
- b[3] = byte(v >> 24)
- b[4] = byte(v >> 32)
- b[5] = byte(v >> 40)
- b[6] = byte(v >> 48)
- b[7] = byte(v >> 56)
- return b[8:]
- }
-
- // pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
- // returning the remaining slice of b..
- func pstring(b []byte, s string) []byte {
- b = pbit16(b, uint16(len(s)))
- n := copy(b, s)
- return b[n:]
- }
-
- // gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
- func gbit8(b []byte) (uint8, []byte) {
- return uint8(b[0]), b[1:]
- }
-
- // gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
- func gbit16(b []byte) (uint16, []byte) {
- return uint16(b[0]) | uint16(b[1])<<8, b[2:]
- }
-
- // gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
- func gbit32(b []byte) (uint32, []byte) {
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
- }
-
- // gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
- func gbit64(b []byte) (uint64, []byte) {
- lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
- hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
- return uint64(lo) | uint64(hi)<<32, b[8:]
- }
-
- // gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
- // It returns the string with the remaining slice of b and a boolean. If the length is
- // greater than the number of bytes in b, the boolean will be false.
- func gstring(b []byte) (string, []byte, bool) {
- n, b := gbit16(b)
- if int(n) > len(b) {
- return "", b, false
- }
- return string(b[:n]), b[n:], true
- }
|