Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(750)

Delta Between Two Patch Sets: src/pkg/archive/tar/reader.go

Issue 6700047: code review 6700047: archive/tar: read/write extended pax/gnu tar archives (Closed)
Left Patch Set: diff -r 39b31d81b947 https://code.google.com/p/go Created 11 years, 5 months ago
Right Patch Set: diff -r 439cb8bad388 https://code.google.com/p/go Created 11 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/archive/tar/common.go ('k') | src/pkg/archive/tar/reader_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b