WSL/test/linux/unit_tests/overlayfs.c

3454 lines
117 KiB
C

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
OverlayFs.c
Abstract:
This file is a overlayfs test.
N.B. This test depends on libmount, which is part of the libmount-dev
apt package.
N.B. In addition to this unit test, the official overlay test on github
should be run when changes are made.
--*/
#include "lxtcommon.h"
#include "unittests.h"
#include <sys/mount.h>
#include <linux/capability.h>
#include <libgen.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libmount/libmount.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/prctl.h>
#include <sys/xattr.h>
#include "lxtmount.h"
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <utime.h>
#include <sys/cdefs.h>
#include <linux/capability.h>
#define LXT_NAME "OverlayFs"
#define OVFS_TEST_PATH "/data"
#define OVFS_TEST_MOUNT_PATH OVFS_TEST_PATH "/" OVFS_TEST_MERGED_DIR
#define OVFS_TEST_MOUNT_NAME "overlay"
#define OVFS_TEST_LOWER_DIR "ovfs_test_lower"
#define OVFS_TEST_LOWER2_DIR "ovfs_test_lower2"
#define OVFS_TEST_LOWER3_DIR "ovfs_test_lower3"
#define OVFS_TEST_UPPER_DIR "ovfs_test_upper"
#define OVFS_TEST_WORK_DIR "ovfs_test_work"
#define OVFS_TEST_MERGED_DIR "ovfs_test_merged"
#define OVFS_TEST_MOUNT_DEFAULT "lowerdir=" OVFS_TEST_LOWER_DIR ",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR
#define OVFS_TEST_MOUNT_MULI_LOWER \
"lowerdir=" OVFS_TEST_LOWER_DIR ":" OVFS_TEST_LOWER2_DIR ":" OVFS_TEST_LOWER3_DIR ",upperdir=" OVFS_TEST_UPPER_DIR \
",workdir=" OVFS_TEST_WORK_DIR
#define OVFS_TEST_MOUNT_FS_OPTS "rw," OVFS_TEST_MOUNT_DEFAULT
#define OVFS_TEST_MOUNT_COMBINED_OPTS "rw,relatime," OVFS_TEST_MOUNT_DEFAULT
const char* g_OvFsTestDirs[] = {
OVFS_TEST_LOWER_DIR, OVFS_TEST_LOWER2_DIR, OVFS_TEST_LOWER3_DIR, OVFS_TEST_UPPER_DIR, OVFS_TEST_WORK_DIR, OVFS_TEST_MOUNT_PATH};
//
// N.B. This data must be kept in sync with OvFsTestDirsPopulate.
//
struct
{
char* Path;
char* Name;
mode_t Mode;
int Hydrates;
} g_OvFsMergedContents[] = {
{OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", "OnlyInLowerDir", S_IFDIR | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", "OnlyInLowerFile", S_IFREG | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLowerSym", "OnlyInLowerSym", S_IFLNK | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInUpperDir", "OnlyInUpperDir", S_IFDIR | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/OnlyInUpperFile", "OnlyInUpperFile", S_IFREG | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/OnlyInUpperSym", "OnlyInUpperSym", S_IFLNK | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/InBothDir", "InBothDir", S_IFDIR | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/InBothFile", "InBothFile", S_IFREG | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/InBothSym", "InBothSym", S_IFLNK | 0777, 0}};
struct
{
char* Path;
char* Name;
mode_t Mode;
int Hydrates;
} g_OvFsMergedMultiContents[] = {
{OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", "OnlyInLowerDir", S_IFDIR | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", "OnlyInLowerFile", S_IFREG | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLowerSym", "OnlyInLowerSym", S_IFLNK | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLower2Dir", "OnlyInLower2Dir", S_IFDIR | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLower2File", "OnlyInLower2File", S_IFREG | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLower23File", "OnlyInLower23File", S_IFREG | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLower3Dir", "OnlyInLower3Dir", S_IFDIR | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInLower3File", "OnlyInLower3File", S_IFREG | 0222, 1},
{OVFS_TEST_MOUNT_PATH "/OnlyInUpperDir", "OnlyInUpperDir", S_IFDIR | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/OnlyInUpperFile", "OnlyInUpperFile", S_IFREG | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/OnlyInUpperSym", "OnlyInUpperSym", S_IFLNK | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/InBothDir", "InBothDir", S_IFDIR | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/InBothFile", "InBothFile", S_IFREG | 0777, 0},
{OVFS_TEST_MOUNT_PATH "/InBothSym", "InBothSym", S_IFLNK | 0777, 0}};
LXT_VARIATION_HANDLER OvFsTestBasicMount;
LXT_VARIATION_HANDLER OvFsTestFileObjectReadOps;
LXT_VARIATION_HANDLER OvFsTestFileObjectWriteOpsUpper;
LXT_VARIATION_HANDLER OvFsTestInodeOpaque;
LXT_VARIATION_HANDLER OvFsTestInodeReadOps;
LXT_VARIATION_HANDLER OvFsTestInodeRename;
LXT_VARIATION_HANDLER OvFsTestInodeWhiteout;
LXT_VARIATION_HANDLER OvFsTestInodeWriteOps;
LXT_VARIATION_HANDLER OvFsTestInodeWriteOpsUpper;
LXT_VARIATION_HANDLER OvFsTestInodeUnlink;
LXT_VARIATION_HANDLER OvFsTestInodeXattr;
LXT_VARIATION_HANDLER OvFsTestLowerWhiteout;
LXT_VARIATION_HANDLER OvFsTestMultipleLower;
int OvFsTestDirsPopulate(void);
int OvFsTestDirsSetup(void);
//
// Global constants
//
static const LXT_VARIATION g_LxtVariations[] = {
{"OverlayFs - basic mount", OvFsTestBasicMount},
{"OverlayFs - inode read ops", OvFsTestInodeReadOps},
{"OverlayFs - file object read ops", OvFsTestFileObjectReadOps},
{"OverlayFs - inode write ops upper", OvFsTestInodeWriteOpsUpper},
{"OverlayFs - file object write ops upper", OvFsTestFileObjectWriteOpsUpper},
{"OverlayFs - inode write ops", OvFsTestInodeWriteOps},
{"OverlayFs - inode unlink", OvFsTestInodeUnlink},
{"OverlayFs - whiteout", OvFsTestInodeWhiteout},
{"OverlayFs - opaque", OvFsTestInodeOpaque},
{"OverlayFs - rename", OvFsTestInodeRename},
{"OverlayFs - xattr", OvFsTestInodeXattr},
{"OverlayFs - multiple lower layers", OvFsTestMultipleLower},
{"OverlayFs - lower layer whiteouts", OvFsTestLowerWhiteout}};
static int g_TestPathMountId;
const int g_LxtUnstableInodes = 0;
int OverlayFsTestEntry(int Argc, char* Argv[])
/*++
--*/
{
LXT_ARGS Args;
int Result;
//
// TODO_LX: Support other filesystems than volfs.
//
LxtCheckResult(g_TestPathMountId = MountGetMountId(OVFS_TEST_PATH));
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
LxtCheckErrno(chdir(OVFS_TEST_PATH));
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
ErrorExit:
char DeleteCmd[128];
for (int Index = 0; Index < LXT_COUNT_OF(g_OvFsTestDirs); ++Index)
{
sprintf(DeleteCmd, "rm -rf %s", g_OvFsTestDirs[Index]);
if (system(DeleteCmd) < 0)
{
LxtLogError("Failed to delete %s", g_OvFsTestDirs[Index]);
}
}
LxtUninitialize();
return !LXT_SUCCESS(Result);
}
int OvFsTestBasicMount(PLXT_ARGS Args)
/*++
Description:
This routine tests the mount and umount system calls for overlayfs.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Index;
struct
{
char* Options;
int Errno;
} InvalidOpts[] = {
{NULL, EINVAL},
{"", EINVAL},
{"lowerdir=doesNotExist"
",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR,
ENOENT},
{"lowerdir=" OVFS_TEST_LOWER_DIR ",lowerdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR, EINVAL},
{"lowerdir=" OVFS_TEST_LOWER_DIR ",workdir=" OVFS_TEST_WORK_DIR, EINVAL},
{"lowerdir=" OVFS_TEST_LOWER_DIR ",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_UPPER_DIR, EINVAL},
{"lowerdir=" OVFS_TEST_LOWER_DIR ",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_UPPER_DIR "/" OVFS_TEST_WORK_DIR, EINVAL},
{"lowerdir=:"
",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR,
EINVAL},
{"lowerdir=" OVFS_TEST_LOWER_DIR ":"
",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR,
EINVAL},
{"lowerdir=" OVFS_TEST_LOWER_DIR ":" OVFS_TEST_LOWER_DIR ":" OVFS_TEST_LOWER_DIR ":"
",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR,
EINVAL},
{"lowerdir=" OVFS_TEST_LOWER_DIR ":" OVFS_TEST_LOWER_DIR ":"
"doesNotExist"
",upperdir=" OVFS_TEST_UPPER_DIR ",workdir=" OVFS_TEST_WORK_DIR,
ENOENT}};
int MountId;
int Result;
//
// Setup the directories and ensure it's not a mount point yet.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Mount an overlayfs instance and check it was mounted.
//
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckResult(
MountId = MountCheckIsMount(
OVFS_TEST_MOUNT_PATH, g_TestPathMountId, "myovfsnew", OVFS_TEST_MOUNT_NAME, "/", "rw,relatime", OVFS_TEST_MOUNT_FS_OPTS, OVFS_TEST_MOUNT_COMBINED_OPTS, 0));
//
// Mounting again should succeed.
//
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckResult(
MountId = MountCheckIsMount(
OVFS_TEST_MOUNT_PATH, MountId, "myovfsnew", OVFS_TEST_MOUNT_NAME, "/", "rw,relatime", OVFS_TEST_MOUNT_FS_OPTS, OVFS_TEST_MOUNT_COMBINED_OPTS, 0));
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(
MountId = MountCheckIsMount(
OVFS_TEST_MOUNT_PATH, g_TestPathMountId, "myovfsnew", OVFS_TEST_MOUNT_NAME, "/", "rw,relatime", OVFS_TEST_MOUNT_FS_OPTS, OVFS_TEST_MOUNT_COMBINED_OPTS, 0));
//
// Unmount and check it was unmounted.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check invalid mount parameters.
//
LxtLogInfo("Checking invalid options...");
mkdir(OVFS_TEST_UPPER_DIR "/" OVFS_TEST_WORK_DIR, 0777);
for (Index = 0; Index < LXT_COUNT_OF(InvalidOpts); ++Index)
{
LxtCheckErrnoFailure(
mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, InvalidOpts[Index].Options), InvalidOpts[Index].Errno);
}
Result = 0;
ErrorExit:
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestDirsPopulate(void)
/*++
Description:
This routine populates the mount directories.
N.B. This data must be kept in sync with g_OvFsMergedContents.
Arguments:
None.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char XattrName[64];
int Fd;
char* FileName;
int Index;
struct
{
char* Name;
int Mode;
} Paths[] = {
{OVFS_TEST_LOWER_DIR "/OnlyInLowerDir", S_IFDIR | 0666},
{OVFS_TEST_LOWER_DIR "/InBothDir", S_IFDIR | 0666},
{OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", S_IFREG | 0666},
{OVFS_TEST_LOWER_DIR "/InBothFile", S_IFREG | 0666},
{OVFS_TEST_LOWER2_DIR "/OnlyInLower2Dir", S_IFDIR | 0444},
{OVFS_TEST_LOWER2_DIR "/InBothDir", S_IFDIR | 0444},
{OVFS_TEST_LOWER2_DIR "/OnlyInLower2File", S_IFREG | 0444},
{OVFS_TEST_LOWER2_DIR "/OnlyInLower23File", S_IFREG | 0444},
{OVFS_TEST_LOWER2_DIR "/InBothFile", S_IFREG | 0444},
{OVFS_TEST_LOWER3_DIR "/OnlyInLower3Dir", S_IFDIR | 0111},
{OVFS_TEST_LOWER3_DIR "/InBothDir", S_IFDIR | 0111},
{OVFS_TEST_LOWER3_DIR "/OnlyInLower3File", S_IFREG | 0111},
{OVFS_TEST_LOWER3_DIR "/OnlyInLower23File", S_IFREG | 0111},
{OVFS_TEST_LOWER3_DIR "/InBothFile", S_IFREG | 0111},
{OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", S_IFDIR | 0777},
{OVFS_TEST_UPPER_DIR "/InBothDir", S_IFDIR | 0777},
{OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", S_IFREG | 0777},
{OVFS_TEST_UPPER_DIR "/InBothFile", S_IFREG | 0777}};
int Result;
Fd = -1;
for (Index = 0; Index < LXT_COUNT_OF(Paths); ++Index)
{
FileName = strrchr(Paths[Index].Name, '/') + 1;
if (S_ISREG(Paths[Index].Mode))
{
LxtCheckErrno(Fd = creat(Paths[Index].Name, Paths[Index].Mode));
LxtCheckErrno(write(Fd, FileName, strlen(FileName) + 1));
LxtClose(Fd);
Fd = -1;
}
else
{
LxtCheckErrno(mkdir(Paths[Index].Name, Paths[Index].Mode));
}
LxtCheckErrno(lsetxattr(Paths[Index].Name, "trusted.overlaytest", FileName, strlen(FileName) + 1, XATTR_CREATE));
sprintf(XattrName, "trusted.%s", FileName);
LxtCheckErrno(lsetxattr(Paths[Index].Name, XattrName, FileName, strlen(FileName) + 1, XATTR_CREATE));
}
//
// N.B. xattrs cannot be set on symbolic links on all filesystems.
//
LxtCheckErrno(symlink(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", OVFS_TEST_LOWER_DIR "/OnlyInLowerSym"));
LxtCheckErrno(symlink(OVFS_TEST_LOWER_DIR "/InBothFile", OVFS_TEST_LOWER_DIR "/InBothSym"));
LxtCheckErrno(symlink(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", OVFS_TEST_UPPER_DIR "/OnlyInUpperSym"));
LxtCheckErrno(symlink(OVFS_TEST_UPPER_DIR "/InBothFile", OVFS_TEST_UPPER_DIR "/InBothSym"));
ErrorExit:
if (Fd != -1)
{
LxtClose(Fd);
}
return Result;
}
int OvFsTestDirsSetup(void)
/*++
Description:
This routine prepares the mount directories.
Arguments:
None.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char DeleteCmd[128];
int Index;
int Result;
umount(OVFS_TEST_MOUNT_PATH);
sprintf(DeleteCmd, "rm -rf %s", OVFS_TEST_MOUNT_PATH);
system(DeleteCmd);
LxtCheckErrno(mkdir(OVFS_TEST_MOUNT_PATH, 0777));
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsTestDirs); ++Index)
{
sprintf(DeleteCmd, "rm -rf %s", g_OvFsTestDirs[Index]);
system(DeleteCmd);
LxtCheckErrno(mkdir(g_OvFsTestDirs[Index], 0777));
}
Result = 0;
ErrorExit:
return Result;
}
int OvFsTestFileObjectReadOps(PLXT_ARGS Args)
/*++
Description:
This routine tests file object operations that do not modify state.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
int BytesRead;
int Count;
struct dirent* Entry;
int EntryPosition;
int Fd;
int Found[LXT_COUNT_OF(g_OvFsMergedContents) + 2];
int FoundIndex;
int Index;
void* Mapping;
void* MapResult;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
Fd = -1;
Mapping = NULL;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check inode operations that do not
// hydrate files.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Check the behavior for VFS file object operations that support file
// descriptors opened for read only.
//
// N.B. All other file operations will fail the request and are verified
// in the VFS access test.
//
//
// Check the behavior for read directory on the root.
//
memset(Found, 0, sizeof(Found));
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
if (strcmp(Entry->d_name, ".") == 0)
{
FoundIndex = 0;
}
else if (strcmp(Entry->d_name, "..") == 0)
{
FoundIndex = 1;
}
else
{
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (strcmp(g_OvFsMergedContents[Index].Name, Entry->d_name) == 0)
{
FoundIndex = Index + 2;
break;
}
}
if (Index == LXT_COUNT_OF(g_OvFsMergedContents))
{
LxtLogError("Unexpected entry %s", Entry->d_name);
LxtCheckNotEqual(Index, LXT_COUNT_OF(g_OvFsMergedContents), "%d");
}
}
LxtCheckEqual(Found[FoundIndex], 0, "%d");
Found[FoundIndex] = 1;
}
Entry = (struct dirent*)Buffer;
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
for (Index = 0; Index < LXT_COUNT_OF(Found); ++Index)
{
LxtCheckEqual(Found[FoundIndex], 1, "%d");
}
LxtClose(Fd);
Fd = -1;
//
// Check the behavior for read directory on sub directories.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for map.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckMapErrno(Mapping = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, Fd, 0));
LxtCheckStringEqual(Mapping, g_OvFsMergedContents[Index].Name);
munmap(Mapping, PAGE_SIZE);
Mapping = MAP_FAILED;
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for ioctl.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckErrno(ioctl(Fd, FIONREAD, &BytesRead));
LxtCheckEqual(BytesRead, strlen(g_OvFsMergedContents[Index].Name) + 1, "%d");
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for sync.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE) && (S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE))
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckErrno(fsync(Fd));
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for read file.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer) - 1));
Buffer[BytesRead] = 0;
LxtCheckStringEqual(Buffer, g_OvFsMergedContents[Index].Name);
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for seek.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE) && (S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE))
{
continue;
}
LxtLogInfo("%s", g_OvFsMergedContents[Index].Path);
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckErrno(lseek(Fd, SEEK_SET, 1));
LxtClose(Fd);
Fd = -1;
}
//
// Check that none of the operations hydrated files from the lower
// directory.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Mapping != MAP_FAILED)
{
munmap(Mapping, PAGE_SIZE);
}
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestFileObjectWriteOpsUpper(PLXT_ARGS Args)
/*++
Description:
This routine tests file object write operations that do not modify the
lower.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
char BufferExpected[100];
int BytesRead;
int BytesWritten;
int Count;
struct dirent* Entry;
int EntryPosition;
int Fd;
int Found[LXT_COUNT_OF(g_OvFsMergedContents) + 2];
int FoundIndex;
int Index;
void* Mapping;
void* MapResult;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
Fd = -1;
Mapping = NULL;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check inode operations that modify the
// upper but do not hydrate files.
//
// N.B. The overlay fs mount does not need to be recreated after each
// variation since only the upper is modified.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Check the behavior for map.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) || (g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDWR));
LxtCheckMapErrno(Mapping = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, Fd, 0));
LxtCheckStringEqual(Mapping, g_OvFsMergedContents[Index].Name);
munmap(Mapping, PAGE_SIZE);
Mapping = MAP_FAILED;
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for truncate.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) || (g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDWR));
LxtCheckErrno(ftruncate(Fd, 0));
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for fallocate.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) || (g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDWR));
LxtCheckErrno(fallocate(Fd, 0, 0, strlen(g_OvFsMergedContents[Index].Name) + 1));
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for write file.
//
memset(BufferExpected, 0, sizeof(BufferExpected));
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) || (g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDWR));
LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer) - 1));
Buffer[BytesRead] = 0;
LxtCheckEqual(BytesRead, strlen(g_OvFsMergedContents[Index].Name) + 1, "%d");
LxtCheckMemoryEqual(Buffer, BufferExpected, BytesRead);
LxtCheckErrno(lseek(Fd, SEEK_SET, 0));
LxtCheckErrno(BytesWritten = write(Fd, g_OvFsMergedContents[Index].Name, strlen(g_OvFsMergedContents[Index].Name) + 1));
LxtCheckEqual(BytesWritten, strlen(g_OvFsMergedContents[Index].Name) + 1, "%d");
LxtCheckErrno(lseek(Fd, SEEK_SET, 0));
LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer) - 1));
Buffer[BytesRead] = 0;
LxtCheckStringEqual(Buffer, g_OvFsMergedContents[Index].Name);
LxtClose(Fd);
Fd = -1;
}
//
// Check that none of the operations hydrated files from the lower
// directory.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Mapping != MAP_FAILED)
{
munmap(Mapping, PAGE_SIZE);
}
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeOpaque(PLXT_ARGS Args)
/*++
Description:
This routine tests inode opaque operations.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
int BytesRead;
int Count;
struct dirent* Entry;
int EntryPosition;
int Fd;
int Result;
struct stat StatBuffer;
Fd = -1;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Create a file in each directory.
//
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir/OnlyInLowerDirFile", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER_DIR "/InBothDir/InBothDirLowerFile", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir/OnlyInUpperDirFile", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_UPPER_DIR "/InBothDir/InBothDirUpperFile", 0777));
LxtClose(Fd);
Fd = -1;
//
// Mount an overlayfs instance and check for the expected file state.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/InBothDir/InBothDirLowerFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/InBothDir/InBothDirUpperFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer));
LxtCheckTrue(S_ISLNK(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckTrue(S_ISLNK(StatBuffer.st_mode));
//
// Remove each directory and check that it is removed, first checking for
// the expected failure code.
//
LxtCheckErrnoFailure(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir"), ENOTEMPTY);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir/OnlyInLowerDirFile"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir/OnlyInLowerDirFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrnoFailure(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir"), ENOTEMPTY);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir/OnlyInUpperDirFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir/OnlyInUpperDirFile", &StatBuffer), ENOENT);
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"), ENOTEMPTY);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothDir/InBothDirUpperFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir/OnlyInUpperDirFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"), ENOTEMPTY);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothDir/InBothDirLowerFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir/OnlyInLowerDirFile", &StatBuffer), ENOENT);
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
//
// Enumerate the top level and check that the three directories have been
// removed.
//
Count = 0;
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
LxtCheckEqual(Count - 2, LXT_COUNT_OF(g_OvFsMergedContents) - 3, "%d");
LxtClose(Fd);
Fd = -1;
//
// Create entries over the whiteouts and check for the expected state.
//
//
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir/OnlyInLowerDirFile", &StatBuffer), ENOENT);
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir/OnlyInUpperDirFile", &StatBuffer), ENOENT);
LxtCheckErrno(Fd = mkdir(OVFS_TEST_MERGED_DIR "/InBothDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/InBothDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/InBothDir/InBothDirLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/InBothDir/InBothDirUpperFile", &StatBuffer), ENOENT);
//
// Enumerate the top level and check that the three directories have been
// replaced.
//
Count = 0;
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
Count += 1;
}
Entry = (struct dirent*)Buffer;
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
LxtCheckEqual(Count - 2, LXT_COUNT_OF(g_OvFsMergedContents), "%d");
LxtClose(Fd);
Fd = -1;
//
// Replace a directory with a file and back again to a directory.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/InBothDir", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(Fd = creat(OVFS_TEST_MERGED_DIR "/InBothDir", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MERGED_DIR "/InBothDir", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/InBothDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeReadOps(PLXT_ARGS Args)
/*++
Description:
This routine tests inode operations that do not modify state.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Fd;
char Path[128];
ssize_t PathSize;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
Fd = -1;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check inode operations that do not
// hydrate files.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Check the behavior for open, lookup, and fstat. The inode numbers in the
// merged folder should be unique for directories but match the files.
//
if (g_LxtUnstableInodes != 0)
{
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothDir", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/InBothDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothFile", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/InBothFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInUpperDir", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInUpperFile", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// Check the behavior for readlink.
//
LxtCheckErrno(PathSize = readlink(OVFS_TEST_MOUNT_PATH "/OnlyInLowerSym", Path, sizeof(Path) - 1));
Path[PathSize] = 0;
LxtCheckStringEqual(Path, OVFS_TEST_LOWER_DIR "/OnlyInLowerFile");
LxtCheckErrno(PathSize = readlink(OVFS_TEST_MOUNT_PATH "/InBothSym", Path, sizeof(Path) - 1));
Path[PathSize] = 0;
LxtCheckStringEqual(Path, OVFS_TEST_UPPER_DIR "/InBothFile");
LxtCheckErrno(PathSize = readlink(OVFS_TEST_MOUNT_PATH "/OnlyInUpperSym", Path, sizeof(Path) - 1));
Path[PathSize] = 0;
LxtCheckStringEqual(Path, OVFS_TEST_UPPER_DIR "/OnlyInUpperFile");
//
//
// Check the behavior for stat. The inode numbers in the merged folder
// should be unique for directories but match the files.
//
if (g_LxtUnstableInodes != 0)
{
LxtCheckResult(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", &StatMergedBuffer));
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_MOUNT_PATH "/InBothDir", &StatMergedBuffer));
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/InBothDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", &StatMergedBuffer));
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_MOUNT_PATH "/InBothFile", &StatMergedBuffer));
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/InBothFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_MOUNT_PATH "/OnlyInUpperDir", &StatMergedBuffer));
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_MOUNT_PATH "/OnlyInUpperFile", &StatMergedBuffer));
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// Check that none of the operations hydrated files from the lower
// directory.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeRename(PLXT_ARGS Args)
/*++
Description:
This routine tests inode operations that may modify state.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
ssize_t BufferSize;
char Buffer;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Rename each file and check for the expected state.
//
//
// When renaming a file from the lower, a whiteout and the renamed file are
// set in the upper.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrno(rename(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile", OVFS_TEST_MERGED_DIR "/OnlyInLowerFileRenamed"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFileRenamed", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/OnlyInLowerFileRenamed", &StatMergedBuffer));
LxtCheckTrue(S_ISREG(StatMergedBuffer.st_mode));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// When renaming a file from the upper, the file is simply renamed.
//
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckErrno(rename(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile", OVFS_TEST_MERGED_DIR "/OnlyInUpperFileRenamed"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFileRenamed", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/OnlyInUpperFileRenamed", &StatMergedBuffer));
LxtCheckTrue(S_ISREG(StatMergedBuffer.st_mode));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// When renaming a file from both, a whiteout and the renamed file are
// set in the upper.
//
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(rename(OVFS_TEST_MERGED_DIR "/InBothFile", OVFS_TEST_MERGED_DIR "/InBothFileRenamed"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFileRenamed", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/InBothFileRenamed", &StatMergedBuffer));
LxtCheckTrue(S_ISREG(StatMergedBuffer.st_mode));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// Check the behavior for renaming a directory.
//
//
// When renaming a directory from the lower, the rename call should fail.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(rename(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", OVFS_TEST_MERGED_DIR "/OnlyInLowerDirRenamed"), EXDEV);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
//
// When renaming a directory from the upper, directory is simply renamed.
//
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckErrno(rename(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir", OVFS_TEST_MERGED_DIR "/OnlyInUpperDirRenamed"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDirRenamed", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MERGED_DIR "/OnlyInUpperDirRenamed", &StatMergedBuffer));
LxtCheckTrue(S_ISDIR(StatMergedBuffer.st_mode));
if (g_LxtUnstableInodes != 0)
{
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// When renaming a directory from both, the rename call should fail.
//
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckErrnoFailure(rename(OVFS_TEST_MERGED_DIR "/InBothDir", OVFS_TEST_MERGED_DIR "/InBothDirRenamed"), EXDEV);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/InBothDirRenamed", &StatBuffer), ENOENT);
//
// When renaming an opaque directory, the rename call should succeed.
//
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/InBothDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(BufferSize = getxattr(OVFS_TEST_UPPER_DIR "/InBothDir", "trusted.overlay.opaque", &Buffer, sizeof(Buffer)));
LxtCheckEqual(Buffer, 'y', "%c");
LxtCheckEqual(BufferSize, 1, "%d");
LxtCheckErrno(rename(OVFS_TEST_MERGED_DIR "/InBothDir", OVFS_TEST_MERGED_DIR "/OnlyInLowerDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(BufferSize = getxattr(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", "trusted.overlay.opaque", &Buffer, sizeof(Buffer)));
LxtCheckEqual(Buffer, 'y', "%c");
LxtCheckEqual(BufferSize, 1, "%d");
//
// Unmount.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeWhiteout(PLXT_ARGS Args)
/*++
Description:
This routine tests inode whiteout operations.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Fd;
int Result;
struct stat StatBuffer;
Fd = -1;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check for the expected file state.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer));
LxtCheckTrue(S_ISLNK(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckTrue(S_ISLNK(StatBuffer.st_mode));
//
// Unlink each entry and check for the expected behavior.
//
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInLowerSym"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer), ENOENT);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer), ENOENT);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperSym"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer), ENOENT);
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothFile"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothSym"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
//
// Create entries over the whiteouts and check for the expected state.
//
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(Fd = creat(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_MERGED_DIR "/OnlyInLowerSym", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(Fd = creat(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_MERGED_DIR "/OnlyInUpperSym", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/InBothDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(mkdir(OVFS_TEST_MERGED_DIR "/InBothFile", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(Fd = creat(OVFS_TEST_MERGED_DIR "/InBothSym", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtClose(Fd);
Fd = -1;
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeWriteOpsUpper(PLXT_ARGS Args)
/*++
Description:
This routine tests inode operations that do not modify state.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
int BytesRead;
int Count;
struct dirent* Entry;
int EntryPosition;
int Fd;
char* writeUpperCreate[] = {"writeUpperDir", "writeUpperFile", "writeUpperSymlink", "writeUpperLink"};
int Found[LXT_COUNT_OF(g_OvFsMergedContents) + 2 + LXT_COUNT_OF(writeUpperCreate)];
int FoundIndex;
int Index;
char Path[128];
ssize_t PathSize;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
struct utimbuf Times;
Fd = -1;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check inode operations that do not
// hydrate files.
//
// N.B. The overlay fs mount does not need to be recreated after each
// variation since only the upper is modified.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Check the behavior for open, chown, chmod, create cases, set times. The
// inode numbers in the merged folder should be unique for directories but
// match the files.
//
if (g_LxtUnstableInodes != 0)
{
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothFile", O_RDWR, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_LOWER_DIR "/InBothFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInUpperFile", O_RDWR, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothSym", O_RDWR | O_PATH | O_NOFOLLOW, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(lstat(OVFS_TEST_LOWER_DIR "/InBothSym", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(lstat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInUpperSym", O_RDWR | O_PATH | O_NOFOLLOW, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(lstat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer));
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
//
// Check the behavior for chown.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) && (S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE)) ||
(g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(chown(g_OvFsMergedContents[Index].Path, 111, 111));
}
//
// Check the behavior for chmod.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) && (S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE)) ||
(g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(chmod(g_OvFsMergedContents[Index].Path, 0777));
}
//
// Check the behavior for the 4 create cases.
//
LxtCheckErrno(mkdir(OVFS_TEST_MOUNT_PATH "/writeUpperDir", 0777));
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/writeUpperDir", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/writeUpperDir", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckNotEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(stat(OVFS_TEST_LOWER_DIR "/writeUpperDir", &StatBuffer), ENOENT);
LxtCheckErrno(Fd = creat(OVFS_TEST_MOUNT_PATH "/writeUpperFile", 0777));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/writeUpperFile", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(stat(OVFS_TEST_LOWER_DIR "/writeUpperFile", &StatBuffer), ENOENT);
LxtCheckErrno(symlink("writeUpperSymlink", OVFS_TEST_MOUNT_PATH "/writeUpperSymlink"));
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/writeUpperSymlink", O_RDONLY | O_PATH | O_NOFOLLOW, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(lstat(OVFS_TEST_UPPER_DIR "/writeUpperSymlink", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(lstat(OVFS_TEST_LOWER_DIR "/writeUpperSymlink", &StatBuffer), ENOENT);
LxtCheckErrno(link(OVFS_TEST_MOUNT_PATH "/writeUpperFile", OVFS_TEST_MOUNT_PATH "/writeUpperLink"));
LxtCheckResult(Fd = open(OVFS_TEST_MOUNT_PATH "/writeUpperLink", O_RDONLY, 0));
LxtCheckResult(fstat(Fd, &StatMergedBuffer));
LxtClose(Fd);
Fd = -1;
LxtCheckResult(stat(OVFS_TEST_UPPER_DIR "/writeUpperLink", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatMergedBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(stat(OVFS_TEST_LOWER_DIR "/writeUpperLink", &StatBuffer), ENOENT);
//
// Check the behavior for set times.
//
Times.actime = time(NULL);
Times.modtime = time(NULL);
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (((S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE) && (S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE)) ||
(g_OvFsMergedContents[Index].Hydrates != 0))
{
continue;
}
LxtCheckErrno(utime(g_OvFsMergedContents[Index].Path, &Times));
}
//
// Check the behavior for read directory on the root after new files were
// added.
//
memset(Found, 0, sizeof(Found));
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
if (strcmp(Entry->d_name, ".") == 0)
{
FoundIndex = 0;
}
else if (strcmp(Entry->d_name, "..") == 0)
{
FoundIndex = 1;
}
else
{
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (strcmp(g_OvFsMergedContents[Index].Name, Entry->d_name) == 0)
{
FoundIndex = Index + 2;
break;
}
}
if (Index == LXT_COUNT_OF(g_OvFsMergedContents))
{
for (Index = 0; Index < LXT_COUNT_OF(writeUpperCreate); ++Index)
{
if (strcmp(writeUpperCreate[Index], Entry->d_name) == 0)
{
FoundIndex = Index + 2 + LXT_COUNT_OF(g_OvFsMergedContents);
break;
}
}
if (Index == LXT_COUNT_OF(writeUpperCreate))
{
LxtLogError("Unexpected entry %s", Entry->d_name);
LxtCheckNotEqual(Index, LXT_COUNT_OF(writeUpperCreate), "%d");
}
}
}
LxtCheckEqual(Found[FoundIndex], 0, "%d");
Found[FoundIndex] = 1;
}
Entry = (struct dirent*)Buffer;
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
for (Index = 0; Index < LXT_COUNT_OF(Found); ++Index)
{
LxtCheckEqual(Found[FoundIndex], 1, "%d");
}
LxtClose(Fd);
Fd = -1;
//
// Check the behavior for read directory on sub directories.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if (S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedContents[Index].Path, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
}
//
// Check that none of the operations hydrated files from the lower
// directory.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeWriteOps(PLXT_ARGS Args)
/*++
Description:
This routine tests inode operations that may modify state.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char BytesRead;
char Buffer[100];
struct __user_cap_data_struct CapData[2];
struct __user_cap_header_struct CapHeader;
pid_t ChildPid;
int Fd;
int FdWrite;
int Result;
struct stat StatBuffer;
struct stat StatBufferWrite;
ChildPid = -1;
Fd = -1;
FdWrite = -1;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Open the same file for read and write. The read file will be from the
// lower layer, but opening the file for write will cause the file to be
// hydated in the upper layer and the inode updated.
//
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", O_RDONLY, 0));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBufferWrite), ENOENT);
LxtCheckErrno(FdWrite = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", O_RDWR, 0));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBufferWrite));
LxtCheckErrno(fstat(FdWrite, &StatBufferWrite));
if (g_LxtUnstableInodes != 0)
{
LxtCheckNotEqual(StatBuffer.st_ino, StatBufferWrite.st_ino, "%d");
}
LxtCheckEqual(StatBuffer.st_mode, StatBufferWrite.st_mode, "%d");
//
// Check that the inode numbers are the same now that both files are open.
// Any open files referring to this inode will access the new inode
// metadata.
//
LxtCheckErrno(fstat(Fd, &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatBufferWrite.st_ino, "%d");
}
LxtCheckErrno(fstat(FdWrite, &StatBufferWrite));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatBuffer.st_ino, StatBufferWrite.st_ino, "%d");
}
LxtCheckEqual(StatBuffer.st_mode, StatBufferWrite.st_mode, "%d");
//
// Check that chmod on one of the file descriptors impacts both. Any open
// files referring to this inode will access the new inode metadata.
//
LxtCheckNotEqual(StatBuffer.st_mode, S_IFREG | 0111, "%d");
LxtCheckErrno(fchmod(FdWrite, 0111));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckErrno(fstat(FdWrite, &StatBufferWrite));
LxtLogInfo("%d, %d", StatBuffer.st_mode, StatBufferWrite.st_mode);
LxtCheckEqual(StatBuffer.st_mode, S_IFREG | 0111, "%d");
LxtCheckEqual(StatBufferWrite.st_mode, S_IFREG | 0111, "%d");
//
// Check that writing only impacts the file object opened for write and not
// the one opened for read. Any open files objects will access the old file
// data.
//
LxtCheckErrno(write(FdWrite, "OnlyInLowerFileModified", sizeof("OnlyInLowerFileModified")));
LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer) - 1));
Buffer[BytesRead] = 0;
LxtCheckStringEqual(Buffer, "OnlyInLowerFile") LxtCheckErrno(lseek(FdWrite, SEEK_SET, 0));
LxtCheckErrno(BytesRead = read(FdWrite, Buffer, sizeof(Buffer) - 1));
Buffer[BytesRead] = 0;
LxtCheckStringEqual(Buffer, "OnlyInLowerFileModified")
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
if (FdWrite != -1)
{
LxtClose(FdWrite);
FdWrite = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check that chmod, chown, and utime hydrate files.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(chmod(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(chown(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", 1, 1));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckErrnoFailure(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(utimensat(-1, OVFS_TEST_MOUNT_PATH "/OnlyInLowerSym", NULL, AT_SYMLINK_NOFOLLOW));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer));
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check that the 4 types of creation hydrate paths.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(symlink("CreatedSymlink", OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir/CreatedSymlink"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir/CreatedSymlink", &StatBuffer));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(Fd = creat(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir/CreatedFile", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir/CreatedFile", &StatBuffer));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(mkdir(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir/CreatedDir", 0777));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir/CreatedDir", &StatBuffer));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(link(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir/CreatedLink"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir/CreatedLink", &StatBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckErrnoFailure(lstat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check the undefined behavior for O_RDONLY with O_TRUNC
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerFile", O_RDONLY | O_TRUNC, 0));
LxtCheckErrnoFailure(ftruncate(Fd, 0), EINVAL);
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInUpperFile", O_RDONLY | O_TRUNC, 0));
LxtCheckErrnoFailure(ftruncate(Fd, 0), EINVAL);
LxtClose(Fd);
Fd = -1;
LxtCheckErrnoFailure(stat(OVFS_TEST_LOWER_DIR "/OnlyInUpperFile", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothFile", O_RDONLY | O_TRUNC, 0));
LxtCheckErrnoFailure(ftruncate(Fd, 0), EINVAL);
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Repeat the above for a file outside of overlay.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrno(Fd = open(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", O_RDONLY | O_TRUNC, 0));
LxtCheckErrnoFailure(ftruncate(Fd, 0), EINVAL);
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckEqual(StatBuffer.st_size, 0, "%d");
//
// Repeat the above for a file where write access is not granted.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckNotEqual(StatBuffer.st_size, 0, "%d");
LxtCheckErrno(chmod(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", 0444));
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
//
// Drop privileges so the current process does not have VFS capabilities
// and is in another user\group.
//
memset(&CapData, 0, sizeof(CapData));
memset(&CapHeader, 0, sizeof(CapHeader));
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
LxtCheckErrno(setgid(2002));
LxtCheckErrno(setuid(2002));
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
//
// Open the file with different trunctate variations.
//
LxtCheckErrno(Fd = open(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", O_RDONLY, 0));
LxtClose(Fd);
Fd = -1;
LxtCheckErrnoFailure(Fd = open(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", O_RDWR, 0), EACCES);
LxtCheckErrnoFailure(Fd = open(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", O_RDONLY | O_TRUNC, 0), EACCES);
_exit(0);
}
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
Result = 0;
ErrorExit:
if (ChildPid == 0)
{
_exit(Result);
}
if (Fd != -1)
{
LxtClose(Fd);
}
if (FdWrite != -1)
{
LxtClose(FdWrite);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeUnlink(PLXT_ARGS Args)
/*++
Description:
This routine tests inode operations unlink.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Fd;
int FdLower;
int Result;
struct stat StatBuffer;
Fd = -1;
FdLower = -1;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check for the expected file state.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer));
LxtCheckTrue(S_ISLNK(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(lstat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckTrue(S_ISLNK(StatBuffer.st_mode));
//
// Unlink each entry and check for the expected behavior.
//
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInLowerSym"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInUpperDir"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperDir", &StatBuffer), ENOENT);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer), ENOENT);
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperSym"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperSym", &StatBuffer), ENOENT);
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothFile"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/InBothSym"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothSym", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
//
// Check that the lower file is detected during open and not on unlink.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile", O_RDWR));
LxtCheckErrno(FdLower = creat(OVFS_TEST_LOWER_DIR "/OnlyInUpperFile", 0777));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer), ENOENT);
//
// Repeat the above, but create the file in the lower first.
//
LxtClose(Fd);
Fd = -1;
LxtClose(FdLower);
FdLower = -1;
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(FdLower = creat(OVFS_TEST_LOWER_DIR "/OnlyInUpperFile", 0777));
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile", O_RDWR));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile"));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInUpperFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtClose(Fd);
Fd = -1;
LxtClose(FdLower);
FdLower = -1;
//
// Check the behavior for unlink while a file is open.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(FdLower = open(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile", O_RDONLY));
LxtCheckErrno(fstat(FdLower, &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile", O_RDWR));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile"));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(fstat(FdLower, &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(fchmod(FdLower, 0777));
LxtCheckErrno(fchmod(Fd, 0777));
LxtClose(Fd);
Fd = -1;
LxtClose(FdLower);
FdLower = -1;
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile", O_RDONLY));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(unlink(OVFS_TEST_MERGED_DIR "/OnlyInUpperFile"));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckTrue(S_ISREG(StatBuffer.st_mode));
LxtCheckErrno(fchmod(Fd, 0777));
LxtClose(Fd);
Fd = -1;
//
// Check the behavior for rmdir while a directory is open.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrno(FdLower = open(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", O_RDONLY));
LxtCheckErrno(fstat(FdLower, &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir"));
LxtCheckErrno(fstat(FdLower, &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrnoFailure(fchmod(FdLower, 0777), ENOTDIR);
LxtCheckErrno(Fd = open(OVFS_TEST_MERGED_DIR "/InBothDir", O_RDONLY));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MERGED_DIR "/InBothDir"));
LxtCheckErrno(fstat(Fd, &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(fchmod(Fd, 0777));
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
if (FdLower != -1)
{
LxtClose(FdLower);
FdLower = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Fd != -1)
{
LxtClose(Fd);
}
if (FdLower != -1)
{
LxtClose(FdLower);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestInodeXattr(PLXT_ARGS Args)
/*++
Description:
This routine tests inode operations that hydrate xattrs.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Count;
struct
{
char* Path;
char* Name;
} HydratedData[] = {
{OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", "OnlyInLowerDir"}, {OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", "OnlyInLowerFile"}};
int Index;
char* ListCurrent;
char List[256];
ssize_t ListSize;
int Result;
struct stat StatBuffer;
char Value[64];
ssize_t ValueSize;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Check the xattr state in the merged directory.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedContents); ++Index)
{
if ((S_ISDIR(g_OvFsMergedContents[Index].Mode) == FALSE) && (S_ISREG(g_OvFsMergedContents[Index].Mode) == FALSE))
{
continue;
}
LxtCheckErrno(ListSize = listxattr(g_OvFsMergedContents[Index].Path, List, sizeof(List)));
ListCurrent = List;
Count = 0;
for (;;)
{
LxtCheckErrno(ValueSize = getxattr(g_OvFsMergedContents[Index].Path, ListCurrent, Value, sizeof(Value)));
LxtCheckStringEqual(Value, g_OvFsMergedContents[Index].Name);
ListCurrent += strlen(ListCurrent) + 1;
Count += 1;
if (ListCurrent >= List + ListSize)
{
break;
}
}
LxtCheckEqual(Count, 2, "%d");
}
//
// Hydrate files and check that the xattr state was copied.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckResult(chmod(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", 0111));
LxtCheckResult(chmod(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile", 0111));
for (Index = 0; Index < LXT_COUNT_OF(HydratedData); ++Index)
{
LxtCheckErrno(stat(HydratedData[Index].Path, &StatBuffer));
LxtCheckErrno(ListSize = listxattr(HydratedData[Index].Path, List, sizeof(List)));
ListCurrent = List;
Count = 0;
for (;;)
{
LxtCheckErrno(ValueSize = getxattr(HydratedData[Index].Path, ListCurrent, Value, sizeof(Value)));
LxtCheckStringEqual(Value, HydratedData[Index].Name);
ListCurrent += strlen(ListCurrent) + 1;
Count += 1;
if (ListCurrent >= List + ListSize)
{
break;
}
}
LxtCheckEqual(Count, 2, "%d");
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check the behavior for hydration of "trusted.overlay.opaque" where the
// value is dropped.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
Value[0] = 'y';
LxtCheckErrno(setxattr(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir", "trusted.overlay.opaque", Value, 1, XATTR_CREATE));
LxtCheckErrno(setxattr(OVFS_TEST_LOWER_DIR "/OnlyInLowerFile", "trusted.overlay.opaque", Value, 1, XATTR_CREATE));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckResult(chmod(OVFS_TEST_MERGED_DIR "/OnlyInLowerDir", 0111));
LxtCheckResult(chmod(OVFS_TEST_MERGED_DIR "/OnlyInLowerFile", 0111));
for (Index = 0; Index < LXT_COUNT_OF(HydratedData); ++Index)
{
LxtCheckErrno(stat(HydratedData[Index].Path, &StatBuffer));
LxtCheckErrno(ListSize = listxattr(HydratedData[Index].Path, List, sizeof(List)));
ListCurrent = List;
Count = 0;
for (;;)
{
LxtCheckErrno(ValueSize = getxattr(HydratedData[Index].Path, ListCurrent, Value, sizeof(Value)));
LxtCheckStringEqual(Value, HydratedData[Index].Name);
ListCurrent += strlen(ListCurrent) + 1;
Count += 1;
if (ListCurrent >= List + ListSize)
{
break;
}
}
LxtCheckEqual(Count, 2, "%d");
}
//
// Unmount and check that it was unmounted.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestLowerWhiteout(PLXT_ARGS Args)
/*++
Description:
This routine tests how whiteouts behavior when they are in the lower layer.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[256];
int BytesRead;
int Count;
struct dirent* Entry;
int EntryPosition;
int Fd;
int Found[LXT_COUNT_OF(g_OvFsMergedMultiContents) + 2];
int FoundIndex;
int Index;
void* Mapping;
void* MapResult;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
Fd = -1;
Mapping = NULL;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Create some whiteout files in the lower directory.
//
LxtCheckResult(mknod(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir/whiteoutFile", S_IFCHR | 0777, 0));
LxtCheckResult(mknod(OVFS_TEST_LOWER_DIR "/InBothDir/whiteoutFile", S_IFCHR | 0777, 0));
//
// Mount an overlayfs instance and check the behavior for the whiteouts
// created above.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_DEFAULT));
//
// Check that the whiteout cannot be opened but are reported through readdir
// when the folder is not merged with the upper.
//
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir/whiteoutFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir/whiteoutFile", &StatMergedBuffer), ENOENT);
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckEqual(Count, 3, "%d");
LxtClose(Fd);
Fd = -1;
//
// Check that the whiteout cannot be opened and is not reported through
// readdir when the folder is merged with the upper.
//
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/InBothDir/whiteoutFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", &StatMergedBuffer), ENOENT);
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
//
// Check that the whiteout can be overwritten in the upper and that it
// is not replaced by a whiteout when removed.
//
LxtCheckErrno(mkdir(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", 0777));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", &StatMergedBuffer));
LxtCheckTrue(S_ISDIR(StatMergedBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir/whiteoutFile", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", &StatMergedBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/InBothDir/whiteoutFile", &StatBuffer), ENOENT);
//
// Repeat the above with multiple lowers.
//
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_MULI_LOWER));
//
// Check that the whiteout cannot be opened but are reported through readdir
// when the folder is not merged with the upper.
//
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/OnlyInLowerDir/whiteoutFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir/whiteoutFile", &StatMergedBuffer), ENOENT);
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/OnlyInLowerDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckEqual(Count, 3, "%d");
LxtClose(Fd);
Fd = -1;
//
// Check that the whiteout cannot be opened and is not reported through
// readdir when the folder is merged with the upper.
//
LxtCheckErrno(stat(OVFS_TEST_LOWER_DIR "/InBothDir/whiteoutFile", &StatBuffer));
LxtCheckTrue(S_ISCHR(StatBuffer.st_mode));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", &StatMergedBuffer), ENOENT);
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/InBothDir", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
//
// Check that the whiteout can be overwritten in the upper and that it
// is not replaced by a whiteout when removed.
//
LxtCheckErrno(mkdir(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", 0777));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", &StatMergedBuffer));
LxtCheckTrue(S_ISDIR(StatMergedBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/InBothDir/whiteoutFile", &StatBuffer));
LxtCheckTrue(S_ISDIR(StatBuffer.st_mode));
LxtCheckErrno(rmdir(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile"));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/InBothDir/whiteoutFile", &StatMergedBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/InBothDir/whiteoutFile", &StatBuffer), ENOENT);
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Mapping != MAP_FAILED)
{
munmap(Mapping, PAGE_SIZE);
}
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}
int OvFsTestMultipleLower(PLXT_ARGS Args)
/*++
Description:
This routine tests various operations with multiple lower layers.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
int BytesRead;
int Count;
struct dirent* Entry;
int EntryPosition;
int Fd;
int Found[LXT_COUNT_OF(g_OvFsMergedMultiContents) + 2];
int FoundIndex;
int Index;
void* Mapping;
void* MapResult;
int Result;
struct stat StatBuffer;
struct stat StatMergedBuffer;
Fd = -1;
Mapping = NULL;
//
// Setup the directories and populate some state.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
//
// Mount an overlayfs instance and check inode operations that do not
// hydrate files.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_MULI_LOWER));
//
// Check the behavior for VFS file object operations that support file
// descriptors opened for read only.
//
// N.B. All other file operations will fail the request and are verified
// in the VFS access test.
//
//
// Check the behavior for read directory on the root.
//
memset(Found, 0, sizeof(Found));
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
if (strcmp(Entry->d_name, ".") == 0)
{
FoundIndex = 0;
}
else if (strcmp(Entry->d_name, "..") == 0)
{
FoundIndex = 1;
}
else
{
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedMultiContents); ++Index)
{
if (strcmp(g_OvFsMergedMultiContents[Index].Name, Entry->d_name) == 0)
{
FoundIndex = Index + 2;
break;
}
}
if (Index == LXT_COUNT_OF(g_OvFsMergedMultiContents))
{
LxtLogError("Unexpected entry %s", Entry->d_name);
LxtCheckNotEqual(Index, LXT_COUNT_OF(g_OvFsMergedMultiContents), "%d");
}
}
LxtCheckEqual(Found[FoundIndex], 0, "%d");
Found[FoundIndex] = 1;
}
Entry = (struct dirent*)Buffer;
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
for (Index = 0; Index < LXT_COUNT_OF(Found); ++Index)
{
LxtCheckEqual(Found[FoundIndex], 1, "%d");
}
LxtClose(Fd);
Fd = -1;
//
// Check the behavior for read directory on sub directories.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedMultiContents); ++Index)
{
if (S_ISDIR(g_OvFsMergedMultiContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedMultiContents[Index].Path, O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)))
Count = 0;
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
Count += 1;
}
LxtCheckEqual(Count, 2, "%d");
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for read file.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedMultiContents); ++Index)
{
if (S_ISREG(g_OvFsMergedMultiContents[Index].Mode) == FALSE)
{
continue;
}
LxtCheckErrno(Fd = open(g_OvFsMergedMultiContents[Index].Path, O_RDONLY));
LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer) - 1));
Buffer[BytesRead] = 0;
LxtCheckStringEqual(Buffer, g_OvFsMergedMultiContents[Index].Name);
LxtClose(Fd);
Fd = -1;
}
//
// Check the behavior for seek.
//
for (Index = 0; Index < LXT_COUNT_OF(g_OvFsMergedMultiContents); ++Index)
{
if ((S_ISDIR(g_OvFsMergedMultiContents[Index].Mode) == FALSE) && (S_ISREG(g_OvFsMergedMultiContents[Index].Mode) == FALSE))
{
continue;
}
LxtLogInfo("%s", g_OvFsMergedMultiContents[Index].Path);
LxtCheckErrno(Fd = open(g_OvFsMergedMultiContents[Index].Path, O_RDONLY));
LxtCheckErrno(lseek(Fd, SEEK_SET, 1));
LxtClose(Fd);
Fd = -1;
}
//
// Check that none of the operations hydrated files from the lower
// directory.
//
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerDir", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerFile", &StatBuffer), ENOENT);
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLowerSym", &StatBuffer), ENOENT);
//
// Check the search order for the multiple lower layers.
//
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower2File", &StatMergedBuffer));
LxtCheckEqual(S_IFREG | 0444, StatMergedBuffer.st_mode, "%d");
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower23File", &StatMergedBuffer));
LxtCheckEqual(S_IFREG | 0444, StatMergedBuffer.st_mode, "%d");
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower3File", &StatMergedBuffer));
LxtCheckEqual(S_IFREG | 0111, StatMergedBuffer.st_mode, "%d");
//
// Hydrate some files from the lower layers.
//
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower2File", &StatMergedBuffer));
LxtCheckErrno(stat(OVFS_TEST_LOWER2_DIR "/OnlyInLower2File", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatMergedBuffer.st_ino, StatBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLower2File", &StatBuffer), ENOENT);
LxtCheckErrno(chmod(OVFS_TEST_MOUNT_PATH "/OnlyInLower2File", 0777));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower2File", &StatMergedBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLower2File", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatMergedBuffer.st_ino, StatBuffer.st_ino, "%d");
}
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower3Dir", &StatMergedBuffer));
LxtCheckErrno(stat(OVFS_TEST_LOWER3_DIR "/OnlyInLower3Dir", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckNotEqual(StatMergedBuffer.st_ino, StatBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLower3Dir", &StatBuffer), ENOENT);
LxtCheckErrno(chown(OVFS_TEST_MOUNT_PATH "/OnlyInLower3Dir", 2001, 2001));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower3Dir", &StatMergedBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLower3Dir", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckNotEqual(StatMergedBuffer.st_ino, StatBuffer.st_ino, "%d");
}
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower23File", &StatMergedBuffer));
LxtCheckErrno(stat(OVFS_TEST_LOWER2_DIR "/OnlyInLower23File", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatMergedBuffer.st_ino, StatBuffer.st_ino, "%d");
}
LxtCheckErrnoFailure(stat(OVFS_TEST_UPPER_DIR "/OnlyInLower23File", &StatBuffer), ENOENT);
LxtCheckErrno(truncate(OVFS_TEST_MOUNT_PATH "/OnlyInLower23File", 0));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/OnlyInLower23File", &StatMergedBuffer));
LxtCheckErrno(stat(OVFS_TEST_UPPER_DIR "/OnlyInLower23File", &StatBuffer));
if (g_LxtUnstableInodes != 0)
{
LxtCheckEqual(StatMergedBuffer.st_ino, StatBuffer.st_ino, "%d");
}
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check the behavior for entries with the same name but differing types in
// the lower.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckErrno(mkdir(OVFS_TEST_LOWER_DIR "/mixedType", 0777));
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER_DIR "/mixedType/onlyInLower1", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER2_DIR "/mixedType", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(mkdir(OVFS_TEST_LOWER3_DIR "/mixedType", 0777));
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER3_DIR "/mixedType/onlyInLower3", 0777));
LxtClose(Fd);
Fd = -1;
//
// Mount an overlayfs instance and check for the expected lookup and readdir
// behavior.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_MULI_LOWER));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/mixedType", &StatMergedBuffer));
LxtCheckTrue(S_ISDIR(StatMergedBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/mixedType/onlyInLower1", &StatMergedBuffer));
LxtCheckTrue(S_ISREG(StatMergedBuffer.st_mode));
LxtCheckErrnoFailure(stat(OVFS_TEST_MOUNT_PATH "/mixedType/onlyInLower3", &StatMergedBuffer), ENOENT);
Count = 0;
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/mixedType", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
LxtCheckEqual(Count, 3, "%d");
LxtClose(Fd);
Fd = -1;
//
// Repeat the above with the mismatch in the lowest layer.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
//
// Check the behavior for entries with the same name but differing types in
// the lower.
//
LxtCheckResult(OvFsTestDirsSetup());
LxtCheckResult(OvFsTestDirsPopulate());
LxtCheckErrno(mkdir(OVFS_TEST_LOWER_DIR "/mixedType", 0777));
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER_DIR "/mixedType/onlyInLower1", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(mkdir(OVFS_TEST_LOWER2_DIR "/mixedType", 0777));
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER2_DIR "/mixedType/onlyInLower2", 0777));
LxtClose(Fd);
Fd = -1;
LxtCheckErrno(Fd = creat(OVFS_TEST_LOWER3_DIR "/mixedType", 0777));
LxtClose(Fd);
Fd = -1;
//
// Mount an overlayfs instance and check for the expected lookup and readdir
// behavior.
//
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
LxtCheckErrnoZeroSuccess(mount("myovfsnew", OVFS_TEST_MOUNT_PATH, OVFS_TEST_MOUNT_NAME, 0, OVFS_TEST_MOUNT_MULI_LOWER));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/mixedType", &StatMergedBuffer));
LxtCheckTrue(S_ISDIR(StatMergedBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/mixedType/onlyInLower1", &StatMergedBuffer));
LxtCheckTrue(S_ISREG(StatMergedBuffer.st_mode));
LxtCheckErrno(stat(OVFS_TEST_MOUNT_PATH "/mixedType/onlyInLower2", &StatMergedBuffer));
LxtCheckTrue(S_ISREG(StatMergedBuffer.st_mode));
Count = 0;
LxtCheckErrno(Fd = open(OVFS_TEST_MOUNT_PATH "/mixedType", O_RDONLY));
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
while (BytesRead > 0)
{
for (EntryPosition = 0; EntryPosition < BytesRead; EntryPosition += Entry->d_reclen)
{
Entry = (struct dirent*)&Buffer[EntryPosition];
LxtLogInfo("%s", Entry->d_name);
Count += 1;
}
LxtCheckErrno(BytesRead = LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)));
}
LxtCheckEqual(Count, 4, "%d");
LxtClose(Fd);
Fd = -1;
//
// Unmount and check it was unmounted.
//
if (Fd != -1)
{
LxtClose(Fd);
Fd = -1;
}
LxtCheckErrnoZeroSuccess(umount(OVFS_TEST_MOUNT_PATH));
LxtCheckResult(MountCheckIsNotMount(OVFS_TEST_MOUNT_PATH));
Result = 0;
ErrorExit:
if (Mapping != MAP_FAILED)
{
munmap(Mapping, PAGE_SIZE);
}
if (Fd != -1)
{
LxtClose(Fd);
}
umount(OVFS_TEST_MOUNT_PATH);
return Result;
}