1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/daemon/graphdriver/graphtest/testutil.go
Derek McGowan bd13c53f8d Fix overlay2 ignoring whiteout files
Currently when overlay creates a whiteout file then the overlay2 layer is archived,
the correct tar header will be created for the whiteout file, but the tar logic will then attempt to open the file causing a failure.
When tar encounters such failures the file is skipped and excluded for the archive, causing the whiteout to be ignored.
By skipping the copy of empty files, no open attempt will be made on whiteout files.

Fixes #23863

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2016-06-23 13:34:38 -07:00

327 lines
8 KiB
Go

package graphtest
import (
"bytes"
"fmt"
"io/ioutil"
"math/rand"
"os"
"path"
"sort"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringid"
)
func randomContent(size int, seed int64) []byte {
s := rand.NewSource(seed)
content := make([]byte, size)
for i := 0; i < len(content); i += 7 {
val := s.Int63()
for j := 0; i+j < len(content) && j < 7; j++ {
content[i+j] = byte(val)
val >>= 8
}
}
return content
}
func addFiles(drv graphdriver.Driver, layer string, seed int64) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
if err := ioutil.WriteFile(path.Join(root, "file-a"), randomContent(64, seed), 0755); err != nil {
return err
}
if err := os.MkdirAll(path.Join(root, "dir-b"), 0755); err != nil {
return err
}
if err := ioutil.WriteFile(path.Join(root, "dir-b", "file-b"), randomContent(128, seed+1), 0755); err != nil {
return err
}
return ioutil.WriteFile(path.Join(root, "file-c"), randomContent(128*128, seed+2), 0755)
}
func checkFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
fileContent, err := ioutil.ReadFile(path.Join(root, filename))
if err != nil {
return err
}
if bytes.Compare(fileContent, content) != 0 {
return fmt.Errorf("mismatched file content %v, expecting %v", fileContent, content)
}
return nil
}
func addFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
return ioutil.WriteFile(path.Join(root, filename), content, 0755)
}
func removeFile(drv graphdriver.Driver, layer, filename string) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
return os.Remove(path.Join(root, filename))
}
func checkFileRemoved(drv graphdriver.Driver, layer, filename string) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
if _, err := os.Stat(path.Join(root, filename)); err == nil {
return fmt.Errorf("file still exists: %s", path.Join(root, filename))
} else if !os.IsNotExist(err) {
return err
}
return nil
}
func addManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
for i := 0; i < count; i += 100 {
dir := path.Join(root, fmt.Sprintf("directory-%d", i))
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
for j := 0; i+j < count && j < 100; j++ {
file := path.Join(dir, fmt.Sprintf("file-%d", i+j))
if err := ioutil.WriteFile(file, randomContent(64, seed+int64(i+j)), 0755); err != nil {
return err
}
}
}
return nil
}
func changeManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) ([]archive.Change, error) {
root, err := drv.Get(layer, "")
if err != nil {
return nil, err
}
defer drv.Put(layer)
changes := []archive.Change{}
for i := 0; i < count; i += 100 {
archiveRoot := fmt.Sprintf("/directory-%d", i)
if err := os.MkdirAll(path.Join(root, archiveRoot), 0755); err != nil {
return nil, err
}
for j := 0; i+j < count && j < 100; j++ {
if j == 0 {
changes = append(changes, archive.Change{
Path: archiveRoot,
Kind: archive.ChangeModify,
})
}
var change archive.Change
switch j % 3 {
// Update file
case 0:
change.Path = path.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
change.Kind = archive.ChangeModify
if err := ioutil.WriteFile(path.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
return nil, err
}
// Add file
case 1:
change.Path = path.Join(archiveRoot, fmt.Sprintf("file-%d-%d", seed, i+j))
change.Kind = archive.ChangeAdd
if err := ioutil.WriteFile(path.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
return nil, err
}
// Remove file
case 2:
change.Path = path.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
change.Kind = archive.ChangeDelete
if err := os.Remove(path.Join(root, change.Path)); err != nil {
return nil, err
}
}
changes = append(changes, change)
}
}
return changes, nil
}
func checkManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
for i := 0; i < count; i += 100 {
dir := path.Join(root, fmt.Sprintf("directory-%d", i))
for j := 0; i+j < count && j < 100; j++ {
file := path.Join(dir, fmt.Sprintf("file-%d", i+j))
fileContent, err := ioutil.ReadFile(file)
if err != nil {
return err
}
content := randomContent(64, seed+int64(i+j))
if bytes.Compare(fileContent, content) != 0 {
return fmt.Errorf("mismatched file content %v, expecting %v", fileContent, content)
}
}
}
return nil
}
type changeList []archive.Change
func (c changeList) Less(i, j int) bool {
if c[i].Path == c[j].Path {
return c[i].Kind < c[j].Kind
}
return c[i].Path < c[j].Path
}
func (c changeList) Len() int { return len(c) }
func (c changeList) Swap(i, j int) { c[j], c[i] = c[i], c[j] }
func checkChanges(expected, actual []archive.Change) error {
if len(expected) != len(actual) {
return fmt.Errorf("unexpected number of changes, expected %d, got %d", len(expected), len(actual))
}
sort.Sort(changeList(expected))
sort.Sort(changeList(actual))
for i := range expected {
if expected[i] != actual[i] {
return fmt.Errorf("unexpected change, expecting %v, got %v", expected[i], actual[i])
}
}
return nil
}
func addLayerFiles(drv graphdriver.Driver, layer, parent string, i int) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
if err := ioutil.WriteFile(path.Join(root, "top-id"), []byte(layer), 0755); err != nil {
return err
}
layerDir := path.Join(root, fmt.Sprintf("layer-%d", i))
if err := os.MkdirAll(layerDir, 0755); err != nil {
return err
}
if err := ioutil.WriteFile(path.Join(layerDir, "layer-id"), []byte(layer), 0755); err != nil {
return err
}
if err := ioutil.WriteFile(path.Join(layerDir, "parent-id"), []byte(parent), 0755); err != nil {
return err
}
return nil
}
func addManyLayers(drv graphdriver.Driver, baseLayer string, count int) (string, error) {
lastLayer := baseLayer
for i := 1; i <= count; i++ {
nextLayer := stringid.GenerateRandomID()
if err := drv.Create(nextLayer, lastLayer, "", nil); err != nil {
return "", err
}
if err := addLayerFiles(drv, nextLayer, lastLayer, i); err != nil {
return "", err
}
lastLayer = nextLayer
}
return lastLayer, nil
}
func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
root, err := drv.Get(layer, "")
if err != nil {
return err
}
defer drv.Put(layer)
layerIDBytes, err := ioutil.ReadFile(path.Join(root, "top-id"))
if err != nil {
return err
}
if bytes.Compare(layerIDBytes, []byte(layer)) != 0 {
return fmt.Errorf("mismatched file content %v, expecting %v", layerIDBytes, []byte(layer))
}
for i := count; i > 0; i-- {
layerDir := path.Join(root, fmt.Sprintf("layer-%d", i))
thisLayerIDBytes, err := ioutil.ReadFile(path.Join(layerDir, "layer-id"))
if err != nil {
return err
}
if bytes.Compare(thisLayerIDBytes, layerIDBytes) != 0 {
return fmt.Errorf("mismatched file content %v, expecting %v", thisLayerIDBytes, layerIDBytes)
}
layerIDBytes, err = ioutil.ReadFile(path.Join(layerDir, "parent-id"))
if err != nil {
return err
}
}
return nil
}
// readDir reads a directory just like ioutil.ReadDir()
// then hides specific files (currently "lost+found")
// so the tests don't "see" it
func readDir(dir string) ([]os.FileInfo, error) {
a, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
}
b := a[:0]
for _, x := range a {
if x.Name() != "lost+found" { // ext4 always have this dir
b = append(b, x)
}
}
return b, nil
}