Fix symlinks treted as hardlinks in resulting tar archive

This commit is contained in:
eleksir
2026-04-18 09:25:13 +03:00
parent d2e0fd2af0
commit 98e7d0f73e

View File

@@ -86,6 +86,8 @@ func writeFilesToTar(ctx context.Context, filepaths []string, tw *tar.Writer, cl
var ( var (
err error err error
linkTarget string linkTarget string
isSymlink bool
isHardLink bool
) )
select { select {
@@ -107,6 +109,7 @@ func writeFilesToTar(ctx context.Context, filepaths []string, tw *tar.Writer, cl
continue continue
} }
// Handle symlinks - read target path and mark as symbolic link.
if st.Mode()&os.ModeSymlink != 0 { if st.Mode()&os.ModeSymlink != 0 {
linkTarget, err = os.Readlink(fpath) linkTarget, err = os.Readlink(fpath)
@@ -115,6 +118,8 @@ func writeFilesToTar(ctx context.Context, filepaths []string, tw *tar.Writer, cl
continue continue
} }
isSymlink = true
} }
// Skip sockets explicitly (they cannot be backed up). // Skip sockets explicitly (they cannot be backed up).
@@ -125,12 +130,15 @@ func writeFilesToTar(ctx context.Context, filepaths []string, tw *tar.Writer, cl
} }
// Check for hard link - if inode was already seen, store as link instead of content. // Check for hard link - if inode was already seen, store as link instead of content.
if st.Mode().IsRegular() { // Only check for regular files (not symlinks).
if st.Mode().IsRegular() && !isSymlink {
inode := getInode(st) inode := getInode(st)
if inode != 0 { if inode != 0 {
if existingPath, seen := seenInodes[inode]; seen { if existingPath, seen := seenInodes[inode]; seen {
// This is a hard link to already-archived file. // This is a hard link to already-archived file.
linkTarget = existingPath linkTarget = existingPath
isHardLink = true
log.Debugf("Hard link detected: %s -> %s", fpath, existingPath) log.Debugf("Hard link detected: %s -> %s", fpath, existingPath)
} else { } else {
// First time seeing this inode - track it. // First time seeing this inode - track it.
@@ -147,8 +155,11 @@ func writeFilesToTar(ctx context.Context, filepaths []string, tw *tar.Writer, cl
continue continue
} }
// If linkTarget is set, ensure the header is marked as a link. // Set correct type flag for symbolic links or hard links.
if linkTarget != "" { if isSymlink {
header.Typeflag = tar.TypeSymlink
header.Linkname = linkTarget
} else if isHardLink {
header.Typeflag = tar.TypeLink header.Typeflag = tar.TypeLink
header.Linkname = linkTarget header.Linkname = linkTarget
} }