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 "crypto/md5" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "reflect" 15 "strings" 16 "testing" 17 "time" 18 ) 19 20 type untarTest struct { 21 file string 22 headers []*Header 23 cksums []string 24 } 25 26 var gnuTarTest = &untarTest{ 27 file: "testdata/gnu.tar", 28 headers: []*Header{ 29 { 30 Name: "small.txt", 31 Mode: 0640, 32 Uid: 73025, 33 Gid: 5000, 34 Size: 5, 35 ModTime: time.Unix(1244428340, 0), 36 Typeflag: '0', 37 Uname: "dsymonds", 38 Gname: "eng", 39 }, 40 { 41 Name: "small2.txt", 42 Mode: 0640, 43 Uid: 73025, 44 Gid: 5000, 45 Size: 11, 46 ModTime: time.Unix(1244436044, 0), 47 Typeflag: '0', 48 Uname: "dsymonds", 49 Gname: "eng", 50 }, 51 }, 52 cksums: []string{ 53 "e38b27eaccb4391bdec553a7f3ae6b2f", 54 "c65bd2e50a56a2138bf1716f2fd56fe9", 55 }, 56 } 57 58 var sparseTarTest = &untarTest{ 59 file: "testdata/sparse-formats.tar", 60 headers: []*Header{ 61 { 62 Name: "sparse-gnu", 63 Mode: 420, 64 Uid: 1000, 65 Gid: 1000, 66 Size: 200, 67 ModTime: time.Unix(1392395740, 0), 68 Typeflag: 0x53, 69 Linkname: "", 70 Uname: "david", 71 Gname: "david", 72 Devmajor: 0, 73 Devminor: 0, 74 }, 75 { 76 Name: "sparse-posix-0.0", 77 Mode: 420, 78 Uid: 1000, 79 Gid: 1000, 80 Size: 200, 81 ModTime: time.Unix(1392342187, 0), 82 Typeflag: 0x30, 83 Linkname: "", 84 Uname: "david", 85 Gname: "david", 86 Devmajor: 0, 87 Devminor: 0, 88 }, 89 { 90 Name: "sparse-posix-0.1", 91 Mode: 420, 92 Uid: 1000, 93 Gid: 1000, 94 Size: 200, 95 ModTime: time.Unix(1392340456, 0), 96 Typeflag: 0x30, 97 Linkname: "", 98 Uname: "david", 99 Gname: "david", 100 Devmajor: 0, 101 Devminor: 0, 102 }, 103 { 104 Name: "sparse-posix-1.0", 105 Mode: 420, 106 Uid: 1000, 107 Gid: 1000, 108 Size: 200, 109 ModTime: time.Unix(1392337404, 0), 110 Typeflag: 0x30, 111 Linkname: "", 112 Uname: "david", 113 Gname: "david", 114 Devmajor: 0, 115 Devminor: 0, 116 }, 117 { 118 Name: "end", 119 Mode: 420, 120 Uid: 1000, 121 Gid: 1000, 122 Size: 4, 123 ModTime: time.Unix(1392398319, 0), 124 Typeflag: 0x30, 125 Linkname: "", 126 Uname: "david", 127 Gname: "david", 128 Devmajor: 0, 129 Devminor: 0, 130 }, 131 }, 132 cksums: []string{ 133 "6f53234398c2449fe67c1812d993012f", 134 "6f53234398c2449fe67c1812d993012f", 135 "6f53234398c2449fe67c1812d993012f", 136 "6f53234398c2449fe67c1812d993012f", 137 "b0061974914468de549a2af8ced10316", 138 }, 139 } 140 141 var untarTests = []*untarTest{ 142 gnuTarTest, 143 sparseTarTest, 144 { 145 file: "testdata/star.tar", 146 headers: []*Header{ 147 { 148 Name: "small.txt", 149 Mode: 0640, 150 Uid: 73025, 151 Gid: 5000, 152 Size: 5, 153 ModTime: time.Unix(1244592783, 0), 154 Typeflag: '0', 155 Uname: "dsymonds", 156 Gname: "eng", 157 AccessTime: time.Unix(1244592783, 0), 158 ChangeTime: time.Unix(1244592783, 0), 159 }, 160 { 161 Name: "small2.txt", 162 Mode: 0640, 163 Uid: 73025, 164 Gid: 5000, 165 Size: 11, 166 ModTime: time.Unix(1244592783, 0), 167 Typeflag: '0', 168 Uname: "dsymonds", 169 Gname: "eng", 170 AccessTime: time.Unix(1244592783, 0), 171 ChangeTime: time.Unix(1244592783, 0), 172 }, 173 }, 174 }, 175 { 176 file: "testdata/v7.tar", 177 headers: []*Header{ 178 { 179 Name: "small.txt", 180 Mode: 0444, 181 Uid: 73025, 182 Gid: 5000, 183 Size: 5, 184 ModTime: time.Unix(1244593104, 0), 185 Typeflag: '\x00', 186 }, 187 { 188 Name: "small2.txt", 189 Mode: 0444, 190 Uid: 73025, 191 Gid: 5000, 192 Size: 11, 193 ModTime: time.Unix(1244593104, 0), 194 Typeflag: '\x00', 195 }, 196 }, 197 }, 198 { 199 file: "testdata/pax.tar", 200 headers: []*Header{ 201 { 202 Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", 203 Mode: 0664, 204 Uid: 1000, 205 Gid: 1000, 206 Uname: "shane", 207 Gname: "shane", 208 Size: 7, 209 ModTime: time.Unix(1350244992, 23960108), 210 ChangeTime: time.Unix(1350244992, 23960108), 211 AccessTime: time.Unix(1350244992, 23960108), 212 Typeflag: TypeReg, 213 }, 214 { 215 Name: "a/b", 216 Mode: 0777, 217 Uid: 1000, 218 Gid: 1000, 219 Uname: "shane", 220 Gname: "shane", 221 Size: 0, 222 ModTime: time.Unix(1350266320, 910238425), 223 ChangeTime: time.Unix(1350266320, 910238425), 224 AccessTime: time.Unix(1350266320, 910238425), 225 Typeflag: TypeSymlink, 226 Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100", 227 }, 228 }, 229 }, 230 { 231 file: "testdata/nil-uid.tar", // golang.org/issue/5290 232 headers: []*Header{ 233 { 234 Name: "P1050238.JPG.log", 235 Mode: 0664, 236 Uid: 0, 237 Gid: 0, 238 Size: 14, 239 ModTime: time.Unix(1365454838, 0), 240 Typeflag: TypeReg, 241 Linkname: "", 242 Uname: "eyefi", 243 Gname: "eyefi", 244 Devmajor: 0, 245 Devminor: 0, 246 }, 247 }, 248 }, 249 { 250 file: "testdata/xattrs.tar", 251 headers: []*Header{ 252 { 253 Name: "small.txt", 254 Mode: 0644, 255 Uid: 1000, 256 Gid: 10, 257 Size: 5, 258 ModTime: time.Unix(1386065770, 448252320), 259 Typeflag: '0', 260 Uname: "alex", 261 Gname: "wheel", 262 AccessTime: time.Unix(1389782991, 419875220), 263 ChangeTime: time.Unix(1389782956, 794414986), 264 Xattrs: map[string]string{ 265 "user.key": "value", 266 "user.key2": "value2", 267 // Interestingly, selinux encodes the terminating null inside the xattr 268 "security.selinux": "unconfined_u:object_r:default_t:s0\x00", 269 }, 270 }, 271 { 272 Name: "small2.txt", 273 Mode: 0644, 274 Uid: 1000, 275 Gid: 10, 276 Size: 11, 277 ModTime: time.Unix(1386065770, 449252304), 278 Typeflag: '0', 279 Uname: "alex", 280 Gname: "wheel", 281 AccessTime: time.Unix(1389782991, 419875220), 282 ChangeTime: time.Unix(1386065770, 449252304), 283 Xattrs: map[string]string{ 284 "security.selinux": "unconfined_u:object_r:default_t:s0\x00", 285 }, 286 }, 287 }, 288 }, 289 } 290 291 func TestReader(t *testing.T) { 292 testLoop: 293 for i, test := range untarTests { 294 f, err := os.Open(test.file) 295 if err != nil { 296 t.Errorf("test %d: Unexpected error: %v", i, err) 297 continue 298 } 299 defer f.Close() 300 tr := NewReader(f) 301 for j, header := range test.headers { 302 hdr, err := tr.Next() 303 if err != nil || hdr == nil { 304 t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err) 305 f.Close() 306 continue testLoop 307 } 308 if !reflect.DeepEqual(*hdr, *header) { 309 t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v", 310 i, j, *hdr, *header) 311 } 312 } 313 hdr, err := tr.Next() 314 if err == io.EOF { 315 continue testLoop 316 } 317 if hdr != nil || err != nil { 318 t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err) 319 } 320 } 321 } 322 323 func TestPartialRead(t *testing.T) { 324 f, err := os.Open("testdata/gnu.tar") 325 if err != nil { 326 t.Fatalf("Unexpected error: %v", err) 327 } 328 defer f.Close() 329 330 tr := NewReader(f) 331 332 // Read the first four bytes; Next() should skip the last byte. 333 hdr, err := tr.Next() 334 if err != nil || hdr == nil { 335 t.Fatalf("Didn't get first file: %v", err) 336 } 337 buf := make([]byte, 4) 338 if _, err := io.ReadFull(tr, buf); err != nil { 339 t.Fatalf("Unexpected error: %v", err) 340 } 341 if expected := []byte("Kilt"); !bytes.Equal(buf, expected) { 342 t.Errorf("Contents = %v, want %v", buf, expected) 343 } 344 345 // Second file 346 hdr, err = tr.Next() 347 if err != nil || hdr == nil { 348 t.Fatalf("Didn't get second file: %v", err) 349 } 350 buf = make([]byte, 6) 351 if _, err := io.ReadFull(tr, buf); err != nil { 352 t.Fatalf("Unexpected error: %v", err) 353 } 354 if expected := []byte("Google"); !bytes.Equal(buf, expected) { 355 t.Errorf("Contents = %v, want %v", buf, expected) 356 } 357 } 358 359 func TestIncrementalRead(t *testing.T) { 360 test := gnuTarTest 361 f, err := os.Open(test.file) 362 if err != nil { 363 t.Fatalf("Unexpected error: %v", err) 364 } 365 defer f.Close() 366 367 tr := NewReader(f) 368 369 headers := test.headers 370 cksums := test.cksums 371 nread := 0 372 373 // loop over all files 374 for ; ; nread++ { 375 hdr, err := tr.Next() 376 if hdr == nil || err == io.EOF { 377 break 378 } 379 380 // check the header 381 if !reflect.DeepEqual(*hdr, *headers[nread]) { 382 t.Errorf("Incorrect header:\nhave %+v\nwant %+v", 383 *hdr, headers[nread]) 384 } 385 386 // read file contents in little chunks EOF, 387 // checksumming all the way 388 h := md5.New() 389 rdbuf := make([]uint8, 8) 390 for { 391 nr, err := tr.Read(rdbuf) 392 if err == io.EOF { 393 break 394 } 395 if err != nil { 396 t.Errorf("Read: unexpected error %v\n", err) 397 break 398 } 399 h.Write(rdbuf[0:nr]) 400 } 401 // verify checksum 402 have := fmt.Sprintf("%x", h.Sum(nil)) 403 want := cksums[nread] 404 if want != have { 405 t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want) 406 } 407 } 408 if nread != len(headers) { 409 t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread) 410 } 411 } 412 413 func TestNonSeekable(t *testing.T) { 414 test := gnuTarTest 415 f, err := os.Open(test.file) 416 if err != nil { 417 t.Fatalf("Unexpected error: %v", err) 418 } 419 defer f.Close() 420 421 type readerOnly struct { 422 io.Reader 423 } 424 tr := NewReader(readerOnly{f}) 425 nread := 0 426 427 for ; ; nread++ { 428 _, err := tr.Next() 429 if err == io.EOF { 430 break 431 } 432 if err != nil { 433 t.Fatalf("Unexpected error: %v", err) 434 } 435 } 436 437 if nread != len(test.headers) { 438 t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread) 439 } 440 } 441 442 func TestParsePAXHeader(t *testing.T) { 443 paxTests := [][3]string{ 444 {"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths 445 {"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length 446 {"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}} 447 for _, test := range paxTests { 448 key, expected, raw := test[0], test[1], test[2] 449 reader := bytes.NewReader([]byte(raw)) 450 headers, err := parsePAX(reader) 451 if err != nil { 452 t.Errorf("Couldn't parse correctly formatted headers: %v", err) 453 continue 454 } 455 if strings.EqualFold(headers[key], expected) { 456 t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected) 457 continue 458 } 459 trailer := make([]byte, 100) 460 n, err := reader.Read(trailer) 461 if err != io.EOF || n != 0 { 462 t.Error("Buffer wasn't consumed") 463 } 464 } 465 badHeaderTests := [][]byte{ 466 []byte("3 somelongkey=\n"), 467 []byte("50 tooshort=\n"), 468 } 469 for _, test := range badHeaderTests { 470 if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader { 471 t.Fatal("Unexpected success when parsing bad header") 472 } 473 } 474 } 475 476 func TestParsePAXTime(t *testing.T) { 477 // Some valid PAX time values 478 timestamps := map[string]time.Time{ 479 "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case 480 "1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value 481 "1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value 482 "1350244992": time.Unix(1350244992, 0), // Low precision value 483 } 484 for input, expected := range timestamps { 485 ts, err := parsePAXTime(input) 486 if err != nil { 487 t.Fatal(err) 488 } 489 if !ts.Equal(expected) { 490 t.Fatalf("Time parsing failure %s %s", ts, expected) 491 } 492 } 493 } 494 495 func TestMergePAX(t *testing.T) { 496 hdr := new(Header) 497 // Test a string, integer, and time based value. 498 headers := map[string]string{ 499 "path": "a/b/c", 500 "uid": "1000", 501 "mtime": "1350244992.023960108", 502 } 503 err := mergePAX(hdr, headers) 504 if err != nil { 505 t.Fatal(err) 506 } 507 want := &Header{ 508 Name: "a/b/c", 509 Uid: 1000, 510 ModTime: time.Unix(1350244992, 23960108), 511 } 512 if !reflect.DeepEqual(hdr, want) { 513 t.Errorf("incorrect merge: got %+v, want %+v", hdr, want) 514 } 515 } 516 517 func TestSparseEndToEnd(t *testing.T) { 518 test := sparseTarTest 519 f, err := os.Open(test.file) 520 if err != nil { 521 t.Fatalf("Unexpected error: %v", err) 522 } 523 defer f.Close() 524 525 tr := NewReader(f) 526 527 headers := test.headers 528 cksums := test.cksums 529 nread := 0 530 531 // loop over all files 532 for ; ; nread++ { 533 hdr, err := tr.Next() 534 if hdr == nil || err == io.EOF { 535 break 536 } 537 538 // check the header 539 if !reflect.DeepEqual(*hdr, *headers[nread]) { 540 t.Errorf("Incorrect header:\nhave %+v\nwant %+v", 541 *hdr, headers[nread]) 542 } 543 544 // read and checksum the file data 545 h := md5.New() 546 _, err = io.Copy(h, tr) 547 if err != nil { 548 t.Fatalf("Unexpected error: %v", err) 549 } 550 551 // verify checksum 552 have := fmt.Sprintf("%x", h.Sum(nil)) 553 want := cksums[nread] 554 if want != have { 555 t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want) 556 } 557 } 558 if nread != len(headers) { 559 t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread) 560 } 561 } 562 563 type sparseFileReadTest struct { 564 sparseData []byte 565 sparseMap []sparseEntry 566 realSize int64 567 expected []byte 568 } 569 570 var sparseFileReadTests = []sparseFileReadTest{ 571 { 572 sparseData: []byte("abcde"), 573 sparseMap: []sparseEntry{ 574 {offset: 0, numBytes: 2}, 575 {offset: 5, numBytes: 3}, 576 }, 577 realSize: 8, 578 expected: []byte("ab\x00\x00\x00cde"), 579 }, 580 { 581 sparseData: []byte("abcde"), 582 sparseMap: []sparseEntry{ 583 {offset: 0, numBytes: 2}, 584 {offset: 5, numBytes: 3}, 585 }, 586 realSize: 10, 587 expected: []byte("ab\x00\x00\x00cde\x00\x00"), 588 }, 589 { 590 sparseData: []byte("abcde"), 591 sparseMap: []sparseEntry{ 592 {offset: 1, numBytes: 3}, 593 {offset: 6, numBytes: 2}, 594 }, 595 realSize: 8, 596 expected: []byte("\x00abc\x00\x00de"), 597 }, 598 { 599 sparseData: []byte("abcde"), 600 sparseMap: []sparseEntry{ 601 {offset: 1, numBytes: 3}, 602 {offset: 6, numBytes: 2}, 603 }, 604 realSize: 10, 605 expected: []byte("\x00abc\x00\x00de\x00\x00"), 606 }, 607 { 608 sparseData: []byte(""), 609 sparseMap: nil, 610 realSize: 2, 611 expected: []byte("\x00\x00"), 612 }, 613 } 614 615 func TestSparseFileReader(t *testing.T) { 616 for i, test := range sparseFileReadTests { 617 r := bytes.NewReader(test.sparseData) 618 nb := int64(r.Len()) 619 sfr := &sparseFileReader{ 620 rfr: ®FileReader{r: r, nb: nb}, 621 sp: test.sparseMap, 622 pos: 0, 623 tot: test.realSize, 624 } 625 if sfr.numBytes() != nb { 626 t.Errorf("test %d: Before reading, sfr.numBytes() = %d, want %d", i, sfr.numBytes(), nb) 627 } 628 buf, err := ioutil.ReadAll(sfr) 629 if err != nil { 630 t.Errorf("test %d: Unexpected error: %v", i, err) 631 } 632 if e := test.expected; !bytes.Equal(buf, e) { 633 t.Errorf("test %d: Contents = %v, want %v", i, buf, e) 634 } 635 if sfr.numBytes() != 0 { 636 t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i) 637 } 638 } 639 } 640 641 func TestSparseIncrementalRead(t *testing.T) { 642 sparseMap := []sparseEntry{{10, 2}} 643 sparseData := []byte("Go") 644 expected := "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Go\x00\x00\x00\x00\x00\x00\x00\x00" 645 646 r := bytes.NewReader(sparseData) 647 nb := int64(r.Len()) 648 sfr := &sparseFileReader{ 649 rfr: ®FileReader{r: r, nb: nb}, 650 sp: sparseMap, 651 pos: 0, 652 tot: int64(len(expected)), 653 } 654 655 // We'll read the data 6 bytes at a time, with a hole of size 10 at 656 // the beginning and one of size 8 at the end. 657 var outputBuf bytes.Buffer 658 buf := make([]byte, 6) 659 for { 660 n, err := sfr.Read(buf) 661 if err == io.EOF { 662 break 663 } 664 if err != nil { 665 t.Errorf("Read: unexpected error %v\n", err) 666 } 667 if n > 0 { 668 _, err := outputBuf.Write(buf[:n]) 669 if err != nil { 670 t.Errorf("Write: unexpected error %v\n", err) 671 } 672 } 673 } 674 got := outputBuf.String() 675 if got != expected { 676 t.Errorf("Contents = %v, want %v", got, expected) 677 } 678 } 679 680 func TestReadGNUSparseMap0x1(t *testing.T) { 681 headers := map[string]string{ 682 paxGNUSparseNumBlocks: "4", 683 paxGNUSparseMap: "0,5,10,5,20,5,30,5", 684 } 685 expected := []sparseEntry{ 686 {offset: 0, numBytes: 5}, 687 {offset: 10, numBytes: 5}, 688 {offset: 20, numBytes: 5}, 689 {offset: 30, numBytes: 5}, 690 } 691 692 sp, err := readGNUSparseMap0x1(headers) 693 if err != nil { 694 t.Errorf("Unexpected error: %v", err) 695 } 696 if !reflect.DeepEqual(sp, expected) { 697 t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected) 698 } 699 } 700 701 func TestReadGNUSparseMap1x0(t *testing.T) { 702 // This test uses lots of holes so the sparse header takes up more than two blocks 703 numEntries := 100 704 expected := make([]sparseEntry, 0, numEntries) 705 sparseMap := new(bytes.Buffer) 706 707 fmt.Fprintf(sparseMap, "%d\n", numEntries) 708 for i := 0; i < numEntries; i++ { 709 offset := int64(2048 * i) 710 numBytes := int64(1024) 711 expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes}) 712 fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes) 713 } 714 715 // Make the header the smallest multiple of blockSize that fits the sparseMap 716 headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize 717 bufLen := blockSize * headerBlocks 718 buf := make([]byte, bufLen) 719 copy(buf, sparseMap.Bytes()) 720 721 // Get an reader to read the sparse map 722 r := bytes.NewReader(buf) 723 724 // Read the sparse map 725 sp, err := readGNUSparseMap1x0(r) 726 if err != nil { 727 t.Errorf("Unexpected error: %v", err) 728 } 729 if !reflect.DeepEqual(sp, expected) { 730 t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected) 731 } 732 } 733 734 func TestUninitializedRead(t *testing.T) { 735 test := gnuTarTest 736 f, err := os.Open(test.file) 737 if err != nil { 738 t.Fatalf("Unexpected error: %v", err) 739 } 740 defer f.Close() 741 742 tr := NewReader(f) 743 _, err = tr.Read([]byte{}) 744 if err == nil || err != io.EOF { 745 t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF) 746 } 747 748 } 749 750 // Negative header size should not cause panic. 751 // Issues 10959 and 10960. 752 func TestNegativeHdrSize(t *testing.T) { 753 f, err := os.Open("testdata/neg-size.tar") 754 if err != nil { 755 t.Fatal(err) 756 } 757 defer f.Close() 758 r := NewReader(f) 759 _, err = r.Next() 760 if err != ErrHeader { 761 t.Error("want ErrHeader, got", err) 762 } 763 io.Copy(ioutil.Discard, r) 764 } 765 766 // This used to hang in (*sparseFileReader).readHole due to missing 767 // verification of sparse offsets against file size. 768 func TestIssue10968(t *testing.T) { 769 f, err := os.Open("testdata/issue10968.tar") 770 if err != nil { 771 t.Fatal(err) 772 } 773 defer f.Close() 774 r := NewReader(f) 775 _, err = r.Next() 776 if err != nil { 777 t.Fatal(err) 778 } 779 _, err = io.Copy(ioutil.Discard, r) 780 if err != io.ErrUnexpectedEOF { 781 t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err) 782 } 783 } 784 785 // Do not panic if there are errors in header blocks after the pax header. 786 // Issue 11169 787 func TestIssue11169(t *testing.T) { 788 f, err := os.Open("testdata/issue11169.tar") 789 if err != nil { 790 t.Fatal(err) 791 } 792 defer f.Close() 793 r := NewReader(f) 794 _, err = r.Next() 795 if err == nil { 796 t.Fatal("Unexpected success") 797 } 798 } 799