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