diff --git a/commands/unpack.go b/commands/unpack.go index f187c13..e4775c6 100644 --- a/commands/unpack.go +++ b/commands/unpack.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "github.com/concourse/go-archive/tarfs" @@ -119,6 +120,12 @@ func extractLayer(dest string, layer v1.Layer, bar *mpb.Bar, chown bool) error { return err } + if runtime.GOOS != "windows" && chown { + err = os.Lchown(dir, hdr.Uid, hdr.Gid) + if err != nil { + return err + } + } continue } else if strings.HasPrefix(base, whiteoutPrefix) { // layer has marked a file as deleted diff --git a/in_test.go b/in_test.go index 9c30a75..8c1733d 100644 --- a/in_test.go +++ b/in_test.go @@ -229,6 +229,18 @@ var _ = Describe("In", func() { stat, err = os.Stat(rootfsPath("top-dir-3", "nested-dir")) Expect(err).ToNot(HaveOccurred()) Expect(stat.IsDir()).To(BeTrue()) + + stat, err = os.Stat(rootfsPath("top-dir-4")) + Expect(err).ToNot(HaveOccurred()) + Expect(stat.IsDir()).To(BeTrue()) + + if os.Geteuid() != 0 { + Skip("Must be run as root to validate file ownership") + } + sys, ok := stat.Sys().(*syscall.Stat_t) + Expect(ok).To(BeTrue()) + Expect(sys.Uid).To(Equal(uint32(1000))) + Expect(sys.Gid).To(Equal(uint32(1000))) }) }) diff --git a/testdata/whiteout/Dockerfile b/testdata/whiteout/Dockerfile index e03464a..d05edff 100644 --- a/testdata/whiteout/Dockerfile +++ b/testdata/whiteout/Dockerfile @@ -17,6 +17,7 @@ RUN touch top-dir-2/nested-dir-gone/nested-file-gone RUN rm -rf top-dir-2 RUN mkdir -p top-dir-3/nested-dir-gone RUN rm -r top-dir-3 && mkdir -p top-dir-3/nested-dir +RUN mkdir top-dir-4 && chown 1000:1000 top-dir-4 # resulting file tree should be: # /top-dir-1/nested-file @@ -24,3 +25,4 @@ RUN rm -r top-dir-3 && mkdir -p top-dir-3/nested-dir # /top-dir-1/nested-dir/file-recreated # /top-dir-1/nested-dir/file-then-dir # /top-dir-3/nested-dir +# /top-dir-4