1
2
3
4
5
6
7 package plan9
8
9 import "errors"
10
11 var (
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
18 type Qid struct {
19 Path uint64
20 Vers uint32
21 Type uint8
22 }
23
24
25 type Dir struct {
26
27 Type uint16
28 Dev uint32
29
30
31 Qid Qid
32 Mode uint32
33 Atime uint32
34 Mtime uint32
35 Length int64
36 Name string
37 Uid string
38 Gid string
39 Muid string
40 }
41
42 var 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
57
58 func (d *Dir) Null() { *d = nullDir }
59
60
61
62
63 func (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
94
95
96
97
98 func 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
139 func pbit8(b []byte, v uint8) []byte {
140 b[0] = byte(v)
141 return b[1:]
142 }
143
144
145 func pbit16(b []byte, v uint16) []byte {
146 b[0] = byte(v)
147 b[1] = byte(v >> 8)
148 return b[2:]
149 }
150
151
152 func 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
161 func 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
174
175 func 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
182 func gbit8(b []byte) (uint8, []byte) {
183 return uint8(b[0]), b[1:]
184 }
185
186
187 func gbit16(b []byte) (uint16, []byte) {
188 return uint16(b[0]) | uint16(b[1])<<8, b[2:]
189 }
190
191
192 func 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
197 func 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
204
205
206 func 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 }
213
View as plain text