Update add to tar to correctly handle hard links
This commit is contained in:
parent
3195b84c25
commit
6668fa0d6f
|
|
@ -18,10 +18,14 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var hardlinks = make(map[uint64]string)
|
||||||
|
|
||||||
// AddToTar adds the file i to tar w at path p
|
// AddToTar adds the file i to tar w at path p
|
||||||
func AddToTar(p string, i os.FileInfo, w *tar.Writer) error {
|
func AddToTar(p string, i os.FileInfo, w *tar.Writer) error {
|
||||||
linkDst := ""
|
linkDst := ""
|
||||||
|
|
@ -32,19 +36,46 @@ func AddToTar(p string, i os.FileInfo, w *tar.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hardlink := false
|
||||||
|
if sys := i.Sys(); sys != nil {
|
||||||
|
if stat, ok := sys.(*syscall.Stat_t); ok {
|
||||||
|
nlinks := stat.Nlink
|
||||||
|
if nlinks > 1 {
|
||||||
|
inode := stat.Ino
|
||||||
|
if original, exists := hardlinks[inode]; exists && original != p {
|
||||||
|
hardlink = true
|
||||||
|
logrus.Infof("%s inode exists in hardlinks map, linking to %s", p, original)
|
||||||
|
linkDst = original
|
||||||
|
} else {
|
||||||
|
hardlinks[inode] = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hdr, err := tar.FileInfoHeader(i, linkDst)
|
hdr, err := tar.FileInfoHeader(i, linkDst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hdr.Name = p
|
hdr.Name = p
|
||||||
w.WriteHeader(hdr)
|
|
||||||
if !i.Mode().IsRegular() {
|
if hardlink {
|
||||||
|
hdr.Linkname = linkDst
|
||||||
|
hdr.Typeflag = tar.TypeLink
|
||||||
|
hdr.Size = 0
|
||||||
|
}
|
||||||
|
if err := w.WriteHeader(hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !(i.Mode().IsRegular()) || hardlink {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
r, err := os.Open(p)
|
r, err := os.Open(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer r.Close()
|
||||||
if _, err := io.Copy(w, r); err != nil {
|
if _, err := io.Copy(w, r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue