Factor out hard link code for cross platform build

Move system specific code out of entry so the build continues to work on
Windows. Hard links are not currently supported on Windows, the behavior
is a no-op.
This commit is contained in:
2023-10-05 12:00:30 -05:00
parent 07c796a46b
commit 756a003fb3
3 changed files with 49 additions and 34 deletions

View File

@@ -18,7 +18,6 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"github.com/vmihailenco/msgpack" "github.com/vmihailenco/msgpack"
@@ -752,11 +751,6 @@ func (files FileInfoCompare) Less(i, j int) bool {
} }
} }
type listEntryLinkKey struct {
dev uint64
ino uint64
}
type ListingState struct { type ListingState struct {
linkIndex int linkIndex int
linkTable map[listEntryLinkKey]int // map unique inode details to initially found path linkTable map[listEntryLinkKey]int // map unique inode details to initially found path
@@ -816,34 +810,30 @@ func ListEntries(top string, path string, patterns []string, nobackupFile string
continue continue
} }
var linkKey *listEntryLinkKey linkKey, isHardLinked := entry.getHardLinkKey(f)
if isHardLinked {
if runtime.GOOS != "windows" && !entry.IsDir() { if linkIndex, seen := listingState.linkTable[linkKey]; seen {
if stat := f.Sys().(*syscall.Stat_t); stat != nil && stat.Nlink > 1 { if linkIndex == -1 {
k := listEntryLinkKey{dev: uint64(stat.Dev), ino: uint64(stat.Ino)} LOG_DEBUG("LIST_EXCLUDE", "%s was excluded or skipped (hard link)", entry.Path)
if linkIndex, seen := listingState.linkTable[k]; seen {
if linkIndex == -1 {
LOG_DEBUG("LIST_EXCLUDE", "%s is excluded by attribute (hard link)", entry.Path)
continue
}
entry.Size = 0
if entry.IsFile() {
entry.Link = strconv.FormatInt(int64(linkIndex), 16)
} else {
entry.EndChunk = entryHardLinkTargetChunkMarker
entry.EndOffset = linkIndex
}
listingChannel <- entry
continue continue
} else {
if entry.IsFile() {
entry.Link = "/"
} else {
entry.EndChunk = entryHardLinkRootChunkMarker
}
listingState.linkTable[k] = -1
linkKey = &k
} }
entry.Size = 0
if entry.IsFile() {
entry.Link = strconv.FormatInt(int64(linkIndex), 16)
} else {
entry.EndChunk = entryHardLinkTargetChunkMarker
entry.EndOffset = linkIndex
}
listingChannel <- entry
continue
} else {
if entry.IsFile() {
entry.Link = "/"
} else {
entry.EndChunk = entryHardLinkRootChunkMarker
}
listingState.linkTable[linkKey] = -1
} }
} }
@@ -892,8 +882,8 @@ func ListEntries(top string, path string, patterns []string, nobackupFile string
continue continue
} }
if linkKey != nil { if isHardLinked {
listingState.linkTable[*linkKey] = listingState.linkIndex listingState.linkTable[linkKey] = listingState.linkIndex
listingState.linkIndex++ listingState.linkIndex++
} }

View File

@@ -47,6 +47,25 @@ func SetOwner(fullPath string, entry *Entry, fileInfo *os.FileInfo) bool {
return true return true
} }
type listEntryLinkKey struct {
dev uint64
ino uint64
}
func (entry *Entry) getHardLinkKey(f os.FileInfo) (key listEntryLinkKey, linked bool) {
if entry.IsDir() {
return
}
stat := f.Sys().(*syscall.Stat_t)
if stat == nil || stat.Nlink < 2 {
return
}
key.dev = uint64(stat.Dev)
key.ino = uint64(stat.Ino)
linked = true
return
}
func (entry *Entry) ReadSpecial(fileInfo os.FileInfo) bool { func (entry *Entry) ReadSpecial(fileInfo os.FileInfo) bool {
if fileInfo.Mode()&(os.ModeDevice|os.ModeCharDevice) == 0 { if fileInfo.Mode()&(os.ModeDevice|os.ModeCharDevice) == 0 {
return true return true

View File

@@ -110,6 +110,12 @@ func SetOwner(fullPath string, entry *Entry, fileInfo *os.FileInfo) bool {
return true return true
} }
type listEntryLinkKey struct{}
func (entry *Entry) getHardLinkKey(f os.FileInfo) (key listEntryLinkKey, linked bool) {
return
}
func (entry *Entry) ReadAttributes(top string) { func (entry *Entry) ReadAttributes(top string) {
} }