123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988 |
- //go:build !windows
- // TODO Windows: Some of these tests may be salvageable and portable to Windows.
- package archive // import "github.com/docker/docker/pkg/archive"
- import (
- "bytes"
- "crypto/sha256"
- "encoding/hex"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "strings"
- "testing"
- "gotest.tools/v3/assert"
- )
- func removeAllPaths(paths ...string) {
- for _, path := range paths {
- os.RemoveAll(path)
- }
- }
- func getTestTempDirs(t *testing.T) (tmpDirA, tmpDirB string) {
- var err error
- tmpDirA, err = os.MkdirTemp("", "archive-copy-test")
- assert.NilError(t, err)
- tmpDirB, err = os.MkdirTemp("", "archive-copy-test")
- assert.NilError(t, err)
- return
- }
- func isNotDir(err error) bool {
- return strings.Contains(err.Error(), "not a directory")
- }
- func joinTrailingSep(pathElements ...string) string {
- joined := filepath.Join(pathElements...)
- return fmt.Sprintf("%s%c", joined, filepath.Separator)
- }
- func fileContentsEqual(t *testing.T, filenameA, filenameB string) (err error) {
- t.Logf("checking for equal file contents: %q and %q\n", filenameA, filenameB)
- fileA, err := os.Open(filenameA)
- if err != nil {
- return
- }
- defer fileA.Close()
- fileB, err := os.Open(filenameB)
- if err != nil {
- return
- }
- defer fileB.Close()
- hasher := sha256.New()
- if _, err = io.Copy(hasher, fileA); err != nil {
- return
- }
- hashA := hasher.Sum(nil)
- hasher.Reset()
- if _, err = io.Copy(hasher, fileB); err != nil {
- return
- }
- hashB := hasher.Sum(nil)
- if !bytes.Equal(hashA, hashB) {
- err = fmt.Errorf("file content hashes not equal - expected %s, got %s", hex.EncodeToString(hashA), hex.EncodeToString(hashB))
- }
- return
- }
- func dirContentsEqual(t *testing.T, newDir, oldDir string) (err error) {
- t.Logf("checking for equal directory contents: %q and %q\n", newDir, oldDir)
- var changes []Change
- if changes, err = ChangesDirs(newDir, oldDir); err != nil {
- return
- }
- if len(changes) != 0 {
- err = fmt.Errorf("expected no changes between directories, but got: %v", changes)
- }
- return
- }
- func logDirContents(t *testing.T, dirPath string) {
- t.Logf("logging directory contents: %q", dirPath)
- err := filepath.WalkDir(dirPath, func(path string, info os.DirEntry, err error) error {
- if err != nil {
- t.Errorf("stat error for path %q: %s", path, err)
- return nil
- }
- if info.IsDir() {
- path = joinTrailingSep(path)
- }
- t.Logf("\t%s", path)
- return nil
- })
- assert.NilError(t, err)
- }
- func testCopyHelper(t *testing.T, srcPath, dstPath string) (err error) {
- t.Logf("copying from %q to %q (not follow symbol link)", srcPath, dstPath)
- return CopyResource(srcPath, dstPath, false)
- }
- func testCopyHelperFSym(t *testing.T, srcPath, dstPath string) (err error) {
- t.Logf("copying from %q to %q (follow symbol link)", srcPath, dstPath)
- return CopyResource(srcPath, dstPath, true)
- }
- // Basic assumptions about SRC and DST:
- // 1. SRC must exist.
- // 2. If SRC ends with a trailing separator, it must be a directory.
- // 3. DST parent directory must exist.
- // 4. If DST exists as a file, it must not end with a trailing separator.
- // First get these easy error cases out of the way.
- // Test for error when SRC does not exist.
- func TestCopyErrSrcNotExists(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- if _, err := CopyInfoSourcePath(filepath.Join(tmpDirA, "file1"), false); !os.IsNotExist(err) {
- t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
- }
- }
- // Test for error when SRC ends in a trailing
- // path separator but it exists as a file.
- func TestCopyErrSrcNotDir(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- if _, err := CopyInfoSourcePath(joinTrailingSep(tmpDirA, "file1"), false); !isNotDir(err) {
- t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
- }
- }
- // Test for error when SRC is a valid file or directory,
- // but the DST parent directory does not exist.
- func TestCopyErrDstParentNotExists(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
- // Try with a file source.
- content, err := TarResource(srcInfo)
- if err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- defer content.Close()
- // Copy to a file whose parent does not exist.
- if err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, "fakeParentDir", "file1")); err == nil {
- t.Fatal("expected IsNotExist error, but got nil instead")
- }
- if !os.IsNotExist(err) {
- t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
- }
- // Try with a directory source.
- srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true}
- content, err = TarResource(srcInfo)
- if err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- defer content.Close()
- // Copy to a directory whose parent does not exist.
- if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "fakeParentDir", "fakeDstDir")); err == nil {
- t.Fatal("expected IsNotExist error, but got nil instead")
- }
- if !os.IsNotExist(err) {
- t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
- }
- }
- // Test for error when DST ends in a trailing
- // path separator but exists as a file.
- func TestCopyErrDstNotDir(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- // Try with a file source.
- srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
- content, err := TarResource(srcInfo)
- if err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- defer content.Close()
- if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil {
- t.Fatal("expected IsNotDir error, but got nil instead")
- }
- if !isNotDir(err) {
- t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
- }
- // Try with a directory source.
- srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true}
- content, err = TarResource(srcInfo)
- if err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- defer content.Close()
- if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil {
- t.Fatal("expected IsNotDir error, but got nil instead")
- }
- if !isNotDir(err) {
- t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
- }
- }
- // Test to check if CopyTo works with a long (>100 characters) destination file name.
- // This is a regression (see https://github.com/docker/for-linux/issues/484).
- func TestCopyLongDstFilename(t *testing.T) {
- const longName = "a_very_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_long_filename_that_is_101_characters"
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
- content, err := TarResource(srcInfo)
- if err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- defer content.Close()
- err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, longName))
- if err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- }
- // Possibilities are reduced to the remaining 10 cases:
- //
- // case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
- // ===================================================================================================
- // A | no | - | no | - | no | create file
- // B | no | - | no | - | yes | error
- // C | no | - | yes | no | - | overwrite file
- // D | no | - | yes | yes | - | create file in dst dir
- // E | yes | no | no | - | - | create dir, copy contents
- // F | yes | no | yes | no | - | error
- // G | yes | no | yes | yes | - | copy dir and contents
- // H | yes | yes | no | - | - | create dir, copy contents
- // I | yes | yes | yes | no | - | error
- // J | yes | yes | yes | yes | - | copy dir contents
- //
- // A. SRC specifies a file and DST (no trailing path separator) doesn't exist.
- //
- // This should create a file with the name DST and copy the contents of the source
- // file into it.
- func TestCopyCaseA(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcPath := filepath.Join(tmpDirA, "file1")
- dstPath := filepath.Join(tmpDirB, "itWorks.txt")
- var err error
- if err = testCopyHelper(t, srcPath, dstPath); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, srcPath, dstPath)
- assert.NilError(t, err)
- os.Remove(dstPath)
- symlinkPath := filepath.Join(tmpDirA, "symlink3")
- symlinkPath1 := filepath.Join(tmpDirA, "symlink4")
- linkTarget := filepath.Join(tmpDirA, "file1")
- if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, linkTarget, dstPath)
- assert.NilError(t, err)
- os.Remove(dstPath)
- if err = testCopyHelperFSym(t, symlinkPath1, dstPath); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, linkTarget, dstPath)
- assert.NilError(t, err)
- }
- // B. SRC specifies a file and DST (with trailing path separator) doesn't exist.
- //
- // This should cause an error because the copy operation cannot create a directory
- // when copying a single file.
- func TestCopyCaseB(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcPath := filepath.Join(tmpDirA, "file1")
- dstDir := joinTrailingSep(tmpDirB, "testDir")
- var err error
- if err = testCopyHelper(t, srcPath, dstDir); err == nil {
- t.Fatal("expected ErrDirNotExists error, but got nil instead")
- }
- if err != ErrDirNotExists {
- t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err)
- }
- symlinkPath := filepath.Join(tmpDirA, "symlink3")
- if err = testCopyHelperFSym(t, symlinkPath, dstDir); err == nil {
- t.Fatal("expected ErrDirNotExists error, but got nil instead")
- }
- if err != ErrDirNotExists {
- t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err)
- }
- }
- // C. SRC specifies a file and DST exists as a file.
- //
- // This should overwrite the file at DST with the contents of the source file.
- func TestCopyCaseC(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcPath := filepath.Join(tmpDirA, "file1")
- dstPath := filepath.Join(tmpDirB, "file2")
- var err error
- // Ensure they start out different.
- if err = fileContentsEqual(t, srcPath, dstPath); err == nil {
- t.Fatal("expected different file contents")
- }
- if err = testCopyHelper(t, srcPath, dstPath); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, srcPath, dstPath)
- assert.NilError(t, err)
- }
- // C. Symbol link following version: SRC specifies a file and DST exists as a file.
- //
- // This should overwrite the file at DST with the contents of the source file.
- func TestCopyCaseCFSym(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- symlinkPathBad := filepath.Join(tmpDirA, "symlink1")
- symlinkPath := filepath.Join(tmpDirA, "symlink3")
- linkTarget := filepath.Join(tmpDirA, "file1")
- dstPath := filepath.Join(tmpDirB, "file2")
- var err error
- // first to test broken link
- if err = testCopyHelperFSym(t, symlinkPathBad, dstPath); err == nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- // test symbol link -> symbol link -> target
- // Ensure they start out different.
- if err = fileContentsEqual(t, linkTarget, dstPath); err == nil {
- t.Fatal("expected different file contents")
- }
- if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, linkTarget, dstPath)
- assert.NilError(t, err)
- }
- // D. SRC specifies a file and DST exists as a directory.
- //
- // This should place a copy of the source file inside it using the basename from
- // SRC. Ensure this works whether DST has a trailing path separator or not.
- func TestCopyCaseD(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcPath := filepath.Join(tmpDirA, "file1")
- dstDir := filepath.Join(tmpDirB, "dir1")
- dstPath := filepath.Join(dstDir, "file1")
- var err error
- // Ensure that dstPath doesn't exist.
- if _, err = os.Stat(dstPath); !os.IsNotExist(err) {
- t.Fatalf("did not expect dstPath %q to exist", dstPath)
- }
- if err = testCopyHelper(t, srcPath, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, srcPath, dstPath)
- assert.NilError(t, err)
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "dir1")
- if err = testCopyHelper(t, srcPath, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, srcPath, dstPath)
- assert.NilError(t, err)
- }
- // D. Symbol link following version: SRC specifies a file and DST exists as a directory.
- //
- // This should place a copy of the source file inside it using the basename from
- // SRC. Ensure this works whether DST has a trailing path separator or not.
- func TestCopyCaseDFSym(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcPath := filepath.Join(tmpDirA, "symlink4")
- linkTarget := filepath.Join(tmpDirA, "file1")
- dstDir := filepath.Join(tmpDirB, "dir1")
- dstPath := filepath.Join(dstDir, "symlink4")
- var err error
- // Ensure that dstPath doesn't exist.
- if _, err = os.Stat(dstPath); !os.IsNotExist(err) {
- t.Fatalf("did not expect dstPath %q to exist", dstPath)
- }
- if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, linkTarget, dstPath)
- assert.NilError(t, err)
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "dir1")
- if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = fileContentsEqual(t, linkTarget, dstPath)
- assert.NilError(t, err)
- }
- // E. SRC specifies a directory and DST does not exist.
- //
- // This should create a directory at DST and copy the contents of the SRC directory
- // into the DST directory. Ensure this works whether DST has a trailing path
- // separator or not.
- func TestCopyCaseE(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcDir := filepath.Join(tmpDirA, "dir1")
- dstDir := filepath.Join(tmpDirB, "testDir")
- var err error
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
- t.Log("dir contents not equal")
- logDirContents(t, tmpDirA)
- logDirContents(t, tmpDirB)
- t.Fatal(err)
- }
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "testDir")
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, dstDir, srcDir)
- assert.NilError(t, err)
- }
- // E. Symbol link following version: SRC specifies a directory and DST does not exist.
- //
- // This should create a directory at DST and copy the contents of the SRC directory
- // into the DST directory. Ensure this works whether DST has a trailing path
- // separator or not.
- func TestCopyCaseEFSym(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcDir := filepath.Join(tmpDirA, "dirSymlink")
- linkTarget := filepath.Join(tmpDirA, "dir1")
- dstDir := filepath.Join(tmpDirB, "testDir")
- var err error
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
- t.Log("dir contents not equal")
- logDirContents(t, tmpDirA)
- logDirContents(t, tmpDirB)
- t.Fatal(err)
- }
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "testDir")
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, dstDir, linkTarget)
- assert.NilError(t, err)
- }
- // F. SRC specifies a directory and DST exists as a file.
- //
- // This should cause an error as it is not possible to overwrite a file with a
- // directory.
- func TestCopyCaseF(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcDir := filepath.Join(tmpDirA, "dir1")
- symSrcDir := filepath.Join(tmpDirA, "dirSymlink")
- dstFile := filepath.Join(tmpDirB, "file1")
- var err error
- if err = testCopyHelper(t, srcDir, dstFile); err == nil {
- t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
- }
- if err != ErrCannotCopyDir {
- t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
- }
- // now test with symbol link
- if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil {
- t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
- }
- if err != ErrCannotCopyDir {
- t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
- }
- }
- // G. SRC specifies a directory and DST exists as a directory.
- //
- // This should copy the SRC directory and all its contents to the DST directory.
- // Ensure this works whether DST has a trailing path separator or not.
- func TestCopyCaseG(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcDir := filepath.Join(tmpDirA, "dir1")
- dstDir := filepath.Join(tmpDirB, "dir2")
- resultDir := filepath.Join(dstDir, "dir1")
- var err error
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, resultDir, srcDir)
- assert.NilError(t, err)
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "dir2")
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, resultDir, srcDir)
- assert.NilError(t, err)
- }
- // G. Symbol link version: SRC specifies a directory and DST exists as a directory.
- //
- // This should copy the SRC directory and all its contents to the DST directory.
- // Ensure this works whether DST has a trailing path separator or not.
- func TestCopyCaseGFSym(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcDir := filepath.Join(tmpDirA, "dirSymlink")
- linkTarget := filepath.Join(tmpDirA, "dir1")
- dstDir := filepath.Join(tmpDirB, "dir2")
- resultDir := filepath.Join(dstDir, "dirSymlink")
- var err error
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, resultDir, linkTarget)
- assert.NilError(t, err)
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "dir2")
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, resultDir, linkTarget)
- assert.NilError(t, err)
- }
- // H. SRC specifies a directory's contents only and DST does not exist.
- //
- // This should create a directory at DST and copy the contents of the SRC
- // directory (but not the directory itself) into the DST directory. Ensure
- // this works whether DST has a trailing path separator or not.
- func TestCopyCaseH(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
- dstDir := filepath.Join(tmpDirB, "testDir")
- var err error
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
- t.Log("dir contents not equal")
- logDirContents(t, tmpDirA)
- logDirContents(t, tmpDirB)
- t.Fatal(err)
- }
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "testDir")
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
- t.Log("dir contents not equal")
- logDirContents(t, tmpDirA)
- logDirContents(t, tmpDirB)
- t.Fatal(err)
- }
- }
- // H. Symbol link following version: SRC specifies a directory's contents only and DST does not exist.
- //
- // This should create a directory at DST and copy the contents of the SRC
- // directory (but not the directory itself) into the DST directory. Ensure
- // this works whether DST has a trailing path separator or not.
- func TestCopyCaseHFSym(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A with some sample files and directories.
- createSampleDir(t, tmpDirA)
- srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "."
- linkTarget := filepath.Join(tmpDirA, "dir1")
- dstDir := filepath.Join(tmpDirB, "testDir")
- var err error
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
- t.Log("dir contents not equal")
- logDirContents(t, tmpDirA)
- logDirContents(t, tmpDirB)
- t.Fatal(err)
- }
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "testDir")
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
- t.Log("dir contents not equal")
- logDirContents(t, tmpDirA)
- logDirContents(t, tmpDirB)
- t.Fatal(err)
- }
- }
- // I. SRC specifies a directory's contents only and DST exists as a file.
- //
- // This should cause an error as it is not possible to overwrite a file with a
- // directory.
- func TestCopyCaseI(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
- symSrcDir := filepath.Join(tmpDirB, "dirSymlink")
- dstFile := filepath.Join(tmpDirB, "file1")
- var err error
- if err = testCopyHelper(t, srcDir, dstFile); err == nil {
- t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
- }
- if err != ErrCannotCopyDir {
- t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
- }
- // now try with symbol link of dir
- if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil {
- t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
- }
- if err != ErrCannotCopyDir {
- t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
- }
- }
- // J. SRC specifies a directory's contents only and DST exists as a directory.
- //
- // This should copy the contents of the SRC directory (but not the directory
- // itself) into the DST directory. Ensure this works whether DST has a
- // trailing path separator or not.
- func TestCopyCaseJ(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
- dstDir := filepath.Join(tmpDirB, "dir5")
- var err error
- // first to create an empty dir
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, dstDir, srcDir)
- assert.NilError(t, err)
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "dir5")
- if err = testCopyHelper(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, dstDir, srcDir)
- assert.NilError(t, err)
- }
- // J. Symbol link following version: SRC specifies a directory's contents only and DST exists as a directory.
- //
- // This should copy the contents of the SRC directory (but not the directory
- // itself) into the DST directory. Ensure this works whether DST has a
- // trailing path separator or not.
- func TestCopyCaseJFSym(t *testing.T) {
- tmpDirA, tmpDirB := getTestTempDirs(t)
- defer removeAllPaths(tmpDirA, tmpDirB)
- // Load A and B with some sample files and directories.
- createSampleDir(t, tmpDirA)
- createSampleDir(t, tmpDirB)
- srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "."
- linkTarget := filepath.Join(tmpDirA, "dir1")
- dstDir := filepath.Join(tmpDirB, "dir5")
- var err error
- // first to create an empty dir
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, dstDir, linkTarget)
- assert.NilError(t, err)
- // Now try again but using a trailing path separator for dstDir.
- if err = os.RemoveAll(dstDir); err != nil {
- t.Fatalf("unable to remove dstDir: %s", err)
- }
- if err = os.MkdirAll(dstDir, os.FileMode(0o755)); err != nil {
- t.Fatalf("unable to make dstDir: %s", err)
- }
- dstDir = joinTrailingSep(tmpDirB, "dir5")
- if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
- t.Fatalf("unexpected error %T: %s", err, err)
- }
- err = dirContentsEqual(t, dstDir, linkTarget)
- assert.NilError(t, err)
- }
|