2018-02-05 16:05:59 -05:00
package archive // import "github.com/docker/docker/pkg/archive"
2016-10-24 20:03:56 -04:00
import (
"os"
"path/filepath"
"syscall"
"testing"
2021-06-18 05:01:24 -04:00
"github.com/containerd/containerd/pkg/userns"
2016-10-24 20:03:56 -04:00
"github.com/docker/docker/pkg/system"
2017-05-23 10:22:32 -04:00
"golang.org/x/sys/unix"
2020-02-07 08:39:24 -05:00
"gotest.tools/v3/assert"
"gotest.tools/v3/skip"
2016-10-24 20:03:56 -04:00
)
// setupOverlayTestDir creates files in a directory with overlay whiteouts
// Tree layout
2022-07-08 12:27:07 -04:00
//
// .
// ├── d1 # opaque, 0700
// │ └── f1 # empty file, 0600
// ├── d2 # opaque, 0750
// │ └── f1 # empty file, 0660
// └── d3 # 0700
// └── f1 # whiteout, 0644
2016-10-24 20:03:56 -04:00
func setupOverlayTestDir ( t * testing . T , src string ) {
2018-04-20 05:59:08 -04:00
skip . If ( t , os . Getuid ( ) != 0 , "skipping test that requires root" )
2021-06-18 05:01:24 -04:00
skip . If ( t , userns . RunningInUserNS ( ) , "skipping test that requires initial userns (trusted.overlay.opaque xattr cannot be set in userns, even with Ubuntu kernel)" )
2016-10-24 20:03:56 -04:00
// Create opaque directory containing single file and permission 0700
2017-08-08 22:27:01 -04:00
err := os . Mkdir ( filepath . Join ( src , "d1" ) , 0700 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
2017-08-08 22:27:01 -04:00
err = system . Lsetxattr ( filepath . Join ( src , "d1" ) , "trusted.overlay.opaque" , [ ] byte ( "y" ) , 0 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
2021-08-24 06:10:50 -04:00
err = os . WriteFile ( filepath . Join ( src , "d1" , "f1" ) , [ ] byte { } , 0600 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
// Create another opaque directory containing single file but with permission 0750
2017-08-08 22:27:01 -04:00
err = os . Mkdir ( filepath . Join ( src , "d2" ) , 0750 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
2017-08-08 22:27:01 -04:00
err = system . Lsetxattr ( filepath . Join ( src , "d2" ) , "trusted.overlay.opaque" , [ ] byte ( "y" ) , 0 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
2021-08-24 06:10:50 -04:00
err = os . WriteFile ( filepath . Join ( src , "d2" , "f1" ) , [ ] byte { } , 0660 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
// Create regular directory with deleted file
2017-08-08 22:27:01 -04:00
err = os . Mkdir ( filepath . Join ( src , "d3" ) , 0700 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
2017-08-08 22:27:01 -04:00
err = system . Mknod ( filepath . Join ( src , "d3" , "f1" ) , unix . S_IFCHR , 0 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
}
func checkOpaqueness ( t * testing . T , path string , opaque string ) {
xattrOpaque , err := system . Lgetxattr ( path , "trusted.overlay.opaque" )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2017-08-08 22:27:01 -04:00
2016-10-24 20:03:56 -04:00
if string ( xattrOpaque ) != opaque {
t . Fatalf ( "Unexpected opaque value: %q, expected %q" , string ( xattrOpaque ) , opaque )
}
}
func checkOverlayWhiteout ( t * testing . T , path string ) {
stat , err := os . Stat ( path )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2017-08-08 22:27:01 -04:00
2016-10-24 20:03:56 -04:00
statT , ok := stat . Sys ( ) . ( * syscall . Stat_t )
if ! ok {
t . Fatalf ( "Unexpected type: %t, expected *syscall.Stat_t" , stat . Sys ( ) )
}
if statT . Rdev != 0 {
t . Fatalf ( "Non-zero device number for whiteout" )
}
}
func checkFileMode ( t * testing . T , path string , perm os . FileMode ) {
stat , err := os . Stat ( path )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2017-08-08 22:27:01 -04:00
2016-10-24 20:03:56 -04:00
if stat . Mode ( ) != perm {
t . Fatalf ( "Unexpected file mode for %s: %o, expected %o" , path , stat . Mode ( ) , perm )
}
}
func TestOverlayTarUntar ( t * testing . T ) {
oldmask , err := system . Umask ( 0 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer system . Umask ( oldmask )
2021-08-24 06:10:50 -04:00
src , err := os . MkdirTemp ( "" , "docker-test-overlay-tar-src" )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer os . RemoveAll ( src )
setupOverlayTestDir ( t , src )
2021-08-24 06:10:50 -04:00
dst , err := os . MkdirTemp ( "" , "docker-test-overlay-tar-dst" )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer os . RemoveAll ( dst )
options := & TarOptions {
Compression : Uncompressed ,
WhiteoutFormat : OverlayWhiteoutFormat ,
}
archive , err := TarWithOptions ( src , options )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer archive . Close ( )
2017-08-08 22:27:01 -04:00
err = Untar ( archive , dst , options )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
checkFileMode ( t , filepath . Join ( dst , "d1" ) , 0700 | os . ModeDir )
checkFileMode ( t , filepath . Join ( dst , "d2" ) , 0750 | os . ModeDir )
checkFileMode ( t , filepath . Join ( dst , "d3" ) , 0700 | os . ModeDir )
checkFileMode ( t , filepath . Join ( dst , "d1" , "f1" ) , 0600 )
checkFileMode ( t , filepath . Join ( dst , "d2" , "f1" ) , 0660 )
checkFileMode ( t , filepath . Join ( dst , "d3" , "f1" ) , os . ModeCharDevice | os . ModeDevice )
checkOpaqueness ( t , filepath . Join ( dst , "d1" ) , "y" )
checkOpaqueness ( t , filepath . Join ( dst , "d2" ) , "y" )
checkOpaqueness ( t , filepath . Join ( dst , "d3" ) , "" )
checkOverlayWhiteout ( t , filepath . Join ( dst , "d3" , "f1" ) )
}
func TestOverlayTarAUFSUntar ( t * testing . T ) {
oldmask , err := system . Umask ( 0 )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer system . Umask ( oldmask )
2021-08-24 06:10:50 -04:00
src , err := os . MkdirTemp ( "" , "docker-test-overlay-tar-src" )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer os . RemoveAll ( src )
setupOverlayTestDir ( t , src )
2021-08-24 06:10:50 -04:00
dst , err := os . MkdirTemp ( "" , "docker-test-overlay-tar-dst" )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer os . RemoveAll ( dst )
archive , err := TarWithOptions ( src , & TarOptions {
Compression : Uncompressed ,
WhiteoutFormat : OverlayWhiteoutFormat ,
} )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
defer archive . Close ( )
2017-08-08 22:27:01 -04:00
err = Untar ( archive , dst , & TarOptions {
2016-10-24 20:03:56 -04:00
Compression : Uncompressed ,
WhiteoutFormat : AUFSWhiteoutFormat ,
2017-08-08 22:27:01 -04:00
} )
2018-03-13 15:28:34 -04:00
assert . NilError ( t , err )
2016-10-24 20:03:56 -04:00
checkFileMode ( t , filepath . Join ( dst , "d1" ) , 0700 | os . ModeDir )
checkFileMode ( t , filepath . Join ( dst , "d1" , WhiteoutOpaqueDir ) , 0700 )
checkFileMode ( t , filepath . Join ( dst , "d2" ) , 0750 | os . ModeDir )
checkFileMode ( t , filepath . Join ( dst , "d2" , WhiteoutOpaqueDir ) , 0750 )
checkFileMode ( t , filepath . Join ( dst , "d3" ) , 0700 | os . ModeDir )
checkFileMode ( t , filepath . Join ( dst , "d1" , "f1" ) , 0600 )
checkFileMode ( t , filepath . Join ( dst , "d2" , "f1" ) , 0660 )
checkFileMode ( t , filepath . Join ( dst , "d3" , WhiteoutPrefix + "f1" ) , 0600 )
}