]>
Commit | Line | Data |
---|---|---|
405ca104 ILT |
1 | // Copyright 2009 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 | package os | |
6 | ||
7 | import ( | |
2fd401c8 ILT |
8 | "errors" |
9 | "io" | |
405ca104 ILT |
10 | "syscall" |
11 | ) | |
12 | ||
501699af ILT |
13 | var errShortStat = errors.New("short stat message") |
14 | var errBadStat = errors.New("bad stat message format") | |
15 | ||
af92e385 | 16 | func (file *File) readdir(n int) (fi []FileInfo, err error) { |
405ca104 ILT |
17 | // If this file has no dirinfo, create one. |
18 | if file.dirinfo == nil { | |
9ff56c95 | 19 | file.dirinfo = new(dirInfo) |
405ca104 | 20 | } |
9ff56c95 | 21 | d := file.dirinfo |
adb0401d ILT |
22 | size := n |
23 | if size <= 0 { | |
405ca104 | 24 | size = 100 |
adb0401d | 25 | n = -1 |
405ca104 | 26 | } |
9ff56c95 | 27 | result := make([]FileInfo, 0, size) // Empty with room to grow. |
adb0401d | 28 | for n != 0 { |
9ff56c95 ILT |
29 | // Refill the buffer if necessary |
30 | if d.bufp >= d.nbuf { | |
31 | d.bufp = 0 | |
2fd401c8 | 32 | var e error |
9ff56c95 | 33 | d.nbuf, e = file.Read(d.buf[:]) |
2fd401c8 | 34 | if e != nil && e != io.EOF { |
adb0401d | 35 | return result, &PathError{"readdir", file.name, e} |
9ff56c95 | 36 | } |
2fd401c8 | 37 | if e == io.EOF { |
405ca104 ILT |
38 | break |
39 | } | |
9ff56c95 | 40 | if d.nbuf < syscall.STATFIXLEN { |
501699af | 41 | return result, &PathError{"readdir", file.name, errShortStat} |
9ff56c95 | 42 | } |
405ca104 ILT |
43 | } |
44 | ||
9ff56c95 ILT |
45 | // Get a record from buffer |
46 | m, _ := gbit16(d.buf[d.bufp:]) | |
47 | m += 2 | |
48 | if m < syscall.STATFIXLEN { | |
501699af | 49 | return result, &PathError{"readdir", file.name, errShortStat} |
405ca104 | 50 | } |
4ccad563 | 51 | dir, e := unmarshalDir(d.buf[d.bufp : d.bufp+int(m)]) |
9ff56c95 | 52 | if e != nil { |
adb0401d | 53 | return result, &PathError{"readdir", file.name, e} |
405ca104 | 54 | } |
9a0e3259 | 55 | result = append(result, fileInfoFromStat(dir)) |
405ca104 | 56 | |
9ff56c95 | 57 | d.bufp += int(m) |
adb0401d | 58 | n-- |
9ff56c95 | 59 | } |
405ca104 | 60 | |
adb0401d | 61 | if n >= 0 && len(result) == 0 { |
2fd401c8 | 62 | return result, io.EOF |
405ca104 | 63 | } |
adb0401d ILT |
64 | return result, nil |
65 | } | |
405ca104 | 66 | |
af92e385 | 67 | func (file *File) readdirnames(n int) (names []string, err error) { |
adb0401d | 68 | fi, err := file.Readdir(n) |
405ca104 | 69 | names = make([]string, len(fi)) |
9ff56c95 | 70 | for i := range fi { |
9a0e3259 | 71 | names[i] = fi[i].Name() |
405ca104 | 72 | } |
405ca104 ILT |
73 | return |
74 | } | |
75 | ||
4ccad563 | 76 | type dir struct { |
405ca104 ILT |
77 | // system-modified data |
78 | Type uint16 // server type | |
79 | Dev uint32 // server subtype | |
80 | // file data | |
4ccad563 | 81 | Qid qid // unique id from server |
405ca104 ILT |
82 | Mode uint32 // permissions |
83 | Atime uint32 // last read time | |
84 | Mtime uint32 // last write time | |
85 | Length uint64 // file length | |
86 | Name string // last element of path | |
87 | Uid string // owner name | |
88 | Gid string // group name | |
89 | Muid string // last modifier name | |
90 | } | |
91 | ||
4ccad563 | 92 | type qid struct { |
405ca104 ILT |
93 | Path uint64 // the file server's unique identification for the file |
94 | Vers uint32 // version number for given Path | |
95 | Type uint8 // the type of the file (syscall.QTDIR for example) | |
96 | } | |
97 | ||
4ccad563 | 98 | var nullDir = dir{ |
405ca104 ILT |
99 | ^uint16(0), |
100 | ^uint32(0), | |
4ccad563 | 101 | qid{^uint64(0), ^uint32(0), ^uint8(0)}, |
405ca104 ILT |
102 | ^uint32(0), |
103 | ^uint32(0), | |
104 | ^uint32(0), | |
105 | ^uint64(0), | |
106 | "", | |
107 | "", | |
108 | "", | |
109 | "", | |
110 | } | |
111 | ||
112 | // Null assigns members of d with special "don't care" values indicating | |
113 | // they should not be written by syscall.Wstat. | |
4ccad563 | 114 | func (d *dir) Null() { |
405ca104 ILT |
115 | *d = nullDir |
116 | } | |
117 | ||
118 | // pdir appends a 9P Stat message based on the contents of Dir d to a byte slice b. | |
4ccad563 | 119 | func pdir(b []byte, d *dir) []byte { |
405ca104 ILT |
120 | n := len(b) |
121 | b = pbit16(b, 0) // length, filled in later | |
122 | b = pbit16(b, d.Type) | |
123 | b = pbit32(b, d.Dev) | |
124 | b = pqid(b, d.Qid) | |
125 | b = pbit32(b, d.Mode) | |
126 | b = pbit32(b, d.Atime) | |
127 | b = pbit32(b, d.Mtime) | |
128 | b = pbit64(b, d.Length) | |
129 | b = pstring(b, d.Name) | |
130 | b = pstring(b, d.Uid) | |
131 | b = pstring(b, d.Gid) | |
132 | b = pstring(b, d.Muid) | |
133 | pbit16(b[0:n], uint16(len(b)-(n+2))) | |
134 | return b | |
135 | } | |
136 | ||
4ccad563 ILT |
137 | // unmarshalDir reads a 9P Stat message from a 9P protocol message stored in b, |
138 | // returning the corresponding dir struct. | |
139 | func unmarshalDir(b []byte) (d *dir, err error) { | |
405ca104 ILT |
140 | n := uint16(0) |
141 | n, b = gbit16(b) | |
142 | ||
143 | if int(n) != len(b) { | |
501699af | 144 | return nil, errBadStat |
405ca104 ILT |
145 | } |
146 | ||
4ccad563 | 147 | d = new(dir) |
405ca104 ILT |
148 | d.Type, b = gbit16(b) |
149 | d.Dev, b = gbit32(b) | |
150 | d.Qid, b = gqid(b) | |
151 | d.Mode, b = gbit32(b) | |
152 | d.Atime, b = gbit32(b) | |
153 | d.Mtime, b = gbit32(b) | |
154 | d.Length, b = gbit64(b) | |
155 | d.Name, b = gstring(b) | |
156 | d.Uid, b = gstring(b) | |
157 | d.Gid, b = gstring(b) | |
158 | d.Muid, b = gstring(b) | |
159 | ||
160 | if len(b) != 0 { | |
501699af | 161 | return nil, errBadStat |
405ca104 ILT |
162 | } |
163 | ||
164 | return d, nil | |
165 | } | |
166 | ||
adb0401d | 167 | // gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b, |
4ccad563 ILT |
168 | // returning the corresponding qid struct and the remaining slice of b. |
169 | func gqid(b []byte) (qid, []byte) { | |
170 | var q qid | |
405ca104 ILT |
171 | q.Path, b = gbit64(b) |
172 | q.Vers, b = gbit32(b) | |
173 | q.Type, b = gbit8(b) | |
174 | return q, b | |
175 | } | |
176 | ||
4ccad563 ILT |
177 | // pqid appends a qid struct q to a 9P message b. |
178 | func pqid(b []byte, q qid) []byte { | |
405ca104 ILT |
179 | b = pbit64(b, q.Path) |
180 | b = pbit32(b, q.Vers) | |
181 | b = pbit8(b, q.Type) | |
182 | return b | |
183 | } | |
184 | ||
adb0401d | 185 | // gbit8 reads a byte-sized numeric value from a 9P protocol message stored in b, |
405ca104 ILT |
186 | // returning the value and the remaining slice of b. |
187 | func gbit8(b []byte) (uint8, []byte) { | |
188 | return uint8(b[0]), b[1:] | |
189 | } | |
190 | ||
adb0401d | 191 | // gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b, |
405ca104 ILT |
192 | // returning the value and the remaining slice of b. |
193 | func gbit16(b []byte) (uint16, []byte) { | |
194 | return uint16(b[0]) | uint16(b[1])<<8, b[2:] | |
195 | } | |
196 | ||
adb0401d | 197 | // gbit32 reads a 32-bit numeric value from a 9P protocol message stored in b, |
405ca104 ILT |
198 | // returning the value and the remaining slice of b. |
199 | func gbit32(b []byte) (uint32, []byte) { | |
200 | return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] | |
201 | } | |
202 | ||
adb0401d | 203 | // gbit64 reads a 64-bit numeric value from a 9P protocol message stored in b, |
405ca104 ILT |
204 | // returning the value and the remaining slice of b. |
205 | func gbit64(b []byte) (uint64, []byte) { | |
206 | lo, b := gbit32(b) | |
207 | hi, b := gbit32(b) | |
208 | return uint64(hi)<<32 | uint64(lo), b | |
209 | } | |
210 | ||
adb0401d | 211 | // gstring reads a string from a 9P protocol message stored in b, |
405ca104 ILT |
212 | // returning the value as a Go string and the remaining slice of b. |
213 | func gstring(b []byte) (string, []byte) { | |
214 | n, b := gbit16(b) | |
215 | return string(b[0:n]), b[n:] | |
216 | } | |
217 | ||
218 | // pbit8 appends a byte-sized numeric value x to a 9P message b. | |
219 | func pbit8(b []byte, x uint8) []byte { | |
220 | n := len(b) | |
221 | if n+1 > cap(b) { | |
222 | nb := make([]byte, n, 100+2*cap(b)) | |
223 | copy(nb, b) | |
224 | b = nb | |
225 | } | |
226 | b = b[0 : n+1] | |
227 | b[n] = x | |
228 | return b | |
229 | } | |
230 | ||
231 | // pbit16 appends a 16-bit numeric value x to a 9P message b. | |
232 | func pbit16(b []byte, x uint16) []byte { | |
233 | n := len(b) | |
234 | if n+2 > cap(b) { | |
235 | nb := make([]byte, n, 100+2*cap(b)) | |
236 | copy(nb, b) | |
237 | b = nb | |
238 | } | |
239 | b = b[0 : n+2] | |
240 | b[n] = byte(x) | |
241 | b[n+1] = byte(x >> 8) | |
242 | return b | |
243 | } | |
244 | ||
245 | // pbit32 appends a 32-bit numeric value x to a 9P message b. | |
246 | func pbit32(b []byte, x uint32) []byte { | |
247 | n := len(b) | |
248 | if n+4 > cap(b) { | |
249 | nb := make([]byte, n, 100+2*cap(b)) | |
250 | copy(nb, b) | |
251 | b = nb | |
252 | } | |
253 | b = b[0 : n+4] | |
254 | b[n] = byte(x) | |
255 | b[n+1] = byte(x >> 8) | |
256 | b[n+2] = byte(x >> 16) | |
257 | b[n+3] = byte(x >> 24) | |
258 | return b | |
259 | } | |
260 | ||
261 | // pbit64 appends a 64-bit numeric value x to a 9P message b. | |
262 | func pbit64(b []byte, x uint64) []byte { | |
263 | b = pbit32(b, uint32(x)) | |
264 | b = pbit32(b, uint32(x>>32)) | |
265 | return b | |
266 | } | |
267 | ||
268 | // pstring appends a Go string s to a 9P message b. | |
269 | func pstring(b []byte, s string) []byte { | |
270 | if len(s) >= 1<<16 { | |
2fd401c8 | 271 | panic(errors.New("string too long")) |
405ca104 ILT |
272 | } |
273 | b = pbit16(b, uint16(len(s))) | |
d8f41257 | 274 | b = append(b, s...) |
405ca104 ILT |
275 | return b |
276 | } |