Skip to content

Commit

Permalink
Always add parent directories of files to snapshots.
Browse files Browse the repository at this point in the history
During a snapshot, when a file changed and not its parent directories,
the parent directories weren't added to the layer. This is inconsistent
with Docker's behavior which always add parent directories to the layer.
In some edge-cases, it could lead to problems with docker considering
that parent directories where owned by root in forthcoming layers
although they shouldn't (see #1163).

Also, Docker seems to be POSIX compliant regarding the name of
directories in the archive, which always have a slash appended. This
commit also fixes this.

Fixes #1163
  • Loading branch information
gilbsgilbs committed Mar 29, 2020
1 parent 54c2a7a commit 5c6f63d
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 1 deletion.
18 changes: 18 additions & 0 deletions pkg/snapshot/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,28 @@ func writeToTar(t util.Tar, files, whiteouts []string) error {
return err
}
}

addedPaths := make(map[string]bool)
for _, path := range files {
if _, fileExists := addedPaths[path]; fileExists {
continue
}
for _, parentPath := range util.ParentDirectories(path) {
if parentPath == "/" {
continue
}
if _, dirExists := addedPaths[parentPath]; dirExists {
continue
}
if err := t.AddFileToTar(parentPath); err != nil {
return err
}
addedPaths[parentPath] = true
}
if err := t.AddFileToTar(path); err != nil {
return err
}
addedPaths[path] = true
}
return nil
}
Expand Down
23 changes: 22 additions & 1 deletion pkg/snapshot/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ func TestSnapshotFSFileChange(t *testing.T) {
fooPath: "newbaz1",
batPath: "baz",
}
for _, path := range util.ParentDirectoriesWithoutLeadingSlash(batPath) {
if path == "/" {
continue
}
snapshotFiles[path+"/"] = ""
}

actualFiles := []string{}
for {
Expand All @@ -76,6 +82,9 @@ func TestSnapshotFSFileChange(t *testing.T) {
if _, isFile := snapshotFiles[hdr.Name]; !isFile {
t.Fatalf("File %s unexpectedly in tar", hdr.Name)
}
if hdr.Typeflag == tar.TypeDir {
continue
}
contents, _ := ioutil.ReadAll(tr)
if string(contents) != snapshotFiles[hdr.Name] {
t.Fatalf("Contents of %s incorrect, expected: %s, actual: %s", hdr.Name, snapshotFiles[hdr.Name], string(contents))
Expand Down Expand Up @@ -152,6 +161,12 @@ func TestSnapshotFSChangePermissions(t *testing.T) {
snapshotFiles := map[string]string{
batPathWithoutLeadingSlash: "baz2",
}
for _, path := range util.ParentDirectoriesWithoutLeadingSlash(batPathWithoutLeadingSlash) {
if path == "/" {
continue
}
snapshotFiles[path+"/"] = ""
}

foundFiles := []string{}
for {
Expand All @@ -164,6 +179,9 @@ func TestSnapshotFSChangePermissions(t *testing.T) {
if _, isFile := snapshotFiles[hdr.Name]; !isFile {
t.Fatalf("File %s unexpectedly in tar", hdr.Name)
}
if hdr.Typeflag == tar.TypeDir {
continue
}
contents, _ := ioutil.ReadAll(tr)
if string(contents) != snapshotFiles[hdr.Name] {
t.Fatalf("Contents of %s incorrect, expected: %s, actual: %s", hdr.Name, snapshotFiles[hdr.Name], string(contents))
Expand Down Expand Up @@ -203,7 +221,9 @@ func TestSnapshotFiles(t *testing.T) {
expectedFiles := []string{
filepath.Join(testDirWithoutLeadingSlash, "foo"),
}
expectedFiles = append(expectedFiles, util.ParentDirectoriesWithoutLeadingSlash(filepath.Join(testDir, "foo"))...)
for _, path := range util.ParentDirectoriesWithoutLeadingSlash(filepath.Join(testDir, "foo")) {
expectedFiles = append(expectedFiles, strings.TrimRight(path, "/")+"/")
}

f, err := os.Open(tarPath)
if err != nil {
Expand All @@ -222,6 +242,7 @@ func TestSnapshotFiles(t *testing.T) {
}
actualFiles = append(actualFiles, hdr.Name)
}

sort.Strings(expectedFiles)
sort.Strings(actualFiles)
testutil.CheckErrorAndDeepEqual(t, false, nil, expectedFiles, actualFiles)
Expand Down
4 changes: 4 additions & 0 deletions pkg/util/tar_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ func (t *Tar) AddFileToTar(p string) error {
hdr.Name = p
}

if hdr.Typeflag == tar.TypeDir && !strings.HasSuffix(hdr.Name, "/") {
hdr.Name = hdr.Name + "/"
}

// rootfs may not have been extracted when using cache, preventing uname/gname from resolving
// this makes this layer unnecessarily differ from a cached layer which does contain this information
hdr.Uname = ""
Expand Down

0 comments on commit 5c6f63d

Please sign in to comment.