Skip to content

Commit

Permalink
Make tar2ext4 deterministic with files without parent dir in tar (#2270)
Browse files Browse the repository at this point in the history
Make tar2ext4 deterministic with files without parent dir in tar

Signed-off-by: Takuro Sato <takurosato@microsoft.com>
  • Loading branch information
takuro-sato authored Sep 25, 2024
1 parent 0b833cc commit 16dc8eb
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 4 deletions.
9 changes: 5 additions & 4 deletions ext4/internal/compactext4/compact.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ func (w *Writer) lookup(name string, mustExist bool) (*inode, *inode, string, er
// with the same permissions as that of it's parent directory. It is expected that the a
// call to make these parent directories will be made at a later point with the correct
// permissions, at that time the permissions of these directories will be updated.
// We treat Atime, Mtime, Ctime, and Crtime in the same way.
func (w *Writer) MakeParents(name string) error {
if err := w.finishInode(); err != nil {
return err
Expand All @@ -556,10 +557,10 @@ func (w *Writer) MakeParents(name string) error {
if _, ok := root.Children[dirname]; !ok {
f := &File{
Mode: root.Mode,
Atime: time.Now(),
Mtime: time.Now(),
Ctime: time.Now(),
Crtime: time.Now(),
Atime: fsTimeToTime(root.Atime),
Mtime: fsTimeToTime(root.Mtime),
Ctime: fsTimeToTime(root.Ctime),
Crtime: fsTimeToTime(root.Crtime),
Size: 0,
Uid: root.Uid,
Gid: root.Gid,
Expand Down
76 changes: 76 additions & 0 deletions ext4/tar2ext4/tar2ext4_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package tar2ext4

import (
"crypto/sha256"
"fmt"
"io"
"path/filepath"
"testing"

Expand Down Expand Up @@ -162,3 +165,76 @@ func Test_TarHardlinkToSymlink(t *testing.T) {
t.Fatalf("failed to convert tar to layer vhd: %s", err)
}
}

func calcExt4Sha256(t *testing.T, layerTar *os.File) string {
t.Helper()
if _, err := layerTar.Seek(0, 0); err != nil {
t.Fatalf("failed to seek file: %s", err)
}

opts := []Option{ConvertWhiteout}

tmpExt4Path := filepath.Join(os.TempDir(), "test.ext4")
layerVhd, err := os.Create(tmpExt4Path)
if err != nil {
t.Fatalf("failed to create output VHD: %s", err)
}
defer os.Remove(tmpExt4Path)

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

if _, err := layerVhd.Seek(0, 0); err != nil {
t.Fatalf("failed to seek file: %s", err)
}

hasher := sha256.New()
if _, err = io.Copy(hasher, layerVhd); err != nil {
t.Fatalf("filed to initialize hasher: %s", err)
}

hash := hasher.Sum(nil)
return fmt.Sprintf("%x", hash)
}

// Test_MissingParentDirExpansion tests that we are correctly able to expand a layer tar file
// even if its file does not include the parent directory in its file name.
func Test_MissingParentDirExpansion(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 file = struct {
path, body string
}{"foo/bar.txt", "inside bar.txt"}
hdr := &tar.Header{
Name: file.path,
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 _, err := tw.Write([]byte(file.body)); err != nil {
t.Fatal(err)
}
if err := tw.Close(); err != nil {
t.Fatal(err)
}

// Now import the tar file and check the conversion to ext4 is deterministic.
hash1 := calcExt4Sha256(t, layerTar)
hash2 := calcExt4Sha256(t, layerTar)

if hash1 != hash2 {
t.Fatalf("hash doesn't match")
}
}

0 comments on commit 16dc8eb

Please # to comment.