Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Fixes Tar.Extract when extracting hardlinked files #171

Merged
merged 1 commit into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions tar.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,11 @@ func (t *Tar) Extract(source, target, destination string) error {
}
th.Name = end

// relativize any hardlink names
if th.Typeflag == tar.TypeLink {
th.Linkname = filepath.Join(filepath.Base(filepath.Dir(th.Linkname)), filepath.Base(th.Linkname))
}

err = t.untarFile(f, destination, th)
if err != nil {
return fmt.Errorf("extracting file %s: %v", th.Name, err)
Expand Down
67 changes: 67 additions & 0 deletions tar_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package archiver_test

import (
"io/ioutil"
"os"
"path"
"testing"

"github.com/mholt/archiver"
)

func requireRegularFile(t *testing.T, path string) os.FileInfo {
fileInfo, err := os.Stat(path)
if err != nil {
t.Fatalf("fileInfo on '%s': %v", path, err)
}

if !fileInfo.Mode().IsRegular() {
t.Fatalf("'%s' expected to be a regular file", path)
}

return fileInfo
}

func assertSameFile(t *testing.T, f1, f2 os.FileInfo) {
if !os.SameFile(f1, f2) {
t.Errorf("expected '%s' and '%s' to be the same file", f1.Name(), f2.Name())
}
}

func TestDefaultTar_Unarchive_HardlinkSuccess(t *testing.T) {
source := "testdata/gnu-hardlinks.tar"

destination, err := ioutil.TempDir("", "archiver_tar_test")
if err != nil {
t.Fatalf("creating temp dir: %v", err)
}
defer os.RemoveAll(destination)

err = archiver.DefaultTar.Unarchive(source, destination)
if err != nil {
t.Fatalf("unarchiving '%s' to '%s': %v", source, destination, err)
}

fileaInfo := requireRegularFile(t, path.Join(destination, "dir-1", "dir-2", "file-a"))
filebInfo := requireRegularFile(t, path.Join(destination, "dir-1", "dir-2", "file-b"))
assertSameFile(t, fileaInfo, filebInfo)
}

func TestDefaultTar_Extract_HardlinkSuccess(t *testing.T) {
source := "testdata/gnu-hardlinks.tar"

destination, err := ioutil.TempDir("", "archiver_tar_test")
if err != nil {
t.Fatalf("creating temp dir: %v", err)
}
defer os.RemoveAll(destination)

err = archiver.DefaultTar.Extract(source, path.Join("dir-1", "dir-2"), destination)
if err != nil {
t.Fatalf("unarchiving '%s' to '%s': %v", source, destination, err)
}

fileaInfo := requireRegularFile(t, path.Join(destination, "dir-2", "file-a"))
filebInfo := requireRegularFile(t, path.Join(destination, "dir-2", "file-b"))
assertSameFile(t, fileaInfo, filebInfo)
}
Binary file added testdata/gnu-hardlinks.tar
Binary file not shown.