Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package tar | 5 package tar |
6 | 6 |
7 // TODO(dsymonds): | 7 // TODO(dsymonds): |
8 // - pax extensions | 8 // - pax extensions |
9 | 9 |
10 import ( | 10 import ( |
(...skipping 10 matching lines...) Expand all Loading... | |
21 var ( | 21 var ( |
22 ErrHeader = errors.New("archive/tar: invalid tar header") | 22 ErrHeader = errors.New("archive/tar: invalid tar header") |
23 ) | 23 ) |
24 | 24 |
25 const maxNanoSecondIntSize = 9 | 25 const maxNanoSecondIntSize = 9 |
26 | 26 |
27 // A Reader provides sequential access to the contents of a tar archive. | 27 // A Reader provides sequential access to the contents of a tar archive. |
28 // A tar archive consists of a sequence of files. | 28 // A tar archive consists of a sequence of files. |
29 // The Next method advances to the next file in the archive (including the first ), | 29 // The Next method advances to the next file in the archive (including the first ), |
30 // and then it can be treated as an io.Reader to access the file's data. | 30 // and then it can be treated as an io.Reader to access the file's data. |
31 // | |
32 // Example: | |
33 // tr := tar.NewReader(r) | |
34 // for { | |
35 // hdr, err := tr.Next() | |
36 // if err == io.EOF { | |
37 // // end of tar archive | |
38 // break | |
39 // } | |
40 // if err != nil { | |
41 // // handle error | |
42 // } | |
43 // io.Copy(data, tr) | |
44 // } | |
45 type Reader struct { | 31 type Reader struct { |
46 r io.Reader | 32 r io.Reader |
47 err error | 33 err error |
48 nb int64 // number of unread bytes for current file entry | 34 nb int64 // number of unread bytes for current file entry |
49 pad int64 // amount of padding (ignored) after current file entry | 35 pad int64 // amount of padding (ignored) after current file entry |
50 } | 36 } |
51 | 37 |
52 // NewReader creates a new Reader reading from r. | 38 // NewReader creates a new Reader reading from r. |
53 func NewReader(r io.Reader) *Reader { return &Reader{r: r} } | 39 func NewReader(r io.Reader) *Reader { return &Reader{r: r} } |
54 | 40 |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
190 if err != nil { | 176 if err != nil { |
191 return time.Time{}, err | 177 return time.Time{}, err |
192 } | 178 } |
193 } | 179 } |
194 ts := time.Unix(seconds, nanoseconds) | 180 ts := time.Unix(seconds, nanoseconds) |
195 return ts, nil | 181 return ts, nil |
196 } | 182 } |
197 | 183 |
198 // parsePAX parses PAX headers. | 184 // parsePAX parses PAX headers. |
199 // If an extended header (type 'x') is invalid, ErrHeader is returned | 185 // If an extended header (type 'x') is invalid, ErrHeader is returned |
200 func parsePAX(tr io.Reader) (map[string]string, error) { | 186 func parsePAX(r io.Reader) (map[string]string, error) { |
201 » buf, err := ioutil.ReadAll(tr) | 187 » buf, err := ioutil.ReadAll(r) |
202 if err != nil { | 188 if err != nil { |
203 return nil, err | 189 return nil, err |
204 } | 190 } |
205 headers := make(map[string]string) | 191 headers := make(map[string]string) |
206 // Each record is constructed as | 192 » // Each record is constructed as |
207 // "%d %s=%s\n", length, keyword, value | 193 » // "%d %s=%s\n", length, keyword, value |
208 » for len(buf) != 0 { | 194 » for len(buf) > 0 { |
dsymonds
2012/10/31 02:44:37
for len(buf) > 0 {
shanemhansen
2012/10/31 04:26:31
Done.
| |
209 // or the header was empty to start with. | 195 // or the header was empty to start with. |
210 var sp int | 196 var sp int |
211 // The size field ends at the first space. | 197 // The size field ends at the first space. |
212 sp = bytes.IndexByte(buf, ' ') | 198 sp = bytes.IndexByte(buf, ' ') |
213 if sp == -1 { | 199 if sp == -1 { |
214 return nil, ErrHeader | 200 return nil, ErrHeader |
215 } | 201 } |
216 // Parse the first token as a decimal integer. | 202 // Parse the first token as a decimal integer. |
217 n, err := strconv.ParseInt(string(buf[:sp]), 10, 0) | 203 n, err := strconv.ParseInt(string(buf[:sp]), 10, 0) |
218 if err != nil { | 204 if err != nil { |
219 return nil, ErrHeader | 205 return nil, ErrHeader |
220 } | 206 } |
221 // Extract everything between the decimal and the n -1 on the | 207 // Extract everything between the decimal and the n -1 on the |
222 // beginning to to eat the ' ', -1 on the end to skip the newlin e. | 208 // beginning to to eat the ' ', -1 on the end to skip the newlin e. |
223 var record []byte | 209 » » var record []byte |
224 » » record, buf = buf[sp+1 : n-1], buf[n:] | 210 » » record, buf = buf[sp+1:n-1], buf[n:] |
225 // The first equals is guaranteed to mark the end of the key. | 211 // The first equals is guaranteed to mark the end of the key. |
226 // Everything else is value. | 212 // Everything else is value. |
227 eq := bytes.IndexByte(record, '=') | 213 eq := bytes.IndexByte(record, '=') |
228 if eq == -1 { | 214 if eq == -1 { |
229 return nil, ErrHeader | 215 return nil, ErrHeader |
230 } | 216 } |
231 key, value := record[:eq], record[eq+1:] | 217 » » key, value := record[:eq], record[eq+1:] |
232 headers[string(key)] = string(value) | 218 headers[string(key)] = string(value) |
233 } | 219 } |
234 return headers, nil | 220 return headers, nil |
235 } | 221 } |
236 | 222 |
237 // cString parses bytes as a NUL-terminated C-style string. | 223 // cString parses bytes as a NUL-terminated C-style string. |
238 // If a NUL byte is not found then the whole slice is returned as a string. | 224 // If a NUL byte is not found then the whole slice is returned as a string. |
239 func cString(b []byte) string { | 225 func cString(b []byte) string { |
240 n := 0 | 226 n := 0 |
241 for n < len(b) && b[n] != 0 { | 227 for n < len(b) && b[n] != 0 { |
242 n++ | 228 n++ |
243 } | 229 } |
244 return string(b[0:n]) | 230 return string(b[0:n]) |
245 } | 231 } |
246 | 232 |
247 func (tr *Reader) octal(b []byte) int64 { | 233 func (tr *Reader) octal(b []byte) int64 { |
234 // Check for binary format first. | |
235 if len(b) > 0 && b[0]&0x80 != 0 { | |
236 var x int64 | |
237 for i, c := range b { | |
238 if i == 0 { | |
239 c &= 0x7f // ignore signal bit in first byte | |
240 } | |
241 x = x<<8 | int64(c) | |
242 } | |
243 return x | |
244 } | |
245 | |
248 // Removing leading spaces. | 246 // Removing leading spaces. |
249 for len(b) > 0 && b[0] == ' ' { | 247 for len(b) > 0 && b[0] == ' ' { |
250 b = b[1:] | 248 b = b[1:] |
251 } | 249 } |
252 // Removing trailing NULs and spaces. | 250 // Removing trailing NULs and spaces. |
253 for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') { | 251 for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') { |
254 b = b[0 : len(b)-1] | 252 b = b[0 : len(b)-1] |
255 } | 253 } |
256 x, err := strconv.ParseUint(cString(b), 8, 64) | 254 x, err := strconv.ParseUint(cString(b), 8, 64) |
257 if err != nil { | 255 if err != nil { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 } | 385 } |
388 n, err = tr.r.Read(b) | 386 n, err = tr.r.Read(b) |
389 tr.nb -= int64(n) | 387 tr.nb -= int64(n) |
390 | 388 |
391 if err == io.EOF && tr.nb > 0 { | 389 if err == io.EOF && tr.nb > 0 { |
392 err = io.ErrUnexpectedEOF | 390 err = io.ErrUnexpectedEOF |
393 } | 391 } |
394 tr.err = err | 392 tr.err = err |
395 return | 393 return |
396 } | 394 } |
LEFT | RIGHT |