|
@@ -2,7 +2,6 @@ package archive
|
|
|
|
|
|
import (
|
|
|
"archive/tar"
|
|
|
- "github.com/dotcloud/docker/utils"
|
|
|
"io"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
@@ -89,95 +88,22 @@ func ApplyLayer(dest string, layer Archive) error {
|
|
|
// The only exception is when it is a directory *and* the file from
|
|
|
// the layer is also a directory. Then we want to merge them (i.e.
|
|
|
// just apply the metadata from the layer).
|
|
|
- hasDir := false
|
|
|
if fi, err := os.Lstat(path); err == nil {
|
|
|
- if fi.IsDir() && hdr.Typeflag == tar.TypeDir {
|
|
|
- hasDir = true
|
|
|
- } else {
|
|
|
+ if !(fi.IsDir() && hdr.Typeflag == tar.TypeDir) {
|
|
|
if err := os.RemoveAll(path); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- switch hdr.Typeflag {
|
|
|
- case tar.TypeDir:
|
|
|
- if !hasDir {
|
|
|
- err = os.Mkdir(path, os.FileMode(hdr.Mode))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
- dirs = append(dirs, hdr)
|
|
|
-
|
|
|
- case tar.TypeReg, tar.TypeRegA:
|
|
|
- // Source is regular file
|
|
|
- file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- if _, err := io.Copy(file, tr); err != nil {
|
|
|
- file.Close()
|
|
|
- return err
|
|
|
- }
|
|
|
- file.Close()
|
|
|
-
|
|
|
- case tar.TypeBlock, tar.TypeChar, tar.TypeFifo:
|
|
|
- mode := uint32(hdr.Mode & 07777)
|
|
|
- switch hdr.Typeflag {
|
|
|
- case tar.TypeBlock:
|
|
|
- mode |= syscall.S_IFBLK
|
|
|
- case tar.TypeChar:
|
|
|
- mode |= syscall.S_IFCHR
|
|
|
- case tar.TypeFifo:
|
|
|
- mode |= syscall.S_IFIFO
|
|
|
- }
|
|
|
-
|
|
|
- if err := syscall.Mknod(path, mode, int(mkdev(hdr.Devmajor, hdr.Devminor))); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- case tar.TypeLink:
|
|
|
- if err := os.Link(filepath.Join(dest, hdr.Linkname), path); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- case tar.TypeSymlink:
|
|
|
- if err := os.Symlink(hdr.Linkname, path); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- default:
|
|
|
- utils.Debugf("unhandled type %d\n", hdr.Typeflag)
|
|
|
- }
|
|
|
-
|
|
|
- if err = syscall.Lchown(path, hdr.Uid, hdr.Gid); err != nil {
|
|
|
+ if err := createTarFile(path, dest, hdr, tr); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- // 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 {
|
|
|
- err = syscall.Chmod(path, uint32(hdr.Mode&07777))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Directories must be handled at the end to avoid further
|
|
|
- // file creation in them to modify the mtime
|
|
|
- if hdr.Typeflag != tar.TypeDir {
|
|
|
- ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
|
|
|
- // syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
|
|
|
- if hdr.Typeflag != tar.TypeSymlink {
|
|
|
- if err := syscall.UtimesNano(path, ts); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- } else {
|
|
|
- if err := LUtimesNano(path, ts); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
+ // Directory mtimes must be handled at the end to avoid further
|
|
|
+ // file creation in them to modify the directory mtime
|
|
|
+ if hdr.Typeflag == tar.TypeDir {
|
|
|
+ dirs = append(dirs, hdr)
|
|
|
}
|
|
|
}
|
|
|
}
|