LEFT | RIGHT |
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 Loading... |
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 Loading... |
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 } |
LEFT | RIGHT |