diff --git a/bench/go.mod b/bench/go.mod index 62d0af87..3c5ba6a2 100644 --- a/bench/go.mod +++ b/bench/go.mod @@ -3,7 +3,7 @@ module github.com/tonistiigi/fsutil/bench go 1.18 require ( - github.com/containerd/continuity v0.3.0 + github.com/containerd/continuity v0.3.1-0.20230206214859-2a963a2f56e8 github.com/docker/docker v20.10.18+incompatible github.com/pkg/errors v0.9.1 github.com/tonistiigi/fsutil v0.0.0-00010101000000-000000000000 diff --git a/bench/go.sum b/bench/go.sum index d124a290..9f248395 100644 --- a/bench/go.sum +++ b/bench/go.sum @@ -140,8 +140,8 @@ github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cE github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/continuity v0.3.1-0.20230206214859-2a963a2f56e8 h1:EdSQb65ohzz4jsyPOhxfu3/+c9nnU0euk0otferwl9A= +github.com/containerd/continuity v0.3.1-0.20230206214859-2a963a2f56e8/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= diff --git a/copy/copy_test.go b/copy/copy_test.go index a7190bee..e77d54e7 100644 --- a/copy/copy_test.go +++ b/copy/copy_test.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "sort" "strings" "testing" @@ -13,10 +14,8 @@ import ( "github.com/containerd/continuity/fs/fstest" "github.com/pkg/errors" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tonistiigi/fsutil" - "golang.org/x/sys/unix" ) // requiresRoot skips tests that require root @@ -44,7 +43,7 @@ func TestCopyDirectory(t *testing.T) { fstest.CreateDir("/home", 0755), ) - exp := "add:/etc,add:/etc/hosts,add:/etc/hosts.allow,add:/home,add:/usr,add:/usr/local,add:/usr/local/lib,add:/usr/local/lib/libnothing.so,add:/usr/local/lib/libnothing.so.2" + exp := filepath.FromSlash("add:/etc,add:/etc/hosts,add:/etc/hosts.allow,add:/home,add:/usr,add:/usr/local,add:/usr/local/lib,add:/usr/local/lib/libnothing.so,add:/usr/local/lib/libnothing.so.2") if err := testCopy(t, apply, exp); err != nil { t.Fatalf("Copy test failed: %+v", err) @@ -60,7 +59,7 @@ func TestCopyDirectoryWithLocalSymlink(t *testing.T) { fstest.Symlink("nothing.txt", "link-no-nothing.txt"), ) - exp := "add:/link-no-nothing.txt,add:/nothing.txt" + exp := filepath.FromSlash("add:/link-no-nothing.txt,add:/nothing.txt") if err := testCopy(t, apply, exp); err != nil { t.Fatalf("Copy test failed: %+v", err) @@ -84,49 +83,6 @@ func TestCopyToWorkDir(t *testing.T) { require.NoError(t, err) } -func TestCopyDevicesAndFifo(t *testing.T) { - requiresRoot(t) - - t1 := t.TempDir() - - err := mknod(filepath.Join(t1, "char"), unix.S_IFCHR|0444, int(unix.Mkdev(1, 9))) - require.NoError(t, err) - - err = mknod(filepath.Join(t1, "block"), unix.S_IFBLK|0441, int(unix.Mkdev(3, 2))) - require.NoError(t, err) - - err = mknod(filepath.Join(t1, "socket"), unix.S_IFSOCK|0555, 0) - require.NoError(t, err) - - err = unix.Mkfifo(filepath.Join(t1, "fifo"), 0555) - require.NoError(t, err) - - t2 := t.TempDir() - - err = Copy(context.TODO(), t1, ".", t2, ".") - require.NoError(t, err) - - fi, err := os.Lstat(filepath.Join(t2, "char")) - require.NoError(t, err) - assert.Equal(t, os.ModeCharDevice, fi.Mode()&os.ModeCharDevice) - assert.Equal(t, os.FileMode(0444), fi.Mode()&0777) - - fi, err = os.Lstat(filepath.Join(t2, "block")) - require.NoError(t, err) - assert.Equal(t, os.ModeDevice, fi.Mode()&os.ModeDevice) - assert.Equal(t, os.FileMode(0441), fi.Mode()&0777) - - fi, err = os.Lstat(filepath.Join(t2, "fifo")) - require.NoError(t, err) - assert.Equal(t, os.ModeNamedPipe, fi.Mode()&os.ModeNamedPipe) - assert.Equal(t, os.FileMode(0555), fi.Mode()&0777) - - fi, err = os.Lstat(filepath.Join(t2, "socket")) - require.NoError(t, err) - assert.NotEqual(t, os.ModeSocket, fi.Mode()&os.ModeSocket) // socket copied as stub - assert.Equal(t, os.FileMode(0555), fi.Mode()&0777) -} - func TestCopySingleFile(t *testing.T) { t1 := t.TempDir() @@ -168,7 +124,7 @@ func TestCopySingleFile(t *testing.T) { _, err = os.Stat(filepath.Join(t4, "a/b/c/foo2.txt")) require.NoError(t, err) - require.Equal(t, "add:/a/b/c/foo2.txt", ch.String()) + require.Equal(t, filepath.FromSlash("add:/a/b/c/foo2.txt"), ch.String()) } func TestCopyOverrideFile(t *testing.T) { @@ -221,7 +177,7 @@ func TestCopyDirectoryBasename(t *testing.T) { err = fstest.CheckDirectoryEqual(t1, t2) require.NoError(t, err) - require.Equal(t, "add:/foo,add:/foo/bar,add:/foo/bar/baz.txt", ch.String()) + require.Equal(t, filepath.FromSlash("add:/foo,add:/foo/bar,add:/foo/bar/baz.txt"), ch.String()) ch = &changeCollector{} err = Copy(context.TODO(), t1, "foo", t2, "foo", WithCopyInfo(CopyInfo{ @@ -230,7 +186,7 @@ func TestCopyDirectoryBasename(t *testing.T) { })) require.NoError(t, err) - require.Equal(t, "add:/foo/bar,add:/foo/bar/baz.txt", ch.String()) + require.Equal(t, filepath.FromSlash("add:/foo/bar,add:/foo/bar/baz.txt"), ch.String()) err = fstest.CheckDirectoryEqual(t1, t2) require.NoError(t, err) @@ -311,9 +267,12 @@ func TestCopyExistingDirDest(t *testing.T) { st, err := os.Lstat(filepath.Join(t2, "dir")) require.NoError(t, err) require.Equal(t, st.Mode()&os.ModePerm, os.FileMode(0700)) - uid, gid := getUIDGID(st) - require.Equal(t, 1, uid) - require.Equal(t, 1, gid) + var uid, gid int + if runtime.GOOS != "windows" { + uid, gid = getUIDGID(st) + require.Equal(t, 1, uid) + require.Equal(t, 1, gid) + } // verify that non-existing file was created _, err = os.Lstat(filepath.Join(t2, "dir/foo.txt")) @@ -323,9 +282,11 @@ func TestCopyExistingDirDest(t *testing.T) { st, err = os.Lstat(filepath.Join(t2, "dir/bar.txt")) require.NoError(t, err) require.Equal(t, os.FileMode(0644), st.Mode()&os.ModePerm) - uid, gid = getUIDGID(st) - require.Equal(t, 0, uid) - require.Equal(t, 0, gid) + if runtime.GOOS != "windows" { + uid, gid = getUIDGID(st) + require.Equal(t, 0, uid) + require.Equal(t, 0, gid) + } dt, err := os.ReadFile(filepath.Join(t2, "dir/bar.txt")) require.NoError(t, err) require.Equal(t, "bar-contents", string(dt)) @@ -376,7 +337,9 @@ func TestCopySymlinks(t *testing.T) { // verify that existing destination dir's metadata was not overwritten st, err := os.Lstat(filepath.Join(t2, "foo")) require.NoError(t, err) - require.Equal(t, os.FileMode(0644), st.Mode()&os.ModePerm) + if runtime.GOOS != "windows" { + require.Equal(t, os.FileMode(0644), st.Mode()&os.ModePerm) + } require.Equal(t, 0, int(st.Mode()&os.ModeSymlink)) dt, err := os.ReadFile(filepath.Join(t2, "foo")) require.NoError(t, err) @@ -439,37 +402,37 @@ func TestCopyIncludeExclude(t *testing.T) { name: "include bar", opts: []Opt{WithIncludePattern("bar")}, expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"}, - expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo"), }, { name: "include *", opts: []Opt{WithIncludePattern("*")}, expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3", "foo2"}, - expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo,add:/foo2", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo,add:/foo2"), }, { name: "include bar/foo", opts: []Opt{WithIncludePattern("bar/foo")}, expectedResults: []string{"bar", "bar/foo"}, - expectedChanges: "add:/bar/foo", + expectedChanges: filepath.FromSlash("add:/bar/foo"), }, { name: "include bar except bar/foo", opts: []Opt{WithIncludePattern("bar"), WithIncludePattern("!bar/foo")}, expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"}, - expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/baz,add:/bar/baz/foo3"), }, { name: "include bar/foo and foo*", opts: []Opt{WithIncludePattern("bar/foo"), WithIncludePattern("foo*")}, expectedResults: []string{"bar", "bar/foo", "foo2"}, - expectedChanges: "add:/bar/foo,add:/foo2", + expectedChanges: filepath.FromSlash("add:/bar/foo,add:/foo2"), }, { name: "include b*", opts: []Opt{WithIncludePattern("b*")}, expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"}, - expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo"), }, { name: "include bar/f*", @@ -530,25 +493,25 @@ func TestCopyIncludeExclude(t *testing.T) { name: "doublestar matching second item in path", opts: []Opt{WithIncludePattern("**/baz")}, expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"}, - expectedChanges: "add:/bar/baz,add:/bar/baz/foo3", + expectedChanges: filepath.FromSlash("add:/bar/baz,add:/bar/baz/foo3"), }, { name: "doublestar matching first item in path", opts: []Opt{WithIncludePattern("**/bar")}, expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"}, - expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo"), }, { name: "doublestar exclude", opts: []Opt{WithIncludePattern("bar"), WithExcludePattern("**/foo3")}, expectedResults: []string{"bar", "bar/foo", "bar/baz"}, - expectedChanges: "add:/bar,add:/bar/baz,add:/bar/foo", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/baz,add:/bar/foo"), }, { name: "exclude bar/baz", opts: []Opt{WithExcludePattern("bar/baz")}, expectedResults: []string{"bar", "bar/foo", "foo2"}, - expectedChanges: "add:/bar,add:/bar/foo,add:/foo2", + expectedChanges: filepath.FromSlash("add:/bar,add:/bar/foo,add:/foo2"), }, } diff --git a/copy/copy_unix_test.go b/copy/copy_unix_test.go new file mode 100644 index 00000000..df710d4c --- /dev/null +++ b/copy/copy_unix_test.go @@ -0,0 +1,58 @@ +//go:build !windows +// +build !windows + +package fs + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/sys/unix" +) + +func TestCopyDevicesAndFifo(t *testing.T) { + requiresRoot(t) + + t1 := t.TempDir() + + err := mknod(filepath.Join(t1, "char"), unix.S_IFCHR|0444, int(unix.Mkdev(1, 9))) + require.NoError(t, err) + + err = mknod(filepath.Join(t1, "block"), unix.S_IFBLK|0441, int(unix.Mkdev(3, 2))) + require.NoError(t, err) + + err = mknod(filepath.Join(t1, "socket"), unix.S_IFSOCK|0555, 0) + require.NoError(t, err) + + err = unix.Mkfifo(filepath.Join(t1, "fifo"), 0555) + require.NoError(t, err) + + t2 := t.TempDir() + + err = Copy(context.TODO(), t1, ".", t2, ".") + require.NoError(t, err) + + fi, err := os.Lstat(filepath.Join(t2, "char")) + require.NoError(t, err) + assert.Equal(t, os.ModeCharDevice, fi.Mode()&os.ModeCharDevice) + assert.Equal(t, os.FileMode(0444), fi.Mode()&0777) + + fi, err = os.Lstat(filepath.Join(t2, "block")) + require.NoError(t, err) + assert.Equal(t, os.ModeDevice, fi.Mode()&os.ModeDevice) + assert.Equal(t, os.FileMode(0441), fi.Mode()&0777) + + fi, err = os.Lstat(filepath.Join(t2, "fifo")) + require.NoError(t, err) + assert.Equal(t, os.ModeNamedPipe, fi.Mode()&os.ModeNamedPipe) + assert.Equal(t, os.FileMode(0555), fi.Mode()&0777) + + fi, err = os.Lstat(filepath.Join(t2, "socket")) + require.NoError(t, err) + assert.NotEqual(t, os.ModeSocket, fi.Mode()&os.ModeSocket) // socket copied as stub + assert.Equal(t, os.FileMode(0555), fi.Mode()&0777) +} diff --git a/copy/copy_windows.go b/copy/copy_windows.go index c89661e9..58f822d0 100644 --- a/copy/copy_windows.go +++ b/copy/copy_windows.go @@ -13,6 +13,10 @@ const ( seTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" ) +func getUIDGID(fi os.FileInfo) (uid, gid int) { + return 0, 0 +} + func getFileSecurityInfo(name string) (*windows.SID, *windows.ACL, error) { secInfo, err := windows.GetNamedSecurityInfo( name, windows.SE_FILE_OBJECT, diff --git a/go.mod b/go.mod index 80b0c6bf..06be2272 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/Microsoft/go-winio v0.5.2 - github.com/containerd/continuity v0.3.0 + github.com/containerd/continuity v0.3.1-0.20230206214859-2a963a2f56e8 github.com/gogo/protobuf v1.3.2 github.com/moby/patternmatcher v0.5.0 github.com/opencontainers/go-digest v1.0.0 diff --git a/go.sum b/go.sum index eb2b7c57..14be0120 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/continuity v0.3.1-0.20230206214859-2a963a2f56e8 h1:EdSQb65ohzz4jsyPOhxfu3/+c9nnU0euk0otferwl9A= +github.com/containerd/continuity v0.3.1-0.20230206214859-2a963a2f56e8/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=