Merge pull request #674 from dmcgowan/fs-hardlink-unmodified
Fix hardlinks in tars for unmodified files
This commit is contained in:
@@ -65,7 +65,7 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error {
|
||||
}
|
||||
continue
|
||||
case (fi.Mode() & os.ModeType) == 0:
|
||||
link, err := GetLinkSource(target, fi, inodes)
|
||||
link, err := getLinkSource(target, fi, inodes)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get hardlink")
|
||||
}
|
||||
|
||||
13
fs/diff.go
13
fs/diff.go
@@ -16,9 +16,13 @@ import (
|
||||
type ChangeKind int
|
||||
|
||||
const (
|
||||
// ChangeKindUnmodified represents an unmodified
|
||||
// file
|
||||
ChangeKindUnmodified = iota
|
||||
|
||||
// ChangeKindAdd represents an addition of
|
||||
// a file
|
||||
ChangeKindAdd = iota
|
||||
ChangeKindAdd
|
||||
|
||||
// ChangeKindModify represents a change to
|
||||
// an existing file
|
||||
@@ -31,6 +35,8 @@ const (
|
||||
|
||||
func (k ChangeKind) String() string {
|
||||
switch k {
|
||||
case ChangeKindUnmodified:
|
||||
return "unmodified"
|
||||
case ChangeKindAdd:
|
||||
return "add"
|
||||
case ChangeKindModify:
|
||||
@@ -287,7 +293,10 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err
|
||||
f1 = nil
|
||||
f2 = nil
|
||||
if same {
|
||||
continue
|
||||
if !isLinked(f) {
|
||||
continue
|
||||
}
|
||||
k = ChangeKindUnmodified
|
||||
}
|
||||
}
|
||||
if err := changeFn(k, p, f, nil); err != nil {
|
||||
|
||||
@@ -90,3 +90,11 @@ func compareCapabilities(p1, p2 string) (bool, error) {
|
||||
}
|
||||
return bytes.Equal(c1, c2), nil
|
||||
}
|
||||
|
||||
func isLinked(f os.FileInfo) bool {
|
||||
s, ok := f.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return !f.IsDir() && s.Nlink > 1
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package fs
|
||||
|
||||
import "os"
|
||||
|
||||
func detectDirDiff(upper, lower string) *diffDirOptions {
|
||||
return nil
|
||||
}
|
||||
@@ -13,3 +15,7 @@ func compareCapabilities(p1, p2 string) (bool, error) {
|
||||
// TODO: Use windows equivalent
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func isLinked(os.FileInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,11 +2,26 @@ package fs
|
||||
|
||||
import "os"
|
||||
|
||||
// GetLinkSource returns a path for the given name and
|
||||
// GetLinkID returns an identifier representing the node a hardlink is pointing
|
||||
// to. If the file is not hard linked then 0 will be returned.
|
||||
func GetLinkInfo(fi os.FileInfo) (uint64, bool) {
|
||||
return getLinkInfo(fi)
|
||||
}
|
||||
|
||||
// getLinkSource returns a path for the given name and
|
||||
// file info to its link source in the provided inode
|
||||
// map. If the given file name is not in the map and
|
||||
// has other links, it is added to the inode map
|
||||
// to be a source for other link locations.
|
||||
func GetLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
|
||||
return getHardLink(name, fi, inodes)
|
||||
func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
|
||||
inode, isHardlink := getLinkInfo(fi)
|
||||
if !isHardlink {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
path, ok := inodes[inode]
|
||||
if !ok {
|
||||
inodes[inode] = name
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
@@ -3,31 +3,15 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func getHardLink(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
|
||||
if fi.IsDir() {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
|
||||
s, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return "", errors.New("unsupported stat type")
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// If inode is not hardlinked, no reason to lookup or save inode
|
||||
if s.Nlink == 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
inode := uint64(s.Ino)
|
||||
|
||||
path, ok := inodes[inode]
|
||||
if !ok {
|
||||
inodes[inode] = name
|
||||
}
|
||||
return path, nil
|
||||
return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@ package fs
|
||||
|
||||
import "os"
|
||||
|
||||
func getHardLink(string, os.FileInfo, map[uint64]string) (string, error) {
|
||||
return "", nil
|
||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user