Skip to content

Commit

Permalink
Merge pull request #1187 from katiewasnothere/allow_hardlinks_to_syml…
Browse files Browse the repository at this point in the history
…inks

Remove block preventing us from making hardlinks to symlinks
  • Loading branch information
katiewasnothere authored Oct 20, 2021
2 parents af3d660 + 510109e commit 60b5fa7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 4 deletions.
6 changes: 4 additions & 2 deletions ext4/internal/compactext4/compact.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ func (w *Writer) Create(name string, f *File) error {
}

// Link adds a hard link to the file system.
// We support creating hardlinks to symlinks themselves instead of what
// the symlinks link to, as this is what containerd does upstream.
func (w *Writer) Link(oldname, newname string) error {
if err := w.finishInode(); err != nil {
return err
Expand All @@ -620,8 +622,8 @@ func (w *Writer) Link(oldname, newname string) error {
return err
}
switch oldfile.Mode & format.TypeMask {
case format.S_IFDIR, format.S_IFLNK:
return fmt.Errorf("%s: link target cannot be a directory or symlink: %s", newname, oldname)
case format.S_IFDIR:
return fmt.Errorf("%s: link target cannot be a directory: %s", newname, oldname)
}

if existing != oldfile && oldfile.LinkCount >= format.MaxLinks {
Expand Down
73 changes: 73 additions & 0 deletions ext4/tar2ext4/tar2ext4_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,76 @@ func Test_UnorderedTarExpansion(t *testing.T) {
t.Fatalf("failed to convert tar to layer vhd: %s", err)
}
}

func Test_TarHardlinkToSymlink(t *testing.T) {
tmpTarFilePath := filepath.Join(os.TempDir(), "test-layer.tar")
layerTar, err := os.Create(tmpTarFilePath)
if err != nil {
t.Fatalf("failed to create output file: %s", err)
}
defer os.Remove(tmpTarFilePath)

tw := tar.NewWriter(layerTar)

var files = []struct {
path string
typeFlag byte
linkName string
body string
}{
{
path: "/tmp/zzz.txt",
body: "inside /tmp/zzz.txt",
},
{
path: "/tmp/xxx.txt",
linkName: "/tmp/zzz.txt",
typeFlag: tar.TypeSymlink,
},
{
path: "/tmp/yyy.txt",
linkName: "/tmp/xxx.txt",
typeFlag: tar.TypeLink,
},
}
for _, file := range files {
hdr := &tar.Header{
Name: file.path,
Typeflag: file.typeFlag,
Linkname: file.linkName,
Mode: 0777,
Size: int64(len(file.body)),
ModTime: time.Now(),
AccessTime: time.Now(),
ChangeTime: time.Now(),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if file.body != "" {
if _, err := tw.Write([]byte(file.body)); err != nil {
t.Fatal(err)
}
}
}
if err := tw.Close(); err != nil {
t.Fatal(err)
}

// Now try to import this tar and verify that there is no failure.
if _, err := layerTar.Seek(0, 0); err != nil {
t.Fatalf("failed to seek file: %s", err)
}

opts := []Option{AppendVhdFooter, ConvertWhiteout}
tmpVhdPath := filepath.Join(os.TempDir(), "test-vhd.vhdx")
layerVhd, err := os.Create(tmpVhdPath)
if err != nil {
t.Fatalf("failed to create output VHD: %s", err)
}
defer os.Remove(tmpVhdPath)

if err := Convert(layerTar, layerVhd, opts...); err != nil {
t.Fatalf("failed to convert tar to layer vhd: %s", err)
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 60b5fa7

Please sign in to comment.