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" |
| 18 "strings" |
15 "time" | 19 "time" |
16 ) | 20 ) |
17 | 21 |
18 var ( | 22 var ( |
19 ErrWriteTooLong = errors.New("archive/tar: write too long") | 23 ErrWriteTooLong = errors.New("archive/tar: write too long") |
20 ErrFieldTooLong = errors.New("archive/tar: header field too long") | 24 ErrFieldTooLong = errors.New("archive/tar: header field too long") |
21 ErrWriteAfterClose = errors.New("archive/tar: write after close") | 25 ErrWriteAfterClose = errors.New("archive/tar: write after close") |
22 ) | 26 ) |
23 | 27 |
24 // A Writer provides sequential writing of a tar archive in POSIX.1 format. | 28 // A Writer provides sequential writing of a tar archive in POSIX.1 format. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 } | 108 } |
105 // Too big: use binary (big-endian). | 109 // Too big: use binary (big-endian). |
106 tw.usedBinary = true | 110 tw.usedBinary = true |
107 for i := len(b) - 1; x > 0 && i >= 0; i-- { | 111 for i := len(b) - 1; x > 0 && i >= 0; i-- { |
108 b[i] = byte(x) | 112 b[i] = byte(x) |
109 x >>= 8 | 113 x >>= 8 |
110 } | 114 } |
111 b[0] |= 0x80 // highest bit indicates binary format | 115 b[0] |= 0x80 // highest bit indicates binary format |
112 } | 116 } |
113 | 117 |
| 118 // splitName cleans s and returns a prefix and name suitable for ustar |
| 119 // prefix and name fields. ok indicates, that s is suitable for ustar. |
| 120 // If s is not suitable for ustar, s is returned as name and prefix is |
| 121 // empty. |
| 122 // The ustar prefix (155 chars) and name (100 chars) are defined to be |
| 123 // separated by a slash. That means a reader concatenates prefix and |
| 124 // name with a slash in between and therefore a writer can omit this |
| 125 // slash in both fields, which yields to names up to 256 chars. |
| 126 func splitName(s string) (prefix, name string, ok bool) { |
| 127 trailingSlash := s[len(s)-1] == '/' |
| 128 s = path.Clean(s) |
| 129 |
| 130 if len(s) > 256 { |
| 131 return "", s, false |
| 132 } |
| 133 |
| 134 // no prefix, just return s as the name. |
| 135 if trailingSlash && len(s) <= 99 { |
| 136 return "", s + "/", true |
| 137 } |
| 138 if !trailingSlash && len(s) <= 100 { |
| 139 return "", s, true |
| 140 } |
| 141 |
| 142 // determine the largest prefix in s |
| 143 // since a trailing slash will be omitted (due to definition of prefix |
| 144 // and name fields in ustar) we consider the first 156 characters, |
| 145 // instead of 155. |
| 146 max := 156 |
| 147 if len(s) < max { |
| 148 max = len(s) |
| 149 } |
| 150 i := strings.LastIndex(s[:max], "/") |
| 151 |
| 152 // s cannot be split: |
| 153 // i == -1: s has no slash, so we deal with a file or directory name >15
6 chars. |
| 154 // i == 0: s starts with a slash. that yields to an empty prefix field. |
| 155 if i <= 0 { |
| 156 return "", s, false |
| 157 } |
| 158 |
| 159 // i does not point to a trailing slash in s, because the path |
| 160 // was cleaned in the beginning. therefore determining the name |
| 161 // without bounds check is safe. |
| 162 prefix, name = s[:i], s[i+1:] |
| 163 if trailingSlash { |
| 164 name += "/" |
| 165 } |
| 166 |
| 167 // prefix can be stored in ustar, but name cannot be stored. |
| 168 if len(name) > 100 { |
| 169 return "", s, false |
| 170 } |
| 171 return prefix, name, true |
| 172 } |
| 173 |
114 var ( | 174 var ( |
115 minTime = time.Unix(0, 0) | 175 minTime = time.Unix(0, 0) |
116 // There is room for 11 octal digits (33 bits) of mtime. | 176 // There is room for 11 octal digits (33 bits) of mtime. |
117 maxTime = minTime.Add((1<<33 - 1) * time.Second) | 177 maxTime = minTime.Add((1<<33 - 1) * time.Second) |
118 ) | 178 ) |
119 | 179 |
120 // WriteHeader writes hdr and prepares to accept the file's contents. | 180 // WriteHeader writes hdr and prepares to accept the file's contents. |
121 // WriteHeader calls Flush if it is not the first header. | 181 // WriteHeader calls Flush if it is not the first header. |
122 // Calling after a Close will return ErrWriteAfterClose. | 182 // Calling after a Close will return ErrWriteAfterClose. |
123 func (tw *Writer) WriteHeader(hdr *Header) error { | 183 func (tw *Writer) WriteHeader(hdr *Header) error { |
124 if tw.closed { | 184 if tw.closed { |
125 return ErrWriteAfterClose | 185 return ErrWriteAfterClose |
126 } | 186 } |
127 if tw.err == nil { | 187 if tw.err == nil { |
128 tw.Flush() | 188 tw.Flush() |
129 } | 189 } |
130 if tw.err != nil { | 190 if tw.err != nil { |
131 return tw.err | 191 return tw.err |
132 } | 192 } |
133 | 193 » // Decide whether or not to use ustar prefix field or PAX extensions |
| 194 » // TODO(shanemhansen): we might want to use PAX headers for |
| 195 » // subsecond time resolution, but for now let's just capture |
| 196 » // the long name/long symlink use case. |
| 197 » prefix, name, ok := splitName(hdr.Name) |
| 198 » if !ok && len(name) > 100 || len(hdr.Linkname) > 100 { |
| 199 » » if err := tw.writePAXHeader(hdr); err != nil { |
| 200 » » » return err |
| 201 » » } |
| 202 » } |
134 tw.nb = int64(hdr.Size) | 203 tw.nb = int64(hdr.Size) |
135 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two | 204 tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two |
136 | 205 |
137 header := make([]byte, blockSize) | 206 header := make([]byte, blockSize) |
138 s := slicer(header) | 207 s := slicer(header) |
139 | 208 » copy(s.next(100), []byte(name)) |
140 » // TODO(dsymonds): handle names longer than 100 chars | |
141 » copy(s.next(100), []byte(hdr.Name)) | |
142 | 209 |
143 // Handle out of range ModTime carefully. | 210 // Handle out of range ModTime carefully. |
144 var modTime int64 | 211 var modTime int64 |
145 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { | 212 if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { |
146 modTime = hdr.ModTime.Unix() | 213 modTime = hdr.ModTime.Unix() |
147 } | 214 } |
148 | 215 |
149 tw.octal(s.next(8), hdr.Mode) // 100:108 | 216 tw.octal(s.next(8), hdr.Mode) // 100:108 |
150 tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 | 217 tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 |
151 tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124 | 218 tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124 |
152 tw.numeric(s.next(12), hdr.Size) // 124:136 | 219 tw.numeric(s.next(12), hdr.Size) // 124:136 |
153 tw.numeric(s.next(12), modTime) // 136:148 | 220 tw.numeric(s.next(12), modTime) // 136:148 |
154 s.next(8) // chksum (148:156) | 221 s.next(8) // chksum (148:156) |
155 s.next(1)[0] = hdr.Typeflag // 156:157 | 222 s.next(1)[0] = hdr.Typeflag // 156:157 |
156 tw.cString(s.next(100), hdr.Linkname) // linkname (157:257) | 223 tw.cString(s.next(100), hdr.Linkname) // linkname (157:257) |
157 copy(s.next(8), []byte("ustar\x0000")) // 257:265 | 224 copy(s.next(8), []byte("ustar\x0000")) // 257:265 |
158 tw.cString(s.next(32), hdr.Uname) // 265:297 | 225 tw.cString(s.next(32), hdr.Uname) // 265:297 |
159 tw.cString(s.next(32), hdr.Gname) // 297:329 | 226 tw.cString(s.next(32), hdr.Gname) // 297:329 |
160 tw.numeric(s.next(8), hdr.Devmajor) // 329:337 | 227 tw.numeric(s.next(8), hdr.Devmajor) // 329:337 |
161 tw.numeric(s.next(8), hdr.Devminor) // 337:345 | 228 tw.numeric(s.next(8), hdr.Devminor) // 337:345 |
| 229 copy(s.next(155), []byte(prefix)) // 345:500 |
162 | 230 |
163 // Use the GNU magic instead of POSIX magic if we used any GNU extension
s. | 231 // Use the GNU magic instead of POSIX magic if we used any GNU extension
s. |
164 if tw.usedBinary { | 232 if tw.usedBinary { |
165 copy(header[257:265], []byte("ustar \x00")) | 233 copy(header[257:265], []byte("ustar \x00")) |
166 } | 234 } |
167 | 235 |
168 // The chksum field is terminated by a NUL and a space. | 236 // The chksum field is terminated by a NUL and a space. |
169 // This is different from the other octal fields. | 237 // This is different from the other octal fields. |
170 chksum, _ := checksum(header) | 238 chksum, _ := checksum(header) |
171 tw.octal(header[148:155], chksum) | 239 tw.octal(header[148:155], chksum) |
172 header[155] = ' ' | 240 header[155] = ' ' |
173 | 241 |
174 if tw.err != nil { | 242 if tw.err != nil { |
175 // problem with header; probably integer too big for a field. | 243 // problem with header; probably integer too big for a field. |
176 return tw.err | 244 return tw.err |
177 } | 245 } |
178 | 246 |
179 _, tw.err = tw.w.Write(header) | 247 _, tw.err = tw.w.Write(header) |
180 | 248 |
181 return tw.err | 249 return tw.err |
182 } | 250 } |
183 | 251 |
| 252 // writePaxHeader writes an extended pax header to the |
| 253 // archive. |
| 254 func (tw *Writer) writePAXHeader(hdr *Header) error { |
| 255 // Prepare extended header |
| 256 ext := new(Header) |
| 257 ext.Typeflag = TypeXHeader |
| 258 // Setting ModTime is required for reader parsing to |
| 259 // succeed, and seems harmless enough. |
| 260 ext.ModTime = hdr.ModTime |
| 261 // The spec asks that we namespace our pseudo files |
| 262 // with the current pid. |
| 263 pid := os.Getpid() |
| 264 dir, file := path.Split(hdr.Name) |
| 265 ext.Name = path.Join(dir, |
| 266 fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100] |
| 267 // Construct the body |
| 268 var buf bytes.Buffer |
| 269 if len(hdr.Name) > 100 { |
| 270 fmt.Fprint(&buf, paxHeader("path="+hdr.Name)) |
| 271 } |
| 272 if len(hdr.Linkname) > 100 { |
| 273 fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname)) |
| 274 } |
| 275 ext.Size = int64(len(buf.Bytes())) |
| 276 if err := tw.WriteHeader(ext); err != nil { |
| 277 return err |
| 278 } |
| 279 if _, err := tw.Write(buf.Bytes()); err != nil { |
| 280 return err |
| 281 } |
| 282 if err := tw.Flush(); err != nil { |
| 283 return err |
| 284 } |
| 285 return nil |
| 286 } |
| 287 |
| 288 // paxHeader formats a single pax record, prefixing it with the appropriate leng
th |
| 289 func paxHeader(msg string) string { |
| 290 const padding = 2 // Extra padding for space and newline |
| 291 size := len(msg) + padding |
| 292 size += len(strconv.Itoa(size)) |
| 293 record := fmt.Sprintf("%d %s\n", size, msg) |
| 294 if len(record) != size { |
| 295 // Final adjustment if adding size increased |
| 296 // the number of digits in size |
| 297 size = len(record) |
| 298 record = fmt.Sprintf("%d %s\n", size, msg) |
| 299 } |
| 300 return record |
| 301 } |
| 302 |
184 // Write writes to the current entry in the tar archive. | 303 // Write writes to the current entry in the tar archive. |
185 // Write returns the error ErrWriteTooLong if more than | 304 // Write returns the error ErrWriteTooLong if more than |
186 // hdr.Size bytes are written after WriteHeader. | 305 // hdr.Size bytes are written after WriteHeader. |
187 func (tw *Writer) Write(b []byte) (n int, err error) { | 306 func (tw *Writer) Write(b []byte) (n int, err error) { |
188 if tw.closed { | 307 if tw.closed { |
189 err = ErrWriteTooLong | 308 err = ErrWriteTooLong |
190 return | 309 return |
191 } | 310 } |
192 overwrite := false | 311 overwrite := false |
193 if int64(len(b)) > tw.nb { | 312 if int64(len(b)) > tw.nb { |
(...skipping 24 matching lines...) Expand all Loading... |
218 | 337 |
219 // trailer: two zero blocks | 338 // trailer: two zero blocks |
220 for i := 0; i < 2; i++ { | 339 for i := 0; i < 2; i++ { |
221 _, tw.err = tw.w.Write(zeroBlock) | 340 _, tw.err = tw.w.Write(zeroBlock) |
222 if tw.err != nil { | 341 if tw.err != nil { |
223 break | 342 break |
224 } | 343 } |
225 } | 344 } |
226 return tw.err | 345 return tw.err |
227 } | 346 } |
OLD | NEW |