pkg/archive: Add support for file flags on FreeBSD
This encodes flag information into the tar stream using ReadFileFlagsToTarHeader and decodes with WriteFileFlagsFromTarHeader. To support applying diffs to trees with flags, this adds logic to reset immutable flags during the UnpackLayer process. To support immutable directories, we also need to defer setting flags on directories until after all modifications to the directory contents. Fortunately, something similar is already in place for setting directory modify times. Signed-off-by: Doug Rabson <dfr@rabson.org>
This commit is contained in:
parent
2baf25d67c
commit
056232e4e5
|
|
@ -527,6 +527,9 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
if err := ReadUserXattrToTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ReadFileFlagsToTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
if ta.CopyPass {
|
||||
copyPassHeader(hdr)
|
||||
}
|
||||
|
|
@ -770,6 +773,15 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
|
||||
}
|
||||
|
||||
// We defer setting flags on directories until the end of
|
||||
// Unpack or UnpackLayer in case setting them makes the
|
||||
// directory immutable.
|
||||
if hdr.Typeflag != tar.TypeDir {
|
||||
if err := WriteFileFlagsFromTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"errors": errs,
|
||||
|
|
@ -1101,6 +1113,9 @@ loop:
|
|||
if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := WriteFileFlagsFromTarHeader(path, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
return nil
|
||||
}
|
||||
if _, exists := unpackedPaths[path]; !exists {
|
||||
if err := resetImmutable(path, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
err := os.RemoveAll(path)
|
||||
return err
|
||||
}
|
||||
|
|
@ -156,6 +159,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
} else {
|
||||
originalBase := base[len(WhiteoutPrefix):]
|
||||
originalPath := filepath.Join(dir, originalBase)
|
||||
if err := resetImmutable(originalPath, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := os.RemoveAll(originalPath); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -165,7 +171,15 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
// The only exception is when it is a directory *and* the file from
|
||||
// the layer is also a directory. Then we want to merge them (i.e.
|
||||
// just apply the metadata from the layer).
|
||||
//
|
||||
// We always reset the immutable flag (if present) to allow metadata
|
||||
// changes and to allow directory modification. The flag will be
|
||||
// re-applied based on the contents of hdr either at the end for
|
||||
// directories or in createTarFile otherwise.
|
||||
if fi, err := os.Lstat(path); err == nil {
|
||||
if err := resetImmutable(path, &fi); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !(fi.IsDir() && hdr.Typeflag == tar.TypeDir) {
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return 0, err
|
||||
|
|
@ -215,6 +229,9 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := WriteFileFlagsFromTarHeader(path, hdr); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return size, nil
|
||||
|
|
|
|||
|
|
@ -41,3 +41,96 @@ load helpers
|
|||
checkchanges
|
||||
checkdiffs
|
||||
}
|
||||
|
||||
set_immutable() {
|
||||
chflags schg $1
|
||||
}
|
||||
|
||||
reset_immutable() {
|
||||
chflags noschg $1
|
||||
}
|
||||
|
||||
is_immutable() {
|
||||
local flags=$(stat -f %#Xf $1)
|
||||
[ "$((($flags & 0x20000) == 0x20000))" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "import-layer-with-immutable" {
|
||||
if [ "$OS" != "FreeBSD" ]; then
|
||||
skip "not supported on $OS"
|
||||
fi
|
||||
|
||||
# Create a layer with a directory containing two files, both
|
||||
# immutable. The directory is also set as immutablr.
|
||||
run storage --debug=false create-layer
|
||||
echo $output
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
lowerlayer="$output"
|
||||
run storage --debug=false mount $lowerlayer
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
local m="$output"
|
||||
mkdir $m/dir
|
||||
createrandom $m/dir/layer1file1
|
||||
createrandom $m/dir/layer1file2
|
||||
set_immutable $m/dir/layer1file1
|
||||
set_immutable $m/dir/layer1file2
|
||||
set_immutable $m/dir
|
||||
storage unmount $lowerlayer
|
||||
|
||||
# Create a second layer which deletes one file and removes immutable from the other
|
||||
run storage --debug=false create-layer "$lowerlayer"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
upperlayer="$output"
|
||||
run storage --debug=false mount $upperlayer
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
m="$output"
|
||||
reset_immutable $m/dir
|
||||
reset_immutable $m/dir/layer1file1
|
||||
rm $m/dir/layer1file1
|
||||
reset_immutable $m/dir/layer1file2
|
||||
set_immutable $m/dir
|
||||
storage unmount $upperlayer
|
||||
|
||||
# Extract the layers.
|
||||
storage diff -u -f $TESTDIR/lower.tar $lowerlayer
|
||||
storage diff -u -f $TESTDIR/upper.tar $upperlayer
|
||||
|
||||
# Delete the layers.
|
||||
storage delete-layer $upperlayer
|
||||
storage delete-layer $lowerlayer
|
||||
|
||||
# Import new layers using the layer diffs.
|
||||
run storage --debug=false import-layer -f $TESTDIR/lower.tar
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
lowerlayer="$output"
|
||||
|
||||
run storage --debug=false import-layer -f $TESTDIR/upper.tar "$lowerlayer"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
upperlayer="$output"
|
||||
|
||||
# Verify layer contents
|
||||
run storage --debug=false mount $lowerlayer
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
m="$output"
|
||||
is_immutable $m/dir/layer1file1
|
||||
is_immutable $m/dir/layer1file2
|
||||
storage unmount $lowerlayer
|
||||
|
||||
run storage --debug=false mount $upperlayer
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" != "" ]
|
||||
m="$output"
|
||||
[ ! -f $m/dir/layer1file1 ]
|
||||
! is_immutable $m/dir/layer1file2
|
||||
storage unmount $upperlayer
|
||||
|
||||
storage delete-layer $upperlayer
|
||||
storage delete-layer $lowerlayer
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue