Update tar path resolution

Fixes bug for resolving symlinks which allowed fully resolving
an existing symlink to a path, causing some symlinks to get
overridden as symlinks to self.
Updates logic to split name into parent path, resolve the parent
path, then safely join back with the base name.
Uses the split code to ensure parent directories are created in
all cases.
Replaces `rootJoin` with filepath.Join to the root, which already
correctly cleans relative symlinks to the root.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
Derek McGowan
2017-07-24 17:51:47 -07:00
parent 9b53b8b68d
commit afec478beb
3 changed files with 291 additions and 45 deletions

View File

@@ -126,19 +126,30 @@ func Apply(ctx context.Context, root string, r io.Reader) (int64, error) {
continue
}
// Note as these operations are platform specific, so must the slash be.
if !strings.HasSuffix(hdr.Name, string(os.PathSeparator)) {
// Not the root directory, ensure that the parent directory exists.
// This happened in some tests where an image had a tarfile without any
// parent directories.
parent := filepath.Dir(hdr.Name)
parentPath, err := rootPath(root, parent)
if err != nil {
return 0, err
}
// Split name and resolve symlinks for root directory.
ppath, base := filepath.Split(hdr.Name)
ppath, err = rootPath(root, ppath)
if err != nil {
return 0, errors.Wrap(err, "failed to get root path")
}
// Join to root before joining to parent path to ensure relative links are
// already resolved based on the root before adding to parent.
path := filepath.Join(ppath, filepath.Join("/", base))
if path == root {
log.G(ctx).Debugf("file %q ignored: resolved to root", hdr.Name)
continue
}
// If file is not directly under root, ensure parent directory
// exists or is created.
if ppath != root {
parentPath := ppath
if base == "" {
parentPath = filepath.Dir(path)
}
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
err = mkdirAll(parentPath, 0600)
err = mkdirAll(parentPath, 0700)
if err != nil {
return 0, err
}
@@ -173,13 +184,6 @@ func Apply(ctx context.Context, root string, r io.Reader) (int64, error) {
}
}
path, err := rootPath(root, hdr.Name)
if err != nil {
return 0, errors.Wrap(err, "failed to get root path")
}
base := filepath.Base(path)
if strings.HasPrefix(base, whiteoutPrefix) {
dir := filepath.Dir(path)
if base == whiteoutOpaqueDir {