Left: | ||
Right: |
OLD | NEW |
---|---|
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 // - catch more errors (no first header, etc.) | 8 // - catch more errors (no first header, etc.) |
9 | 9 |
10 import ( | 10 import ( |
11 "bytes" | |
11 "errors" | 12 "errors" |
12 "fmt" | 13 "fmt" |
13 "io" | 14 "io" |
15 "os" | |
16 "path" | |
14 "strconv" | 17 "strconv" |
15 "time" | 18 "time" |
16 ) | 19 ) |
17 | 20 |
18 var ( | 21 var ( |
19 ErrWriteTooLong = errors.New("archive/tar: write too long") | 22 ErrWriteTooLong = errors.New("archive/tar: write too long") |
20 ErrFieldTooLong = errors.New("archive/tar: header field too long") | 23 ErrFieldTooLong = errors.New("archive/tar: header field too long") |
21 ErrWriteAfterClose = errors.New("archive/tar: write after close") | 24 ErrWriteAfterClose = errors.New("archive/tar: write after close") |
22 ) | 25 ) |
23 | 26 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
123 func (tw *Writer) WriteHeader(hdr *Header) error { | 126 func (tw *Writer) WriteHeader(hdr *Header) error { |
124 if tw.closed { | 127 if tw.closed { |
125 return ErrWriteAfterClose | 128 return ErrWriteAfterClose |
126 } | 129 } |
127 if tw.err == nil { | 130 if tw.err == nil { |
128 tw.Flush() | 131 tw.Flush() |
129 } | 132 } |
130 if tw.err != nil { | 133 if tw.err != nil { |
131 return tw.err | 134 return tw.err |
132 } | 135 } |
133 | 136 » // Decide whether or not to use PAX extensions |
rsc
2013/01/09 19:43:49
Please don't use PAX headers for names that are on
shanemhansen
2013/01/11 01:52:42
I'm not super familiar with bsd. I've downloaded f
| |
137 » // TODO(shanemhansen): we might want to use PAX headers for | |
138 » // subsecond time resolution, but for now let's just capture | |
139 » // the long name/long symlink use case. | |
140 » if len(hdr.Name) > 100 || len(hdr.Linkname) > 100 { | |
141 » » if err := tw.writePAXHeader(hdr); err != nil { | |
142 » » » return err | |
143 » » } | |
144 » } | |
134 tw.nb = int64(hdr.Size) | 145 tw.nb = int64(hdr.Size) |
135 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two | 146 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two |
136 | 147 |
137 header := make([]byte, blockSize) | 148 header := make([]byte, blockSize) |
138 s := slicer(header) | 149 s := slicer(header) |
139 | |
140 // TODO(dsymonds): handle names longer than 100 chars | |
141 copy(s.next(100), []byte(hdr.Name)) | 150 copy(s.next(100), []byte(hdr.Name)) |
142 | 151 |
143 // Handle out of range ModTime carefully. | 152 // Handle out of range ModTime carefully. |
144 var modTime int64 | 153 var modTime int64 |
145 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { | 154 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { |
146 modTime = hdr.ModTime.Unix() | 155 modTime = hdr.ModTime.Unix() |
147 } | 156 } |
148 | 157 |
149 tw.octal(s.next(8), hdr.Mode) // 100:108 | 158 tw.octal(s.next(8), hdr.Mode) // 100:108 |
150 tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 | 159 tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 |
(...skipping 23 matching lines...) Expand all Loading... | |
174 if tw.err != nil { | 183 if tw.err != nil { |
175 // problem with header; probably integer too big for a field. | 184 // problem with header; probably integer too big for a field. |
176 return tw.err | 185 return tw.err |
177 } | 186 } |
178 | 187 |
179 _, tw.err = tw.w.Write(header) | 188 _, tw.err = tw.w.Write(header) |
180 | 189 |
181 return tw.err | 190 return tw.err |
182 } | 191 } |
183 | 192 |
193 // writePaxHeader writes an extended pax header to the | |
194 // archive. | |
195 func (tw *Writer) writePAXHeader(hdr *Header) error { | |
196 // Prepare extended header | |
197 ext := new(Header) | |
198 ext.Typeflag = TypeXHeader | |
199 // Setting ModTime is required for reader parsing to | |
200 // succeed, and seems harmless enough. | |
201 ext.ModTime = hdr.ModTime | |
202 // The spec asks that we namespace our pseudo files | |
203 // with the current pid. | |
204 pid := os.Getpid() | |
205 dir, file := path.Split(hdr.Name) | |
206 ext.Name = path.Join(dir, | |
207 fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100] | |
208 // Construct the body | |
209 var buf bytes.Buffer | |
210 if len(hdr.Name) > 100 { | |
211 fmt.Fprint(&buf, paxHeader("path="+hdr.Name)) | |
212 } | |
213 if len(hdr.Linkname) > 100 { | |
214 fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname)) | |
215 } | |
216 ext.Size = int64(len(buf.Bytes())) | |
217 if err := tw.WriteHeader(ext); err != nil { | |
218 return err | |
219 } | |
220 if _, err := tw.Write(buf.Bytes()); err != nil { | |
221 return err | |
222 } | |
223 if err := tw.Flush(); err != nil { | |
224 return err | |
225 } | |
226 return nil | |
227 } | |
228 | |
229 // paxHeader formats a single pax record, prefixing it with the appropriate leng th | |
230 func paxHeader(msg string) string { | |
231 const padding = 2 // Extra padding for space and newline | |
232 size := len(msg) + padding | |
233 size += len(strconv.Itoa(size)) | |
234 record := fmt.Sprintf("%d %s\n", size, msg) | |
235 if len(record) != size { | |
236 // Final adjustment if adding size increased | |
237 // the number of digits in size | |
238 size = len(record) | |
239 record = fmt.Sprintf("%d %s\n", size, msg) | |
240 } | |
241 return record | |
242 } | |
243 | |
184 // Write writes to the current entry in the tar archive. | 244 // Write writes to the current entry in the tar archive. |
185 // Write returns the error ErrWriteTooLong if more than | 245 // Write returns the error ErrWriteTooLong if more than |
186 // hdr.Size bytes are written after WriteHeader. | 246 // hdr.Size bytes are written after WriteHeader. |
187 func (tw *Writer) Write(b []byte) (n int, err error) { | 247 func (tw *Writer) Write(b []byte) (n int, err error) { |
188 if tw.closed { | 248 if tw.closed { |
189 err = ErrWriteTooLong | 249 err = ErrWriteTooLong |
190 return | 250 return |
191 } | 251 } |
192 overwrite := false | 252 overwrite := false |
193 if int64(len(b)) > tw.nb { | 253 if int64(len(b)) > tw.nb { |
(...skipping 24 matching lines...) Expand all Loading... | |
218 | 278 |
219 // trailer: two zero blocks | 279 // trailer: two zero blocks |
220 for i := 0; i < 2; i++ { | 280 for i := 0; i < 2; i++ { |
221 _, tw.err = tw.w.Write(zeroBlock) | 281 _, tw.err = tw.w.Write(zeroBlock) |
222 if tw.err != nil { | 282 if tw.err != nil { |
223 break | 283 break |
224 } | 284 } |
225 } | 285 } |
226 return tw.err | 286 return tw.err |
227 } | 287 } |
OLD | NEW |