Skip to content

Commit

Permalink
copier: add NoOverwriteNonDirDir option
Browse files Browse the repository at this point in the history
Similar to the `NoOverwriteDirNonDir` one, add an option that disables
non-directories from being overwritten by directories.

Required-for: containers/podman/issues/14420
Signed-off-by: Valentin Rothberg <[email protected]>
  • Loading branch information
vrothberg committed Jun 7, 2022
1 parent b94d4ce commit 7cc5f19
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
10 changes: 7 additions & 3 deletions copier/copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ type PutOptions struct {
IgnoreXattrErrors bool // ignore any errors encountered when attempting to set extended attributes
IgnoreDevices bool // ignore items which are character or block devices
NoOverwriteDirNonDir bool // instead of quietly overwriting directories with non-directories, return an error
NoOverwriteNonDirDir bool // instead of quietly overwriting non-directories with directories, return an error
Rename map[string]string // rename items with the specified names, or under the specified names
}

Expand Down Expand Up @@ -1794,12 +1795,15 @@ func copierHandlerPut(bulkReader io.Reader, req request, idMappings *idtools.IDM
}
case tar.TypeDir:
if err = os.Mkdir(path, 0700); err != nil && os.IsExist(err) {
var st os.FileInfo
if st, err = os.Lstat(path); err == nil && !st.IsDir() {
// it's not a directory, so remove it and mkdir
if st, stErr := os.Lstat(path); stErr == nil && !st.IsDir() {
if req.PutOptions.NoOverwriteNonDirDir {
break
}
if err = os.Remove(path); err == nil {
err = os.Mkdir(path, 0700)
}
} else {
err = stErr
}
// either we removed it and retried, or it was a directory,
// in which case we want to just add the new stuff under it
Expand Down
30 changes: 29 additions & 1 deletion copier/copier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,10 @@ func testPut(t *testing.T) {
}
}

// Overwrite directory
for _, overwrite := range []bool{false, true} {
for _, typeFlag := range []byte{tar.TypeReg, tar.TypeLink, tar.TypeSymlink, tar.TypeChar, tar.TypeBlock, tar.TypeFifo} {
t.Run(fmt.Sprintf("overwrite=%v,type=%c", overwrite, typeFlag), func(t *testing.T) {
t.Run(fmt.Sprintf("overwrite (dir)=%v,type=%c", overwrite, typeFlag), func(t *testing.T) {
archive := makeArchiveSlice([]tar.Header{
{Name: "target", Typeflag: tar.TypeSymlink, Mode: 0755, Linkname: "target", ModTime: testDate},
{Name: "target", Typeflag: tar.TypeDir, Mode: 0755, ModTime: testDate},
Expand All @@ -563,6 +564,33 @@ func testPut(t *testing.T) {
}
}

// Overwrite non-directory
for _, overwrite := range []bool{false, true} {
for _, typeFlag := range []byte{tar.TypeReg, tar.TypeLink, tar.TypeSymlink, tar.TypeChar, tar.TypeBlock, tar.TypeFifo} {
t.Run(fmt.Sprintf("overwrite (non-dir)=%v,type=%c", overwrite, typeFlag), func(t *testing.T) {
archive := makeArchiveSlice([]tar.Header{
{Name: "target", Typeflag: tar.TypeSymlink, Mode: 0755, Linkname: "target", ModTime: testDate},
{Name: "target", Typeflag: tar.TypeReg, Mode: 0755, ModTime: testDate},
{Name: "target", Typeflag: tar.TypeSymlink, Mode: 0755, Linkname: "target", ModTime: testDate},
{Name: "target", Typeflag: tar.TypeReg, Size: 123, Mode: 0755, ModTime: testDate},
{Name: "test", Typeflag: typeFlag, Size: 0, Mode: 0755, Linkname: "target", ModTime: testDate},
{Name: "test", Typeflag: tar.TypeDir, Size: 0, Mode: 0755, ModTime: testDate},
{Name: "test/content", Typeflag: tar.TypeReg, Size: 0, Mode: 0755, ModTime: testDate},
})
tmp, err := ioutil.TempDir("", "copier-test-")
require.NoErrorf(t, err, "error creating temporary directory")
defer os.RemoveAll(tmp)
err = Put(tmp, tmp, PutOptions{UIDMap: uidMap, GIDMap: gidMap, NoOverwriteNonDirDir: !overwrite}, bytes.NewReader(archive))
if overwrite {
if unwrapError(err) != syscall.EPERM {
assert.Nilf(t, err, "expected to overwrite file with type %c: %v", typeFlag, err)
}
} else {
assert.Errorf(t, err, "expected an error trying to overwrite file of type %c", typeFlag)
}
})
}
}
for _, ignoreDevices := range []bool{false, true} {
for _, typeFlag := range []byte{tar.TypeChar, tar.TypeBlock} {
t.Run(fmt.Sprintf("ignoreDevices=%v,type=%c", ignoreDevices, typeFlag), func(t *testing.T) {
Expand Down

0 comments on commit 7cc5f19

Please sign in to comment.