github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/pkg/tar/tar_test.go (about) 1 // Copyright 2014 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tar 16 17 import ( 18 "archive/tar" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "runtime" 25 "syscall" 26 "testing" 27 "time" 28 29 "github.com/coreos/rkt/pkg/multicall" 30 "github.com/coreos/rkt/pkg/sys" 31 "github.com/coreos/rkt/pkg/uid" 32 ) 33 34 func init() { 35 multicall.MaybeExec() 36 } 37 38 type testTarEntry struct { 39 header *tar.Header 40 contents string 41 } 42 43 func newTestTar(entries []*testTarEntry) (string, error) { 44 t, err := ioutil.TempFile("", "test-tar") 45 if err != nil { 46 return "", err 47 } 48 defer t.Close() 49 tw := tar.NewWriter(t) 50 for _, entry := range entries { 51 // Add default mode 52 if entry.header.Mode == 0 { 53 if entry.header.Typeflag == tar.TypeDir { 54 entry.header.Mode = 0755 55 } else { 56 entry.header.Mode = 0644 57 } 58 } 59 // Add calling user uid and gid or tests will fail 60 entry.header.Uid = os.Getuid() 61 entry.header.Gid = os.Getgid() 62 if err := tw.WriteHeader(entry.header); err != nil { 63 return "", err 64 } 65 if _, err := io.WriteString(tw, entry.contents); err != nil { 66 return "", err 67 } 68 } 69 if err := tw.Close(); err != nil { 70 return "", err 71 } 72 return t.Name(), nil 73 } 74 75 type fileInfo struct { 76 path string 77 typeflag byte 78 size int64 79 contents string 80 mode os.FileMode 81 } 82 83 func fileInfoSliceToMap(slice []*fileInfo) map[string]*fileInfo { 84 fim := make(map[string]*fileInfo, len(slice)) 85 for _, fi := range slice { 86 fim[fi.path] = fi 87 } 88 return fim 89 } 90 91 func checkExpectedFiles(dir string, expectedFiles map[string]*fileInfo) error { 92 files := make(map[string]*fileInfo) 93 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 94 fm := info.Mode() 95 if path == dir { 96 return nil 97 } 98 relpath, err := filepath.Rel(dir, path) 99 if err != nil { 100 return err 101 } 102 switch { 103 case fm.IsRegular(): 104 files[relpath] = &fileInfo{path: relpath, typeflag: tar.TypeReg, size: info.Size(), mode: info.Mode().Perm()} 105 case info.IsDir(): 106 files[relpath] = &fileInfo{path: relpath, typeflag: tar.TypeDir, mode: info.Mode().Perm()} 107 case fm&os.ModeSymlink != 0: 108 files[relpath] = &fileInfo{path: relpath, typeflag: tar.TypeSymlink, mode: info.Mode()} 109 default: 110 return fmt.Errorf("file mode not handled: %v", fm) 111 } 112 113 return nil 114 }) 115 if err != nil { 116 return err 117 } 118 119 // Set defaults for not specified expected file mode 120 for _, ef := range expectedFiles { 121 if ef.mode == 0 { 122 if ef.typeflag == tar.TypeDir { 123 ef.mode = 0755 124 } else { 125 ef.mode = 0644 126 } 127 } 128 } 129 130 for _, ef := range expectedFiles { 131 _, ok := files[ef.path] 132 if !ok { 133 return fmt.Errorf("Expected file %q not in files", ef.path) 134 } 135 136 } 137 138 for _, file := range files { 139 ef, ok := expectedFiles[file.path] 140 if !ok { 141 return fmt.Errorf("file %q not in expectedFiles", file.path) 142 } 143 if ef.typeflag != file.typeflag { 144 return fmt.Errorf("file %q: file type differs: wanted: %d, got: %d", file.path, ef.typeflag, file.typeflag) 145 } 146 if ef.typeflag == tar.TypeReg { 147 if ef.size != file.size { 148 return fmt.Errorf("file %q: size differs: wanted %d, wanted: %d", file.path, ef.size, file.size) 149 } 150 if ef.contents != "" { 151 buf, err := ioutil.ReadFile(filepath.Join(dir, file.path)) 152 if err != nil { 153 return fmt.Errorf("unexpected error: %v", err) 154 } 155 if string(buf) != ef.contents { 156 return fmt.Errorf("unexpected contents, wanted: %s, got: %s", ef.contents, buf) 157 } 158 159 } 160 } 161 // Check modes but ignore symlinks 162 if ef.mode != file.mode && ef.typeflag != tar.TypeSymlink { 163 return fmt.Errorf("file %q: mode differs: wanted %#o, got: %#o", file.path, ef.mode, file.mode) 164 } 165 166 } 167 return nil 168 } 169 170 func TestExtractTarFolders(t *testing.T) { 171 if !sys.HasChrootCapability() { 172 t.Skipf("chroot capability not available. Disabling test.") 173 } 174 testExtractTarFolders(t, extractTarHelper) 175 } 176 func TestExtractTarFoldersInsecure(t *testing.T) { 177 testExtractTarFolders(t, extractTarInsecureHelper) 178 } 179 func testExtractTarFolders(t *testing.T, extractTar func(io.Reader, string) error) { 180 entries := []*testTarEntry{ 181 { 182 contents: "foo", 183 header: &tar.Header{ 184 Name: "deep/folder/foo.txt", 185 Size: 3, 186 }, 187 }, 188 { 189 header: &tar.Header{ 190 Name: "deep/folder/", 191 Typeflag: tar.TypeDir, 192 Mode: int64(0747), 193 }, 194 }, 195 { 196 contents: "bar", 197 header: &tar.Header{ 198 Name: "deep/folder/bar.txt", 199 Size: 3, 200 }, 201 }, 202 { 203 header: &tar.Header{ 204 Name: "deep/folder2/symlink.txt", 205 Typeflag: tar.TypeSymlink, 206 Linkname: "deep/folder/foo.txt", 207 }, 208 }, 209 { 210 header: &tar.Header{ 211 Name: "deep/folder2/", 212 Typeflag: tar.TypeDir, 213 Mode: int64(0747), 214 }, 215 }, 216 { 217 contents: "bar", 218 header: &tar.Header{ 219 Name: "deep/folder2/bar.txt", 220 Size: 3, 221 }, 222 }, 223 { 224 header: &tar.Header{ 225 Name: "deep/deep/folder", 226 Typeflag: tar.TypeDir, 227 Mode: int64(0755), 228 }, 229 }, 230 { 231 header: &tar.Header{ 232 Name: "deep/deep/", 233 Typeflag: tar.TypeDir, 234 Mode: int64(0747), 235 }, 236 }, 237 } 238 239 testTarPath, err := newTestTar(entries) 240 if err != nil { 241 t.Errorf("unexpected error: %v", err) 242 } 243 defer os.Remove(testTarPath) 244 containerTar, err := os.Open(testTarPath) 245 if err != nil { 246 t.Errorf("unexpected error: %v", err) 247 } 248 defer containerTar.Close() 249 tmpdir, err := ioutil.TempDir("", "rkt-temp-dir") 250 if err != nil { 251 t.Errorf("unexpected error: %v", err) 252 } 253 os.RemoveAll(tmpdir) 254 err = os.MkdirAll(tmpdir, 0755) 255 if err != nil { 256 t.Errorf("unexpected error: %v", err) 257 } 258 defer os.RemoveAll(tmpdir) 259 err = extractTar(containerTar, tmpdir) 260 if err != nil { 261 t.Errorf("unexpected error: %v", err) 262 } 263 matches, err := filepath.Glob(filepath.Join(tmpdir, "deep/folder/*.txt")) 264 if err != nil { 265 t.Errorf("unexpected error: %v", err) 266 } 267 if len(matches) != 2 { 268 t.Errorf("unexpected number of files found: %d, wanted 2", len(matches)) 269 } 270 matches, err = filepath.Glob(filepath.Join(tmpdir, "deep/folder2/*.txt")) 271 if err != nil { 272 t.Errorf("unexpected error: %v", err) 273 } 274 if len(matches) != 2 { 275 t.Errorf("unexpected number of files found: %d, wanted 2", len(matches)) 276 } 277 278 dirInfo, err := os.Lstat(filepath.Join(tmpdir, "deep/folder")) 279 if err != nil { 280 t.Errorf("unexpected error: %v", err) 281 } else if dirInfo.Mode().Perm() != os.FileMode(0747) { 282 t.Errorf("unexpected dir mode: %s", dirInfo.Mode()) 283 } 284 dirInfo, err = os.Lstat(filepath.Join(tmpdir, "deep/deep")) 285 if err != nil { 286 t.Errorf("unexpected error: %v", err) 287 } else if dirInfo.Mode().Perm() != os.FileMode(0747) { 288 t.Errorf("unexpected dir mode: %s", dirInfo.Mode()) 289 } 290 } 291 292 func TestExtractTarFileToBuf(t *testing.T) { 293 entries := []*testTarEntry{ 294 { 295 header: &tar.Header{ 296 Name: "folder/", 297 Typeflag: tar.TypeDir, 298 Mode: int64(0747), 299 }, 300 }, 301 { 302 contents: "foo", 303 header: &tar.Header{ 304 Name: "folder/foo.txt", 305 Size: 3, 306 }, 307 }, 308 { 309 contents: "bar", 310 header: &tar.Header{ 311 Name: "folder/bar.txt", 312 Size: 3, 313 }, 314 }, 315 { 316 header: &tar.Header{ 317 Name: "folder/symlink.txt", 318 Typeflag: tar.TypeSymlink, 319 Linkname: "folder/foo.txt", 320 }, 321 }, 322 } 323 testTarPath, err := newTestTar(entries) 324 if err != nil { 325 t.Fatalf("unexpected error: %v", err) 326 } 327 defer os.Remove(testTarPath) 328 containerTar1, err := os.Open(testTarPath) 329 if err != nil { 330 t.Fatalf("unexpected error: %v", err) 331 } 332 defer containerTar1.Close() 333 334 tr := tar.NewReader(containerTar1) 335 buf, err := extractFileFromTar(tr, "folder/foo.txt") 336 if err != nil { 337 t.Errorf("unexpected error: %v", err) 338 } 339 if string(buf) != "foo" { 340 t.Errorf("unexpected contents, wanted: %s, got: %s", "foo", buf) 341 } 342 343 containerTar2, err := os.Open(testTarPath) 344 if err != nil { 345 t.Errorf("unexpected error: %v", err) 346 } 347 defer containerTar2.Close() 348 tr = tar.NewReader(containerTar2) 349 buf, err = extractFileFromTar(tr, "folder/symlink.txt") 350 if err == nil { 351 t.Errorf("expected error") 352 } 353 } 354 355 func TestExtractTarPWL(t *testing.T) { 356 if !sys.HasChrootCapability() { 357 t.Skipf("chroot capability not available. Disabling test.") 358 } 359 testExtractTarPWL(t, extractTarHelperPWL) 360 } 361 func TestExtractTarPWLInsecure(t *testing.T) { 362 testExtractTarPWL(t, extractTarInsecureHelperPWL) 363 } 364 func testExtractTarPWL(t *testing.T, extractTar func(rdr io.Reader, target string, pwl PathWhitelistMap) error) { 365 entries := []*testTarEntry{ 366 { 367 header: &tar.Header{ 368 Name: "folder/", 369 Typeflag: tar.TypeDir, 370 Mode: int64(0747), 371 }, 372 }, 373 { 374 contents: "foo", 375 header: &tar.Header{ 376 Name: "folder/foo.txt", 377 Size: 3, 378 }, 379 }, 380 { 381 contents: "bar", 382 header: &tar.Header{ 383 Name: "folder/bar.txt", 384 Size: 3, 385 }, 386 }, 387 { 388 header: &tar.Header{ 389 Name: "folder/symlink.txt", 390 Typeflag: tar.TypeSymlink, 391 Linkname: "folder/foo.txt", 392 }, 393 }, 394 } 395 testTarPath, err := newTestTar(entries) 396 if err != nil { 397 t.Errorf("unexpected error: %v", err) 398 } 399 defer os.Remove(testTarPath) 400 containerTar, err := os.Open(testTarPath) 401 if err != nil { 402 t.Errorf("unexpected error: %v", err) 403 } 404 defer containerTar.Close() 405 tmpdir, err := ioutil.TempDir("", "rkt-temp-dir") 406 if err != nil { 407 t.Errorf("unexpected error: %v", err) 408 } 409 defer os.RemoveAll(tmpdir) 410 411 pwl := make(PathWhitelistMap) 412 pwl["folder/foo.txt"] = struct{}{} 413 err = extractTar(containerTar, tmpdir, pwl) 414 if err != nil { 415 t.Errorf("unexpected error: %v", err) 416 } 417 matches, err := filepath.Glob(filepath.Join(tmpdir, "folder/*.txt")) 418 if err != nil { 419 t.Errorf("unexpected error: %v", err) 420 } 421 if len(matches) != 1 { 422 t.Errorf("unexpected number of files found: %d, wanted 1", len(matches)) 423 } 424 } 425 426 func TestExtractTarOverwrite(t *testing.T) { 427 if !sys.HasChrootCapability() { 428 t.Skipf("chroot capability not available. Disabling test.") 429 } 430 testExtractTarOverwrite(t, extractTarHelper) 431 } 432 func TestExtractTarOverwriteInsecure(t *testing.T) { 433 testExtractTarOverwrite(t, extractTarInsecureHelper) 434 } 435 func testExtractTarOverwrite(t *testing.T, extractTar func(io.Reader, string) error) { 436 tmpdir, err := ioutil.TempDir("", "rkt-temp-dir") 437 if err != nil { 438 t.Fatalf("unexpected error: %v", err) 439 } 440 defer os.RemoveAll(tmpdir) 441 442 entries := []*testTarEntry{ 443 { 444 contents: "hello", 445 header: &tar.Header{ 446 Name: "hello.txt", 447 Size: 5, 448 }, 449 }, 450 { 451 header: &tar.Header{ 452 Name: "afolder", 453 Typeflag: tar.TypeDir, 454 }, 455 }, 456 { 457 contents: "hello", 458 header: &tar.Header{ 459 Name: "afolder/hello.txt", 460 Size: 5, 461 }, 462 }, 463 { 464 contents: "hello", 465 header: &tar.Header{ 466 Name: "afile", 467 Size: 5, 468 }, 469 }, 470 { 471 header: &tar.Header{ 472 Name: "folder01", 473 Typeflag: tar.TypeDir, 474 }, 475 }, 476 { 477 contents: "hello", 478 header: &tar.Header{ 479 Name: "folder01/file01", 480 Size: 5, 481 }, 482 }, 483 { 484 contents: "hello", 485 header: &tar.Header{ 486 Name: "filesymlinked", 487 Size: 5, 488 }, 489 }, 490 { 491 header: &tar.Header{ 492 Name: "linktofile", 493 Linkname: "filesymlinked", 494 Typeflag: tar.TypeSymlink, 495 }, 496 }, 497 498 { 499 header: &tar.Header{ 500 Name: "dirsymlinked", 501 Typeflag: tar.TypeDir, 502 }, 503 }, 504 { 505 header: &tar.Header{ 506 Name: "linktodir", 507 Linkname: "dirsymlinked", 508 Typeflag: tar.TypeSymlink, 509 }, 510 }, 511 } 512 513 testTarPath, err := newTestTar(entries) 514 if err != nil { 515 t.Fatalf("unexpected error: %v", err) 516 } 517 defer os.Remove(testTarPath) 518 containerTar1, err := os.Open(testTarPath) 519 if err != nil { 520 t.Fatalf("unexpected error: %v", err) 521 } 522 defer containerTar1.Close() 523 err = extractTar(containerTar1, tmpdir) 524 if err != nil { 525 t.Fatalf("unexpected error: %v", err) 526 } 527 528 // Now overwrite: 529 // a file with a new file 530 // a dir with a file 531 entries = []*testTarEntry{ 532 { 533 contents: "newhello", 534 header: &tar.Header{ 535 Name: "hello.txt", 536 Size: 8, 537 }, 538 }, 539 // Now this is a file 540 { 541 contents: "nowafile", 542 header: &tar.Header{ 543 Name: "afolder", 544 Typeflag: tar.TypeReg, 545 Size: 8, 546 }, 547 }, 548 // Now this is a dir 549 { 550 header: &tar.Header{ 551 Name: "afile", 552 Typeflag: tar.TypeDir, 553 }, 554 }, 555 // Overwrite symlink to a file with a regular file 556 // the linked file shouldn't be removed 557 { 558 contents: "filereplacingsymlink", 559 header: &tar.Header{ 560 Name: "linktofile", 561 Typeflag: tar.TypeReg, 562 Size: 20, 563 }, 564 }, 565 // Overwrite symlink to a dir with a regular file 566 // the linked directory and all its contents shouldn't be 567 // removed 568 { 569 contents: "filereplacingsymlink", 570 header: &tar.Header{ 571 Name: "linktodir", 572 Typeflag: tar.TypeReg, 573 Size: 20, 574 }, 575 }, 576 // folder01 already exists and shouldn't be removed (keeping folder01/file01) 577 { 578 header: &tar.Header{ 579 Name: "folder01", 580 Typeflag: tar.TypeDir, 581 Mode: int64(0755), 582 }, 583 }, 584 { 585 contents: "hello", 586 header: &tar.Header{ 587 Name: "folder01/file02", 588 Size: 5, 589 Mode: int64(0644), 590 }, 591 }, 592 } 593 testTarPath, err = newTestTar(entries) 594 if err != nil { 595 t.Errorf("unexpected error: %v", err) 596 } 597 defer os.Remove(testTarPath) 598 containerTar2, err := os.Open(testTarPath) 599 if err != nil { 600 t.Errorf("unexpected error: %v", err) 601 } 602 defer containerTar2.Close() 603 err = extractTar(containerTar2, tmpdir) 604 605 expectedFiles := []*fileInfo{ 606 &fileInfo{path: "hello.txt", typeflag: tar.TypeReg, size: 8, contents: "newhello"}, 607 &fileInfo{path: "linktofile", typeflag: tar.TypeReg, size: 20}, 608 &fileInfo{path: "linktodir", typeflag: tar.TypeReg, size: 20}, 609 &fileInfo{path: "afolder", typeflag: tar.TypeReg, size: 8}, 610 &fileInfo{path: "dirsymlinked", typeflag: tar.TypeDir}, 611 &fileInfo{path: "afile", typeflag: tar.TypeDir}, 612 &fileInfo{path: "filesymlinked", typeflag: tar.TypeReg, size: 5}, 613 &fileInfo{path: "folder01", typeflag: tar.TypeDir}, 614 &fileInfo{path: "folder01/file01", typeflag: tar.TypeReg, size: 5}, 615 &fileInfo{path: "folder01/file02", typeflag: tar.TypeReg, size: 5}, 616 } 617 618 err = checkExpectedFiles(tmpdir, fileInfoSliceToMap(expectedFiles)) 619 if err != nil { 620 t.Errorf("unexpected error: %v", err) 621 } 622 } 623 624 func TestExtractTarTimes(t *testing.T) { 625 if !sys.HasChrootCapability() { 626 t.Skipf("chroot capability not available. Disabling test.") 627 } 628 testExtractTarTimes(t, extractTarHelper) 629 } 630 func TestExtractTarTimesInsecure(t *testing.T) { 631 testExtractTarTimes(t, extractTarInsecureHelper) 632 } 633 func testExtractTarTimes(t *testing.T, extractTar func(io.Reader, string) error) { 634 // Do not set ns as tar has second precision 635 time1 := time.Unix(100000, 0) 636 time2 := time.Unix(200000, 0) 637 time3 := time.Unix(300000, 0) 638 entries := []*testTarEntry{ 639 { 640 header: &tar.Header{ 641 Name: "folder/", 642 Typeflag: tar.TypeDir, 643 Mode: int64(0747), 644 ModTime: time1, 645 }, 646 }, 647 { 648 contents: "foo", 649 header: &tar.Header{ 650 Name: "folder/foo.txt", 651 Size: 3, 652 ModTime: time2, 653 }, 654 }, 655 { 656 header: &tar.Header{ 657 Name: "folder/symlink.txt", 658 Typeflag: tar.TypeSymlink, 659 Linkname: "folder/foo.txt", 660 ModTime: time3, 661 }, 662 }, 663 } 664 665 testTarPath, err := newTestTar(entries) 666 if err != nil { 667 t.Errorf("unexpected error: %v", err) 668 } 669 defer os.Remove(testTarPath) 670 containerTar, err := os.Open(testTarPath) 671 if err != nil { 672 t.Errorf("unexpected error: %v", err) 673 } 674 defer containerTar.Close() 675 tmpdir, err := ioutil.TempDir("", "rkt-temp-dir") 676 if err != nil { 677 t.Errorf("unexpected error: %v", err) 678 } 679 os.RemoveAll(tmpdir) 680 err = os.MkdirAll(tmpdir, 0755) 681 if err != nil { 682 t.Errorf("unexpected error: %v", err) 683 } 684 err = extractTar(containerTar, tmpdir) 685 if err != nil { 686 t.Errorf("unexpected error: %v", err) 687 } 688 err = checkTime(filepath.Join(tmpdir, "folder/"), time1) 689 if err != nil { 690 t.Errorf("unexpected error: %v", err) 691 } 692 err = checkTime(filepath.Join(tmpdir, "folder/foo.txt"), time2) 693 if err != nil { 694 t.Errorf("unexpected error: %v", err) 695 } 696 697 //Check only (by now) on linux 698 if runtime.GOOS == "linux" { 699 err = checkTime(filepath.Join(tmpdir, "folder/symlink.txt"), time3) 700 if err != nil { 701 t.Errorf("unexpected error: %v", err) 702 } 703 } 704 } 705 706 func checkTime(path string, time time.Time) error { 707 info, err := os.Lstat(path) 708 if err != nil { 709 return err 710 } 711 712 if info.ModTime() != time { 713 return fmt.Errorf("%s: info.ModTime: %s, different from expected time: %s", path, info.ModTime(), time) 714 } 715 return nil 716 } 717 718 func TestExtractTarHardLink(t *testing.T) { 719 if !sys.HasChrootCapability() { 720 t.Skipf("chroot capability not available. Disabling test.") 721 } 722 testExtractTarHardLink(t, extractTarHelper) 723 } 724 func TestExtractTarHardLinkInsecure(t *testing.T) { 725 testExtractTarHardLink(t, extractTarInsecureHelper) 726 } 727 func testExtractTarHardLink(t *testing.T, extractTar func(io.Reader, string) error) { 728 entries := []*testTarEntry{ 729 { 730 contents: "foo", 731 header: &tar.Header{ 732 Name: "/foo.txt", 733 Size: 3, 734 }, 735 }, 736 { 737 header: &tar.Header{ 738 Name: "foolink", 739 Typeflag: tar.TypeLink, 740 Linkname: "/foo.txt", 741 }, 742 }, 743 } 744 745 testTarPath, err := newTestTar(entries) 746 if err != nil { 747 t.Errorf("unexpected error: %v", err) 748 } 749 defer os.Remove(testTarPath) 750 containerTar, err := os.Open(testTarPath) 751 if err != nil { 752 t.Errorf("unexpected error: %v", err) 753 } 754 defer containerTar.Close() 755 tmpdir, err := ioutil.TempDir("", "rkt-temp-dir") 756 if err != nil { 757 t.Errorf("unexpected error: %v", err) 758 } 759 os.RemoveAll(tmpdir) 760 err = os.MkdirAll(tmpdir, 0755) 761 if err != nil { 762 t.Errorf("unexpected error: %v", err) 763 } 764 defer os.RemoveAll(tmpdir) 765 err = extractTar(containerTar, tmpdir) 766 if err != nil { 767 t.Errorf("unexpected error: %v", err) 768 } 769 var origFile syscall.Stat_t 770 err = syscall.Stat(filepath.Join(tmpdir, "/foo.txt"), &origFile) 771 if err != nil { 772 t.Errorf("unexpected error: %v", err) 773 } 774 var linkedFile syscall.Stat_t 775 err = syscall.Stat(filepath.Join(tmpdir, "/foolink"), &linkedFile) 776 if err != nil { 777 t.Errorf("unexpected error: %v", err) 778 } 779 if origFile.Nlink != 2 { 780 t.Errorf("wrong number of nlinks on original file, expecting: 2, actual: %d", origFile.Nlink) 781 } 782 if linkedFile.Nlink != 2 { 783 t.Errorf("wrong number of nlinks on linked file, expecting: 2, actual: %d", origFile.Nlink) 784 } 785 if origFile.Ino != linkedFile.Ino { 786 t.Errorf("original file and linked file have different inodes") 787 } 788 } 789 790 func extractTarHelper(rdr io.Reader, target string) error { 791 return extractTarHelperPWL(rdr, target, nil) 792 } 793 794 func extractTarHelperPWL(rdr io.Reader, target string, pwl PathWhitelistMap) error { 795 return ExtractTar(rdr, target, false, uid.NewBlankUidRange(), pwl) 796 } 797 798 func extractTarInsecureHelper(rdr io.Reader, target string) error { 799 return extractTarInsecureHelperPWL(rdr, target, nil) 800 } 801 802 func extractTarInsecureHelperPWL(rdr io.Reader, target string, pwl PathWhitelistMap) error { 803 editor, err := NewUidShiftingFilePermEditor(uid.NewBlankUidRange()) 804 if err != nil { 805 return err 806 } 807 return ExtractTarInsecure(tar.NewReader(rdr), target, true, pwl, editor) 808 }