From 2a421289266d0fd3055b821e0b643e77da594c68 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 11 Nov 2016 22:43:10 +1100 Subject: [PATCH] layer unpack: fix whiteout errors on AUFS lstat(2) returns EPERM if you try to get information about a whiteout path. This is one of the reasons I think that matching the AUFS semantics is insane. Ref: opencontainers/image-spec#24 Signed-off-by: Aleksa Sarai --- image/layer/tar_extract.go | 48 ++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/image/layer/tar_extract.go b/image/layer/tar_extract.go index f398e01db..8c60ab7e3 100644 --- a/image/layer/tar_extract.go +++ b/image/layer/tar_extract.go @@ -138,27 +138,6 @@ func unpackEntry(root string, hdr *tar.Header, r io.Reader) error { }() } - // FIXME: Currently we cannot use os.Link because we have to wait until the - // entire archive has been extracted to be sure that hardlinks will - // work. There are a few ways of solving this, one of which is to - // keep an inode index. For now we don't have any other option than - // to "fake" hardlinks with symlinks. - if hdr.Typeflag == tar.TypeLink { - hdr.Typeflag = tar.TypeSymlink - } - - // Get information about the path. - hdrFi := hdr.FileInfo() - fi, err := os.Lstat(path) - if err != nil { - if !os.IsNotExist(err) { - return err - } - - // File doesn't exist, just switch fi to the file header. - fi = hdr.FileInfo() - } - // Currently the spec doesn't specify what the hdr.Typeflag of whiteout // files is meant to be. We specifically only produce regular files // ('\x00') but it could be possible that someone produces a different @@ -173,9 +152,9 @@ func unpackEntry(root string, hdr *tar.Header, r io.Reader) error { // first place. if _, err := os.Lstat(path); err != nil { if os.IsNotExist(err) { - err = fmt.Errorf("unpack entry: encountered whiteout %s: %s", hdr.Name, err) + err = fmt.Errorf("unpack entry: encountered invalid whiteout %s: %s", hdr.Name, err) } - return err + return fmt.Errorf("unpack entry: error checking whiteout path %s: %s", path, err) } // Just remove the path. The defer will reapply the correct parent @@ -183,6 +162,29 @@ func unpackEntry(root string, hdr *tar.Header, r io.Reader) error { return os.RemoveAll(path) } + // FIXME: Currently we cannot use os.Link because we have to wait until the + // entire archive has been extracted to be sure that hardlinks will + // work. There are a few ways of solving this, one of which is to + // keep an inode index. For now we don't have any other option than + // to "fake" hardlinks with symlinks. + if hdr.Typeflag == tar.TypeLink { + hdr.Typeflag = tar.TypeSymlink + } + + // Get information about the path. This has to be done after we've dealt + // with whiteouts because it turns out that lstat(2) will return EPERM if + // you try to stat a whiteout on AUFS. + hdrFi := hdr.FileInfo() + fi, err := os.Lstat(path) + if err != nil { + if !os.IsNotExist(err) { + return err + } + + // File doesn't exist, just switch fi to the file header. + fi = hdr.FileInfo() + } + // If the type of the file has changed, there's nothing we can do other // than just remove the old path and replace it. // XXX Is this actually valid according to the spec? Do you need to have a