gvisor/pkg/sentry/fs/inode_overlay_test.go

252 lines
5.7 KiB
Go

// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fs_test
import (
"testing"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/context/contexttest"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
ramfstest "gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs/test"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
func TestLookup(t *testing.T) {
ctx := contexttest.Context(t)
for _, test := range []struct {
// Test description.
desc string
// Lookup parameters.
dir *fs.Inode
name string
// Want from lookup.
err error
found bool
hasUpper bool
hasLower bool
}{
{
desc: "no upper, lower has name",
dir: fs.NewTestOverlayDir(ctx,
nil, /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* lower */
),
name: "a",
found: true,
hasUpper: false,
hasLower: true,
},
{
desc: "no lower, upper has name",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* upper */
nil, /* lower */
),
name: "a",
found: true,
hasUpper: true,
hasLower: false,
},
{
desc: "upper and lower, only lower has name",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{
name: "b",
dir: false,
},
}, nil), /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* lower */
),
name: "a",
found: true,
hasUpper: false,
hasLower: true,
},
{
desc: "upper and lower, only upper has name",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "b",
dir: false,
},
}, nil), /* lower */
),
name: "a",
found: true,
hasUpper: true,
hasLower: false,
},
{
desc: "upper and lower, both have file",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* lower */
),
name: "a",
found: true,
hasUpper: true,
hasLower: false,
},
{
desc: "upper and lower, both have directory",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: true,
},
}, nil), /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: true,
},
}, nil), /* lower */
),
name: "a",
found: true,
hasUpper: true,
hasLower: true,
},
{
desc: "upper and lower, upper negative masks lower file",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, nil, []string{"a"}), /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* lower */
),
name: "a",
found: false,
hasUpper: false,
hasLower: false,
},
{
desc: "upper and lower, upper negative does not mask lower file",
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, nil, []string{"b"}), /* upper */
newTestRamfsDir(ctx, []dirContent{
{
name: "a",
dir: false,
},
}, nil), /* lower */
),
name: "a",
found: true,
hasUpper: false,
hasLower: true,
},
} {
t.Run(test.desc, func(t *testing.T) {
dirent, err := test.dir.Lookup(ctx, test.name)
if err != test.err {
t.Fatalf("lookup got error %v, want %v", err, test.err)
}
if test.found && dirent.IsNegative() {
t.Fatalf("lookup expected to find %q, got negative dirent", test.name)
}
if !test.found {
return
}
if hasUpper := dirent.Inode.TestHasUpperFS(); hasUpper != test.hasUpper {
t.Fatalf("lookup got upper filesystem %v, want %v", hasUpper, test.hasUpper)
}
if hasLower := dirent.Inode.TestHasLowerFS(); hasLower != test.hasLower {
t.Errorf("lookup got lower filesystem %v, want %v", hasLower, test.hasLower)
}
})
}
}
type dir struct {
fs.InodeOperations
// list of negative child names.
negative []string
}
func (d *dir) Getxattr(inode *fs.Inode, name string) ([]byte, error) {
for _, n := range d.negative {
if name == fs.XattrOverlayWhiteout(n) {
return []byte("y"), nil
}
}
return nil, syserror.ENOATTR
}
type dirContent struct {
name string
dir bool
}
func newTestRamfsDir(ctx context.Context, contains []dirContent, negative []string) *fs.Inode {
msrc := fs.NewCachingMountSource(nil, fs.MountSourceFlags{})
contents := make(map[string]*fs.Inode)
for _, c := range contains {
if c.dir {
contents[c.name] = newTestRamfsDir(ctx, nil, nil)
} else {
contents[c.name] = fs.NewInode(ramfstest.NewFile(ctx, fs.FilePermissions{}), msrc, fs.StableAttr{Type: fs.RegularFile})
}
}
dops := ramfstest.NewDir(ctx, contents, fs.FilePermissions{
User: fs.PermMask{Read: true, Execute: true},
})
return fs.NewInode(&dir{
InodeOperations: dops,
negative: negative,
}, msrc, fs.StableAttr{Type: fs.Directory})
}