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