archive_unix_test.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // +build !windows
  2. package archive
  3. import (
  4. "bytes"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "syscall"
  10. "testing"
  11. )
  12. func TestCanonicalTarNameForPath(t *testing.T) {
  13. cases := []struct{ in, expected string }{
  14. {"foo", "foo"},
  15. {"foo/bar", "foo/bar"},
  16. {"foo/dir/", "foo/dir/"},
  17. }
  18. for _, v := range cases {
  19. if out, err := CanonicalTarNameForPath(v.in); err != nil {
  20. t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
  21. } else if out != v.expected {
  22. t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
  23. }
  24. }
  25. }
  26. func TestCanonicalTarName(t *testing.T) {
  27. cases := []struct {
  28. in string
  29. isDir bool
  30. expected string
  31. }{
  32. {"foo", false, "foo"},
  33. {"foo", true, "foo/"},
  34. {"foo/bar", false, "foo/bar"},
  35. {"foo/bar", true, "foo/bar/"},
  36. }
  37. for _, v := range cases {
  38. if out, err := canonicalTarName(v.in, v.isDir); err != nil {
  39. t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
  40. } else if out != v.expected {
  41. t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
  42. }
  43. }
  44. }
  45. func TestChmodTarEntry(t *testing.T) {
  46. cases := []struct {
  47. in, expected os.FileMode
  48. }{
  49. {0000, 0000},
  50. {0777, 0777},
  51. {0644, 0644},
  52. {0755, 0755},
  53. {0444, 0444},
  54. }
  55. for _, v := range cases {
  56. if out := chmodTarEntry(v.in); out != v.expected {
  57. t.Fatalf("wrong chmod. expected:%v got:%v", v.expected, out)
  58. }
  59. }
  60. }
  61. func TestTarWithHardLink(t *testing.T) {
  62. origin, err := ioutil.TempDir("", "docker-test-tar-hardlink")
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. defer os.RemoveAll(origin)
  67. if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
  68. t.Fatal(err)
  69. }
  70. if err := os.Link(path.Join(origin, "1"), path.Join(origin, "2")); err != nil {
  71. t.Fatal(err)
  72. }
  73. var i1, i2 uint64
  74. if i1, err = getNlink(path.Join(origin, "1")); err != nil {
  75. t.Fatal(err)
  76. }
  77. // sanity check that we can hardlink
  78. if i1 != 2 {
  79. t.Skipf("skipping since hardlinks don't work here; expected 2 links, got %d", i1)
  80. }
  81. dest, err := ioutil.TempDir("", "docker-test-tar-hardlink-dest")
  82. if err != nil {
  83. t.Fatal(err)
  84. }
  85. defer os.RemoveAll(dest)
  86. // we'll do this in two steps to separate failure
  87. fh, err := Tar(origin, Uncompressed)
  88. if err != nil {
  89. t.Fatal(err)
  90. }
  91. // ensure we can read the whole thing with no error, before writing back out
  92. buf, err := ioutil.ReadAll(fh)
  93. if err != nil {
  94. t.Fatal(err)
  95. }
  96. bRdr := bytes.NewReader(buf)
  97. err = Untar(bRdr, dest, &TarOptions{Compression: Uncompressed})
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. if i1, err = getInode(path.Join(dest, "1")); err != nil {
  102. t.Fatal(err)
  103. }
  104. if i2, err = getInode(path.Join(dest, "2")); err != nil {
  105. t.Fatal(err)
  106. }
  107. if i1 != i2 {
  108. t.Errorf("expected matching inodes, but got %d and %d", i1, i2)
  109. }
  110. }
  111. func getNlink(path string) (uint64, error) {
  112. stat, err := os.Stat(path)
  113. if err != nil {
  114. return 0, err
  115. }
  116. statT, ok := stat.Sys().(*syscall.Stat_t)
  117. if !ok {
  118. return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys())
  119. }
  120. // We need this conversion on ARM64
  121. return uint64(statT.Nlink), nil
  122. }
  123. func getInode(path string) (uint64, error) {
  124. stat, err := os.Stat(path)
  125. if err != nil {
  126. return 0, err
  127. }
  128. statT, ok := stat.Sys().(*syscall.Stat_t)
  129. if !ok {
  130. return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys())
  131. }
  132. return statT.Ino, nil
  133. }