OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The LUCI Authors. All rights reserved. | |
2 // Use of this source code is governed under the Apache License, Version 2.0 | |
3 // that can be found in the LICENSE file. | |
4 | |
5 // Read an ar file with BSD formatted file names. | |
6 | |
7 package ar | |
8 | |
9 import ( | |
10 "bytes" | |
11 "errors" | |
12 "fmt" | |
13 "io" | |
14 "os" | |
15 "time" | |
16 ) | |
17 | |
18 type arFileInfo struct { | |
19 // os.FileInfo parts | |
20 name string | |
21 size int64 | |
22 mode uint32 | |
23 modtime uint64 | |
24 // Extra parts | |
25 uid int | |
26 gid int | |
27 } | |
28 | |
29 // os.FileInfo interface | |
30 func (fi *arFileInfo) Name() string { return fi.name } | |
31 func (fi *arFileInfo) Size() int64 { return fi.size } | |
32 func (fi *arFileInfo) Mode() os.FileMode { return os.FileMode(fi.mode) } | |
33 func (fi *arFileInfo) ModTime() time.Time { return time.Unix(int64(fi.modtime), 0) } | |
34 func (fi *arFileInfo) IsDir() bool { return fi.Mode().IsDir() } | |
35 func (fi *arFileInfo) Sys() interface{} { return fi } | |
36 | |
37 // Extra | |
38 func (fi *arFileInfo) UserId() int { return fi.uid } | |
39 func (fi *arFileInfo) GroupId() int { return fi.gid } | |
40 | |
41 var ( | |
42 ErrHeader = errors.New("archive/ar: invalid ar header") | |
43 ) | |
44 | |
45 type ReaderStage uint | |
M-A Ruel
2016/06/08 20:25:31
this one doesn't look like it needs to be exported
mithro
2016/06/10 10:09:52
Done.
| |
46 | |
47 const ( | |
48 READ_HEADER ReaderStage = iota | |
49 READ_BODY | |
50 READ_CLOSED | |
51 ) | |
52 | |
53 type Reader struct { | |
54 stage ReaderStage | |
55 r io.Reader | |
56 bytesrequired int64 | |
57 needspadding bool | |
58 } | |
59 | |
60 func NewReader(r io.Reader) (*Reader, error) { | |
61 reader := Reader{r: r, bytesrequired: 0, needspadding: false} | |
M-A Ruel
2016/06/08 20:25:31
reader := &Reader{r: r}
mithro
2016/06/10 10:09:53
Done.
| |
62 err := reader.checkBytes("header", []byte("!<arch>\n")) | |
63 if err != nil { | |
64 return nil, err | |
65 } else { | |
M-A Ruel
2016/06/08 20:25:31
remove the else, just close the bracket.
mithro
2016/06/10 10:09:52
Done.
| |
66 return &reader, nil | |
67 } | |
68 } | |
69 | |
70 func (ar *Reader) checkBytes(name string, str []byte) error { | |
M-A Ruel
2016/06/08 20:25:31
the name: prefix can be added at call site.
mithro
2016/06/10 10:09:52
I originally had it that way, but it seems to be c
| |
71 buffer := make([]byte, len(str)) | |
72 | |
73 count, err := io.ReadFull(ar.r, buffer) | |
74 if err != nil { | |
75 return err | |
76 } | |
77 | |
78 if count != len(buffer) { | |
M-A Ruel
2016/06/08 20:25:31
it's a guarantee of ReadFull()
mithro
2016/06/10 10:09:53
Looks like you are right, I thought that if io.Rea
| |
79 return errors.New(fmt.Sprintf("%s: Not enough data read (only %d , needed %d)", name, count, len(buffer))) | |
80 } | |
81 | |
82 if bytes.Equal(str, buffer) { | |
83 return nil | |
84 } else { | |
85 return errors.New(fmt.Sprintf("%s: error in bytes (wanted: %v go t: %v)", name, buffer, str)) | |
86 } | |
87 } | |
88 | |
89 func (ar *Reader) Close() error { | |
90 switch ar.stage { | |
91 case READ_HEADER: | |
92 // Good | |
93 case READ_BODY: | |
94 return errors.New("Usage error, reading a file.") | |
95 case READ_CLOSED: | |
96 return errors.New("Usage error, archive already closed.") | |
97 default: | |
98 panic(fmt.Sprintf("Unknown reader mode: %d", ar.stage)) | |
99 } | |
100 //ar.r.Close() | |
M-A Ruel
2016/06/08 20:25:31
remove, generally it's up to the caller to do it.
mithro
2016/06/10 10:09:53
Done.
| |
101 ar.stage = READ_CLOSED | |
102 return nil | |
103 } | |
104 | |
105 func (ar *Reader) readBytes(numbytes int64) error { | |
M-A Ruel
2016/06/08 20:25:31
I don't understand this function
mithro
2016/06/10 10:09:52
This function is called after reading a number of
M-A Ruel
2016/06/10 17:51:09
That's https://golang.org/pkg/io/#WriterTo
| |
106 if numbytes > ar.bytesrequired { | |
107 return errors.New(fmt.Sprintf("To much data read! Needed %d, got %d", ar.bytesrequired, numbytes)) | |
108 } | |
109 | |
110 ar.bytesrequired -= numbytes | |
111 if ar.bytesrequired != 0 { | |
112 return nil | |
113 } | |
114 | |
115 // Padding to 16bit boundary | |
116 if ar.needspadding { | |
117 err := ar.checkBytes("padding", []byte("\n")) | |
118 if err != nil { | |
119 return err | |
120 } | |
121 ar.needspadding = false | |
122 } | |
123 ar.stage = READ_HEADER | |
124 return nil | |
125 } | |
126 | |
127 // Check you can write bytes to the ar at this moment. | |
M-A Ruel
2016/06/08 20:25:31
s/write/read/
mithro
2016/06/10 10:09:53
Done. (Plus changed the name slightly.)
| |
128 func (ar *Reader) checkRead() error { | |
129 switch ar.stage { | |
130 case READ_HEADER: | |
131 return errors.New("Usage error, need to read header first.") | |
M-A Ruel
2016/06/08 20:25:31
all errors should start with a lower case
mithro
2016/06/10 10:09:53
Done.
| |
132 // Good | |
133 case READ_BODY: | |
134 return nil | |
135 case READ_CLOSED: | |
136 return errors.New("Usage error, archive closed.") | |
137 default: | |
138 panic(fmt.Sprintf("Unknown reader mode: %d", ar.stage)) | |
139 } | |
140 } | |
141 | |
142 // Check we have finished writing bytes | |
143 func (ar *Reader) checkFinished() error { | |
144 if ar.bytesrequired != 0 { | |
145 return errors.New(fmt.Sprintf("Didn't read enough bytes %d still needed!", ar.bytesrequired)) | |
146 } | |
147 return nil | |
148 } | |
149 | |
150 func (ar *Reader) readPartial(name string, data []byte) error { | |
151 err := ar.checkRead() | |
M-A Ruel
2016/06/08 20:25:31
inline the function since it's only used once.
mithro
2016/06/10 10:09:52
Done.
| |
152 if err != nil { | |
153 return err | |
154 } | |
155 | |
156 datalen := int64(len(data)) | |
157 if datalen > ar.bytesrequired { | |
158 return errors.New(fmt.Sprintf("To much data! Wanted %d, but had %d", ar.bytesrequired, datalen)) | |
159 } | |
160 | |
161 count, err := io.ReadFull(ar.r, data) | |
162 ar.readBytes(int64(count)) | |
163 return nil | |
164 } | |
165 | |
166 func (ar *Reader) readHeaderBytes(name string, bytes int, formatstr string) (int 64, error) { | |
167 data := make([]byte, bytes) | |
168 _, err := io.ReadFull(ar.r, data) | |
169 if err != nil { | |
170 return -1, err | |
171 } | |
172 | |
173 var output int64 = 0 | |
174 _, err = fmt.Sscanf(string(data), formatstr, &output) | |
175 if err != nil { | |
176 return -1, err | |
177 } | |
178 | |
179 if output <= 0 { | |
180 return -1, errors.New(fmt.Sprintf("%s: bad value %d", name, outp ut)) | |
181 } | |
182 return output, nil | |
183 } | |
184 | |
185 func (ar *Reader) readHeader() (*arFileInfo, error) { | |
186 switch ar.stage { | |
187 case READ_HEADER: | |
188 // Good | |
189 case READ_BODY: | |
190 return nil, errors.New("Usage error, already writing a file.") | |
191 case READ_CLOSED: | |
192 return nil, errors.New("Usage error, archive closed.") | |
193 default: | |
194 panic(fmt.Sprintf("Unknown writer mode: %d", ar.stage)) | |
195 } | |
196 | |
197 var fi arFileInfo | |
198 | |
199 // File name length prefixed with '#1/' (BSD variant), 16 bytes | |
200 namelen, err := ar.readHeaderBytes("filename length", 16, "#1/%13d") | |
201 if err != nil { | |
202 return nil, err | |
203 } | |
204 | |
205 // Modtime, 12 bytes | |
206 modtime, err := ar.readHeaderBytes("modtime", 12, "%12d") | |
207 if err != nil { | |
208 return nil, err | |
209 } | |
210 fi.modtime = uint64(modtime) | |
211 | |
212 // Owner ID, 6 bytes | |
213 ownerid, err := ar.readHeaderBytes("ownerid", 6, "%6d") | |
214 if err != nil { | |
215 return nil, err | |
216 } | |
217 fi.uid = int(ownerid) | |
218 | |
219 // Group ID, 6 bytes | |
220 groupid, err := ar.readHeaderBytes("groupid", 6, "%6d") | |
221 if err != nil { | |
222 return nil, err | |
223 } | |
224 fi.gid = int(groupid) | |
225 | |
226 // File mode, 8 bytes | |
227 filemod, err := ar.readHeaderBytes("groupid", 8, "%8o") | |
228 if err != nil { | |
229 return nil, err | |
230 } | |
231 fi.mode = uint32(filemod) | |
232 | |
233 // File size, 10 bytes | |
234 size, err := ar.readHeaderBytes("datasize", 10, "%10d") | |
235 if err != nil { | |
236 return nil, err | |
237 } | |
238 fi.size = size - namelen | |
239 | |
240 ar.stage = READ_BODY | |
241 ar.bytesrequired = size | |
242 ar.needspadding = (ar.bytesrequired%2 != 0) | |
243 | |
244 // File magic, 2 bytes | |
245 err = ar.checkBytes("filemagic", []byte("\x60\n")) | |
246 if err != nil { | |
247 return nil, err | |
248 } | |
249 | |
250 // Filename - BSD variant | |
251 filename := make([]byte, namelen) | |
252 err = ar.readPartial("filename", filename) | |
253 if err != nil { | |
254 return nil, err | |
255 } | |
256 fi.name = string(filename) | |
257 | |
258 return &fi, nil | |
259 } | |
260 | |
261 func (ar *Reader) Read(b []byte) (n int, err error) { | |
262 err = ar.readPartial("data", b) | |
263 if err != nil { | |
264 return -1, err | |
265 } | |
266 err = ar.checkFinished() | |
267 if err != nil { | |
268 return -1, err | |
269 } | |
270 return len(b), nil | |
271 } | |
272 func (ar *Reader) Next() (*arFileInfo, error) { | |
M-A Ruel
2016/06/08 20:25:31
don't return a private type on a public function;
mithro
2016/06/10 10:09:52
Done.
| |
273 return ar.readHeader() | |
274 } | |
OLD | NEW |