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

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

Issue 6700047: code review 6700047: archive/tar: read/write extended pax/gnu tar archives (Closed)
Left Patch Set: diff -r 439cb8bad388 https://code.google.com/p/go Created 11 years, 1 month 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/testdata/ustar.tar ('k') | src/pkg/archive/tar/writer_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 // - catch more errors (no first header, etc.) 8 // - catch more errors (no first header, etc.)
9 9
10 import ( 10 import (
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 } 106 }
107 107
108 var ( 108 var (
109 minTime = time.Unix(0, 0) 109 minTime = time.Unix(0, 0)
110 // There is room for 11 octal digits (33 bits) of mtime. 110 // There is room for 11 octal digits (33 bits) of mtime.
111 maxTime = minTime.Add((1<<33 - 1) * time.Second) 111 maxTime = minTime.Add((1<<33 - 1) * time.Second)
112 ) 112 )
113 113
114 // WriteHeader writes hdr and prepares to accept the file's contents. 114 // WriteHeader writes hdr and prepares to accept the file's contents.
115 // WriteHeader calls Flush if it is not the first header. 115 // WriteHeader calls Flush if it is not the first header.
116 // Calling afte a Close will return ErrWriteAfterClose. 116 // Calling after a Close will return ErrWriteAfterClose.
117 func (tw *Writer) WriteHeader(hdr *Header) error { 117 func (tw *Writer) WriteHeader(hdr *Header) error {
118 if tw.closed { 118 if tw.closed {
119 return ErrWriteAfterClose 119 return ErrWriteAfterClose
120 } 120 }
121 if tw.err == nil { 121 if tw.err == nil {
122 tw.Flush() 122 tw.Flush()
123 } 123 }
124 if tw.err != nil { 124 if tw.err != nil {
125 return tw.err 125 return tw.err
126 } 126 }
127 // Decide whether or not to use PAX extensions 127 // Decide whether or not to use PAX extensions
128 // TODO(shanemhansen): we might want to use PAX headers for 128 // TODO(shanemhansen): we might want to use PAX headers for
129 // subsecond time resolution, but for now let's just capture 129 // subsecond time resolution, but for now let's just capture
130 // the long name/long symlink use case. 130 // the long name/long symlink use case.
131 suffix := hdr.Name 131 suffix := hdr.Name
132 prefix := "" 132 prefix := ""
133 » if len(hdr.Name) > FileNameSize || len(hdr.Linkname) > FileNameSize { 133 » if len(hdr.Name) > fileNameSize || len(hdr.Linkname) > fileNameSize {
134 var err error 134 var err error
135 » » prefix, suffix, err = tw.splitUSTARLongName(hdr) 135 » » prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
136 // Either we were unable to pack the long name into ustar format 136 // Either we were unable to pack the long name into ustar format
137 » » // or the link name is too long, use PAX headers. 137 » » // or the link name is too long; use PAX headers.
138 » » if err == errNameTooLong || len(hdr.Linkname) > FileNameSize { 138 » » if err == errNameTooLong || len(hdr.Linkname) > fileNameSize {
139 if err := tw.writePAXHeader(hdr); err != nil { 139 if err := tw.writePAXHeader(hdr); err != nil {
140 return err 140 return err
141 } 141 }
142 } else if err != nil {
143 return err
142 } 144 }
143 } 145 }
144 tw.nb = int64(hdr.Size) 146 tw.nb = int64(hdr.Size)
145 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two 147 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
146 148
147 header := make([]byte, blockSize) 149 header := make([]byte, blockSize)
148 s := slicer(header) 150 s := slicer(header)
149 » tw.cString(s.next(FileNameSize), suffix) 151 » tw.cString(s.next(fileNameSize), suffix)
150 152
151 // Handle out of range ModTime carefully. 153 // Handle out of range ModTime carefully.
152 var modTime int64 154 var modTime int64
153 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { 155 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
154 modTime = hdr.ModTime.Unix() 156 modTime = hdr.ModTime.Unix()
155 } 157 }
156 158
157 tw.octal(s.next(8), hdr.Mode) // 100:108 159 tw.octal(s.next(8), hdr.Mode) // 100:108
158 tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 160 tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
159 tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124 161 tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
160 tw.numeric(s.next(12), hdr.Size) // 124:136 162 tw.numeric(s.next(12), hdr.Size) // 124:136
161 tw.numeric(s.next(12), modTime) // 136:148 163 tw.numeric(s.next(12), modTime) // 136:148
162 s.next(8) // chksum (148:156) 164 s.next(8) // chksum (148:156)
163 s.next(1)[0] = hdr.Typeflag // 156:157 165 s.next(1)[0] = hdr.Typeflag // 156:157
164 tw.cString(s.next(100), hdr.Linkname) // linkname (157:257) 166 tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
165 copy(s.next(8), []byte("ustar\x0000")) // 257:265 167 copy(s.next(8), []byte("ustar\x0000")) // 257:265
166 tw.cString(s.next(32), hdr.Uname) // 265:297 168 tw.cString(s.next(32), hdr.Uname) // 265:297
167 tw.cString(s.next(32), hdr.Gname) // 297:329 169 tw.cString(s.next(32), hdr.Gname) // 297:329
168 tw.numeric(s.next(8), hdr.Devmajor) // 329:337 170 tw.numeric(s.next(8), hdr.Devmajor) // 329:337
169 tw.numeric(s.next(8), hdr.Devminor) // 337:345 171 tw.numeric(s.next(8), hdr.Devminor) // 337:345
170 tw.cString(s.next(155), prefix) // 345:500 172 tw.cString(s.next(155), prefix) // 345:500
171 // Use the GNU magic instead of POSIX magic if we used any GNU extension s. 173 // Use the GNU magic instead of POSIX magic if we used any GNU extension s.
172 if tw.usedBinary { 174 if tw.usedBinary {
173 copy(header[257:265], []byte("ustar \x00")) 175 copy(header[257:265], []byte("ustar \x00"))
174 } 176 }
175 » // Use the ustar magic if we used ustar long names 177 » // Use the ustar magic if we used ustar long names.
176 if len(prefix) > 0 { 178 if len(prefix) > 0 {
177 copy(header[257:265], []byte("ustar\000")) 179 copy(header[257:265], []byte("ustar\000"))
178 } 180 }
179 181
180 // The chksum field is terminated by a NUL and a space. 182 // The chksum field is terminated by a NUL and a space.
181 // This is different from the other octal fields. 183 // This is different from the other octal fields.
182 chksum, _ := checksum(header) 184 chksum, _ := checksum(header)
183 tw.octal(header[148:155], chksum) 185 tw.octal(header[148:155], chksum)
184 header[155] = ' ' 186 header[155] = ' '
185 187
186 if tw.err != nil { 188 if tw.err != nil {
187 // problem with header; probably integer too big for a field. 189 // problem with header; probably integer too big for a field.
188 return tw.err 190 return tw.err
189 } 191 }
190 192
191 _, tw.err = tw.w.Write(header) 193 _, tw.err = tw.w.Write(header)
192 194
193 return tw.err 195 return tw.err
194 } 196 }
195 197
196 // writeUSTARLongName splits a USTAR long name hdr.Name 198 // writeUSTARLongName splits a USTAR long name hdr.Name.
197 // must be < 256 characters. errNameTooLong is returned 199 // name must be < 256 characters. errNameTooLong is returned
198 // if hdr.Name can't be split. The splitting heuristic 200 // if hdr.Name can't be split. The splitting heuristic
199 // is compatible with gnu tar. 201 // is compatible with gnu tar.
200 func (tw *Writer) splitUSTARLongName(hdr *Header) (prefix, suffix string, err er ror) { 202 func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err er ror) {
201 » length := len(hdr.Name) 203 » length := len(name)
202 » if length > FileNamePrefixSize+1 { 204 » if length > fileNamePrefixSize+1 {
203 » » length = FileNamePrefixSize + 1 205 » » length = fileNamePrefixSize + 1
204 » } else if hdr.Name[length-1] == '/' { 206 » } else if name[length-1] == '/' {
205 length-- 207 length--
206 } 208 }
207 » i := strings.LastIndex(hdr.Name, "/") 209 » i := strings.LastIndex(name[:length], "/")
208 nlen := length - i - 1 210 nlen := length - i - 1
209 » if i == 0 || nlen > FileNameSize || nlen == 0 { 211 » if i <= 0 || nlen > fileNameSize || nlen == 0 {
210 err = errNameTooLong 212 err = errNameTooLong
211 return 213 return
212 } 214 }
213 » prefix, suffix = hdr.Name[:i], hdr.Name[i+1:] 215 » prefix, suffix = name[:i], name[i+1:]
214 return 216 return
215 } 217 }
216 218
217 // writePaxHeader writes an extended pax header to the 219 // writePaxHeader writes an extended pax header to the
218 // archive. 220 // archive.
219 func (tw *Writer) writePAXHeader(hdr *Header) error { 221 func (tw *Writer) writePAXHeader(hdr *Header) error {
220 // Prepare extended header 222 // Prepare extended header
221 ext := new(Header) 223 ext := new(Header)
222 ext.Typeflag = TypeXHeader 224 ext.Typeflag = TypeXHeader
223 // Setting ModTime is required for reader parsing to 225 // Setting ModTime is required for reader parsing to
224 // succeed, and seems harmless enough. 226 // succeed, and seems harmless enough.
225 ext.ModTime = hdr.ModTime 227 ext.ModTime = hdr.ModTime
226 // The spec asks that we namespace our pseudo files 228 // The spec asks that we namespace our pseudo files
227 // with the current pid. 229 // with the current pid.
228 pid := os.Getpid() 230 pid := os.Getpid()
229 dir, file := path.Split(hdr.Name) 231 dir, file := path.Split(hdr.Name)
230 ext.Name = path.Join(dir, 232 ext.Name = path.Join(dir,
231 fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100] 233 fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100]
232 // Construct the body 234 // Construct the body
233 var buf bytes.Buffer 235 var buf bytes.Buffer
234 » if len(hdr.Name) > FileNameSize { 236 » if len(hdr.Name) > fileNameSize {
235 fmt.Fprint(&buf, paxHeader("path="+hdr.Name)) 237 fmt.Fprint(&buf, paxHeader("path="+hdr.Name))
236 } 238 }
237 » if len(hdr.Linkname) > FileNameSize { 239 » if len(hdr.Linkname) > fileNameSize {
238 fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname)) 240 fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname))
239 } 241 }
240 ext.Size = int64(len(buf.Bytes())) 242 ext.Size = int64(len(buf.Bytes()))
241 if err := tw.WriteHeader(ext); err != nil { 243 if err := tw.WriteHeader(ext); err != nil {
242 return err 244 return err
243 } 245 }
244 if _, err := tw.Write(buf.Bytes()); err != nil { 246 if _, err := tw.Write(buf.Bytes()); err != nil {
245 return err 247 return err
246 } 248 }
247 if err := tw.Flush(); err != nil { 249 if err := tw.Flush(); err != nil {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 304
303 // trailer: two zero blocks 305 // trailer: two zero blocks
304 for i := 0; i < 2; i++ { 306 for i := 0; i < 2; i++ {
305 _, tw.err = tw.w.Write(zeroBlock) 307 _, tw.err = tw.w.Write(zeroBlock)
306 if tw.err != nil { 308 if tw.err != nil {
307 break 309 break
308 } 310 }
309 } 311 }
310 return tw.err 312 return tw.err
311 } 313 }
LEFTRIGHT

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