chunked: refactor doHardLink to get full destination path

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2024-06-07 09:28:43 +02:00
parent 0e780f7616
commit 62c4c243a3
No known key found for this signature in database
GPG Key ID: 67E38F7A8BA21772
2 changed files with 22 additions and 28 deletions

View File

@ -48,7 +48,18 @@ type fileMetadata struct {
skipSetAttrs bool
}
func doHardLink(srcFd int, destDirFd int, destBase string) error {
func doHardLink(dirfd, srcFd int, destFile string) error {
destDir, destBase := filepath.Split(destFile)
destDirFd := dirfd
if destDir != "" && destDir != "." {
f, err := openOrCreateDirUnderRoot(dirfd, destDir, 0)
if err != nil {
return err
}
defer f.Close()
destDirFd = int(f.Fd())
}
doLink := func() error {
// Using unix.AT_EMPTY_PATH requires CAP_DAC_READ_SEARCH while this variant that uses
// /proc/self/fd doesn't and can be used with rootless.
@ -77,17 +88,11 @@ func copyFileContent(srcFd int, fileMetadata *fileMetadata, dirfd int, mode os.F
copyWithFileRange, copyWithFileClone := true, true
if useHardLinks {
destDirPath, destBase := filepath.Split(destFile)
destDir, err := openFileUnderRoot(dirfd, destDirPath, 0, 0)
err := doHardLink(dirfd, srcFd, destFile)
if err == nil {
defer destDir.Close()
err := doHardLink(srcFd, int(destDir.Fd()), destBase)
if err == nil {
// if the file was deduplicated with a hard link, skip overriding file metadata.
fileMetadata.skipSetAttrs = true
return nil, st.Size(), nil
}
// if the file was deduplicated with a hard link, skip overriding file metadata.
fileMetadata.skipSetAttrs = true
return nil, st.Size(), nil
}
}
@ -412,20 +417,9 @@ func safeLink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *arch
}
defer sourceFile.Close()
destDir, destBase := filepath.Split(metadata.Name)
destDirFd := dirfd
if destDir != "" && destDir != "." {
f, err := openOrCreateDirUnderRoot(dirfd, destDir, 0)
if err != nil {
return err
}
defer f.Close()
destDirFd = int(f.Fd())
}
err = doHardLink(int(sourceFile.Fd()), destDirFd, destBase)
err = doHardLink(dirfd, int(sourceFile.Fd()), metadata.Name)
if err != nil {
return fmt.Errorf("create hardlink %q pointing to %q: %w", metadata.Name, metadata.Linkname, err)
return err
}
newFile, err := openFileUnderRoot(dirfd, metadata.Name, unix.O_WRONLY|unix.O_NOFOLLOW, 0)

View File

@ -70,17 +70,17 @@ func TestDoHardLink(t *testing.T) {
defer syscall.Close(destDirFd)
destBase := "dest-file"
err = doHardLink(srcFd, destDirFd, destBase)
err = doHardLink(destDirFd, srcFd, destBase)
require.NoError(t, err)
// an existing file is unlinked first
err = doHardLink(srcFd, destDirFd, destBase)
err = doHardLink(destDirFd, srcFd, destBase)
assert.NoError(t, err)
err = doHardLink(-1, destDirFd, destBase)
err = doHardLink(destDirFd, -1, destBase)
assert.Error(t, err)
err = doHardLink(srcFd, -1, destBase)
err = doHardLink(-1, srcFd, destBase)
assert.Error(t, err)
}