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 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 if pos == -1 { | 155 if pos == -1 { |
170 seconds, err = strconv.ParseInt(t, 10, 0) | 156 seconds, err = strconv.ParseInt(t, 10, 0) |
171 if err != nil { | 157 if err != nil { |
172 return time.Time{}, err | 158 return time.Time{}, err |
173 } | 159 } |
174 } else { | 160 } else { |
175 seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0) | 161 seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0) |
176 if err != nil { | 162 if err != nil { |
177 return time.Time{}, err | 163 return time.Time{}, err |
178 } | 164 } |
179 nano_buf := string(buf[pos+1:]) | 165 nano_buf := string(buf[pos+1:]) |
rsc
2013/01/09 19:43:49
nanoBuf
shanemhansen
2013/01/11 01:52:42
Done.
| |
180 // Pad as needed before converting to a decimal. | 166 // Pad as needed before converting to a decimal. |
181 // For example .030 -> .030000000 -> 30000000 nanoseconds | 167 // For example .030 -> .030000000 -> 30000000 nanoseconds |
182 if len(nano_buf) < maxNanoSecondIntSize { | 168 if len(nano_buf) < maxNanoSecondIntSize { |
183 // Right pad | 169 // Right pad |
184 nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len (nano_buf)) | 170 nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len (nano_buf)) |
185 } else if len(nano_buf) > maxNanoSecondIntSize { | 171 } else if len(nano_buf) > maxNanoSecondIntSize { |
186 // Right truncate | 172 // Right truncate |
187 nano_buf = nano_buf[:maxNanoSecondIntSize] | 173 nano_buf = nano_buf[:maxNanoSecondIntSize] |
188 } | 174 } |
189 nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0) | 175 nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0) |
(...skipping 13 matching lines...) Expand all Loading... | |
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 { |
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 { |
rsc
2013/01/09 19:43:49
sp < 0
shanemhansen
2013/01/11 01:52:42
Done.
| |
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 { |
rsc
2013/01/09 19:43:49
eq < 0
shanemhansen
2013/01/11 01:52:42
Done.
| |
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. |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
399 } | 385 } |
400 n, err = tr.r.Read(b) | 386 n, err = tr.r.Read(b) |
401 tr.nb -= int64(n) | 387 tr.nb -= int64(n) |
402 | 388 |
403 if err == io.EOF && tr.nb > 0 { | 389 if err == io.EOF && tr.nb > 0 { |
404 err = io.ErrUnexpectedEOF | 390 err = io.ErrUnexpectedEOF |
405 } | 391 } |
406 tr.err = err | 392 tr.err = err |
407 return | 393 return |
408 } | 394 } |
LEFT | RIGHT |