From 48e42540d215e13717238acfe8a1cb3dafc2eacc Mon Sep 17 00:00:00 2001 From: Justin Cormack Date: Tue, 1 Aug 2017 17:04:57 +0100 Subject: [PATCH] Fix hardlinks in tar output When we converted these to cpio we were not noticing that they were invalid as they had incorrect paths as we converted the path to a symlink anyway. Only the busybox images have hard links in, the Alpine ones are symlinks anyway, which is why it was less visible too. Signed-off-by: Justin Cormack --- src/initrd/initrd.go | 12 +++++++++++- src/moby/image.go | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/initrd/initrd.go b/src/initrd/initrd.go index 5f6dadc45..31f987de6 100644 --- a/src/initrd/initrd.go +++ b/src/initrd/initrd.go @@ -7,6 +7,7 @@ import ( "errors" "io" "io/ioutil" + "path/filepath" "github.com/moby/tool/src/pad4" "github.com/surma/gocpio" @@ -27,8 +28,17 @@ func typeconv(thdr *tar.Header) int64 { case tar.TypeRegA: return cpio.TYPE_REG // Currently hard links not supported very well :) + // Convert to relative symlink as absolute will not work in container + // cpio does support hardlinks but file contents still duplicated, so rely + // on compression to fix that which is fairly ugly. Symlink has not caused issues. case tar.TypeLink: - thdr.Linkname = "/" + thdr.Linkname + dir := filepath.Dir(thdr.Name) + rel, err := filepath.Rel(dir, thdr.Linkname) + if err != nil { + // should never happen, but leave as full abs path + rel = "/" + thdr.Linkname + } + thdr.Linkname = rel return cpio.TYPE_SYMLINK case tar.TypeSymlink: return cpio.TYPE_SYMLINK diff --git a/src/moby/image.go b/src/moby/image.go index 6a5854962..09435908c 100644 --- a/src/moby/image.go +++ b/src/moby/image.go @@ -172,6 +172,10 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv } else { log.Debugf("image tar: %s %s add %s", image, prefix, hdr.Name) hdr.Name = prefix + hdr.Name + if hdr.Typeflag == tar.TypeLink { + // hard links are referenced by full path so need to be adjusted + hdr.Linkname = prefix + hdr.Linkname + } if err := tw.WriteHeader(hdr); err != nil { return err }