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