1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
//go:build linux
// +build linux
package copy
import (
"fmt"
"math/rand"
"os"
"path/filepath"
"syscall"
"testing"
"time"
"github.com/containers/storage/pkg/system"
"golang.org/x/sys/unix"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
func TestCopy(t *testing.T) {
copyWithFileRange := true
copyWithFileClone := true
doCopyTest(t, ©WithFileRange, ©WithFileClone)
}
func TestCopyWithoutRange(t *testing.T) {
copyWithFileRange := false
copyWithFileClone := false
doCopyTest(t, ©WithFileRange, ©WithFileClone)
}
func TestCopyDir(t *testing.T) {
srcDir := t.TempDir()
populateSrcDir(t, srcDir, 3)
dstDir := t.TempDir()
assert.Check(t, DirCopy(srcDir, dstDir, Content, false))
assert.NilError(t, filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error {
if err != nil {
return err
}
// Rebase path
relPath, err := filepath.Rel(srcDir, srcPath)
assert.NilError(t, err)
if relPath == "." {
return nil
}
dstPath := filepath.Join(dstDir, relPath)
assert.NilError(t, err)
// If we add non-regular dirs and files to the test
// then we need to add more checks here.
dstFileInfo, err := os.Lstat(dstPath)
assert.NilError(t, err)
srcFileSys := f.Sys().(*syscall.Stat_t)
dstFileSys := dstFileInfo.Sys().(*syscall.Stat_t)
t.Log(relPath)
if srcFileSys.Dev == dstFileSys.Dev {
assert.Check(t, srcFileSys.Ino != dstFileSys.Ino)
}
// Todo: check size, and ctim is not equal
/// on filesystems that have granular ctimes
assert.Check(t, is.DeepEqual(srcFileSys.Mode, dstFileSys.Mode))
assert.Check(t, is.DeepEqual(srcFileSys.Uid, dstFileSys.Uid))
assert.Check(t, is.DeepEqual(srcFileSys.Gid, dstFileSys.Gid))
assert.Check(t, is.DeepEqual(srcFileSys.Mtim, dstFileSys.Mtim))
return nil
}))
}
func randomMode(baseMode int) os.FileMode {
for i := 0; i < 7; i++ {
baseMode = baseMode | (1&rand.Intn(2))<<uint(i)
}
return os.FileMode(baseMode)
}
func populateSrcDir(t *testing.T, srcDir string, remainingDepth int) {
if remainingDepth == 0 {
return
}
aTime := time.Unix(rand.Int63(), 0)
mTime := time.Unix(rand.Int63(), 0)
for i := 0; i < 10; i++ {
dirName := filepath.Join(srcDir, fmt.Sprintf("srcdir-%d", i))
// Owner all bits set
assert.NilError(t, os.Mkdir(dirName, randomMode(0o700)))
populateSrcDir(t, dirName, remainingDepth-1)
assert.NilError(t, system.Chtimes(dirName, aTime, mTime))
}
for i := 0; i < 10; i++ {
fileName := filepath.Join(srcDir, fmt.Sprintf("srcfile-%d", i))
// Owner read bit set
assert.NilError(t, os.WriteFile(fileName, []byte{}, randomMode(0o400)))
assert.NilError(t, system.Chtimes(fileName, aTime, mTime))
}
}
func doCopyTest(t *testing.T, copyWithFileRange, copyWithFileClone *bool) {
dir := t.TempDir()
srcFilename := filepath.Join(dir, "srcFilename")
dstFilename := filepath.Join(dir, "dstilename")
r := rand.New(rand.NewSource(0))
buf := make([]byte, 1024)
_, err := r.Read(buf)
assert.NilError(t, err)
assert.NilError(t, os.WriteFile(srcFilename, buf, 0o777))
fileinfo, err := os.Stat(srcFilename)
assert.NilError(t, err)
assert.NilError(t, CopyRegular(srcFilename, dstFilename, fileinfo, copyWithFileRange, copyWithFileClone))
readBuf, err := os.ReadFile(dstFilename)
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(buf, readBuf))
}
func TestCopyHardlink(t *testing.T) {
var srcFile1FileInfo, srcFile2FileInfo, dstFile1FileInfo, dstFile2FileInfo unix.Stat_t
srcDir := t.TempDir()
dstDir := t.TempDir()
srcFile1 := filepath.Join(srcDir, "file1")
srcFile2 := filepath.Join(srcDir, "file2")
dstFile1 := filepath.Join(dstDir, "file1")
dstFile2 := filepath.Join(dstDir, "file2")
assert.NilError(t, os.WriteFile(srcFile1, []byte{}, 0o777))
assert.NilError(t, os.Link(srcFile1, srcFile2))
assert.Check(t, DirCopy(srcDir, dstDir, Content, false))
assert.NilError(t, unix.Stat(srcFile1, &srcFile1FileInfo))
assert.NilError(t, unix.Stat(srcFile2, &srcFile2FileInfo))
assert.Equal(t, srcFile1FileInfo.Ino, srcFile2FileInfo.Ino)
assert.NilError(t, unix.Stat(dstFile1, &dstFile1FileInfo))
assert.NilError(t, unix.Stat(dstFile2, &dstFile2FileInfo))
assert.Check(t, is.Equal(dstFile1FileInfo.Ino, dstFile2FileInfo.Ino))
}
|