diff --git a/chrootarchive/archive.go b/chrootarchive/archive.go index 1e79837..9876100 100644 --- a/chrootarchive/archive.go +++ b/chrootarchive/archive.go @@ -1,15 +1,11 @@ package chrootarchive import ( - "errors" "io" - "os" - "path/filepath" "github.com/moby/sys/user" "github.com/moby/go-archive" - "github.com/moby/go-archive/compression" ) // NewArchiver returns a new Archiver which uses chrootarchive.Untar @@ -51,41 +47,6 @@ func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOp return untarHandler(tarArchive, dest, options, false, dest) } -// Handler for teasing out the automatic decompression -func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool, root string) error { - if tarArchive == nil { - return errors.New("empty archive") - } - if options == nil { - options = &archive.TarOptions{} - } - - // If dest is inside a root then directory is created within chroot by extractor. - // This case is only currently used by cp. - if dest == root { - uid, gid := options.IDMap.RootPair() - - dest = filepath.Clean(dest) - if _, err := os.Stat(dest); os.IsNotExist(err) { - if err := user.MkdirAllAndChown(dest, 0o755, uid, gid, user.WithOnlyNew); err != nil { - return err - } - } - } - - r := io.NopCloser(tarArchive) - if decompress { - decompressedArchive, err := compression.DecompressStream(tarArchive) - if err != nil { - return err - } - defer decompressedArchive.Close() - r = decompressedArchive - } - - return invokeUnpack(r, dest, options, root) -} - // Tar tars the requested path while chrooted to the specified root. func Tar(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) { if options == nil { diff --git a/chrootarchive/archive_unix.go b/chrootarchive/archive_unix.go index e2b8d50..c8c64b2 100644 --- a/chrootarchive/archive_unix.go +++ b/chrootarchive/archive_unix.go @@ -5,12 +5,51 @@ package chrootarchive import ( "errors" "io" + "os" "path/filepath" "strings" "github.com/moby/go-archive" + "github.com/moby/go-archive/compression" + "github.com/moby/sys/user" ) +// Handler for teasing out the automatic decompression +func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool, root string) error { + if tarArchive == nil { + return errors.New("empty archive") + } + if options == nil { + options = &archive.TarOptions{} + } + + // Create dest here only if it is the root itself; paths below the root are + // created by the extractor after entering the chroot. + // This case is only currently used by cp. + if dest == root { + uid, gid := options.IDMap.RootPair() + + dest = filepath.Clean(dest) + if _, err := os.Stat(dest); os.IsNotExist(err) { + if err := user.MkdirAllAndChown(dest, 0o755, uid, gid, user.WithOnlyNew); err != nil { + return err + } + } + } + + r := io.NopCloser(tarArchive) + if decompress { + decompressedArchive, err := compression.DecompressStream(tarArchive) + if err != nil { + return err + } + defer decompressedArchive.Close() + r = decompressedArchive + } + + return invokeUnpack(r, dest, options, root) +} + func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error { relDest, err := resolvePathInChroot(root, dest) if err != nil { diff --git a/chrootarchive/archive_windows.go b/chrootarchive/archive_windows.go index 078341f..88e2aab 100644 --- a/chrootarchive/archive_windows.go +++ b/chrootarchive/archive_windows.go @@ -1,7 +1,10 @@ package chrootarchive import ( + "errors" "io" + "os" + "path/filepath" "strings" "github.com/moby/go-archive" @@ -25,14 +28,34 @@ func addLongPathPrefix(srcPath string) string { return longPathPrefix + srcPath } -func invokeUnpack(decompressedArchive io.ReadCloser, dest string, options *archive.TarOptions, root string) error { +// Handler for teasing out the automatic decompression +func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool, root string) error { + if tarArchive == nil { + return errors.New("empty archive") + } + + // Create dest here only if it is the root itself; paths below the root are + // created by the extractor after entering the chroot. + // This case is only currently used by cp. + if dest == root { + dest = filepath.Clean(dest) + if _, err := os.Stat(dest); os.IsNotExist(err) { + if err := os.MkdirAll(dest, 0); err != nil { + return err + } + } + } + // Windows is different to Linux here because Windows does not support // chroot. Hence there is no point sandboxing a chrooted process to // do the unpack. We call inline instead within the daemon process. - return archive.Unpack(decompressedArchive, addLongPathPrefix(dest), options) + if decompress { + return archive.Untar(tarArchive, addLongPathPrefix(dest), options) + } + return archive.UntarUncompressed(tarArchive, addLongPathPrefix(dest), options) } -func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) { +func invokePack(srcPath string, options *archive.TarOptions, _ string) (io.ReadCloser, error) { // Windows is different to Linux here because Windows does not support // chroot. Hence there is no point sandboxing a chrooted process to // do the pack. We call inline instead within the daemon process.