github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/archive/tar/reader.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 // TODO(dsymonds): 8 // - pax extensions 9 10 import ( 11 "bytes" 12 "errors" 13 "io" 14 "io/ioutil" 15 "os" 16 "strconv" 17 "strings" 18 "time" 19 ) 20 21 var ( 22 ErrHeader = errors.New("archive/tar: invalid tar header") 23 ) 24 25 const maxNanoSecondIntSize = 9 26 27 // A Reader provides sequential access to the contents of a tar archive. 28 // A tar archive consists of a sequence of files. 29 // The Next method advances to the next file in the archive (including the first), 30 // and then it can be treated as an io.Reader to access the file's data. 31 type Reader struct { 32 r io.Reader 33 err error 34 pad int64 // amount of padding (ignored) after current file entry 35 curr numBytesReader // reader for current file entry 36 hdrBuff [blockSize]byte // buffer to use in readHeader 37 } 38 39 // A numBytesReader is an io.Reader with a numBytes method, returning the number 40 // of bytes remaining in the underlying encoded data. 41 type numBytesReader interface { 42 io.Reader 43 numBytes() int64 44 } 45 46 // A regFileReader is a numBytesReader for reading file data from a tar archive. 47 type regFileReader struct { 48 r io.Reader // underlying reader 49 nb int64 // number of unread bytes for current file entry 50 } 51 52 // A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive. 53 type sparseFileReader struct { 54 rfr *regFileReader // reads the sparse-encoded file data 55 sp []sparseEntry // the sparse map for the file 56 pos int64 // keeps track of file position 57 tot int64 // total size of the file 58 } 59 60 // Keywords for GNU sparse files in a PAX extended header 61 const ( 62 paxGNUSparseNumBlocks = "GNU.sparse.numblocks" 63 paxGNUSparseOffset = "GNU.sparse.offset" 64 paxGNUSparseNumBytes = "GNU.sparse.numbytes" 65 paxGNUSparseMap = "GNU.sparse.map" 66 paxGNUSparseName = "GNU.sparse.name" 67 paxGNUSparseMajor = "GNU.sparse.major" 68 paxGNUSparseMinor = "GNU.sparse.minor" 69 paxGNUSparseSize = "GNU.sparse.size" 70 paxGNUSparseRealSize = "GNU.sparse.realsize" 71 ) 72 73 // Keywords for old GNU sparse headers 74 const ( 75 oldGNUSparseMainHeaderOffset = 386 76 oldGNUSparseMainHeaderIsExtendedOffset = 482 77 oldGNUSparseMainHeaderNumEntries = 4 78 oldGNUSparseExtendedHeaderIsExtendedOffset = 504 79 oldGNUSparseExtendedHeaderNumEntries = 21 80 oldGNUSparseOffsetSize = 12 81 oldGNUSparseNumBytesSize = 12 82 ) 83 84 // NewReader creates a new Reader reading from r. 85 func NewReader(r io.Reader) *Reader { return &Reader{r: r} } 86 87 // Next advances to the next entry in the tar archive. 88 func (tr *Reader) Next() (*Header, error) { 89 var hdr *Header 90 if tr.err == nil { 91 tr.skipUnread() 92 } 93 if tr.err != nil { 94 return hdr, tr.err 95 } 96 hdr = tr.readHeader() 97 if hdr == nil { 98 return hdr, tr.err 99 } 100 // Check for PAX/GNU header. 101 switch hdr.Typeflag { 102 case TypeXHeader: 103 // PAX extended header 104 headers, err := parsePAX(tr) 105 if err != nil { 106 return nil, err 107 } 108 // We actually read the whole file, 109 // but this skips alignment padding 110 tr.skipUnread() 111 hdr = tr.readHeader() 112 mergePAX(hdr, headers) 113 114 // Check for a PAX format sparse file 115 sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers) 116 if err != nil { 117 tr.err = err 118 return nil, err 119 } 120 if sp != nil { 121 // Current file is a PAX format GNU sparse file. 122 // Set the current file reader to a sparse file reader. 123 tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size} 124 } 125 return hdr, nil 126 case TypeGNULongName: 127 // We have a GNU long name header. Its contents are the real file name. 128 realname, err := ioutil.ReadAll(tr) 129 if err != nil { 130 return nil, err 131 } 132 hdr, err := tr.Next() 133 hdr.Name = cString(realname) 134 return hdr, err 135 case TypeGNULongLink: 136 // We have a GNU long link header. 137 realname, err := ioutil.ReadAll(tr) 138 if err != nil { 139 return nil, err 140 } 141 hdr, err := tr.Next() 142 hdr.Linkname = cString(realname) 143 return hdr, err 144 } 145 return hdr, tr.err 146 } 147 148 // checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then 149 // this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to 150 // be treated as a regular file. 151 func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) { 152 var sparseFormat string 153 154 // Check for sparse format indicators 155 major, majorOk := headers[paxGNUSparseMajor] 156 minor, minorOk := headers[paxGNUSparseMinor] 157 sparseName, sparseNameOk := headers[paxGNUSparseName] 158 _, sparseMapOk := headers[paxGNUSparseMap] 159 sparseSize, sparseSizeOk := headers[paxGNUSparseSize] 160 sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize] 161 162 // Identify which, if any, sparse format applies from which PAX headers are set 163 if majorOk && minorOk { 164 sparseFormat = major + "." + minor 165 } else if sparseNameOk && sparseMapOk { 166 sparseFormat = "0.1" 167 } else if sparseSizeOk { 168 sparseFormat = "0.0" 169 } else { 170 // Not a PAX format GNU sparse file. 171 return nil, nil 172 } 173 174 // Check for unknown sparse format 175 if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" { 176 return nil, nil 177 } 178 179 // Update hdr from GNU sparse PAX headers 180 if sparseNameOk { 181 hdr.Name = sparseName 182 } 183 if sparseSizeOk { 184 realSize, err := strconv.ParseInt(sparseSize, 10, 0) 185 if err != nil { 186 return nil, ErrHeader 187 } 188 hdr.Size = realSize 189 } else if sparseRealSizeOk { 190 realSize, err := strconv.ParseInt(sparseRealSize, 10, 0) 191 if err != nil { 192 return nil, ErrHeader 193 } 194 hdr.Size = realSize 195 } 196 197 // Set up the sparse map, according to the particular sparse format in use 198 var sp []sparseEntry 199 var err error 200 switch sparseFormat { 201 case "0.0", "0.1": 202 sp, err = readGNUSparseMap0x1(headers) 203 case "1.0": 204 sp, err = readGNUSparseMap1x0(tr.curr) 205 } 206 return sp, err 207 } 208 209 // mergePAX merges well known headers according to PAX standard. 210 // In general headers with the same name as those found 211 // in the header struct overwrite those found in the header 212 // struct with higher precision or longer values. Esp. useful 213 // for name and linkname fields. 214 func mergePAX(hdr *Header, headers map[string]string) error { 215 for k, v := range headers { 216 switch k { 217 case paxPath: 218 hdr.Name = v 219 case paxLinkpath: 220 hdr.Linkname = v 221 case paxGname: 222 hdr.Gname = v 223 case paxUname: 224 hdr.Uname = v 225 case paxUid: 226 uid, err := strconv.ParseInt(v, 10, 0) 227 if err != nil { 228 return err 229 } 230 hdr.Uid = int(uid) 231 case paxGid: 232 gid, err := strconv.ParseInt(v, 10, 0) 233 if err != nil { 234 return err 235 } 236 hdr.Gid = int(gid) 237 case paxAtime: 238 t, err := parsePAXTime(v) 239 if err != nil { 240 return err 241 } 242 hdr.AccessTime = t 243 case paxMtime: 244 t, err := parsePAXTime(v) 245 if err != nil { 246 return err 247 } 248 hdr.ModTime = t 249 case paxCtime: 250 t, err := parsePAXTime(v) 251 if err != nil { 252 return err 253 } 254 hdr.ChangeTime = t 255 case paxSize: 256 size, err := strconv.ParseInt(v, 10, 0) 257 if err != nil { 258 return err 259 } 260 hdr.Size = int64(size) 261 default: 262 if strings.HasPrefix(k, paxXattr) { 263 if hdr.Xattrs == nil { 264 hdr.Xattrs = make(map[string]string) 265 } 266 hdr.Xattrs[k[len(paxXattr):]] = v 267 } 268 } 269 } 270 return nil 271 } 272 273 // parsePAXTime takes a string of the form %d.%d as described in 274 // the PAX specification. 275 func parsePAXTime(t string) (time.Time, error) { 276 buf := []byte(t) 277 pos := bytes.IndexByte(buf, '.') 278 var seconds, nanoseconds int64 279 var err error 280 if pos == -1 { 281 seconds, err = strconv.ParseInt(t, 10, 0) 282 if err != nil { 283 return time.Time{}, err 284 } 285 } else { 286 seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0) 287 if err != nil { 288 return time.Time{}, err 289 } 290 nano_buf := string(buf[pos+1:]) 291 // Pad as needed before converting to a decimal. 292 // For example .030 -> .030000000 -> 30000000 nanoseconds 293 if len(nano_buf) < maxNanoSecondIntSize { 294 // Right pad 295 nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf)) 296 } else if len(nano_buf) > maxNanoSecondIntSize { 297 // Right truncate 298 nano_buf = nano_buf[:maxNanoSecondIntSize] 299 } 300 nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0) 301 if err != nil { 302 return time.Time{}, err 303 } 304 } 305 ts := time.Unix(seconds, nanoseconds) 306 return ts, nil 307 } 308 309 // parsePAX parses PAX headers. 310 // If an extended header (type 'x') is invalid, ErrHeader is returned 311 func parsePAX(r io.Reader) (map[string]string, error) { 312 buf, err := ioutil.ReadAll(r) 313 if err != nil { 314 return nil, err 315 } 316 317 // For GNU PAX sparse format 0.0 support. 318 // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers. 319 var sparseMap bytes.Buffer 320 321 headers := make(map[string]string) 322 // Each record is constructed as 323 // "%d %s=%s\n", length, keyword, value 324 for len(buf) > 0 { 325 // or the header was empty to start with. 326 var sp int 327 // The size field ends at the first space. 328 sp = bytes.IndexByte(buf, ' ') 329 if sp == -1 { 330 return nil, ErrHeader 331 } 332 // Parse the first token as a decimal integer. 333 n, err := strconv.ParseInt(string(buf[:sp]), 10, 0) 334 if err != nil { 335 return nil, ErrHeader 336 } 337 // Extract everything between the decimal and the n -1 on the 338 // beginning to eat the ' ', -1 on the end to skip the newline. 339 var record []byte 340 record, buf = buf[sp+1:n-1], buf[n:] 341 // The first equals is guaranteed to mark the end of the key. 342 // Everything else is value. 343 eq := bytes.IndexByte(record, '=') 344 if eq == -1 { 345 return nil, ErrHeader 346 } 347 key, value := record[:eq], record[eq+1:] 348 349 keyStr := string(key) 350 if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes { 351 // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map. 352 sparseMap.Write(value) 353 sparseMap.Write([]byte{','}) 354 } else { 355 // Normal key. Set the value in the headers map. 356 headers[keyStr] = string(value) 357 } 358 } 359 if sparseMap.Len() != 0 { 360 // Add sparse info to headers, chopping off the extra comma 361 sparseMap.Truncate(sparseMap.Len() - 1) 362 headers[paxGNUSparseMap] = sparseMap.String() 363 } 364 return headers, nil 365 } 366 367 // cString parses bytes as a NUL-terminated C-style string. 368 // If a NUL byte is not found then the whole slice is returned as a string. 369 func cString(b []byte) string { 370 n := 0 371 for n < len(b) && b[n] != 0 { 372 n++ 373 } 374 return string(b[0:n]) 375 } 376 377 func (tr *Reader) octal(b []byte) int64 { 378 // Check for binary format first. 379 if len(b) > 0 && b[0]&0x80 != 0 { 380 var x int64 381 for i, c := range b { 382 if i == 0 { 383 c &= 0x7f // ignore signal bit in first byte 384 } 385 x = x<<8 | int64(c) 386 } 387 return x 388 } 389 390 // Because unused fields are filled with NULs, we need 391 // to skip leading NULs. Fields may also be padded with 392 // spaces or NULs. 393 // So we remove leading and trailing NULs and spaces to 394 // be sure. 395 b = bytes.Trim(b, " \x00") 396 397 if len(b) == 0 { 398 return 0 399 } 400 x, err := strconv.ParseUint(cString(b), 8, 64) 401 if err != nil { 402 tr.err = err 403 } 404 return int64(x) 405 } 406 407 // skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding. 408 func (tr *Reader) skipUnread() { 409 nr := tr.numBytes() + tr.pad // number of bytes to skip 410 tr.curr, tr.pad = nil, 0 411 if sr, ok := tr.r.(io.Seeker); ok { 412 if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil { 413 return 414 } 415 } 416 _, tr.err = io.CopyN(ioutil.Discard, tr.r, nr) 417 } 418 419 func (tr *Reader) verifyChecksum(header []byte) bool { 420 if tr.err != nil { 421 return false 422 } 423 424 given := tr.octal(header[148:156]) 425 unsigned, signed := checksum(header) 426 return given == unsigned || given == signed 427 } 428 429 func (tr *Reader) readHeader() *Header { 430 header := tr.hdrBuff[:] 431 copy(header, zeroBlock) 432 433 if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil { 434 return nil 435 } 436 437 // Two blocks of zero bytes marks the end of the archive. 438 if bytes.Equal(header, zeroBlock[0:blockSize]) { 439 if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil { 440 return nil 441 } 442 if bytes.Equal(header, zeroBlock[0:blockSize]) { 443 tr.err = io.EOF 444 } else { 445 tr.err = ErrHeader // zero block and then non-zero block 446 } 447 return nil 448 } 449 450 if !tr.verifyChecksum(header) { 451 tr.err = ErrHeader 452 return nil 453 } 454 455 // Unpack 456 hdr := new(Header) 457 s := slicer(header) 458 459 hdr.Name = cString(s.next(100)) 460 hdr.Mode = tr.octal(s.next(8)) 461 hdr.Uid = int(tr.octal(s.next(8))) 462 hdr.Gid = int(tr.octal(s.next(8))) 463 hdr.Size = tr.octal(s.next(12)) 464 hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0) 465 s.next(8) // chksum 466 hdr.Typeflag = s.next(1)[0] 467 hdr.Linkname = cString(s.next(100)) 468 469 // The remainder of the header depends on the value of magic. 470 // The original (v7) version of tar had no explicit magic field, 471 // so its magic bytes, like the rest of the block, are NULs. 472 magic := string(s.next(8)) // contains version field as well. 473 var format string 474 switch { 475 case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988) 476 if string(header[508:512]) == "tar\x00" { 477 format = "star" 478 } else { 479 format = "posix" 480 } 481 case magic == "ustar \x00": // old GNU tar 482 format = "gnu" 483 } 484 485 switch format { 486 case "posix", "gnu", "star": 487 hdr.Uname = cString(s.next(32)) 488 hdr.Gname = cString(s.next(32)) 489 devmajor := s.next(8) 490 devminor := s.next(8) 491 if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock { 492 hdr.Devmajor = tr.octal(devmajor) 493 hdr.Devminor = tr.octal(devminor) 494 } 495 var prefix string 496 switch format { 497 case "posix", "gnu": 498 prefix = cString(s.next(155)) 499 case "star": 500 prefix = cString(s.next(131)) 501 hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0) 502 hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0) 503 } 504 if len(prefix) > 0 { 505 hdr.Name = prefix + "/" + hdr.Name 506 } 507 } 508 509 if tr.err != nil { 510 tr.err = ErrHeader 511 return nil 512 } 513 514 // Maximum value of hdr.Size is 64 GB (12 octal digits), 515 // so there's no risk of int64 overflowing. 516 nb := int64(hdr.Size) 517 tr.pad = -nb & (blockSize - 1) // blockSize is a power of two 518 519 // Set the current file reader. 520 tr.curr = ®FileReader{r: tr.r, nb: nb} 521 522 // Check for old GNU sparse format entry. 523 if hdr.Typeflag == TypeGNUSparse { 524 // Get the real size of the file. 525 hdr.Size = tr.octal(header[483:495]) 526 527 // Read the sparse map. 528 sp := tr.readOldGNUSparseMap(header) 529 if tr.err != nil { 530 return nil 531 } 532 // Current file is a GNU sparse file. Update the current file reader. 533 tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size} 534 } 535 536 return hdr 537 } 538 539 // A sparseEntry holds a single entry in a sparse file's sparse map. 540 // A sparse entry indicates the offset and size in a sparse file of a 541 // block of data. 542 type sparseEntry struct { 543 offset int64 544 numBytes int64 545 } 546 547 // readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format. 548 // The sparse map is stored in the tar header if it's small enough. If it's larger than four entries, 549 // then one or more extension headers are used to store the rest of the sparse map. 550 func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry { 551 isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0 552 spCap := oldGNUSparseMainHeaderNumEntries 553 if isExtended { 554 spCap += oldGNUSparseExtendedHeaderNumEntries 555 } 556 sp := make([]sparseEntry, 0, spCap) 557 s := slicer(header[oldGNUSparseMainHeaderOffset:]) 558 559 // Read the four entries from the main tar header 560 for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ { 561 offset := tr.octal(s.next(oldGNUSparseOffsetSize)) 562 numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize)) 563 if tr.err != nil { 564 tr.err = ErrHeader 565 return nil 566 } 567 if offset == 0 && numBytes == 0 { 568 break 569 } 570 sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) 571 } 572 573 for isExtended { 574 // There are more entries. Read an extension header and parse its entries. 575 sparseHeader := make([]byte, blockSize) 576 if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil { 577 return nil 578 } 579 isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0 580 s = slicer(sparseHeader) 581 for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ { 582 offset := tr.octal(s.next(oldGNUSparseOffsetSize)) 583 numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize)) 584 if tr.err != nil { 585 tr.err = ErrHeader 586 return nil 587 } 588 if offset == 0 && numBytes == 0 { 589 break 590 } 591 sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) 592 } 593 } 594 return sp 595 } 596 597 // readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0. 598 // The sparse map is stored just before the file data and padded out to the nearest block boundary. 599 func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) { 600 buf := make([]byte, 2*blockSize) 601 sparseHeader := buf[:blockSize] 602 603 // readDecimal is a helper function to read a decimal integer from the sparse map 604 // while making sure to read from the file in blocks of size blockSize 605 readDecimal := func() (int64, error) { 606 // Look for newline 607 nl := bytes.IndexByte(sparseHeader, '\n') 608 if nl == -1 { 609 if len(sparseHeader) >= blockSize { 610 // This is an error 611 return 0, ErrHeader 612 } 613 oldLen := len(sparseHeader) 614 newLen := oldLen + blockSize 615 if cap(sparseHeader) < newLen { 616 // There's more header, but we need to make room for the next block 617 copy(buf, sparseHeader) 618 sparseHeader = buf[:newLen] 619 } else { 620 // There's more header, and we can just reslice 621 sparseHeader = sparseHeader[:newLen] 622 } 623 624 // Now that sparseHeader is large enough, read next block 625 if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil { 626 return 0, err 627 } 628 629 // Look for a newline in the new data 630 nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n') 631 if nl == -1 { 632 // This is an error 633 return 0, ErrHeader 634 } 635 nl += oldLen // We want the position from the beginning 636 } 637 // Now that we've found a newline, read a number 638 n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0) 639 if err != nil { 640 return 0, ErrHeader 641 } 642 643 // Update sparseHeader to consume this number 644 sparseHeader = sparseHeader[nl+1:] 645 return n, nil 646 } 647 648 // Read the first block 649 if _, err := io.ReadFull(r, sparseHeader); err != nil { 650 return nil, err 651 } 652 653 // The first line contains the number of entries 654 numEntries, err := readDecimal() 655 if err != nil { 656 return nil, err 657 } 658 659 // Read all the entries 660 sp := make([]sparseEntry, 0, numEntries) 661 for i := int64(0); i < numEntries; i++ { 662 // Read the offset 663 offset, err := readDecimal() 664 if err != nil { 665 return nil, err 666 } 667 // Read numBytes 668 numBytes, err := readDecimal() 669 if err != nil { 670 return nil, err 671 } 672 673 sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) 674 } 675 676 return sp, nil 677 } 678 679 // readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format version 0.1. 680 // The sparse map is stored in the PAX headers. 681 func readGNUSparseMap0x1(headers map[string]string) ([]sparseEntry, error) { 682 // Get number of entries 683 numEntriesStr, ok := headers[paxGNUSparseNumBlocks] 684 if !ok { 685 return nil, ErrHeader 686 } 687 numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) 688 if err != nil { 689 return nil, ErrHeader 690 } 691 692 sparseMap := strings.Split(headers[paxGNUSparseMap], ",") 693 694 // There should be two numbers in sparseMap for each entry 695 if int64(len(sparseMap)) != 2*numEntries { 696 return nil, ErrHeader 697 } 698 699 // Loop through the entries in the sparse map 700 sp := make([]sparseEntry, 0, numEntries) 701 for i := int64(0); i < numEntries; i++ { 702 offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0) 703 if err != nil { 704 return nil, ErrHeader 705 } 706 numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0) 707 if err != nil { 708 return nil, ErrHeader 709 } 710 sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) 711 } 712 713 return sp, nil 714 } 715 716 // numBytes returns the number of bytes left to read in the current file's entry 717 // in the tar archive, or 0 if there is no current file. 718 func (tr *Reader) numBytes() int64 { 719 if tr.curr == nil { 720 // No current file, so no bytes 721 return 0 722 } 723 return tr.curr.numBytes() 724 } 725 726 // Read reads from the current entry in the tar archive. 727 // It returns 0, io.EOF when it reaches the end of that entry, 728 // until Next is called to advance to the next entry. 729 func (tr *Reader) Read(b []byte) (n int, err error) { 730 if tr.curr == nil { 731 return 0, io.EOF 732 } 733 n, err = tr.curr.Read(b) 734 if err != nil && err != io.EOF { 735 tr.err = err 736 } 737 return 738 } 739 740 func (rfr *regFileReader) Read(b []byte) (n int, err error) { 741 if rfr.nb == 0 { 742 // file consumed 743 return 0, io.EOF 744 } 745 if int64(len(b)) > rfr.nb { 746 b = b[0:rfr.nb] 747 } 748 n, err = rfr.r.Read(b) 749 rfr.nb -= int64(n) 750 751 if err == io.EOF && rfr.nb > 0 { 752 err = io.ErrUnexpectedEOF 753 } 754 return 755 } 756 757 // numBytes returns the number of bytes left to read in the file's data in the tar archive. 758 func (rfr *regFileReader) numBytes() int64 { 759 return rfr.nb 760 } 761 762 // readHole reads a sparse file hole ending at offset toOffset 763 func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int { 764 n64 := toOffset - sfr.pos 765 if n64 > int64(len(b)) { 766 n64 = int64(len(b)) 767 } 768 n := int(n64) 769 for i := 0; i < n; i++ { 770 b[i] = 0 771 } 772 sfr.pos += n64 773 return n 774 } 775 776 // Read reads the sparse file data in expanded form. 777 func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { 778 if len(sfr.sp) == 0 { 779 // No more data fragments to read from. 780 if sfr.pos < sfr.tot { 781 // We're in the last hole 782 n = sfr.readHole(b, sfr.tot) 783 return 784 } 785 // Otherwise, we're at the end of the file 786 return 0, io.EOF 787 } 788 if sfr.pos < sfr.sp[0].offset { 789 // We're in a hole 790 n = sfr.readHole(b, sfr.sp[0].offset) 791 return 792 } 793 794 // We're not in a hole, so we'll read from the next data fragment 795 posInFragment := sfr.pos - sfr.sp[0].offset 796 bytesLeft := sfr.sp[0].numBytes - posInFragment 797 if int64(len(b)) > bytesLeft { 798 b = b[0:bytesLeft] 799 } 800 801 n, err = sfr.rfr.Read(b) 802 sfr.pos += int64(n) 803 804 if int64(n) == bytesLeft { 805 // We're done with this fragment 806 sfr.sp = sfr.sp[1:] 807 } 808 809 if err == io.EOF && sfr.pos < sfr.tot { 810 // We reached the end of the last fragment's data, but there's a final hole 811 err = nil 812 } 813 return 814 } 815 816 // numBytes returns the number of bytes left to read in the sparse file's 817 // sparse-encoded data in the tar archive. 818 func (sfr *sparseFileReader) numBytes() int64 { 819 return sfr.rfr.nb 820 }