@@ -1871,3 +1871,95 @@ func testRemove(t *testing.T) {
1871
1871
})
1872
1872
}
1873
1873
}
1874
+
1875
+ func TestGetNoDerefSymlink (t * testing.T ) {
1876
+ couldChroot := canChroot
1877
+ canChroot = false
1878
+ testGetNoDerefSymlink (t )
1879
+ canChroot = couldChroot
1880
+ }
1881
+
1882
+ func testGetNoDerefSymlink (t * testing.T ) {
1883
+ var testArchives = []struct {
1884
+ name string
1885
+ rootOnly bool
1886
+ headers []tar.Header
1887
+ contents map [string ][]byte
1888
+ }{
1889
+ {
1890
+ name : "regular" ,
1891
+ rootOnly : false ,
1892
+ headers : []tar.Header {
1893
+ {Name : "link-b" , Typeflag : tar .TypeSymlink , Linkname : "../file-doesnt-exist" , Size : 23 , Mode : 0777 , ModTime : testDate },
1894
+ },
1895
+ contents : map [string ][]byte {
1896
+ "archive-a" : testArchiveSlice ,
1897
+ },
1898
+ },
1899
+ }
1900
+
1901
+ topdir := "."
1902
+ for _ , testArchive := range testArchives {
1903
+ if uid != 0 && testArchive .rootOnly {
1904
+ t .Logf ("test archive %q can only be tested with root privileges, skipping" , testArchive .name )
1905
+ continue
1906
+ }
1907
+
1908
+ dir , err := makeContextFromArchive (t , makeArchive (testArchive .headers , testArchive .contents ), topdir )
1909
+ require .NoErrorf (t , err , "error creating context from archive %q" , testArchive .name )
1910
+
1911
+ root := dir
1912
+
1913
+ for _ , noDerefSymlinks := range []bool {true , false } {
1914
+ for _ , testItem := range testArchive .headers {
1915
+ name := filepath .FromSlash (testItem .Name )
1916
+ name = filepath .Join (root , topdir , name )
1917
+ if ! t .Failed () && testItem .Typeflag == tar .TypeSymlink {
1918
+ t .Run (fmt .Sprintf ("testSymlink" ), func (t * testing.T ) {
1919
+ var getErr error
1920
+ var wg sync.WaitGroup
1921
+ getOptions := GetOptions {}
1922
+ getOptions .NoDerefSymlinks = noDerefSymlinks
1923
+ pipeReader , pipeWriter := io .Pipe ()
1924
+ wg .Add (1 )
1925
+ go func () {
1926
+ getErr = Get (root , topdir , getOptions , []string {name }, pipeWriter )
1927
+ pipeWriter .Close ()
1928
+ wg .Done ()
1929
+ }()
1930
+ tr := tar .NewReader (pipeReader )
1931
+ hdr , err := tr .Next ()
1932
+ actualContents := []string {}
1933
+ for err == nil {
1934
+ actualContents = append (actualContents , filepath .FromSlash (hdr .Linkname ))
1935
+ hdr , err = tr .Next ()
1936
+ }
1937
+ sort .Strings (actualContents )
1938
+ wg .Wait ()
1939
+
1940
+ assert .Equal (t , io .EOF .Error (), err .Error (), "expected EOF at end of archive, got %q" , err .Error ())
1941
+
1942
+ // We stat the target(name) and then assert the err
1943
+ // If we're following links (noDerefSymlinks: false)
1944
+ // we expect an error because copier would create
1945
+ // a link with a target which is non-existent (../file-b).
1946
+ // https://github.com/containers/podman/issues/16585
1947
+ //
1948
+ // But if we're not following links, copier would
1949
+ // create the link by following the target and stat
1950
+ // should therefore return success.
1951
+ _ , err = os .Stat (name )
1952
+ if ! noDerefSymlinks {
1953
+ fmt .Println (">>>>>>>> NAME: " , name )
1954
+ assert .ErrorContains (t , getErr , fmt .Sprintf ("copier: get: lstat %q" , name ))
1955
+ } else {
1956
+ assert .NoErrorf (t , getErr , "unexpected error from Get(%q): %v" , name , getErr )
1957
+ }
1958
+
1959
+ pipeReader .Close ()
1960
+ })
1961
+ }
1962
+ }
1963
+ }
1964
+ }
1965
+ }
0 commit comments