github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/pkg/archive/copy_unix_test.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  // TODO Windows: Some of these tests may be salvageable and portable to Windows.
     5  
     6  package archive // import "github.com/docker/docker/pkg/archive"
     7  
     8  import (
     9  	"bytes"
    10  	"crypto/sha256"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"io"
    14  	"os"
    15  	"path/filepath"
    16  	"strings"
    17  	"testing"
    18  
    19  	"gotest.tools/v3/assert"
    20  )
    21  
    22  func removeAllPaths(paths ...string) {
    23  	for _, path := range paths {
    24  		os.RemoveAll(path)
    25  	}
    26  }
    27  
    28  func getTestTempDirs(t *testing.T) (tmpDirA, tmpDirB string) {
    29  	var err error
    30  
    31  	tmpDirA, err = os.MkdirTemp("", "archive-copy-test")
    32  	assert.NilError(t, err)
    33  
    34  	tmpDirB, err = os.MkdirTemp("", "archive-copy-test")
    35  	assert.NilError(t, err)
    36  
    37  	return
    38  }
    39  
    40  func isNotDir(err error) bool {
    41  	return strings.Contains(err.Error(), "not a directory")
    42  }
    43  
    44  func joinTrailingSep(pathElements ...string) string {
    45  	joined := filepath.Join(pathElements...)
    46  
    47  	return fmt.Sprintf("%s%c", joined, filepath.Separator)
    48  }
    49  
    50  func fileContentsEqual(t *testing.T, filenameA, filenameB string) (err error) {
    51  	t.Logf("checking for equal file contents: %q and %q\n", filenameA, filenameB)
    52  
    53  	fileA, err := os.Open(filenameA)
    54  	if err != nil {
    55  		return
    56  	}
    57  	defer fileA.Close()
    58  
    59  	fileB, err := os.Open(filenameB)
    60  	if err != nil {
    61  		return
    62  	}
    63  	defer fileB.Close()
    64  
    65  	hasher := sha256.New()
    66  
    67  	if _, err = io.Copy(hasher, fileA); err != nil {
    68  		return
    69  	}
    70  
    71  	hashA := hasher.Sum(nil)
    72  	hasher.Reset()
    73  
    74  	if _, err = io.Copy(hasher, fileB); err != nil {
    75  		return
    76  	}
    77  
    78  	hashB := hasher.Sum(nil)
    79  
    80  	if !bytes.Equal(hashA, hashB) {
    81  		err = fmt.Errorf("file content hashes not equal - expected %s, got %s", hex.EncodeToString(hashA), hex.EncodeToString(hashB))
    82  	}
    83  
    84  	return
    85  }
    86  
    87  func dirContentsEqual(t *testing.T, newDir, oldDir string) (err error) {
    88  	t.Logf("checking for equal directory contents: %q and %q\n", newDir, oldDir)
    89  
    90  	var changes []Change
    91  
    92  	if changes, err = ChangesDirs(newDir, oldDir); err != nil {
    93  		return
    94  	}
    95  
    96  	if len(changes) != 0 {
    97  		err = fmt.Errorf("expected no changes between directories, but got: %v", changes)
    98  	}
    99  
   100  	return
   101  }
   102  
   103  func logDirContents(t *testing.T, dirPath string) {
   104  	logWalkedPaths := filepath.WalkFunc(func(path string, info os.FileInfo, err error) error {
   105  		if err != nil {
   106  			t.Errorf("stat error for path %q: %s", path, err)
   107  			return nil
   108  		}
   109  
   110  		if info.IsDir() {
   111  			path = joinTrailingSep(path)
   112  		}
   113  
   114  		t.Logf("\t%s", path)
   115  
   116  		return nil
   117  	})
   118  
   119  	t.Logf("logging directory contents: %q", dirPath)
   120  
   121  	err := filepath.Walk(dirPath, logWalkedPaths)
   122  	assert.NilError(t, err)
   123  }
   124  
   125  func testCopyHelper(t *testing.T, srcPath, dstPath string) (err error) {
   126  	t.Logf("copying from %q to %q (not follow symbol link)", srcPath, dstPath)
   127  
   128  	return CopyResource(srcPath, dstPath, false)
   129  }
   130  
   131  func testCopyHelperFSym(t *testing.T, srcPath, dstPath string) (err error) {
   132  	t.Logf("copying from %q to %q (follow symbol link)", srcPath, dstPath)
   133  
   134  	return CopyResource(srcPath, dstPath, true)
   135  }
   136  
   137  // Basic assumptions about SRC and DST:
   138  // 1. SRC must exist.
   139  // 2. If SRC ends with a trailing separator, it must be a directory.
   140  // 3. DST parent directory must exist.
   141  // 4. If DST exists as a file, it must not end with a trailing separator.
   142  
   143  // First get these easy error cases out of the way.
   144  
   145  // Test for error when SRC does not exist.
   146  func TestCopyErrSrcNotExists(t *testing.T) {
   147  	tmpDirA, tmpDirB := getTestTempDirs(t)
   148  	defer removeAllPaths(tmpDirA, tmpDirB)
   149  
   150  	if _, err := CopyInfoSourcePath(filepath.Join(tmpDirA, "file1"), false); !os.IsNotExist(err) {
   151  		t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
   152  	}
   153  }
   154  
   155  // Test for error when SRC ends in a trailing
   156  // path separator but it exists as a file.
   157  func TestCopyErrSrcNotDir(t *testing.T) {
   158  	tmpDirA, tmpDirB := getTestTempDirs(t)
   159  	defer removeAllPaths(tmpDirA, tmpDirB)
   160  
   161  	// Load A with some sample files and directories.
   162  	createSampleDir(t, tmpDirA)
   163  
   164  	if _, err := CopyInfoSourcePath(joinTrailingSep(tmpDirA, "file1"), false); !isNotDir(err) {
   165  		t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
   166  	}
   167  }
   168  
   169  // Test for error when SRC is a valid file or directory,
   170  // but the DST parent directory does not exist.
   171  func TestCopyErrDstParentNotExists(t *testing.T) {
   172  	tmpDirA, tmpDirB := getTestTempDirs(t)
   173  	defer removeAllPaths(tmpDirA, tmpDirB)
   174  
   175  	// Load A with some sample files and directories.
   176  	createSampleDir(t, tmpDirA)
   177  
   178  	srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
   179  
   180  	// Try with a file source.
   181  	content, err := TarResource(srcInfo)
   182  	if err != nil {
   183  		t.Fatalf("unexpected error %T: %s", err, err)
   184  	}
   185  	defer content.Close()
   186  
   187  	// Copy to a file whose parent does not exist.
   188  	if err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, "fakeParentDir", "file1")); err == nil {
   189  		t.Fatal("expected IsNotExist error, but got nil instead")
   190  	}
   191  
   192  	if !os.IsNotExist(err) {
   193  		t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
   194  	}
   195  
   196  	// Try with a directory source.
   197  	srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true}
   198  
   199  	content, err = TarResource(srcInfo)
   200  	if err != nil {
   201  		t.Fatalf("unexpected error %T: %s", err, err)
   202  	}
   203  	defer content.Close()
   204  
   205  	// Copy to a directory whose parent does not exist.
   206  	if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "fakeParentDir", "fakeDstDir")); err == nil {
   207  		t.Fatal("expected IsNotExist error, but got nil instead")
   208  	}
   209  
   210  	if !os.IsNotExist(err) {
   211  		t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
   212  	}
   213  }
   214  
   215  // Test for error when DST ends in a trailing
   216  // path separator but exists as a file.
   217  func TestCopyErrDstNotDir(t *testing.T) {
   218  	tmpDirA, tmpDirB := getTestTempDirs(t)
   219  	defer removeAllPaths(tmpDirA, tmpDirB)
   220  
   221  	// Load A and B with some sample files and directories.
   222  	createSampleDir(t, tmpDirA)
   223  	createSampleDir(t, tmpDirB)
   224  
   225  	// Try with a file source.
   226  	srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
   227  
   228  	content, err := TarResource(srcInfo)
   229  	if err != nil {
   230  		t.Fatalf("unexpected error %T: %s", err, err)
   231  	}
   232  	defer content.Close()
   233  
   234  	if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil {
   235  		t.Fatal("expected IsNotDir error, but got nil instead")
   236  	}
   237  
   238  	if !isNotDir(err) {
   239  		t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
   240  	}
   241  
   242  	// Try with a directory source.
   243  	srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true}
   244  
   245  	content, err = TarResource(srcInfo)
   246  	if err != nil {
   247  		t.Fatalf("unexpected error %T: %s", err, err)
   248  	}
   249  	defer content.Close()
   250  
   251  	if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil {
   252  		t.Fatal("expected IsNotDir error, but got nil instead")
   253  	}
   254  
   255  	if !isNotDir(err) {
   256  		t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
   257  	}
   258  }
   259  
   260  // Test to check if CopyTo works with a long (>100 characters) destination file name.
   261  // This is a regression (see https://github.com/docker/for-linux/issues/484).
   262  func TestCopyLongDstFilename(t *testing.T) {
   263  	const longName = "a_very_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_long_filename_that_is_101_characters"
   264  	tmpDirA, tmpDirB := getTestTempDirs(t)
   265  	defer removeAllPaths(tmpDirA, tmpDirB)
   266  
   267  	// Load A with some sample files and directories.
   268  	createSampleDir(t, tmpDirA)
   269  
   270  	srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
   271  
   272  	content, err := TarResource(srcInfo)
   273  	if err != nil {
   274  		t.Fatalf("unexpected error %T: %s", err, err)
   275  	}
   276  	defer content.Close()
   277  
   278  	err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, longName))
   279  	if err != nil {
   280  		t.Fatalf("unexpected error %T: %s", err, err)
   281  	}
   282  }
   283  
   284  // Possibilities are reduced to the remaining 10 cases:
   285  //
   286  //  case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
   287  // ===================================================================================================
   288  //   A   |  no      |  -              |  no       |  -       |  no      |  create file
   289  //   B   |  no      |  -              |  no       |  -       |  yes     |  error
   290  //   C   |  no      |  -              |  yes      |  no      |  -       |  overwrite file
   291  //   D   |  no      |  -              |  yes      |  yes     |  -       |  create file in dst dir
   292  //   E   |  yes     |  no             |  no       |  -       |  -       |  create dir, copy contents
   293  //   F   |  yes     |  no             |  yes      |  no      |  -       |  error
   294  //   G   |  yes     |  no             |  yes      |  yes     |  -       |  copy dir and contents
   295  //   H   |  yes     |  yes            |  no       |  -       |  -       |  create dir, copy contents
   296  //   I   |  yes     |  yes            |  yes      |  no      |  -       |  error
   297  //   J   |  yes     |  yes            |  yes      |  yes     |  -       |  copy dir contents
   298  //
   299  
   300  // A. SRC specifies a file and DST (no trailing path separator) doesn't exist.
   301  //
   302  // This should create a file with the name DST and copy the contents of the source
   303  // file into it.
   304  func TestCopyCaseA(t *testing.T) {
   305  	tmpDirA, tmpDirB := getTestTempDirs(t)
   306  	defer removeAllPaths(tmpDirA, tmpDirB)
   307  
   308  	// Load A with some sample files and directories.
   309  	createSampleDir(t, tmpDirA)
   310  
   311  	srcPath := filepath.Join(tmpDirA, "file1")
   312  	dstPath := filepath.Join(tmpDirB, "itWorks.txt")
   313  
   314  	var err error
   315  
   316  	if err = testCopyHelper(t, srcPath, dstPath); err != nil {
   317  		t.Fatalf("unexpected error %T: %s", err, err)
   318  	}
   319  
   320  	err = fileContentsEqual(t, srcPath, dstPath)
   321  	assert.NilError(t, err)
   322  	os.Remove(dstPath)
   323  
   324  	symlinkPath := filepath.Join(tmpDirA, "symlink3")
   325  	symlinkPath1 := filepath.Join(tmpDirA, "symlink4")
   326  	linkTarget := filepath.Join(tmpDirA, "file1")
   327  
   328  	if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil {
   329  		t.Fatalf("unexpected error %T: %s", err, err)
   330  	}
   331  
   332  	err = fileContentsEqual(t, linkTarget, dstPath)
   333  	assert.NilError(t, err)
   334  	os.Remove(dstPath)
   335  	if err = testCopyHelperFSym(t, symlinkPath1, dstPath); err != nil {
   336  		t.Fatalf("unexpected error %T: %s", err, err)
   337  	}
   338  
   339  	err = fileContentsEqual(t, linkTarget, dstPath)
   340  	assert.NilError(t, err)
   341  }
   342  
   343  // B. SRC specifies a file and DST (with trailing path separator) doesn't exist.
   344  //
   345  // This should cause an error because the copy operation cannot create a directory
   346  // when copying a single file.
   347  func TestCopyCaseB(t *testing.T) {
   348  	tmpDirA, tmpDirB := getTestTempDirs(t)
   349  	defer removeAllPaths(tmpDirA, tmpDirB)
   350  
   351  	// Load A with some sample files and directories.
   352  	createSampleDir(t, tmpDirA)
   353  
   354  	srcPath := filepath.Join(tmpDirA, "file1")
   355  	dstDir := joinTrailingSep(tmpDirB, "testDir")
   356  
   357  	var err error
   358  
   359  	if err = testCopyHelper(t, srcPath, dstDir); err == nil {
   360  		t.Fatal("expected ErrDirNotExists error, but got nil instead")
   361  	}
   362  
   363  	if err != ErrDirNotExists {
   364  		t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err)
   365  	}
   366  
   367  	symlinkPath := filepath.Join(tmpDirA, "symlink3")
   368  
   369  	if err = testCopyHelperFSym(t, symlinkPath, dstDir); err == nil {
   370  		t.Fatal("expected ErrDirNotExists error, but got nil instead")
   371  	}
   372  	if err != ErrDirNotExists {
   373  		t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err)
   374  	}
   375  
   376  }
   377  
   378  // C. SRC specifies a file and DST exists as a file.
   379  //
   380  // This should overwrite the file at DST with the contents of the source file.
   381  func TestCopyCaseC(t *testing.T) {
   382  	tmpDirA, tmpDirB := getTestTempDirs(t)
   383  	defer removeAllPaths(tmpDirA, tmpDirB)
   384  
   385  	// Load A and B with some sample files and directories.
   386  	createSampleDir(t, tmpDirA)
   387  	createSampleDir(t, tmpDirB)
   388  
   389  	srcPath := filepath.Join(tmpDirA, "file1")
   390  	dstPath := filepath.Join(tmpDirB, "file2")
   391  
   392  	var err error
   393  
   394  	// Ensure they start out different.
   395  	if err = fileContentsEqual(t, srcPath, dstPath); err == nil {
   396  		t.Fatal("expected different file contents")
   397  	}
   398  
   399  	if err = testCopyHelper(t, srcPath, dstPath); err != nil {
   400  		t.Fatalf("unexpected error %T: %s", err, err)
   401  	}
   402  
   403  	err = fileContentsEqual(t, srcPath, dstPath)
   404  	assert.NilError(t, err)
   405  }
   406  
   407  // C. Symbol link following version: SRC specifies a file and DST exists as a file.
   408  //
   409  // This should overwrite the file at DST with the contents of the source file.
   410  func TestCopyCaseCFSym(t *testing.T) {
   411  	tmpDirA, tmpDirB := getTestTempDirs(t)
   412  	defer removeAllPaths(tmpDirA, tmpDirB)
   413  
   414  	// Load A and B with some sample files and directories.
   415  	createSampleDir(t, tmpDirA)
   416  	createSampleDir(t, tmpDirB)
   417  
   418  	symlinkPathBad := filepath.Join(tmpDirA, "symlink1")
   419  	symlinkPath := filepath.Join(tmpDirA, "symlink3")
   420  	linkTarget := filepath.Join(tmpDirA, "file1")
   421  	dstPath := filepath.Join(tmpDirB, "file2")
   422  
   423  	var err error
   424  
   425  	// first to test broken link
   426  	if err = testCopyHelperFSym(t, symlinkPathBad, dstPath); err == nil {
   427  		t.Fatalf("unexpected error %T: %s", err, err)
   428  	}
   429  
   430  	// test symbol link -> symbol link -> target
   431  	// Ensure they start out different.
   432  	if err = fileContentsEqual(t, linkTarget, dstPath); err == nil {
   433  		t.Fatal("expected different file contents")
   434  	}
   435  
   436  	if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil {
   437  		t.Fatalf("unexpected error %T: %s", err, err)
   438  	}
   439  
   440  	err = fileContentsEqual(t, linkTarget, dstPath)
   441  	assert.NilError(t, err)
   442  }
   443  
   444  // D. SRC specifies a file and DST exists as a directory.
   445  //
   446  // This should place a copy of the source file inside it using the basename from
   447  // SRC. Ensure this works whether DST has a trailing path separator or not.
   448  func TestCopyCaseD(t *testing.T) {
   449  	tmpDirA, tmpDirB := getTestTempDirs(t)
   450  	defer removeAllPaths(tmpDirA, tmpDirB)
   451  
   452  	// Load A and B with some sample files and directories.
   453  	createSampleDir(t, tmpDirA)
   454  	createSampleDir(t, tmpDirB)
   455  
   456  	srcPath := filepath.Join(tmpDirA, "file1")
   457  	dstDir := filepath.Join(tmpDirB, "dir1")
   458  	dstPath := filepath.Join(dstDir, "file1")
   459  
   460  	var err error
   461  
   462  	// Ensure that dstPath doesn't exist.
   463  	if _, err = os.Stat(dstPath); !os.IsNotExist(err) {
   464  		t.Fatalf("did not expect dstPath %q to exist", dstPath)
   465  	}
   466  
   467  	if err = testCopyHelper(t, srcPath, dstDir); err != nil {
   468  		t.Fatalf("unexpected error %T: %s", err, err)
   469  	}
   470  
   471  	err = fileContentsEqual(t, srcPath, dstPath)
   472  	assert.NilError(t, err)
   473  
   474  	// Now try again but using a trailing path separator for dstDir.
   475  
   476  	if err = os.RemoveAll(dstDir); err != nil {
   477  		t.Fatalf("unable to remove dstDir: %s", err)
   478  	}
   479  
   480  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   481  		t.Fatalf("unable to make dstDir: %s", err)
   482  	}
   483  
   484  	dstDir = joinTrailingSep(tmpDirB, "dir1")
   485  
   486  	if err = testCopyHelper(t, srcPath, dstDir); err != nil {
   487  		t.Fatalf("unexpected error %T: %s", err, err)
   488  	}
   489  
   490  	err = fileContentsEqual(t, srcPath, dstPath)
   491  	assert.NilError(t, err)
   492  }
   493  
   494  // D. Symbol link following version: SRC specifies a file and DST exists as a directory.
   495  //
   496  // This should place a copy of the source file inside it using the basename from
   497  // SRC. Ensure this works whether DST has a trailing path separator or not.
   498  func TestCopyCaseDFSym(t *testing.T) {
   499  	tmpDirA, tmpDirB := getTestTempDirs(t)
   500  	defer removeAllPaths(tmpDirA, tmpDirB)
   501  
   502  	// Load A and B with some sample files and directories.
   503  	createSampleDir(t, tmpDirA)
   504  	createSampleDir(t, tmpDirB)
   505  
   506  	srcPath := filepath.Join(tmpDirA, "symlink4")
   507  	linkTarget := filepath.Join(tmpDirA, "file1")
   508  	dstDir := filepath.Join(tmpDirB, "dir1")
   509  	dstPath := filepath.Join(dstDir, "symlink4")
   510  
   511  	var err error
   512  
   513  	// Ensure that dstPath doesn't exist.
   514  	if _, err = os.Stat(dstPath); !os.IsNotExist(err) {
   515  		t.Fatalf("did not expect dstPath %q to exist", dstPath)
   516  	}
   517  
   518  	if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil {
   519  		t.Fatalf("unexpected error %T: %s", err, err)
   520  	}
   521  
   522  	err = fileContentsEqual(t, linkTarget, dstPath)
   523  	assert.NilError(t, err)
   524  
   525  	// Now try again but using a trailing path separator for dstDir.
   526  
   527  	if err = os.RemoveAll(dstDir); err != nil {
   528  		t.Fatalf("unable to remove dstDir: %s", err)
   529  	}
   530  
   531  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   532  		t.Fatalf("unable to make dstDir: %s", err)
   533  	}
   534  
   535  	dstDir = joinTrailingSep(tmpDirB, "dir1")
   536  
   537  	if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil {
   538  		t.Fatalf("unexpected error %T: %s", err, err)
   539  	}
   540  
   541  	err = fileContentsEqual(t, linkTarget, dstPath)
   542  	assert.NilError(t, err)
   543  }
   544  
   545  // E. SRC specifies a directory and DST does not exist.
   546  //
   547  // This should create a directory at DST and copy the contents of the SRC directory
   548  // into the DST directory. Ensure this works whether DST has a trailing path
   549  // separator or not.
   550  func TestCopyCaseE(t *testing.T) {
   551  	tmpDirA, tmpDirB := getTestTempDirs(t)
   552  	defer removeAllPaths(tmpDirA, tmpDirB)
   553  
   554  	// Load A with some sample files and directories.
   555  	createSampleDir(t, tmpDirA)
   556  
   557  	srcDir := filepath.Join(tmpDirA, "dir1")
   558  	dstDir := filepath.Join(tmpDirB, "testDir")
   559  
   560  	var err error
   561  
   562  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   563  		t.Fatalf("unexpected error %T: %s", err, err)
   564  	}
   565  
   566  	if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
   567  		t.Log("dir contents not equal")
   568  		logDirContents(t, tmpDirA)
   569  		logDirContents(t, tmpDirB)
   570  		t.Fatal(err)
   571  	}
   572  
   573  	// Now try again but using a trailing path separator for dstDir.
   574  
   575  	if err = os.RemoveAll(dstDir); err != nil {
   576  		t.Fatalf("unable to remove dstDir: %s", err)
   577  	}
   578  
   579  	dstDir = joinTrailingSep(tmpDirB, "testDir")
   580  
   581  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   582  		t.Fatalf("unexpected error %T: %s", err, err)
   583  	}
   584  
   585  	err = dirContentsEqual(t, dstDir, srcDir)
   586  	assert.NilError(t, err)
   587  }
   588  
   589  // E. Symbol link following version: SRC specifies a directory and DST does not exist.
   590  //
   591  // This should create a directory at DST and copy the contents of the SRC directory
   592  // into the DST directory. Ensure this works whether DST has a trailing path
   593  // separator or	not.
   594  func TestCopyCaseEFSym(t *testing.T) {
   595  	tmpDirA, tmpDirB := getTestTempDirs(t)
   596  	defer removeAllPaths(tmpDirA, tmpDirB)
   597  
   598  	// Load A with some sample files and directories.
   599  	createSampleDir(t, tmpDirA)
   600  
   601  	srcDir := filepath.Join(tmpDirA, "dirSymlink")
   602  	linkTarget := filepath.Join(tmpDirA, "dir1")
   603  	dstDir := filepath.Join(tmpDirB, "testDir")
   604  
   605  	var err error
   606  
   607  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   608  		t.Fatalf("unexpected error %T: %s", err, err)
   609  	}
   610  
   611  	if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
   612  		t.Log("dir contents not equal")
   613  		logDirContents(t, tmpDirA)
   614  		logDirContents(t, tmpDirB)
   615  		t.Fatal(err)
   616  	}
   617  
   618  	// Now try again but using a trailing path separator for dstDir.
   619  
   620  	if err = os.RemoveAll(dstDir); err != nil {
   621  		t.Fatalf("unable to remove dstDir: %s", err)
   622  	}
   623  
   624  	dstDir = joinTrailingSep(tmpDirB, "testDir")
   625  
   626  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   627  		t.Fatalf("unexpected error %T: %s", err, err)
   628  	}
   629  
   630  	err = dirContentsEqual(t, dstDir, linkTarget)
   631  	assert.NilError(t, err)
   632  }
   633  
   634  // F. SRC specifies a directory and DST exists as a file.
   635  //
   636  // This should cause an	error as it is not possible to overwrite a file with a
   637  // directory.
   638  func TestCopyCaseF(t *testing.T) {
   639  	tmpDirA, tmpDirB := getTestTempDirs(t)
   640  	defer removeAllPaths(tmpDirA, tmpDirB)
   641  
   642  	// Load A and B with some sample files and directories.
   643  	createSampleDir(t, tmpDirA)
   644  	createSampleDir(t, tmpDirB)
   645  
   646  	srcDir := filepath.Join(tmpDirA, "dir1")
   647  	symSrcDir := filepath.Join(tmpDirA, "dirSymlink")
   648  	dstFile := filepath.Join(tmpDirB, "file1")
   649  
   650  	var err error
   651  
   652  	if err = testCopyHelper(t, srcDir, dstFile); err == nil {
   653  		t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
   654  	}
   655  
   656  	if err != ErrCannotCopyDir {
   657  		t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
   658  	}
   659  
   660  	// now test with symbol link
   661  	if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil {
   662  		t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
   663  	}
   664  
   665  	if err != ErrCannotCopyDir {
   666  		t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
   667  	}
   668  }
   669  
   670  // G. SRC specifies a directory and DST exists as a directory.
   671  //
   672  // This should copy	the SRC directory and all its contents to the DST directory.
   673  // Ensure this works whether DST has a trailing path separator or not.
   674  func TestCopyCaseG(t *testing.T) {
   675  	tmpDirA, tmpDirB := getTestTempDirs(t)
   676  	defer removeAllPaths(tmpDirA, tmpDirB)
   677  
   678  	// Load A and B with some sample files and directories.
   679  	createSampleDir(t, tmpDirA)
   680  	createSampleDir(t, tmpDirB)
   681  
   682  	srcDir := filepath.Join(tmpDirA, "dir1")
   683  	dstDir := filepath.Join(tmpDirB, "dir2")
   684  	resultDir := filepath.Join(dstDir, "dir1")
   685  
   686  	var err error
   687  
   688  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   689  		t.Fatalf("unexpected error %T: %s", err, err)
   690  	}
   691  
   692  	err = dirContentsEqual(t, resultDir, srcDir)
   693  	assert.NilError(t, err)
   694  
   695  	// Now try again but using a trailing path separator for dstDir.
   696  
   697  	if err = os.RemoveAll(dstDir); err != nil {
   698  		t.Fatalf("unable to remove dstDir: %s", err)
   699  	}
   700  
   701  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   702  		t.Fatalf("unable to make dstDir: %s", err)
   703  	}
   704  
   705  	dstDir = joinTrailingSep(tmpDirB, "dir2")
   706  
   707  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   708  		t.Fatalf("unexpected error %T: %s", err, err)
   709  	}
   710  
   711  	err = dirContentsEqual(t, resultDir, srcDir)
   712  	assert.NilError(t, err)
   713  }
   714  
   715  // G. Symbol link version: SRC specifies a directory and DST exists as a directory.
   716  //
   717  // This should copy the SRC directory and all its contents to the DST directory.
   718  // Ensure this works whether DST has a trailing path separator or not.
   719  func TestCopyCaseGFSym(t *testing.T) {
   720  	tmpDirA, tmpDirB := getTestTempDirs(t)
   721  	defer removeAllPaths(tmpDirA, tmpDirB)
   722  
   723  	// Load A and B with some sample files and directories.
   724  	createSampleDir(t, tmpDirA)
   725  	createSampleDir(t, tmpDirB)
   726  
   727  	srcDir := filepath.Join(tmpDirA, "dirSymlink")
   728  	linkTarget := filepath.Join(tmpDirA, "dir1")
   729  	dstDir := filepath.Join(tmpDirB, "dir2")
   730  	resultDir := filepath.Join(dstDir, "dirSymlink")
   731  
   732  	var err error
   733  
   734  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   735  		t.Fatalf("unexpected error %T: %s", err, err)
   736  	}
   737  
   738  	err = dirContentsEqual(t, resultDir, linkTarget)
   739  	assert.NilError(t, err)
   740  
   741  	// Now try again but using a trailing path separator for dstDir.
   742  
   743  	if err = os.RemoveAll(dstDir); err != nil {
   744  		t.Fatalf("unable to remove dstDir: %s", err)
   745  	}
   746  
   747  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   748  		t.Fatalf("unable to make dstDir: %s", err)
   749  	}
   750  
   751  	dstDir = joinTrailingSep(tmpDirB, "dir2")
   752  
   753  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   754  		t.Fatalf("unexpected error %T: %s", err, err)
   755  	}
   756  
   757  	err = dirContentsEqual(t, resultDir, linkTarget)
   758  	assert.NilError(t, err)
   759  }
   760  
   761  // H. SRC specifies a directory's contents only and DST does not exist.
   762  //
   763  // This	should create a directory at DST and copy the contents of the SRC
   764  // directory (but not the directory itself) into the DST directory. Ensure
   765  // this works whether DST has a trailing path separator or not.
   766  func TestCopyCaseH(t *testing.T) {
   767  	tmpDirA, tmpDirB := getTestTempDirs(t)
   768  	defer removeAllPaths(tmpDirA, tmpDirB)
   769  
   770  	// Load A with some sample files and directories.
   771  	createSampleDir(t, tmpDirA)
   772  
   773  	srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
   774  	dstDir := filepath.Join(tmpDirB, "testDir")
   775  
   776  	var err error
   777  
   778  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   779  		t.Fatalf("unexpected error %T: %s", err, err)
   780  	}
   781  
   782  	if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
   783  		t.Log("dir contents not equal")
   784  		logDirContents(t, tmpDirA)
   785  		logDirContents(t, tmpDirB)
   786  		t.Fatal(err)
   787  	}
   788  
   789  	// Now try again but using a trailing path separator for dstDir.
   790  
   791  	if err = os.RemoveAll(dstDir); err != nil {
   792  		t.Fatalf("unable to remove dstDir: %s", err)
   793  	}
   794  
   795  	dstDir = joinTrailingSep(tmpDirB, "testDir")
   796  
   797  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   798  		t.Fatalf("unexpected error %T: %s", err, err)
   799  	}
   800  
   801  	if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
   802  		t.Log("dir contents not equal")
   803  		logDirContents(t, tmpDirA)
   804  		logDirContents(t, tmpDirB)
   805  		t.Fatal(err)
   806  	}
   807  }
   808  
   809  // H. Symbol link following version: SRC specifies a directory's contents only and DST does not exist.
   810  //
   811  // This	should create a directory at DST and copy the contents of the SRC
   812  // directory (but not the directory itself) into the DST directory. Ensure
   813  // this works whether DST has a trailing path separator or not.
   814  func TestCopyCaseHFSym(t *testing.T) {
   815  	tmpDirA, tmpDirB := getTestTempDirs(t)
   816  	defer removeAllPaths(tmpDirA, tmpDirB)
   817  
   818  	// Load A with some sample files and directories.
   819  	createSampleDir(t, tmpDirA)
   820  
   821  	srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "."
   822  	linkTarget := filepath.Join(tmpDirA, "dir1")
   823  	dstDir := filepath.Join(tmpDirB, "testDir")
   824  
   825  	var err error
   826  
   827  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   828  		t.Fatalf("unexpected error %T: %s", err, err)
   829  	}
   830  
   831  	if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
   832  		t.Log("dir contents not equal")
   833  		logDirContents(t, tmpDirA)
   834  		logDirContents(t, tmpDirB)
   835  		t.Fatal(err)
   836  	}
   837  
   838  	// Now try again but using a trailing path separator for dstDir.
   839  
   840  	if err = os.RemoveAll(dstDir); err != nil {
   841  		t.Fatalf("unable to remove dstDir: %s", err)
   842  	}
   843  
   844  	dstDir = joinTrailingSep(tmpDirB, "testDir")
   845  
   846  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   847  		t.Fatalf("unexpected error %T: %s", err, err)
   848  	}
   849  
   850  	if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
   851  		t.Log("dir contents not equal")
   852  		logDirContents(t, tmpDirA)
   853  		logDirContents(t, tmpDirB)
   854  		t.Fatal(err)
   855  	}
   856  }
   857  
   858  // I. SRC specifies a directory's contents only and DST exists as a file.
   859  //
   860  // This	should cause an error as it is not possible to overwrite a file with a
   861  // directory.
   862  func TestCopyCaseI(t *testing.T) {
   863  	tmpDirA, tmpDirB := getTestTempDirs(t)
   864  	defer removeAllPaths(tmpDirA, tmpDirB)
   865  
   866  	// Load A and B with some sample files and directories.
   867  	createSampleDir(t, tmpDirA)
   868  	createSampleDir(t, tmpDirB)
   869  
   870  	srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
   871  	symSrcDir := filepath.Join(tmpDirB, "dirSymlink")
   872  	dstFile := filepath.Join(tmpDirB, "file1")
   873  
   874  	var err error
   875  
   876  	if err = testCopyHelper(t, srcDir, dstFile); err == nil {
   877  		t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
   878  	}
   879  
   880  	if err != ErrCannotCopyDir {
   881  		t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
   882  	}
   883  
   884  	// now try with symbol link of dir
   885  	if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil {
   886  		t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
   887  	}
   888  
   889  	if err != ErrCannotCopyDir {
   890  		t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
   891  	}
   892  }
   893  
   894  // J. SRC specifies a directory's contents only and DST exists as a directory.
   895  //
   896  // This should copy the contents of the SRC directory (but not the directory
   897  // itself) into the DST directory. Ensure this works whether DST has a
   898  // trailing path separator or not.
   899  func TestCopyCaseJ(t *testing.T) {
   900  	tmpDirA, tmpDirB := getTestTempDirs(t)
   901  	defer removeAllPaths(tmpDirA, tmpDirB)
   902  
   903  	// Load A and B with some sample files and directories.
   904  	createSampleDir(t, tmpDirA)
   905  	createSampleDir(t, tmpDirB)
   906  
   907  	srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
   908  	dstDir := filepath.Join(tmpDirB, "dir5")
   909  
   910  	var err error
   911  
   912  	// first to create an empty dir
   913  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   914  		t.Fatalf("unable to make dstDir: %s", err)
   915  	}
   916  
   917  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   918  		t.Fatalf("unexpected error %T: %s", err, err)
   919  	}
   920  
   921  	err = dirContentsEqual(t, dstDir, srcDir)
   922  	assert.NilError(t, err)
   923  
   924  	// Now try again but using a trailing path separator for dstDir.
   925  
   926  	if err = os.RemoveAll(dstDir); err != nil {
   927  		t.Fatalf("unable to remove dstDir: %s", err)
   928  	}
   929  
   930  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   931  		t.Fatalf("unable to make dstDir: %s", err)
   932  	}
   933  
   934  	dstDir = joinTrailingSep(tmpDirB, "dir5")
   935  
   936  	if err = testCopyHelper(t, srcDir, dstDir); err != nil {
   937  		t.Fatalf("unexpected error %T: %s", err, err)
   938  	}
   939  
   940  	err = dirContentsEqual(t, dstDir, srcDir)
   941  	assert.NilError(t, err)
   942  }
   943  
   944  // J. Symbol link following version: SRC specifies a directory's contents only and DST exists as a directory.
   945  //
   946  // This should copy the contents of the SRC directory (but not the directory
   947  // itself) into the DST directory. Ensure this works whether DST has a
   948  // trailing path separator or not.
   949  func TestCopyCaseJFSym(t *testing.T) {
   950  	tmpDirA, tmpDirB := getTestTempDirs(t)
   951  	defer removeAllPaths(tmpDirA, tmpDirB)
   952  
   953  	// Load A and B with some sample files and directories.
   954  	createSampleDir(t, tmpDirA)
   955  	createSampleDir(t, tmpDirB)
   956  
   957  	srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "."
   958  	linkTarget := filepath.Join(tmpDirA, "dir1")
   959  	dstDir := filepath.Join(tmpDirB, "dir5")
   960  
   961  	var err error
   962  
   963  	// first to create an empty dir
   964  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   965  		t.Fatalf("unable to make dstDir: %s", err)
   966  	}
   967  
   968  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   969  		t.Fatalf("unexpected error %T: %s", err, err)
   970  	}
   971  
   972  	err = dirContentsEqual(t, dstDir, linkTarget)
   973  	assert.NilError(t, err)
   974  
   975  	// Now try again but using a trailing path separator for dstDir.
   976  
   977  	if err = os.RemoveAll(dstDir); err != nil {
   978  		t.Fatalf("unable to remove dstDir: %s", err)
   979  	}
   980  
   981  	if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   982  		t.Fatalf("unable to make dstDir: %s", err)
   983  	}
   984  
   985  	dstDir = joinTrailingSep(tmpDirB, "dir5")
   986  
   987  	if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
   988  		t.Fatalf("unexpected error %T: %s", err, err)
   989  	}
   990  
   991  	err = dirContentsEqual(t, dstDir, linkTarget)
   992  	assert.NilError(t, err)
   993  }