diff --git a/archive/archive.go b/archive/archive.go index c0551d9fa3..16c01993b7 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -187,19 +187,24 @@ func addTarFile(path, name string, tw *tar.Writer) error { } func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader) error { + // hdr.Mode is in linux format, which we can use for sycalls, + // but for os.Foo() calls we need the mode converted to os.FileMode, + // so use hdrInfo.Mode() (they differ for e.g. setuid bits) + hdrInfo := hdr.FileInfo() + switch hdr.Typeflag { case tar.TypeDir: // Create directory unless it exists as a directory already. // In that case we just want to merge the two if fi, err := os.Lstat(path); !(err == nil && fi.IsDir()) { - if err := os.Mkdir(path, os.FileMode(hdr.Mode)); err != nil { + if err := os.Mkdir(path, hdrInfo.Mode()); err != nil { return err } } case tar.TypeReg, tar.TypeRegA: // Source is regular file - file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode)) + file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode()) if err != nil { return err } @@ -249,7 +254,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader) e // There is no LChmod, so ignore mode for symlink. Also, this // must happen after chown, as that can modify the file mode if hdr.Typeflag != tar.TypeSymlink { - if err := os.Chmod(path, os.FileMode(hdr.Mode&07777)); err != nil { + if err := os.Chmod(path, hdrInfo.Mode()); err != nil { return err } }