github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/archive/tar/writer.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package tar 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "path" 12 "sort" 13 "strings" 14 "time" 15 ) 16 17 // Writer provides sequential writing of a tar archive. 18 // Write.WriteHeader begins a new file with the provided Header, 19 // and then Writer can be treated as an io.Writer to supply that file's data. 20 type Writer struct { 21 w io.Writer 22 pad int64 // Amount of padding to write after current file entry 23 curr fileWriter // Writer for current file entry 24 hdr Header // Shallow copy of Header that is safe for mutations 25 blk block // Buffer to use as temporary local storage 26 27 // err is a persistent error. 28 // It is only the responsibility of every exported method of Writer to 29 // ensure that this error is sticky. 30 err error 31 } 32 33 // NewWriter creates a new Writer writing to w. 34 func NewWriter(w io.Writer) *Writer { 35 return &Writer{w: w, curr: ®FileWriter{w, 0}} 36 } 37 38 type fileWriter interface { 39 io.Writer 40 fileState 41 42 ReadFrom(io.Reader) (int64, error) 43 } 44 45 // Flush finishes writing the current file's block padding. 46 // The current file must be fully written before Flush can be called. 47 // 48 // This is unnecessary as the next call to WriteHeader or Close 49 // will implicitly flush out the file's padding. 50 func (tw *Writer) Flush() error { 51 if tw.err != nil { 52 return tw.err 53 } 54 if nb := tw.curr.LogicalRemaining(); nb > 0 { 55 return fmt.Errorf("archive/tar: missed writing %d bytes", nb) 56 } 57 if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil { 58 return tw.err 59 } 60 tw.pad = 0 61 return nil 62 } 63 64 // WriteHeader writes hdr and prepares to accept the file's contents. 65 // The Header.Size determines how many bytes can be written for the next file. 66 // If the current file is not fully written, then this returns an error. 67 // This implicitly flushes any padding necessary before writing the header. 68 func (tw *Writer) WriteHeader(hdr *Header) error { 69 if err := tw.Flush(); err != nil { 70 return err 71 } 72 tw.hdr = *hdr // Shallow copy of Header 73 74 // Avoid usage of the legacy TypeRegA flag, and automatically promote 75 // it to use TypeReg or TypeDir. 76 if tw.hdr.Typeflag == TypeRegA { 77 if strings.HasSuffix(tw.hdr.Name, "/") { 78 tw.hdr.Typeflag = TypeDir 79 } else { 80 tw.hdr.Typeflag = TypeReg 81 } 82 } 83 84 // Round ModTime and ignore AccessTime and ChangeTime unless 85 // the format is explicitly chosen. 86 // This ensures nominal usage of WriteHeader (without specifying the format) 87 // does not always result in the PAX format being chosen, which 88 // causes a 1KiB increase to every header. 89 if tw.hdr.Format == FormatUnknown { 90 tw.hdr.ModTime = tw.hdr.ModTime.Round(time.Second) 91 tw.hdr.AccessTime = time.Time{} 92 tw.hdr.ChangeTime = time.Time{} 93 } 94 95 allowedFormats, paxHdrs, err := tw.hdr.allowedFormats() 96 switch { 97 case allowedFormats.has(FormatUSTAR): 98 tw.err = tw.writeUSTARHeader(&tw.hdr) 99 return tw.err 100 case allowedFormats.has(FormatPAX): 101 tw.err = tw.writePAXHeader(&tw.hdr, paxHdrs) 102 return tw.err 103 case allowedFormats.has(FormatGNU): 104 tw.err = tw.writeGNUHeader(&tw.hdr) 105 return tw.err 106 default: 107 return err // Non-fatal error 108 } 109 } 110 111 func (tw *Writer) writeUSTARHeader(hdr *Header) error { 112 // Check if we can use USTAR prefix/suffix splitting. 113 var namePrefix string 114 if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok { 115 namePrefix, hdr.Name = prefix, suffix 116 } 117 118 // Pack the main header. 119 var f formatter 120 blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal) 121 f.formatString(blk.USTAR().Prefix(), namePrefix) 122 blk.SetFormat(FormatUSTAR) 123 if f.err != nil { 124 return f.err // Should never happen since header is validated 125 } 126 return tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag) 127 } 128 129 func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { 130 realName, realSize := hdr.Name, hdr.Size 131 132 // TODO(dsnet): Re-enable this when adding sparse support. 133 // See https://golang.org/issue/22735 134 /* 135 // Handle sparse files. 136 var spd sparseDatas 137 var spb []byte 138 if len(hdr.SparseHoles) > 0 { 139 sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map 140 sph = alignSparseEntries(sph, hdr.Size) 141 spd = invertSparseEntries(sph, hdr.Size) 142 143 // Format the sparse map. 144 hdr.Size = 0 // Replace with encoded size 145 spb = append(strconv.AppendInt(spb, int64(len(spd)), 10), '\n') 146 for _, s := range spd { 147 hdr.Size += s.Length 148 spb = append(strconv.AppendInt(spb, s.Offset, 10), '\n') 149 spb = append(strconv.AppendInt(spb, s.Length, 10), '\n') 150 } 151 pad := blockPadding(int64(len(spb))) 152 spb = append(spb, zeroBlock[:pad]...) 153 hdr.Size += int64(len(spb)) // Accounts for encoded sparse map 154 155 // Add and modify appropriate PAX records. 156 dir, file := path.Split(realName) 157 hdr.Name = path.Join(dir, "GNUSparseFile.0", file) 158 paxHdrs[paxGNUSparseMajor] = "1" 159 paxHdrs[paxGNUSparseMinor] = "0" 160 paxHdrs[paxGNUSparseName] = realName 161 paxHdrs[paxGNUSparseRealSize] = strconv.FormatInt(realSize, 10) 162 paxHdrs[paxSize] = strconv.FormatInt(hdr.Size, 10) 163 delete(paxHdrs, paxPath) // Recorded by paxGNUSparseName 164 } 165 */ 166 _ = realSize 167 168 // Write PAX records to the output. 169 isGlobal := hdr.Typeflag == TypeXGlobalHeader 170 if len(paxHdrs) > 0 || isGlobal { 171 // Sort keys for deterministic ordering. 172 var keys []string 173 for k := range paxHdrs { 174 keys = append(keys, k) 175 } 176 sort.Strings(keys) 177 178 // Write each record to a buffer. 179 var buf bytes.Buffer 180 for _, k := range keys { 181 rec, err := formatPAXRecord(k, paxHdrs[k]) 182 if err != nil { 183 return err 184 } 185 buf.WriteString(rec) 186 } 187 188 // Write the extended header file. 189 var name string 190 var flag byte 191 if isGlobal { 192 name = realName 193 if name == "" { 194 name = "GlobalHead.0.0" 195 } 196 flag = TypeXGlobalHeader 197 } else { 198 dir, file := path.Split(realName) 199 name = path.Join(dir, "PaxHeaders.0", file) 200 flag = TypeXHeader 201 } 202 data := buf.String() 203 if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { 204 return err // Global headers return here 205 } 206 } 207 208 // Pack the main header. 209 var f formatter // Ignore errors since they are expected 210 fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) } 211 blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal) 212 blk.SetFormat(FormatPAX) 213 if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil { 214 return err 215 } 216 217 // TODO(dsnet): Re-enable this when adding sparse support. 218 // See https://golang.org/issue/22735 219 /* 220 // Write the sparse map and setup the sparse writer if necessary. 221 if len(spd) > 0 { 222 // Use tw.curr since the sparse map is accounted for in hdr.Size. 223 if _, err := tw.curr.Write(spb); err != nil { 224 return err 225 } 226 tw.curr = &sparseFileWriter{tw.curr, spd, 0} 227 } 228 */ 229 return nil 230 } 231 232 func (tw *Writer) writeGNUHeader(hdr *Header) error { 233 // Use long-link files if Name or Linkname exceeds the field size. 234 const longName = "././@LongLink" 235 if len(hdr.Name) > nameSize { 236 data := hdr.Name + "\x00" 237 if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil { 238 return err 239 } 240 } 241 if len(hdr.Linkname) > nameSize { 242 data := hdr.Linkname + "\x00" 243 if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil { 244 return err 245 } 246 } 247 248 // Pack the main header. 249 var f formatter // Ignore errors since they are expected 250 var spd sparseDatas 251 var spb []byte 252 blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric) 253 if !hdr.AccessTime.IsZero() { 254 f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix()) 255 } 256 if !hdr.ChangeTime.IsZero() { 257 f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix()) 258 } 259 // TODO(dsnet): Re-enable this when adding sparse support. 260 // See https://golang.org/issue/22735 261 /* 262 if hdr.Typeflag == TypeGNUSparse { 263 sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map 264 sph = alignSparseEntries(sph, hdr.Size) 265 spd = invertSparseEntries(sph, hdr.Size) 266 267 // Format the sparse map. 268 formatSPD := func(sp sparseDatas, sa sparseArray) sparseDatas { 269 for i := 0; len(sp) > 0 && i < sa.MaxEntries(); i++ { 270 f.formatNumeric(sa.Entry(i).Offset(), sp[0].Offset) 271 f.formatNumeric(sa.Entry(i).Length(), sp[0].Length) 272 sp = sp[1:] 273 } 274 if len(sp) > 0 { 275 sa.IsExtended()[0] = 1 276 } 277 return sp 278 } 279 sp2 := formatSPD(spd, blk.GNU().Sparse()) 280 for len(sp2) > 0 { 281 var spHdr block 282 sp2 = formatSPD(sp2, spHdr.Sparse()) 283 spb = append(spb, spHdr[:]...) 284 } 285 286 // Update size fields in the header block. 287 realSize := hdr.Size 288 hdr.Size = 0 // Encoded size; does not account for encoded sparse map 289 for _, s := range spd { 290 hdr.Size += s.Length 291 } 292 copy(blk.V7().Size(), zeroBlock[:]) // Reset field 293 f.formatNumeric(blk.V7().Size(), hdr.Size) 294 f.formatNumeric(blk.GNU().RealSize(), realSize) 295 } 296 */ 297 blk.SetFormat(FormatGNU) 298 if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil { 299 return err 300 } 301 302 // Write the extended sparse map and setup the sparse writer if necessary. 303 if len(spd) > 0 { 304 // Use tw.w since the sparse map is not accounted for in hdr.Size. 305 if _, err := tw.w.Write(spb); err != nil { 306 return err 307 } 308 tw.curr = &sparseFileWriter{tw.curr, spd, 0} 309 } 310 return nil 311 } 312 313 type ( 314 stringFormatter func([]byte, string) 315 numberFormatter func([]byte, int64) 316 ) 317 318 // templateV7Plus fills out the V7 fields of a block using values from hdr. 319 // It also fills out fields (uname, gname, devmajor, devminor) that are 320 // shared in the USTAR, PAX, and GNU formats using the provided formatters. 321 // 322 // The block returned is only valid until the next call to 323 // templateV7Plus or writeRawFile. 324 func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block { 325 tw.blk.Reset() 326 327 modTime := hdr.ModTime 328 if modTime.IsZero() { 329 modTime = time.Unix(0, 0) 330 } 331 332 v7 := tw.blk.V7() 333 v7.TypeFlag()[0] = hdr.Typeflag 334 fmtStr(v7.Name(), hdr.Name) 335 fmtStr(v7.LinkName(), hdr.Linkname) 336 fmtNum(v7.Mode(), hdr.Mode) 337 fmtNum(v7.UID(), int64(hdr.Uid)) 338 fmtNum(v7.GID(), int64(hdr.Gid)) 339 fmtNum(v7.Size(), hdr.Size) 340 fmtNum(v7.ModTime(), modTime.Unix()) 341 342 ustar := tw.blk.USTAR() 343 fmtStr(ustar.UserName(), hdr.Uname) 344 fmtStr(ustar.GroupName(), hdr.Gname) 345 fmtNum(ustar.DevMajor(), hdr.Devmajor) 346 fmtNum(ustar.DevMinor(), hdr.Devminor) 347 348 return &tw.blk 349 } 350 351 // writeRawFile writes a minimal file with the given name and flag type. 352 // It uses format to encode the header format and will write data as the body. 353 // It uses default values for all of the other fields (as BSD and GNU tar does). 354 func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error { 355 tw.blk.Reset() 356 357 // Best effort for the filename. 358 name = toASCII(name) 359 if len(name) > nameSize { 360 name = name[:nameSize] 361 } 362 name = strings.TrimRight(name, "/") 363 364 var f formatter 365 v7 := tw.blk.V7() 366 v7.TypeFlag()[0] = flag 367 f.formatString(v7.Name(), name) 368 f.formatOctal(v7.Mode(), 0) 369 f.formatOctal(v7.UID(), 0) 370 f.formatOctal(v7.GID(), 0) 371 f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB 372 f.formatOctal(v7.ModTime(), 0) 373 tw.blk.SetFormat(format) 374 if f.err != nil { 375 return f.err // Only occurs if size condition is violated 376 } 377 378 // Write the header and data. 379 if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil { 380 return err 381 } 382 _, err := io.WriteString(tw, data) 383 return err 384 } 385 386 // writeRawHeader writes the value of blk, regardless of its value. 387 // It sets up the Writer such that it can accept a file of the given size. 388 // If the flag is a special header-only flag, then the size is treated as zero. 389 func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error { 390 if err := tw.Flush(); err != nil { 391 return err 392 } 393 if _, err := tw.w.Write(blk[:]); err != nil { 394 return err 395 } 396 if isHeaderOnlyType(flag) { 397 size = 0 398 } 399 tw.curr = ®FileWriter{tw.w, size} 400 tw.pad = blockPadding(size) 401 return nil 402 } 403 404 // splitUSTARPath splits a path according to USTAR prefix and suffix rules. 405 // If the path is not splittable, then it will return ("", "", false). 406 func splitUSTARPath(name string) (prefix, suffix string, ok bool) { 407 length := len(name) 408 if length <= nameSize || !isASCII(name) { 409 return "", "", false 410 } else if length > prefixSize+1 { 411 length = prefixSize + 1 412 } else if name[length-1] == '/' { 413 length-- 414 } 415 416 i := strings.LastIndex(name[:length], "/") 417 nlen := len(name) - i - 1 // nlen is length of suffix 418 plen := i // plen is length of prefix 419 if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize { 420 return "", "", false 421 } 422 return name[:i], name[i+1:], true 423 } 424 425 // Write writes to the current file in the tar archive. 426 // Write returns the error ErrWriteTooLong if more than 427 // Header.Size bytes are written after WriteHeader. 428 // 429 // Calling Write on special types like TypeLink, TypeSymlink, TypeChar, 430 // TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless 431 // of what the Header.Size claims. 432 func (tw *Writer) Write(b []byte) (int, error) { 433 if tw.err != nil { 434 return 0, tw.err 435 } 436 n, err := tw.curr.Write(b) 437 if err != nil && err != ErrWriteTooLong { 438 tw.err = err 439 } 440 return n, err 441 } 442 443 // readFrom populates the content of the current file by reading from r. 444 // The bytes read must match the number of remaining bytes in the current file. 445 // 446 // If the current file is sparse and r is an io.ReadSeeker, 447 // then readFrom uses Seek to skip past holes defined in Header.SparseHoles, 448 // assuming that skipped regions are all NULs. 449 // This always reads the last byte to ensure r is the right size. 450 // 451 // TODO(dsnet): Re-export this when adding sparse file support. 452 // See https://golang.org/issue/22735 453 func (tw *Writer) readFrom(r io.Reader) (int64, error) { 454 if tw.err != nil { 455 return 0, tw.err 456 } 457 n, err := tw.curr.ReadFrom(r) 458 if err != nil && err != ErrWriteTooLong { 459 tw.err = err 460 } 461 return n, err 462 } 463 464 // Close closes the tar archive by flushing the padding, and writing the footer. 465 // If the current file (from a prior call to WriteHeader) is not fully written, 466 // then this returns an error. 467 func (tw *Writer) Close() error { 468 if tw.err == ErrWriteAfterClose { 469 return nil 470 } 471 if tw.err != nil { 472 return tw.err 473 } 474 475 // Trailer: two zero blocks. 476 err := tw.Flush() 477 for i := 0; i < 2 && err == nil; i++ { 478 _, err = tw.w.Write(zeroBlock[:]) 479 } 480 481 // Ensure all future actions are invalid. 482 tw.err = ErrWriteAfterClose 483 return err // Report IO errors 484 } 485 486 // regFileWriter is a fileWriter for writing data to a regular file entry. 487 type regFileWriter struct { 488 w io.Writer // Underlying Writer 489 nb int64 // Number of remaining bytes to write 490 } 491 492 func (fw *regFileWriter) Write(b []byte) (n int, err error) { 493 overwrite := int64(len(b)) > fw.nb 494 if overwrite { 495 b = b[:fw.nb] 496 } 497 if len(b) > 0 { 498 n, err = fw.w.Write(b) 499 fw.nb -= int64(n) 500 } 501 switch { 502 case err != nil: 503 return n, err 504 case overwrite: 505 return n, ErrWriteTooLong 506 default: 507 return n, nil 508 } 509 } 510 511 func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) { 512 return io.Copy(struct{ io.Writer }{fw}, r) 513 } 514 515 func (fw regFileWriter) LogicalRemaining() int64 { 516 return fw.nb 517 } 518 func (fw regFileWriter) PhysicalRemaining() int64 { 519 return fw.nb 520 } 521 522 // sparseFileWriter is a fileWriter for writing data to a sparse file entry. 523 type sparseFileWriter struct { 524 fw fileWriter // Underlying fileWriter 525 sp sparseDatas // Normalized list of data fragments 526 pos int64 // Current position in sparse file 527 } 528 529 func (sw *sparseFileWriter) Write(b []byte) (n int, err error) { 530 overwrite := int64(len(b)) > sw.LogicalRemaining() 531 if overwrite { 532 b = b[:sw.LogicalRemaining()] 533 } 534 535 b0 := b 536 endPos := sw.pos + int64(len(b)) 537 for endPos > sw.pos && err == nil { 538 var nf int // Bytes written in fragment 539 dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset() 540 if sw.pos < dataStart { // In a hole fragment 541 bf := b[:min(int64(len(b)), dataStart-sw.pos)] 542 nf, err = zeroWriter{}.Write(bf) 543 } else { // In a data fragment 544 bf := b[:min(int64(len(b)), dataEnd-sw.pos)] 545 nf, err = sw.fw.Write(bf) 546 } 547 b = b[nf:] 548 sw.pos += int64(nf) 549 if sw.pos >= dataEnd && len(sw.sp) > 1 { 550 sw.sp = sw.sp[1:] // Ensure last fragment always remains 551 } 552 } 553 554 n = len(b0) - len(b) 555 switch { 556 case err == ErrWriteTooLong: 557 return n, errMissData // Not possible; implies bug in validation logic 558 case err != nil: 559 return n, err 560 case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0: 561 return n, errUnrefData // Not possible; implies bug in validation logic 562 case overwrite: 563 return n, ErrWriteTooLong 564 default: 565 return n, nil 566 } 567 } 568 569 func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) { 570 rs, ok := r.(io.ReadSeeker) 571 if ok { 572 if _, err := rs.Seek(0, io.SeekCurrent); err != nil { 573 ok = false // Not all io.Seeker can really seek 574 } 575 } 576 if !ok { 577 return io.Copy(struct{ io.Writer }{sw}, r) 578 } 579 580 var readLastByte bool 581 pos0 := sw.pos 582 for sw.LogicalRemaining() > 0 && !readLastByte && err == nil { 583 var nf int64 // Size of fragment 584 dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset() 585 if sw.pos < dataStart { // In a hole fragment 586 nf = dataStart - sw.pos 587 if sw.PhysicalRemaining() == 0 { 588 readLastByte = true 589 nf-- 590 } 591 _, err = rs.Seek(nf, io.SeekCurrent) 592 } else { // In a data fragment 593 nf = dataEnd - sw.pos 594 nf, err = io.CopyN(sw.fw, rs, nf) 595 } 596 sw.pos += nf 597 if sw.pos >= dataEnd && len(sw.sp) > 1 { 598 sw.sp = sw.sp[1:] // Ensure last fragment always remains 599 } 600 } 601 602 // If the last fragment is a hole, then seek to 1-byte before EOF, and 603 // read a single byte to ensure the file is the right size. 604 if readLastByte && err == nil { 605 _, err = mustReadFull(rs, []byte{0}) 606 sw.pos++ 607 } 608 609 n = sw.pos - pos0 610 switch { 611 case err == io.EOF: 612 return n, io.ErrUnexpectedEOF 613 case err == ErrWriteTooLong: 614 return n, errMissData // Not possible; implies bug in validation logic 615 case err != nil: 616 return n, err 617 case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0: 618 return n, errUnrefData // Not possible; implies bug in validation logic 619 default: 620 return n, ensureEOF(rs) 621 } 622 } 623 624 func (sw sparseFileWriter) LogicalRemaining() int64 { 625 return sw.sp[len(sw.sp)-1].endOffset() - sw.pos 626 } 627 func (sw sparseFileWriter) PhysicalRemaining() int64 { 628 return sw.fw.PhysicalRemaining() 629 } 630 631 // zeroWriter may only be written with NULs, otherwise it returns errWriteHole. 632 type zeroWriter struct{} 633 634 func (zeroWriter) Write(b []byte) (int, error) { 635 for i, c := range b { 636 if c != 0 { 637 return i, errWriteHole 638 } 639 } 640 return len(b), nil 641 } 642 643 // ensureEOF checks whether r is at EOF, reporting ErrWriteTooLong if not so. 644 func ensureEOF(r io.Reader) error { 645 n, err := tryReadFull(r, []byte{0}) 646 switch { 647 case n > 0: 648 return ErrWriteTooLong 649 case err == io.EOF: 650 return nil 651 default: 652 return err 653 } 654 }