@@ -30,10 +30,14 @@ const maxNanoSecondIntSize = 9
30
30
// and then it can be treated as an io.Reader to access the file's data.
31
31
type Reader struct {
32
32
r io.Reader
33
- err error
34
33
pad int64 // amount of padding (ignored) after current file entry
35
34
curr numBytesReader // reader for current file entry
36
35
blk block // buffer to use as temporary local storage
36
+
37
+ // err is a persistent error.
38
+ // It is only the responsibility of every exported method of Reader to
39
+ // ensure that this error is sticky.
40
+ err error
37
41
}
38
42
39
43
type parser struct {
@@ -108,9 +112,12 @@ func (tr *Reader) Next() (*Header, error) {
108
112
if tr .err != nil {
109
113
return nil , tr .err
110
114
}
115
+ hdr , err := tr .next ()
116
+ tr .err = err
117
+ return hdr , err
118
+ }
111
119
112
- var hdr * Header
113
- var rawHdr * block
120
+ func (tr * Reader ) next () (* Header , error ) {
114
121
var extHdrs map [string ]string
115
122
116
123
// Externally, Next iterates through the tar archive as if it is a series of
@@ -120,34 +127,29 @@ func (tr *Reader) Next() (*Header, error) {
120
127
// one or more "header files" until it finds a "normal file".
121
128
loop:
122
129
for {
123
- tr .err = tr .skipUnread ()
124
- if tr .err != nil {
125
- return nil , tr .err
130
+ if err := tr .skipUnread (); err != nil {
131
+ return nil , err
126
132
}
127
-
128
- hdr , rawHdr = tr .readHeader ()
129
- if tr .err != nil {
130
- return nil , tr .err
133
+ hdr , rawHdr , err := tr .readHeader ()
134
+ if err != nil {
135
+ return nil , err
131
136
}
132
-
133
- tr .err = tr .handleRegularFile (hdr )
134
- if tr .err != nil {
135
- return nil , tr .err
137
+ if err := tr .handleRegularFile (hdr ); err != nil {
138
+ return nil , err
136
139
}
137
140
138
141
// Check for PAX/GNU special headers and files.
139
142
switch hdr .Typeflag {
140
143
case TypeXHeader :
141
- extHdrs , tr . err = parsePAX (tr )
142
- if tr . err != nil {
143
- return nil , tr . err
144
+ extHdrs , err = parsePAX (tr )
145
+ if err != nil {
146
+ return nil , err
144
147
}
145
148
continue loop // This is a meta header affecting the next header
146
149
case TypeGNULongName , TypeGNULongLink :
147
- var realname []byte
148
- realname , tr .err = ioutil .ReadAll (tr )
149
- if tr .err != nil {
150
- return nil , tr .err
150
+ realname , err := ioutil .ReadAll (tr )
151
+ if err != nil {
152
+ return nil , err
151
153
}
152
154
153
155
// Convert GNU extensions to use PAX headers.
@@ -162,30 +164,28 @@ loop:
162
164
extHdrs [paxLinkpath ] = p .parseString (realname )
163
165
}
164
166
if p .err != nil {
165
- tr .err = p .err
166
- return nil , tr .err
167
+ return nil , p .err
167
168
}
168
169
continue loop // This is a meta header affecting the next header
169
170
default :
170
171
// The old GNU sparse format is handled here since it is technically
171
172
// just a regular file with additional attributes.
172
173
173
- // TODO(dsnet): We should handle errors reported by mergePAX.
174
- mergePAX (hdr , extHdrs )
174
+ if err := mergePAX (hdr , extHdrs ); err != nil {
175
+ return nil , err
176
+ }
175
177
176
178
// TODO(dsnet): The extended headers may have updated the size.
177
179
// Thus, we must setup the regFileReader again here.
178
180
//
179
181
// See golang.org/issue/15573
180
182
181
- tr .err = tr .handleSparseFile (hdr , rawHdr , extHdrs )
182
- if tr .err != nil {
183
- return nil , tr .err
183
+ if err := tr .handleSparseFile (hdr , rawHdr , extHdrs ); err != nil {
184
+ return nil , err
184
185
}
185
- break loop // This is a file, so stop
186
+ return hdr , nil // This is a file, so stop
186
187
}
187
188
}
188
- return hdr , nil
189
189
}
190
190
191
191
// handleRegularFile sets up the current file reader and padding such that it
@@ -217,9 +217,9 @@ func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block, extHdrs map[strin
217
217
return p .err
218
218
}
219
219
220
- sp = tr .readOldGNUSparseMap (rawHdr )
221
- if tr . err != nil {
222
- return tr . err
220
+ sp , err = tr .readOldGNUSparseMap (rawHdr )
221
+ if err != nil {
222
+ return err
223
223
}
224
224
} else {
225
225
sp , err = tr .checkForGNUSparsePAXHeaders (hdr , extHdrs )
@@ -302,53 +302,32 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
302
302
// in the header struct overwrite those found in the header
303
303
// struct with higher precision or longer values. Esp. useful
304
304
// for name and linkname fields.
305
- func mergePAX (hdr * Header , headers map [string ]string ) error {
305
+ func mergePAX (hdr * Header , headers map [string ]string ) (err error ) {
306
+ var id64 int64
306
307
for k , v := range headers {
307
308
switch k {
308
309
case paxPath :
309
310
hdr .Name = v
310
311
case paxLinkpath :
311
312
hdr .Linkname = v
312
- case paxGname :
313
- hdr .Gname = v
314
313
case paxUname :
315
314
hdr .Uname = v
315
+ case paxGname :
316
+ hdr .Gname = v
316
317
case paxUid :
317
- uid , err := strconv .ParseInt (v , 10 , 0 )
318
- if err != nil {
319
- return err
320
- }
321
- hdr .Uid = int (uid )
318
+ id64 , err = strconv .ParseInt (v , 10 , 0 )
319
+ hdr .Uid = int (id64 )
322
320
case paxGid :
323
- gid , err := strconv .ParseInt (v , 10 , 0 )
324
- if err != nil {
325
- return err
326
- }
327
- hdr .Gid = int (gid )
321
+ id64 , err = strconv .ParseInt (v , 10 , 0 )
322
+ hdr .Gid = int (id64 )
328
323
case paxAtime :
329
- t , err := parsePAXTime (v )
330
- if err != nil {
331
- return err
332
- }
333
- hdr .AccessTime = t
324
+ hdr .AccessTime , err = parsePAXTime (v )
334
325
case paxMtime :
335
- t , err := parsePAXTime (v )
336
- if err != nil {
337
- return err
338
- }
339
- hdr .ModTime = t
326
+ hdr .ModTime , err = parsePAXTime (v )
340
327
case paxCtime :
341
- t , err := parsePAXTime (v )
342
- if err != nil {
343
- return err
344
- }
345
- hdr .ChangeTime = t
328
+ hdr .ChangeTime , err = parsePAXTime (v )
346
329
case paxSize :
347
- size , err := strconv .ParseInt (v , 10 , 0 )
348
- if err != nil {
349
- return err
350
- }
351
- hdr .Size = size
330
+ hdr .Size , err = strconv .ParseInt (v , 10 , 0 )
352
331
default :
353
332
if strings .HasPrefix (k , paxXattr ) {
354
333
if hdr .Xattrs == nil {
@@ -357,6 +336,9 @@ func mergePAX(hdr *Header, headers map[string]string) error {
357
336
hdr .Xattrs [k [len (paxXattr ):]] = v
358
337
}
359
338
}
339
+ if err != nil {
340
+ return ErrHeader
341
+ }
360
342
}
361
343
return nil
362
344
}
@@ -569,19 +551,17 @@ func (tr *Reader) skipUnread() error {
569
551
// Seek seems supported, so perform the real Seek.
570
552
pos2 , err := sr .Seek (dataSkip - 1 , io .SeekCurrent )
571
553
if err != nil {
572
- tr .err = err
573
- return tr .err
554
+ return err
574
555
}
575
556
seekSkipped = pos2 - pos1
576
557
}
577
558
}
578
559
579
- var copySkipped int64 // Number of bytes skipped via CopyN
580
- copySkipped , tr .err = io .CopyN (ioutil .Discard , tr .r , totalSkip - seekSkipped )
581
- if tr .err == io .EOF && seekSkipped + copySkipped < dataSkip {
582
- tr .err = io .ErrUnexpectedEOF
560
+ copySkipped , err := io .CopyN (ioutil .Discard , tr .r , totalSkip - seekSkipped )
561
+ if err == io .EOF && seekSkipped + copySkipped < dataSkip {
562
+ err = io .ErrUnexpectedEOF
583
563
}
584
- return tr . err
564
+ return err
585
565
}
586
566
587
567
// readHeader reads the next block header and assumes that the underlying reader
@@ -592,29 +572,25 @@ func (tr *Reader) skipUnread() error {
592
572
// * Exactly 0 bytes are read and EOF is hit.
593
573
// * Exactly 1 block of zeros is read and EOF is hit.
594
574
// * At least 2 blocks of zeros are read.
595
- func (tr * Reader ) readHeader () (* Header , * block ) {
596
- if _ , tr .err = io .ReadFull (tr .r , tr .blk [:]); tr .err != nil {
597
- return nil , nil // io.EOF is okay here
598
- }
599
-
575
+ func (tr * Reader ) readHeader () (* Header , * block , error ) {
600
576
// Two blocks of zero bytes marks the end of the archive.
577
+ if _ , err := io .ReadFull (tr .r , tr .blk [:]); err != nil {
578
+ return nil , nil , err // EOF is okay here; exactly 0 bytes read
579
+ }
601
580
if bytes .Equal (tr .blk [:], zeroBlock [:]) {
602
- if _ , tr . err = io .ReadFull (tr .r , tr .blk [:]); tr . err != nil {
603
- return nil , nil // io. EOF is okay here
581
+ if _ , err : = io .ReadFull (tr .r , tr .blk [:]); err != nil {
582
+ return nil , nil , err // EOF is okay here; exactly 1 block of zeros read
604
583
}
605
584
if bytes .Equal (tr .blk [:], zeroBlock [:]) {
606
- tr .err = io .EOF
607
- } else {
608
- tr .err = ErrHeader // zero block and then non-zero block
585
+ return nil , nil , io .EOF // normal EOF; exactly 2 block of zeros read
609
586
}
610
- return nil , nil
587
+ return nil , nil , ErrHeader // Zero block and then non-zero block
611
588
}
612
589
613
590
// Verify the header matches a known format.
614
591
format := tr .blk .GetFormat ()
615
592
if format == formatUnknown {
616
- tr .err = ErrHeader
617
- return nil , nil
593
+ return nil , nil , ErrHeader
618
594
}
619
595
620
596
var p parser
@@ -658,28 +634,21 @@ func (tr *Reader) readHeader() (*Header, *block) {
658
634
hdr .Name = prefix + "/" + hdr .Name
659
635
}
660
636
}
661
-
662
- // Check for parsing errors.
663
- if p .err != nil {
664
- tr .err = p .err
665
- return nil , nil
666
- }
667
- return hdr , & tr .blk
637
+ return hdr , & tr .blk , p .err
668
638
}
669
639
670
640
// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
671
641
// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
672
642
// then one or more extension headers are used to store the rest of the sparse map.
673
- func (tr * Reader ) readOldGNUSparseMap (blk * block ) []sparseEntry {
643
+ func (tr * Reader ) readOldGNUSparseMap (blk * block ) ( []sparseEntry , error ) {
674
644
var p parser
675
645
var s sparseArray = blk .GNU ().Sparse ()
676
646
var sp = make ([]sparseEntry , 0 , s .MaxEntries ())
677
647
for i := 0 ; i < s .MaxEntries (); i ++ {
678
648
offset := p .parseOctal (s .Entry (i ).Offset ())
679
649
numBytes := p .parseOctal (s .Entry (i ).NumBytes ())
680
650
if p .err != nil {
681
- tr .err = p .err
682
- return nil
651
+ return nil , p .err
683
652
}
684
653
if offset == 0 && numBytes == 0 {
685
654
break
@@ -690,25 +659,24 @@ func (tr *Reader) readOldGNUSparseMap(blk *block) []sparseEntry {
690
659
for s .IsExtended ()[0 ] > 0 {
691
660
// There are more entries. Read an extension header and parse its entries.
692
661
var blk block
693
- if _ , tr . err = io .ReadFull (tr .r , blk [:]); tr . err != nil {
694
- return nil
662
+ if _ , err : = io .ReadFull (tr .r , blk [:]); err != nil {
663
+ return nil , err
695
664
}
696
665
s = blk .Sparse ()
697
666
698
667
for i := 0 ; i < s .MaxEntries (); i ++ {
699
668
offset := p .parseOctal (s .Entry (i ).Offset ())
700
669
numBytes := p .parseOctal (s .Entry (i ).NumBytes ())
701
670
if p .err != nil {
702
- tr .err = p .err
703
- return nil
671
+ return nil , p .err
704
672
}
705
673
if offset == 0 && numBytes == 0 {
706
674
break
707
675
}
708
676
sp = append (sp , sparseEntry {offset : offset , numBytes : numBytes })
709
677
}
710
678
}
711
- return sp
679
+ return sp , nil
712
680
}
713
681
714
682
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
@@ -836,19 +804,19 @@ func (tr *Reader) numBytes() int64 {
836
804
// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
837
805
// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
838
806
// the Header.Size claims.
839
- func (tr * Reader ) Read (b []byte ) (n int , err error ) {
807
+ func (tr * Reader ) Read (b []byte ) (int , error ) {
840
808
if tr .err != nil {
841
809
return 0 , tr .err
842
810
}
843
811
if tr .curr == nil {
844
812
return 0 , io .EOF
845
813
}
846
814
847
- n , err = tr .curr .Read (b )
815
+ n , err : = tr .curr .Read (b )
848
816
if err != nil && err != io .EOF {
849
817
tr .err = err
850
818
}
851
- return
819
+ return n , err
852
820
}
853
821
854
822
func (rfr * regFileReader ) Read (b []byte ) (n int , err error ) {
0 commit comments