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