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