mirror of
https://github.com/containers/podman.git
synced 2025-05-21 09:05:56 +08:00
Handle hard links in remote builds
Fixes: https://github.com/containers/podman/issues/9893 Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:

committed by
Matthew Heon

parent
c53638e9f6
commit
ba884865c5
3
Makefile
3
Makefile
@ -382,6 +382,9 @@ bin/podman.cross.%: .gopathok
|
|||||||
.PHONY: local-cross
|
.PHONY: local-cross
|
||||||
local-cross: $(CROSS_BUILD_TARGETS) ## Cross compile podman binary for multiple architectures
|
local-cross: $(CROSS_BUILD_TARGETS) ## Cross compile podman binary for multiple architectures
|
||||||
|
|
||||||
|
.PHONY: cross
|
||||||
|
cross: local-cross
|
||||||
|
|
||||||
# Update nix/nixpkgs.json its latest stable commit
|
# Update nix/nixpkgs.json its latest stable commit
|
||||||
.PHONY: nixpkgs
|
.PHONY: nixpkgs
|
||||||
nixpkgs:
|
nixpkgs:
|
||||||
|
@ -28,6 +28,11 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type devino struct {
|
||||||
|
Dev uint64
|
||||||
|
Ino uint64
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
iidRegex = regexp.MustCompile(`^[0-9a-f]{12}`)
|
iidRegex = regexp.MustCompile(`^[0-9a-f]{12}`)
|
||||||
)
|
)
|
||||||
@ -402,7 +407,7 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
|
|||||||
defer pw.Close()
|
defer pw.Close()
|
||||||
defer gw.Close()
|
defer gw.Close()
|
||||||
defer tw.Close()
|
defer tw.Close()
|
||||||
|
seen := make(map[devino]string)
|
||||||
for _, src := range sources {
|
for _, src := range sources {
|
||||||
s, err := filepath.Abs(src)
|
s, err := filepath.Abs(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -431,25 +436,40 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if info.Mode().IsRegular() { // add file item
|
if info.Mode().IsRegular() { // add file item
|
||||||
f, lerr := os.Open(path)
|
di, isHardLink := checkHardLink(info)
|
||||||
if lerr != nil {
|
if err != nil {
|
||||||
return lerr
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr, lerr := tar.FileInfoHeader(info, name)
|
hdr, err := tar.FileInfoHeader(info, "")
|
||||||
if lerr != nil {
|
if err != nil {
|
||||||
f.Close()
|
return err
|
||||||
return lerr
|
|
||||||
}
|
}
|
||||||
|
orig, ok := seen[di]
|
||||||
|
if ok {
|
||||||
|
hdr.Typeflag = tar.TypeLink
|
||||||
|
hdr.Linkname = orig
|
||||||
|
hdr.Size = 0
|
||||||
|
|
||||||
|
return tw.WriteHeader(hdr)
|
||||||
|
}
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
hdr.Name = name
|
hdr.Name = name
|
||||||
if lerr := tw.WriteHeader(hdr); lerr != nil {
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
return lerr
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, cerr := io.Copy(tw, f)
|
_, err = io.Copy(tw, f)
|
||||||
f.Close()
|
f.Close()
|
||||||
return cerr
|
if err == nil && isHardLink {
|
||||||
|
seen[di] = name
|
||||||
|
}
|
||||||
|
return err
|
||||||
} else if info.Mode().IsDir() { // add folders
|
} else if info.Mode().IsDir() { // add folders
|
||||||
hdr, lerr := tar.FileInfoHeader(info, name)
|
hdr, lerr := tar.FileInfoHeader(info, name)
|
||||||
if lerr != nil {
|
if lerr != nil {
|
||||||
|
16
pkg/bindings/images/build_unix.go
Normal file
16
pkg/bindings/images/build_unix.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package images
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkHardLink(fi os.FileInfo) (devino, bool) {
|
||||||
|
st := fi.Sys().(*syscall.Stat_t)
|
||||||
|
return devino{
|
||||||
|
Dev: uint64(st.Dev),
|
||||||
|
Ino: uint64(st.Ino),
|
||||||
|
}, st.Nlink > 1
|
||||||
|
}
|
9
pkg/bindings/images/build_windows.go
Normal file
9
pkg/bindings/images/build_windows.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package images
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkHardLink(fi os.FileInfo) (devino, bool) {
|
||||||
|
return devino{}, false
|
||||||
|
}
|
@ -766,6 +766,26 @@ EOF
|
|||||||
is "$output" ".*/tmp/bogus: no such file or directory"
|
is "$output" ".*/tmp/bogus: no such file or directory"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "podman build COPY hardlinks " {
|
||||||
|
tmpdir=$PODMAN_TMPDIR/build-test
|
||||||
|
mkdir -p $tmpdir
|
||||||
|
|
||||||
|
dockerfile=$tmpdir/Dockerfile
|
||||||
|
cat >$dockerfile <<EOF
|
||||||
|
FROM $IMAGE
|
||||||
|
COPY . /test
|
||||||
|
EOF
|
||||||
|
ln $dockerfile $tmpdir/hardlink
|
||||||
|
|
||||||
|
run_podman build -t build_test $tmpdir
|
||||||
|
run_podman run --rm build_test stat -c '%i' /test/Dockerfile
|
||||||
|
dinode=$output
|
||||||
|
run_podman run --rm build_test stat -c '%i' /test/hardlink
|
||||||
|
is "$output" "$dinode" "COPY hardlinks work"
|
||||||
|
|
||||||
|
run_podman rmi -f build_test
|
||||||
|
}
|
||||||
|
|
||||||
function teardown() {
|
function teardown() {
|
||||||
# A timeout or other error in 'build' can leave behind stale images
|
# A timeout or other error in 'build' can leave behind stale images
|
||||||
# that podman can't even see and which will cascade into subsequent
|
# that podman can't even see and which will cascade into subsequent
|
||||||
|
Reference in New Issue
Block a user