dir_plan9.go

  1// Copyright 2012 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5// Plan 9 directory marshalling. See intro(5).
  6
  7package plan9
  8
  9import "errors"
 10
 11var (
 12	ErrShortStat = errors.New("stat buffer too short")
 13	ErrBadStat   = errors.New("malformed stat buffer")
 14	ErrBadName   = errors.New("bad character in file name")
 15)
 16
 17// A Qid represents a 9P server's unique identification for a file.
 18type Qid struct {
 19	Path uint64 // the file server's unique identification for the file
 20	Vers uint32 // version number for given Path
 21	Type uint8  // the type of the file (plan9.QTDIR for example)
 22}
 23
 24// A Dir contains the metadata for a file.
 25type Dir struct {
 26	// system-modified data
 27	Type uint16 // server type
 28	Dev  uint32 // server subtype
 29
 30	// file data
 31	Qid    Qid    // unique id from server
 32	Mode   uint32 // permissions
 33	Atime  uint32 // last read time
 34	Mtime  uint32 // last write time
 35	Length int64  // file length
 36	Name   string // last element of path
 37	Uid    string // owner name
 38	Gid    string // group name
 39	Muid   string // last modifier name
 40}
 41
 42var nullDir = Dir{
 43	Type: ^uint16(0),
 44	Dev:  ^uint32(0),
 45	Qid: Qid{
 46		Path: ^uint64(0),
 47		Vers: ^uint32(0),
 48		Type: ^uint8(0),
 49	},
 50	Mode:   ^uint32(0),
 51	Atime:  ^uint32(0),
 52	Mtime:  ^uint32(0),
 53	Length: ^int64(0),
 54}
 55
 56// Null assigns special "don't touch" values to members of d to
 57// avoid modifying them during plan9.Wstat.
 58func (d *Dir) Null() { *d = nullDir }
 59
 60// Marshal encodes a 9P stat message corresponding to d into b
 61//
 62// If there isn't enough space in b for a stat message, ErrShortStat is returned.
 63func (d *Dir) Marshal(b []byte) (n int, err error) {
 64	n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
 65	if n > len(b) {
 66		return n, ErrShortStat
 67	}
 68
 69	for _, c := range d.Name {
 70		if c == '/' {
 71			return n, ErrBadName
 72		}
 73	}
 74
 75	b = pbit16(b, uint16(n)-2)
 76	b = pbit16(b, d.Type)
 77	b = pbit32(b, d.Dev)
 78	b = pbit8(b, d.Qid.Type)
 79	b = pbit32(b, d.Qid.Vers)
 80	b = pbit64(b, d.Qid.Path)
 81	b = pbit32(b, d.Mode)
 82	b = pbit32(b, d.Atime)
 83	b = pbit32(b, d.Mtime)
 84	b = pbit64(b, uint64(d.Length))
 85	b = pstring(b, d.Name)
 86	b = pstring(b, d.Uid)
 87	b = pstring(b, d.Gid)
 88	b = pstring(b, d.Muid)
 89
 90	return n, nil
 91}
 92
 93// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
 94//
 95// If b is too small to hold a valid stat message, ErrShortStat is returned.
 96//
 97// If the stat message itself is invalid, ErrBadStat is returned.
 98func UnmarshalDir(b []byte) (*Dir, error) {
 99	if len(b) < STATFIXLEN {
100		return nil, ErrShortStat
101	}
102	size, buf := gbit16(b)
103	if len(b) != int(size)+2 {
104		return nil, ErrBadStat
105	}
106	b = buf
107
108	var d Dir
109	d.Type, b = gbit16(b)
110	d.Dev, b = gbit32(b)
111	d.Qid.Type, b = gbit8(b)
112	d.Qid.Vers, b = gbit32(b)
113	d.Qid.Path, b = gbit64(b)
114	d.Mode, b = gbit32(b)
115	d.Atime, b = gbit32(b)
116	d.Mtime, b = gbit32(b)
117
118	n, b := gbit64(b)
119	d.Length = int64(n)
120
121	var ok bool
122	if d.Name, b, ok = gstring(b); !ok {
123		return nil, ErrBadStat
124	}
125	if d.Uid, b, ok = gstring(b); !ok {
126		return nil, ErrBadStat
127	}
128	if d.Gid, b, ok = gstring(b); !ok {
129		return nil, ErrBadStat
130	}
131	if d.Muid, b, ok = gstring(b); !ok {
132		return nil, ErrBadStat
133	}
134
135	return &d, nil
136}
137
138// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
139func pbit8(b []byte, v uint8) []byte {
140	b[0] = byte(v)
141	return b[1:]
142}
143
144// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
145func pbit16(b []byte, v uint16) []byte {
146	b[0] = byte(v)
147	b[1] = byte(v >> 8)
148	return b[2:]
149}
150
151// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
152func pbit32(b []byte, v uint32) []byte {
153	b[0] = byte(v)
154	b[1] = byte(v >> 8)
155	b[2] = byte(v >> 16)
156	b[3] = byte(v >> 24)
157	return b[4:]
158}
159
160// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
161func pbit64(b []byte, v uint64) []byte {
162	b[0] = byte(v)
163	b[1] = byte(v >> 8)
164	b[2] = byte(v >> 16)
165	b[3] = byte(v >> 24)
166	b[4] = byte(v >> 32)
167	b[5] = byte(v >> 40)
168	b[6] = byte(v >> 48)
169	b[7] = byte(v >> 56)
170	return b[8:]
171}
172
173// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
174// returning the remaining slice of b..
175func pstring(b []byte, s string) []byte {
176	b = pbit16(b, uint16(len(s)))
177	n := copy(b, s)
178	return b[n:]
179}
180
181// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
182func gbit8(b []byte) (uint8, []byte) {
183	return uint8(b[0]), b[1:]
184}
185
186// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
187func gbit16(b []byte) (uint16, []byte) {
188	return uint16(b[0]) | uint16(b[1])<<8, b[2:]
189}
190
191// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
192func gbit32(b []byte) (uint32, []byte) {
193	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
194}
195
196// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
197func gbit64(b []byte) (uint64, []byte) {
198	lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
199	hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
200	return uint64(lo) | uint64(hi)<<32, b[8:]
201}
202
203// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
204// It returns the string with the remaining slice of b and a boolean. If the length is
205// greater than the number of bytes in b, the boolean will be false.
206func gstring(b []byte) (string, []byte, bool) {
207	n, b := gbit16(b)
208	if int(n) > len(b) {
209		return "", b, false
210	}
211	return string(b[:n]), b[n:], true
212}