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

Side by Side Diff: src/pkg/archive/tar/writer.go

Issue 6700047: code review 6700047: archive/tar: read/write extended pax/gnu tar archives (Closed)
Patch Set: diff -r 1399878c6731 https://code.google.com/p/go Created 11 years, 2 months 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:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

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