changes_posix_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package archive // import "github.com/docker/docker/pkg/archive"
  2. import (
  3. "archive/tar"
  4. "fmt"
  5. "io"
  6. "os"
  7. "path"
  8. "sort"
  9. "testing"
  10. "github.com/docker/docker/pkg/idtools"
  11. )
  12. func TestHardLinkOrder(t *testing.T) {
  13. names := []string{"file1.txt", "file2.txt", "file3.txt"}
  14. msg := []byte("Hey y'all")
  15. // Create dir
  16. src, err := os.MkdirTemp("", "docker-hardlink-test-src-")
  17. if err != nil {
  18. t.Fatal(err)
  19. }
  20. defer os.RemoveAll(src)
  21. for _, name := range names {
  22. func() {
  23. err := os.WriteFile(path.Join(src, name), msg, 0666)
  24. if err != nil {
  25. t.Fatal(err)
  26. }
  27. }()
  28. }
  29. // Create dest, with changes that includes hardlinks
  30. dest, err := os.MkdirTemp("", "docker-hardlink-test-dest-")
  31. if err != nil {
  32. t.Fatal(err)
  33. }
  34. os.RemoveAll(dest) // we just want the name, at first
  35. if err := copyDir(src, dest); err != nil {
  36. t.Fatal(err)
  37. }
  38. defer os.RemoveAll(dest)
  39. for _, name := range names {
  40. for i := 0; i < 5; i++ {
  41. if err := os.Link(path.Join(dest, name), path.Join(dest, fmt.Sprintf("%s.link%d", name, i))); err != nil {
  42. t.Fatal(err)
  43. }
  44. }
  45. }
  46. // get changes
  47. changes, err := ChangesDirs(dest, src)
  48. if err != nil {
  49. t.Fatal(err)
  50. }
  51. // sort
  52. sort.Sort(changesByPath(changes))
  53. // ExportChanges
  54. ar, err := ExportChanges(dest, changes, idtools.IdentityMapping{})
  55. if err != nil {
  56. t.Fatal(err)
  57. }
  58. hdrs, err := walkHeaders(ar)
  59. if err != nil {
  60. t.Fatal(err)
  61. }
  62. // reverse sort
  63. sort.Sort(sort.Reverse(changesByPath(changes)))
  64. // ExportChanges
  65. arRev, err := ExportChanges(dest, changes, idtools.IdentityMapping{})
  66. if err != nil {
  67. t.Fatal(err)
  68. }
  69. hdrsRev, err := walkHeaders(arRev)
  70. if err != nil {
  71. t.Fatal(err)
  72. }
  73. // line up the two sets
  74. sort.Sort(tarHeaders(hdrs))
  75. sort.Sort(tarHeaders(hdrsRev))
  76. // compare Size and LinkName
  77. for i := range hdrs {
  78. if hdrs[i].Name != hdrsRev[i].Name {
  79. t.Errorf("headers - expected name %q; but got %q", hdrs[i].Name, hdrsRev[i].Name)
  80. }
  81. if hdrs[i].Size != hdrsRev[i].Size {
  82. t.Errorf("headers - %q expected size %d; but got %d", hdrs[i].Name, hdrs[i].Size, hdrsRev[i].Size)
  83. }
  84. if hdrs[i].Typeflag != hdrsRev[i].Typeflag {
  85. t.Errorf("headers - %q expected type %d; but got %d", hdrs[i].Name, hdrs[i].Typeflag, hdrsRev[i].Typeflag)
  86. }
  87. if hdrs[i].Linkname != hdrsRev[i].Linkname {
  88. t.Errorf("headers - %q expected linkname %q; but got %q", hdrs[i].Name, hdrs[i].Linkname, hdrsRev[i].Linkname)
  89. }
  90. }
  91. }
  92. type tarHeaders []tar.Header
  93. func (th tarHeaders) Len() int { return len(th) }
  94. func (th tarHeaders) Swap(i, j int) { th[j], th[i] = th[i], th[j] }
  95. func (th tarHeaders) Less(i, j int) bool { return th[i].Name < th[j].Name }
  96. func walkHeaders(r io.Reader) ([]tar.Header, error) {
  97. t := tar.NewReader(r)
  98. var headers []tar.Header
  99. for {
  100. hdr, err := t.Next()
  101. if err != nil {
  102. if err == io.EOF {
  103. break
  104. }
  105. return headers, err
  106. }
  107. headers = append(headers, *hdr)
  108. }
  109. return headers, nil
  110. }