@@ -117,92 +117,82 @@ func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
117
117
//
118
118
// io.EOF is returned at the end of the input.
119
119
func (tr * Reader ) Next () (* Header , error ) {
120
- var p parser
121
- var hdr * Header
122
- if tr .err == nil {
123
- tr .skipUnread ()
124
- }
125
120
if tr .err != nil {
126
- return hdr , tr .err
121
+ return nil , tr .err
127
122
}
128
- hdr = tr .readHeader ()
129
- if hdr == nil {
130
- return hdr , tr .err
131
- }
132
- // Check for PAX/GNU header.
133
- switch hdr .Typeflag {
134
- case TypeXHeader :
135
- // PAX extended header
136
- headers , err := parsePAX (tr )
137
- if err != nil {
138
- return nil , err
139
- }
140
- // We actually read the whole file,
141
- // but this skips alignment padding
142
- tr .skipUnread ()
123
+
124
+ var hdr * Header
125
+ var extHdrs map [string ]string
126
+
127
+ // Externally, Next iterates through the tar archive as if it is a series of
128
+ // files. Internally, the tar format often uses fake "files" to add meta
129
+ // data that describes the next file. These meta data "files" should not
130
+ // normally be visible to the outside. As such, this loop iterates through
131
+ // one or more "header files" until it finds a "normal file".
132
+ loop:
133
+ for {
134
+ tr .err = tr .skipUnread ()
143
135
if tr .err != nil {
144
136
return nil , tr .err
145
137
}
138
+
146
139
hdr = tr .readHeader ()
147
- if hdr = = nil {
140
+ if tr . err ! = nil {
148
141
return nil , tr .err
149
142
}
150
- mergePAX (hdr , headers )
151
143
152
- // Check for a PAX format sparse file
153
- sp , err := tr .checkForGNUSparsePAXHeaders (hdr , headers )
154
- if err != nil {
155
- tr .err = err
156
- return nil , err
157
- }
158
- if sp != nil {
159
- // Sparse files do not make sense when applied to the special header
160
- // types that never have a data section.
161
- if isHeaderOnlyType (hdr .Typeflag ) {
162
- tr .err = ErrHeader
144
+ // Check for PAX/GNU special headers and files.
145
+ switch hdr .Typeflag {
146
+ case TypeXHeader :
147
+ extHdrs , tr .err = parsePAX (tr )
148
+ if tr .err != nil {
163
149
return nil , tr .err
164
150
}
165
-
166
- // Current file is a PAX format GNU sparse file.
167
- // Set the current file reader to a sparse file reader.
168
- tr . curr , tr .err = newSparseFileReader (tr . curr , sp , hdr . Size )
151
+ continue loop // This is a meta header affecting the next header
152
+ case TypeGNULongName , TypeGNULongLink :
153
+ var realname [] byte
154
+ realname , tr .err = ioutil . ReadAll (tr )
169
155
if tr .err != nil {
170
156
return nil , tr .err
171
157
}
158
+
159
+ // Convert GNU extensions to use PAX headers.
160
+ if extHdrs == nil {
161
+ extHdrs = make (map [string ]string )
162
+ }
163
+ var p parser
164
+ switch hdr .Typeflag {
165
+ case TypeGNULongName :
166
+ extHdrs [paxPath ] = p .parseString (realname )
167
+ case TypeGNULongLink :
168
+ extHdrs [paxLinkpath ] = p .parseString (realname )
169
+ }
170
+ if p .err != nil {
171
+ tr .err = p .err
172
+ return nil , tr .err
173
+ }
174
+ continue loop // This is a meta header affecting the next header
175
+ default :
176
+ mergePAX (hdr , extHdrs )
177
+
178
+ // Check for a PAX format sparse file
179
+ sp , err := tr .checkForGNUSparsePAXHeaders (hdr , extHdrs )
180
+ if err != nil {
181
+ tr .err = err
182
+ return nil , err
183
+ }
184
+ if sp != nil {
185
+ // Current file is a PAX format GNU sparse file.
186
+ // Set the current file reader to a sparse file reader.
187
+ tr .curr , tr .err = newSparseFileReader (tr .curr , sp , hdr .Size )
188
+ if tr .err != nil {
189
+ return nil , tr .err
190
+ }
191
+ }
192
+ break loop // This is a file, so stop
172
193
}
173
- return hdr , nil
174
- case TypeGNULongName :
175
- // We have a GNU long name header. Its contents are the real file name.
176
- realname , err := ioutil .ReadAll (tr )
177
- if err != nil {
178
- return nil , err
179
- }
180
- hdr , tr .err = tr .Next ()
181
- if tr .err != nil {
182
- return nil , tr .err
183
- }
184
- hdr .Name = p .parseString (realname )
185
- if p .err != nil {
186
- return nil , p .err
187
- }
188
- return hdr , nil
189
- case TypeGNULongLink :
190
- // We have a GNU long link header.
191
- realname , err := ioutil .ReadAll (tr )
192
- if err != nil {
193
- return nil , err
194
- }
195
- hdr , tr .err = tr .Next ()
196
- if tr .err != nil {
197
- return nil , tr .err
198
- }
199
- hdr .Linkname = p .parseString (realname )
200
- if p .err != nil {
201
- return nil , p .err
202
- }
203
- return hdr , nil
204
194
}
205
- return hdr , tr . err
195
+ return hdr , nil
206
196
}
207
197
208
198
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
0 commit comments