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  }