github.com/apcera/util@v0.0.0-20180322191801-7a50bc84ee48/tarhelper/tar_test.go (about) 1 // Copyright 2013-2016 Apcera Inc. All rights reserved. 2 3 package tarhelper 4 5 import ( 6 "archive/tar" 7 "bytes" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "os" 12 "path" 13 "testing" 14 "time" 15 16 tt "github.com/apcera/util/testtool" 17 ) 18 19 func makeTestDir(t *testing.T) string { 20 testHelper := tt.StartTest(t) 21 //defer testHelper.FinishTest() 22 23 cwd, err := os.Getwd() 24 tt.TestExpectSuccess(t, err) 25 testHelper.AddTestFinalizer(func() { 26 tt.TestExpectSuccess(t, os.Chdir(cwd)) 27 }) 28 dir := testHelper.TempDir() 29 tt.TestExpectSuccess(t, os.Chdir(dir)) 30 mode := os.FileMode(0755) 31 os.Mkdir(cwd, mode) //Don't care about return value. For some reason CWD is not created by go test on all systems. 32 tt.TestExpectSuccess(t, os.Mkdir("a", mode)) 33 tt.TestExpectSuccess(t, os.Mkdir("a/b", mode)) 34 tt.TestExpectSuccess(t, os.Mkdir("a/b/c", mode)) 35 tt.TestExpectSuccess(t, os.Mkdir("a/b/c/d", mode)) 36 tt.TestExpectSuccess(t, os.Mkdir("a/b/i", mode)) 37 tt.TestExpectSuccess(t, os.Mkdir("a/b/i/j", mode)) 38 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/c/d/e", []byte{}, mode)) 39 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/c/f", []byte{}, mode)) 40 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/g", []byte{}, mode)) 41 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/i/j/k", []byte{}, mode)) 42 tt.TestExpectSuccess(t, os.Symlink("/bin/bash", "a/b/bash")) 43 tt.TestExpectSuccess(t, os.Symlink("../i", "a/b/c/l")) 44 tt.TestExpectSuccess(t, os.Symlink("g", "a/b/h")) 45 tt.TestExpectSuccess(t, os.Symlink("k", "a/b/i/j/l")) 46 tt.TestExpectSuccess(t, os.Symlink("../../g", "a/b/i/j/m")) 47 return dir 48 } 49 50 func TestTarSimple(t *testing.T) { 51 testHelper := tt.StartTest(t) 52 defer testHelper.FinishTest() 53 54 w := bytes.NewBufferString("") 55 tw := NewTar(w, makeTestDir(t)) 56 tt.TestExpectSuccess(t, tw.Archive()) 57 } 58 59 func TestTarHooks(t *testing.T) { 60 testHelper := tt.StartTest(t) 61 defer testHelper.FinishTest() 62 63 w := bytes.NewBufferString("") 64 tw := NewTar(w, makeTestDir(t)) 65 prefixRan := false 66 suffixRan := false 67 tw.PrefixHook = func(archive *tar.Writer) error { 68 prefixRan = true 69 return nil 70 } 71 tw.SuffixHook = func(archive *tar.Writer) error { 72 suffixRan = true 73 return nil 74 } 75 tt.TestExpectSuccess(t, tw.Archive()) 76 tt.TestTrue(t, prefixRan) 77 tt.TestTrue(t, suffixRan) 78 } 79 80 func TestTarVirtualPath(t *testing.T) { 81 testHelper := tt.StartTest(t) 82 defer testHelper.FinishTest() 83 84 w := bytes.NewBufferString("") 85 tw := NewTar(w, makeTestDir(t)) 86 tw.VirtualPath = "foo" 87 tt.TestExpectSuccess(t, tw.Archive()) 88 } 89 90 func TestExcludeRootPath(t *testing.T) { 91 testHelper := tt.StartTest(t) 92 defer testHelper.FinishTest() 93 94 w := bytes.NewBufferString("") 95 tw := NewTar(w, makeTestDir(t)) 96 tw.ExcludeRootPath = true 97 tt.TestEqual(t, tw.excludeRootPath("./"), true) 98 tt.TestExpectSuccess(t, tw.Archive()) 99 100 archive := tar.NewReader(w) 101 rootHeader := "" 102 for { 103 header, err := archive.Next() 104 if err == io.EOF { 105 break 106 } 107 if header.Name == "./" { 108 rootHeader = header.Name 109 } 110 } 111 112 tt.TestNotEqual(t, rootHeader, "./") 113 } 114 115 func TestIncludeRootPath(t *testing.T) { 116 testHelper := tt.StartTest(t) 117 defer testHelper.FinishTest() 118 119 w := bytes.NewBufferString("") 120 tw := NewTar(w, makeTestDir(t)) 121 tw.ExcludeRootPath = false 122 tt.TestEqual(t, tw.excludeRootPath("./"), false) 123 tt.TestExpectSuccess(t, tw.Archive()) 124 125 archive := tar.NewReader(w) 126 rootHeader := "" 127 for { 128 header, err := archive.Next() 129 if err == io.EOF { 130 break 131 } 132 if header.Name == "./" { 133 rootHeader = header.Name 134 } 135 } 136 137 tt.TestEqual(t, rootHeader, "./") 138 } 139 140 func TestPathExclusion(t *testing.T) { 141 testHelper := tt.StartTest(t) 142 defer testHelper.FinishTest() 143 144 type testcase struct { 145 RE string // e.g. "p.*h" 146 Path string // e.g. "path" 147 Expected map[string]bool 148 } 149 150 testcases := []testcase{ 151 { 152 RE: "simple", Path: "simple", 153 Expected: map[string]bool{ 154 "simple": true, 155 "/simple": true, 156 "simple/": true, 157 "/simple/": true, 158 "/before/simple": true, 159 "/three/levels/before/simple": true, 160 }, 161 }, { 162 RE: "/simple", Path: "simple", 163 Expected: map[string]bool{ 164 "/simple": true, "/simple/": true, 165 }, 166 }, { 167 RE: "slash/", 168 Path: "slash", 169 Expected: map[string]bool{}, 170 }, { 171 RE: "/simple/", 172 Path: "simple", 173 Expected: map[string]bool{}, 174 }, { 175 RE: "sim.*-RE", 176 Path: "simple-RE", 177 Expected: map[string]bool{ 178 "simple-RE": true, 179 "/simple-RE": true, 180 "simple-RE/": true, 181 "/simple-RE/": true, 182 "/before/simple-RE": true, 183 "/three/levels/before/simple-RE": true, 184 "simp-middle-le-RE": true, 185 }, 186 }, { 187 RE: "simple-RE.*", 188 Path: "simple-RE", 189 Expected: map[string]bool{ 190 "simple-RE": true, 191 "/simple-RE": true, 192 "simple-RE/": true, 193 "/simple-RE/": true, 194 "/before/simple-RE": true, 195 "/three/levels/before/simple-RE": true, 196 "simple-RE-after": true, 197 }, 198 }, { 199 RE: "/simple-RE.*", 200 Path: "simple-RE", 201 Expected: map[string]bool{ 202 "/simple-RE": true, 203 "/simple-RE/": true, 204 "/simple-RE/after": true, 205 "/simple-RE/three/levels/after": true, 206 }, 207 }, 208 } 209 210 // test the "empty exclusion list" cases 211 w := bytes.NewBufferString("") 212 tw := NewTar(w, makeTestDir(t)) 213 tt.TestEqual(t, tw.shouldBeExcluded("/any/thing", false), false) 214 tw.ExcludePath("") 215 tt.TestEqual(t, tw.shouldBeExcluded("/any/thing", false), false) 216 217 // test these cases on new instances of Tar object to avoid any 218 // possible side effects/conflicts 219 220 for _, tc := range testcases { 221 w = bytes.NewBufferString("") 222 tw = NewTar(w, makeTestDir(t)) 223 tw.ExcludePath(tc.RE) 224 225 stdPaths := []string{ 226 tc.Path, 227 "/" + tc.Path, 228 tc.Path + "/", 229 "/" + tc.Path + "/", 230 "/before/" + tc.Path, 231 "/" + tc.Path + "/after", 232 "/before/" + tc.Path + "/after", 233 "/three/levels/before/" + tc.Path, 234 "/" + tc.Path + "/three/levels/after", 235 "before-" + tc.Path, 236 tc.Path + "-after", 237 "before-" + tc.Path + "-after", 238 tc.Path[:len(tc.Path)/2] + "-middle-" + tc.Path[len(tc.Path)/2:], 239 } 240 241 for _, path := range stdPaths { 242 tt.TestEqual(t, tw.shouldBeExcluded(path, false), tc.Expected[path], 243 fmt.Sprintf("Path:%q, tc:%v", path, tc)) 244 delete(tc.Expected, path) 245 } 246 247 for path, exp := range tc.Expected { 248 tt.TestEqual(t, tw.shouldBeExcluded(path, false), exp) 249 } 250 } 251 252 // This should return nil for these paths as they are excluded. 253 // An extra check that processEntry indeed bails on excluded items 254 w = bytes.NewBufferString("") 255 tw = NewTar(w, makeTestDir(t)) 256 tw.ExcludePath("/one.*") 257 tw.ExcludePath("/two/two/.*") 258 tw.ExcludePath("/three/three/three.*") 259 var fi staticFileInfo 260 tt.TestExpectSuccess(t, tw.processEntry("/one/something", fi, []string{})) 261 tt.TestExpectSuccess(t, tw.processEntry("/two/two/something", fi, []string{})) 262 tt.TestExpectSuccess(t, tw.processEntry("/three/three/three-something", fi, []string{})) 263 } 264 265 func TestTarIDMapping(t *testing.T) { 266 testHelper := tt.StartTest(t) 267 defer testHelper.FinishTest() 268 269 // set up our mapping funcs 270 uidFuncCalled := false 271 gidFuncCalled := false 272 uidMappingFunc := func(uid int) (int, error) { 273 uidFuncCalled = true 274 return 0, nil 275 } 276 gidMappingFunc := func(gid int) (int, error) { 277 gidFuncCalled = true 278 return 0, nil 279 } 280 281 // set up our untar and use the test tar helper 282 w := bytes.NewBufferString("") 283 tw := NewTar(w, makeTestDir(t)) 284 tw.IncludeOwners = true 285 tw.OwnerMappingFunc = uidMappingFunc 286 tw.GroupMappingFunc = gidMappingFunc 287 tt.TestExpectSuccess(t, tw.Archive()) 288 289 // untar it and verify all of the uid/gids are 0 290 archive := tar.NewReader(w) 291 for { 292 header, err := archive.Next() 293 if err == io.EOF { 294 break 295 } 296 tt.TestExpectSuccess(t, err) 297 tt.TestEqual(t, header.Uid, 0) 298 tt.TestEqual(t, header.Gid, 0) 299 } 300 } 301 302 func TestSymlinkOptDereferenceLinkToFile(t *testing.T) { 303 testHelper := tt.StartTest(t) 304 defer testHelper.FinishTest() 305 306 cwd, err := os.Getwd() 307 tt.TestExpectSuccess(t, err) 308 testHelper.AddTestFinalizer(func() { 309 tt.TestExpectSuccess(t, os.Chdir(cwd)) 310 }) 311 312 dir := testHelper.TempDir() 313 tt.TestExpectSuccess(t, os.Chdir(dir)) 314 mode := os.FileMode(0755) 315 tt.TestExpectSuccess(t, os.Mkdir("a", mode)) 316 tt.TestExpectSuccess(t, os.Mkdir("a/b", mode)) 317 tt.TestExpectSuccess(t, os.Mkdir("a/b/c", mode)) 318 tt.TestExpectSuccess(t, os.Mkdir("a/b/c/d", mode)) 319 tt.TestExpectSuccess(t, os.Mkdir("a/b/i", mode)) 320 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/i/j", []byte{'t', 'e', 's', 't'}, mode)) 321 tt.TestExpectSuccess(t, os.Symlink("/bin/bash", "a/b/bash")) 322 tt.TestExpectSuccess(t, os.Symlink("../i/j", "a/b/c/lj")) 323 w := bytes.NewBufferString("") 324 tw := NewTar(w, dir) 325 tw.UserOptions |= c_DEREF 326 tt.TestExpectSuccess(t, tw.Archive()) 327 328 extractionPath := path.Join(dir, "pkg") 329 err = os.MkdirAll(extractionPath, 0755) 330 tt.TestExpectSuccess(t, err) 331 332 // extract 333 r := bytes.NewReader(w.Bytes()) 334 u := NewUntar(r, extractionPath) 335 u.AbsoluteRoot = dir 336 tt.TestExpectSuccess(t, u.Extract()) 337 338 dirExists := func(name string) { 339 f, err := os.Stat(path.Join(extractionPath, name)) 340 tt.TestExpectSuccess(t, err) 341 tt.TestEqual(t, true, f.IsDir()) 342 } 343 344 sameFileContents := func(f1 string, f2 string) { 345 b1, err := ioutil.ReadFile(f1) 346 tt.TestExpectSuccess(t, err) 347 348 b2, err := ioutil.ReadFile(f2) 349 tt.TestExpectSuccess(t, err) 350 tt.TestEqual(t, b1, b2) 351 } 352 353 // Verify dirs a, a/b, a/b/c, a/b/c/d 354 dirExists("./a") 355 dirExists("./a/b") 356 dirExists("./a/b/c") 357 dirExists("./a/b/c/d") 358 dirExists("./a/b/i") 359 360 // Verify a/b/bash and /bin/bash are same 361 sameFileContents(path.Join(extractionPath, "./a/b/bash"), "/bin/bash") 362 363 // Verify that a/b/i/j and a/b/c/lj contents are same 364 sameFileContents(path.Join(extractionPath, "./a/b/i/j"), path.Join(extractionPath, "./a/b/c/lj")) 365 } 366 367 func TestSymlinkOptDereferenceLinkToDir(t *testing.T) { 368 testHelper := tt.StartTest(t) 369 defer testHelper.FinishTest() 370 371 cwd, err := os.Getwd() 372 tt.TestExpectSuccess(t, err) 373 testHelper.AddTestFinalizer(func() { 374 tt.TestExpectSuccess(t, os.Chdir(cwd)) 375 }) 376 377 dir := testHelper.TempDir() 378 tt.TestExpectSuccess(t, os.Chdir(dir)) 379 mode := os.FileMode(0755) 380 tt.TestExpectSuccess(t, os.Mkdir("a", mode)) 381 tt.TestExpectSuccess(t, os.Mkdir("a/b", mode)) 382 tt.TestExpectSuccess(t, os.Mkdir("a/b/c", mode)) 383 tt.TestExpectSuccess(t, os.Mkdir("a/b/c/d", mode)) 384 tt.TestExpectSuccess(t, os.Mkdir("a/b/i", mode)) 385 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/i/j", []byte{'t', 'e', 's', 't'}, mode)) 386 tt.TestExpectSuccess(t, os.Symlink("/bin/bash", "a/b/bash")) 387 tt.TestExpectSuccess(t, os.Symlink("../i", "a/b/c/l")) 388 w := bytes.NewBufferString("") 389 tw := NewTar(w, dir) 390 tw.UserOptions |= c_DEREF 391 tt.TestExpectSuccess(t, tw.Archive()) 392 393 extractionPath := path.Join(dir, "pkg") 394 err = os.MkdirAll(extractionPath, 0755) 395 tt.TestExpectSuccess(t, err) 396 397 // extract 398 r := bytes.NewReader(w.Bytes()) 399 u := NewUntar(r, extractionPath) 400 u.AbsoluteRoot = dir 401 tt.TestExpectSuccess(t, u.Extract()) 402 403 dirExists := func(name string) { 404 f, err := os.Stat(path.Join(extractionPath, name)) 405 tt.TestExpectSuccess(t, err) 406 tt.TestEqual(t, true, f.IsDir()) 407 } 408 409 sameFileContents := func(f1 string, f2 string) { 410 b1, err := ioutil.ReadFile(f1) 411 tt.TestExpectSuccess(t, err) 412 413 b2, err := ioutil.ReadFile(f2) 414 tt.TestExpectSuccess(t, err) 415 tt.TestEqual(t, b1, b2) 416 } 417 418 // Verify dirs a, a/b, a/b/c, a/b/c/d 419 dirExists("./a") 420 dirExists("./a/b") 421 dirExists("./a/b/c") 422 dirExists("./a/b/c/d") 423 dirExists("./a/b/i") 424 425 // Verify a/b/bash and /bin/bash are same 426 sameFileContents(path.Join(extractionPath, "./a/b/bash"), "/bin/bash") 427 428 // Verify that a/b/i/j and a/b/c/l/j contents are same 429 sameFileContents(path.Join(extractionPath, "./a/b/i/j"), path.Join(extractionPath, "./a/b/c/l/j")) 430 } 431 432 func TestSymlinkOptDereferenceCircular(t *testing.T) { 433 testHelper := tt.StartTest(t) 434 defer testHelper.FinishTest() 435 436 cwd, err := os.Getwd() 437 tt.TestExpectSuccess(t, err) 438 testHelper.AddTestFinalizer(func() { 439 tt.TestExpectSuccess(t, os.Chdir(cwd)) 440 }) 441 442 dir := testHelper.TempDir() 443 tt.TestExpectSuccess(t, os.Chdir(dir)) 444 mode := os.FileMode(0755) 445 tt.TestExpectSuccess(t, os.Mkdir("a", mode)) 446 tt.TestExpectSuccess(t, os.Mkdir("a/b", mode)) 447 tt.TestExpectSuccess(t, os.Mkdir("a/b/c", mode)) 448 tt.TestExpectSuccess(t, os.Mkdir("a/b/c/d", mode)) 449 tt.TestExpectSuccess(t, os.Mkdir("a/b/i", mode)) 450 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/i/j", []byte{'t', 'e', 's', 't'}, mode)) 451 tt.TestExpectSuccess(t, os.Symlink("/bin/bash", "a/b/bash")) 452 tt.TestExpectSuccess(t, os.Symlink(dir+"/a/b/c/l", "a/b/i/ll")) 453 tt.TestExpectSuccess(t, os.Symlink("../i", "a/b/c/l")) 454 w := bytes.NewBufferString("") 455 tw := NewTar(w, dir) 456 tw.UserOptions |= c_DEREF 457 tt.TestExpectSuccess(t, tw.Archive()) 458 459 extractionPath := path.Join(dir, "pkg") 460 err = os.MkdirAll(extractionPath, 0755) 461 tt.TestExpectSuccess(t, err) 462 463 // extract 464 r := bytes.NewReader(w.Bytes()) 465 u := NewUntar(r, extractionPath) 466 u.AbsoluteRoot = dir 467 tt.TestExpectSuccess(t, u.Extract()) 468 469 fileExists := func(name string) { 470 _, err := os.Stat(path.Join(extractionPath, name)) 471 tt.TestExpectSuccess(t, err) 472 } 473 474 dirExists := func(name string) { 475 f, err := os.Stat(path.Join(extractionPath, name)) 476 tt.TestExpectSuccess(t, err) 477 tt.TestEqual(t, true, f.IsDir()) 478 } 479 480 sameFileContents := func(f1 string, f2 string) { 481 b1, err := ioutil.ReadFile(f1) 482 tt.TestExpectSuccess(t, err) 483 484 b2, err := ioutil.ReadFile(f2) 485 tt.TestExpectSuccess(t, err) 486 tt.TestEqual(t, b1, b2) 487 } 488 489 // Verify dirs a, a/b, a/b/c, a/b/c/d 490 dirExists("./a") 491 dirExists("./a/b") 492 dirExists("./a/b/c") 493 dirExists("./a/b/c/d") 494 dirExists("./a/b/i") 495 496 // Verify that the file 'j' exists in both a/b/i and a/b/c/l 497 fileExists("./a/b/i/j") 498 fileExists("./a/b/c/l/j") 499 500 // Verify a/b/bash 501 sameFileContents(path.Join(extractionPath, "./a/b/bash"), "/bin/bash") 502 503 // Verify that a/b/i/j and a/b/c/l/j contents are same 504 sameFileContents(path.Join(extractionPath, "./a/b/i/j"), path.Join(extractionPath, "./a/b/c/l/j")) 505 506 // Verify that the circular symbolic link a/b/i/ll does not exis 507 _, err = os.Stat(path.Join(extractionPath, "./a/b/i/ll")) 508 tt.TestEqual(t, true, os.IsNotExist(err)) 509 } 510 511 func TestSymlinkOptDereferenceCircularToRoot(t *testing.T) { 512 testHelper := tt.StartTest(t) 513 defer testHelper.FinishTest() 514 515 cwd, err := os.Getwd() 516 tt.TestExpectSuccess(t, err) 517 testHelper.AddTestFinalizer(func() { 518 tt.TestExpectSuccess(t, os.Chdir(cwd)) 519 }) 520 521 dir := testHelper.TempDir() 522 tt.TestExpectSuccess(t, os.Chdir(dir)) 523 mode := os.FileMode(0755) 524 tt.TestExpectSuccess(t, os.Mkdir("a", mode)) 525 tt.TestExpectSuccess(t, os.Mkdir("a/b", mode)) 526 tt.TestExpectSuccess(t, os.Mkdir("a/b/c", mode)) 527 tt.TestExpectSuccess(t, os.Mkdir("a/b/c/d", mode)) 528 tt.TestExpectSuccess(t, os.Mkdir("a/b/i", mode)) 529 tt.TestExpectSuccess(t, ioutil.WriteFile("a/b/i/j", []byte{'t', 'e', 's', 't'}, mode)) 530 tt.TestExpectSuccess(t, os.Symlink("/bin/bash", "a/b/bash")) 531 tt.TestExpectSuccess(t, os.Symlink(dir+"/a", "a/b/i/ll")) 532 w := bytes.NewBufferString("") 533 tw := NewTar(w, dir) 534 tw.UserOptions |= c_DEREF 535 tt.TestExpectSuccess(t, tw.Archive()) 536 537 extractionPath := path.Join(dir, "pkg") 538 err = os.MkdirAll(extractionPath, 0755) 539 tt.TestExpectSuccess(t, err) 540 541 // extract 542 r := bytes.NewReader(w.Bytes()) 543 u := NewUntar(r, extractionPath) 544 u.AbsoluteRoot = dir 545 tt.TestExpectSuccess(t, u.Extract()) 546 547 fileExists := func(name string) { 548 _, err := os.Stat(path.Join(extractionPath, name)) 549 tt.TestExpectSuccess(t, err) 550 } 551 552 dirExists := func(name string) { 553 f, err := os.Stat(path.Join(extractionPath, name)) 554 tt.TestExpectSuccess(t, err) 555 tt.TestEqual(t, true, f.IsDir()) 556 } 557 558 sameFileContents := func(f1 string, f2 string) { 559 b1, err := ioutil.ReadFile(f1) 560 tt.TestExpectSuccess(t, err) 561 562 b2, err := ioutil.ReadFile(f2) 563 tt.TestExpectSuccess(t, err) 564 tt.TestEqual(t, b1, b2) 565 } 566 567 // Verify dirs a, a/b, a/b/c, a/b/c/d 568 dirExists("./a") 569 dirExists("./a/b") 570 dirExists("./a/b/c") 571 dirExists("./a/b/c/d") 572 dirExists("./a/b/i") 573 574 // Verify that the file 'j' exists in a/b/i 575 fileExists("./a/b/i/j") 576 577 // Verify a/b/bash 578 sameFileContents(path.Join(extractionPath, "./a/b/bash"), "/bin/bash") 579 580 // Verify that the circular symbolic link a/b/i/ll does not exist 581 _, err = os.Stat(path.Join(extractionPath, "./a/b/i/ll")) 582 tt.TestEqual(t, true, os.IsNotExist(err)) 583 } 584 585 func TestTarPointedToFile(t *testing.T) { 586 testHelper := tt.StartTest(t) 587 defer testHelper.FinishTest() 588 589 dir := testHelper.TempDir() 590 apath := path.Join(dir, "a") 591 592 // write the file, then read it the same way that we'll validate it 593 tt.TestExpectSuccess(t, ioutil.WriteFile(apath, []byte("hello world"), os.FileMode(0644))) 594 contents, err := ioutil.ReadFile(apath) 595 tt.TestExpectSuccess(t, err) 596 tt.TestEqual(t, string(contents), "hello world") 597 598 // tar the file 599 w := bytes.NewBufferString("") 600 tw := NewTar(w, apath) 601 tt.TestExpectSuccess(t, tw.Archive()) 602 603 // should then also be able to untar it 604 dir = testHelper.TempDir() 605 u := NewUntar(w, dir) 606 u.AbsoluteRoot = dir 607 tt.TestExpectSuccess(t, u.Extract()) 608 609 // stat it, ensure it exists and is a file, not a directory 610 stat, err := os.Stat(path.Join(dir, "a")) 611 tt.TestExpectSuccess(t, err) 612 tt.TestEqual(t, stat.IsDir(), false, "should be a file, not a directory") 613 614 // read the contents to verify 615 contents, err = ioutil.ReadFile(path.Join(dir, "a")) 616 tt.TestExpectSuccess(t, err) 617 tt.TestEqual(t, string(contents), "hello world") 618 } 619 620 func TestTarPreserveSetuid(t *testing.T) { 621 testHelper := tt.StartTest(t) 622 defer testHelper.FinishTest() 623 624 dir := testHelper.TempDir() 625 apath := path.Join(dir, "a") 626 627 err := ioutil.WriteFile(apath, []byte("hello world"), os.FileMode(0644)) 628 tt.TestExpectSuccess(t, err) 629 630 err = os.Chmod(apath, os.FileMode(0644)|os.ModeSetuid) 631 tt.TestExpectSuccess(t, err) 632 633 w := bytes.NewBufferString("") 634 tw := NewTar(w, apath) 635 err = tw.Archive() 636 tt.TestExpectSuccess(t, err) 637 638 dir = testHelper.TempDir() 639 u := NewUntar(w, dir) 640 u.AbsoluteRoot = dir 641 err = u.Extract() 642 tt.TestExpectSuccess(t, err) 643 644 stat, err := os.Stat(path.Join(dir, "a")) 645 tt.TestExpectSuccess(t, err) 646 tt.TestEqual(t, stat.Mode()&os.ModeSetuid != 0, true, "must have setuid bit") 647 } 648 649 func TestTarCustomHandler(t *testing.T) { 650 testHelper := tt.StartTest(t) 651 defer testHelper.FinishTest() 652 653 w := bytes.NewBufferString("") 654 tw := NewTar(w, makeTestDir(t)) 655 tw.CustomHandlers = []TarCustomHandler{ 656 func(fullpath string, fi os.FileInfo, header *tar.Header) (bool, error) { 657 if header.Name == "a/b/i/j/m" { 658 header.Name = "a/b/i/j/n" 659 header.Size = 0 660 return true, nil 661 } 662 return false, nil 663 }, 664 } 665 tt.TestExpectSuccess(t, tw.Archive()) 666 667 archive := tar.NewReader(w) 668 hasRenamedFile := false 669 for { 670 header, err := archive.Next() 671 if err == io.EOF { 672 break 673 } 674 if header.Name == "a/b/i/j/m" { 675 tt.Fatalf(t, "The \"a/b/i/j/m\" file should have been omitted") 676 } 677 if header.Name == "a/b/i/j/n" { 678 hasRenamedFile = true 679 } 680 } 681 682 tt.TestEqual(t, hasRenamedFile, true, "The tar file did not include the renamed file") 683 } 684 685 type staticFileInfo struct{} 686 687 func (m staticFileInfo) Name() string { return "foo" } 688 func (m staticFileInfo) Size() int64 { return 1 } 689 func (m staticFileInfo) Mode() os.FileMode { return 7777 } 690 func (m staticFileInfo) ModTime() time.Time { return time.Now() } 691 func (m staticFileInfo) IsDir() bool { return false } 692 func (m staticFileInfo) Sys() interface{} { return nil }