mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 07:23:20 +00:00

Many Microsoft employees have contributed to the Windows Subsystem for Linux, this commit is the result of their work since 2016. The entire history of the Windows Subsystem for Linux can't be shared here, but here's an overview of WSL's history after it moved to it own repository in 2021: Number of commits on the main branch: 2930 Number of contributors: 31 Head over https://github.com/microsoft/WSL/releases for a more detailed history of the features added to WSL since 2021.
996 lines
30 KiB
C
996 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
inotify.c
|
|
|
|
Abstract:
|
|
|
|
This file contains extensive inotify unit tests.
|
|
|
|
--*/
|
|
|
|
#include "lxtcommon.h"
|
|
#include "unittests.h"
|
|
#include "lxtfs.h"
|
|
#include <poll.h>
|
|
#include <dirent.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/inotify.h>
|
|
#include <sys/mount.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <errno.h>
|
|
|
|
#define LXT_NAME "INOTIFY"
|
|
|
|
#define INOTIFY_TEST_BASE_DIR_LXFS "/data/inotify_test/"
|
|
#define INOTIFY_TEST_PROCFS_MAX_QUEUED_EVENTS_FILE "/proc/sys/fs/inotify/max_queued_events"
|
|
|
|
int TestInotifyComprehensive1Common(char* BaseDir);
|
|
|
|
int TestInotifyComprehensive2Common(char* BaseDir);
|
|
|
|
LXT_VARIATION_HANDLER TestInotifyNonBlockRead;
|
|
LXT_VARIATION_HANDLER TestInotifyEventQueueOverflow;
|
|
LXT_VARIATION_HANDLER TestInotifyEpollLxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyBasicLxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyComprehensive1Lxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyComprehensive2Lxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyPosixUnlinkRenameLxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyUnmountBindLxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyFtruncateLxfs;
|
|
LXT_VARIATION_HANDLER TestInotifyPseudoPlugin;
|
|
|
|
//
|
|
// Global constants
|
|
//
|
|
|
|
static const LXT_VARIATION g_LxtVariations[] = {
|
|
{"Test non-blocking read of inotify descriptor", TestInotifyNonBlockRead},
|
|
{"Test overflow of inotify event queue", TestInotifyEventQueueOverflow},
|
|
{"Test inotify with epoll - lxfs", TestInotifyEpollLxfs},
|
|
{"Test inotify watching basic paths - lxfs", TestInotifyBasicLxfs},
|
|
{"Comprehensive inotify tests 1 - lxfs", TestInotifyComprehensive1Lxfs},
|
|
{"Comprehensive inotify tests 2 - lxfs", TestInotifyComprehensive2Lxfs},
|
|
{"Test inotify with POSIX unlink/rename - lxfs", TestInotifyPosixUnlinkRenameLxfs},
|
|
{"Test unmounting of a bind mount - lxfs", TestInotifyUnmountBindLxfs},
|
|
{"Test ftruncate - lxfs", TestInotifyFtruncateLxfs},
|
|
{"Test inotify pseudo plugin", TestInotifyPseudoPlugin}};
|
|
|
|
int InotifyTestEntry(int Argc, char* Argv[])
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
LXT_ARGS Args;
|
|
int Result;
|
|
|
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
|
|
|
ErrorExit:
|
|
LxtUninitialize();
|
|
return !LXT_SUCCESS(Result);
|
|
}
|
|
|
|
int TestInotifyNonBlockRead(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
int Id;
|
|
char Buf[10];
|
|
int Result;
|
|
|
|
//
|
|
// There is nothing to read here, but should not block.
|
|
//
|
|
|
|
LxtCheckErrno(Id = inotify_init1(IN_NONBLOCK));
|
|
LxtCheckErrnoFailure(Result = read(Id, Buf, 1), EAGAIN);
|
|
LxtCheckErrnoZeroSuccess(close(Id));
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
return Result;
|
|
}
|
|
|
|
int TestInotifyEventQueueOverflow(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
int Id;
|
|
int Fd;
|
|
int ProcFd;
|
|
char Buf[11];
|
|
int Result;
|
|
int OriginalMaxQueuedEvents;
|
|
char InotifyBuf[500];
|
|
struct inotify_event* Events[INOTIFY_TEST_EVENTS_BUF_SIZE];
|
|
int NumEvents;
|
|
char TestFile1[PATH_MAX];
|
|
char TestFile2[PATH_MAX];
|
|
char TestFile1Hlink[PATH_MAX];
|
|
char TestFile1Slink[PATH_MAX];
|
|
|
|
//
|
|
// Initialize and also do cleanup if the files have not been removed.
|
|
//
|
|
|
|
sprintf(TestFile1, "%s%s", INOTIFY_TEST_BASE_DIR_LXFS, INOTIFY_TEST_FILE1_NAME_ONLY);
|
|
|
|
sprintf(TestFile2, "%s%s", INOTIFY_TEST_BASE_DIR_LXFS, INOTIFY_TEST_FILE2_NAME_ONLY);
|
|
|
|
sprintf(TestFile1Hlink, "%s%s", INOTIFY_TEST_BASE_DIR_LXFS, INOTIFY_TEST_FILE1_HLINK_NAME_ONLY);
|
|
|
|
sprintf(TestFile1Slink, "%s%s", INOTIFY_TEST_BASE_DIR_LXFS, INOTIFY_TEST_FILE1_SLINK_NAME_ONLY);
|
|
|
|
unlink(TestFile1);
|
|
unlink(TestFile2);
|
|
unlink(TestFile1Hlink);
|
|
unlink(TestFile1Slink);
|
|
rmdir(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
LxtCheckErrnoZeroSuccess(mkdir(INOTIFY_TEST_BASE_DIR_LXFS, 0777));
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Read the procFS value /proc/sys/fs/inotify/max_queued_events.
|
|
//
|
|
|
|
LxtCheckErrno(ProcFd = open(INOTIFY_TEST_PROCFS_MAX_QUEUED_EVENTS_FILE, O_RDWR));
|
|
|
|
LxtCheckErrno(Result = read(ProcFd, Buf, sizeof(Buf)));
|
|
OriginalMaxQueuedEvents = atoi(Buf);
|
|
LxtCheckNotEqual(OriginalMaxQueuedEvents, 0, "%d");
|
|
|
|
//
|
|
// Change the value to -1, verify failed.
|
|
//
|
|
|
|
sprintf(Buf, "-1");
|
|
LxtCheckErrnoFailure(Result = write(ProcFd, Buf, strlen(Buf)), EINVAL);
|
|
|
|
//
|
|
// Change the value to INT_MAX + 1 (2^31), verify failed.
|
|
//
|
|
|
|
sprintf(Buf, "2147483648");
|
|
LxtCheckErrnoFailure(Result = write(ProcFd, Buf, strlen(Buf)), EINVAL);
|
|
|
|
//
|
|
// Change the value to INT_MAX (2^31 - 1), verify succeeded.
|
|
//
|
|
|
|
sprintf(Buf, "2147483647");
|
|
LxtCheckErrno(Result = write(ProcFd, Buf, strlen(Buf)));
|
|
LxtCheckEqual(atoi(Buf), INT_MAX, "%d");
|
|
|
|
//
|
|
// Change the value to 2, and then read it back to verify.
|
|
//
|
|
|
|
sprintf(Buf, "2");
|
|
LxtCheckErrno(Result = write(ProcFd, Buf, strlen(Buf)));
|
|
LxtCheckErrno(Result = read(ProcFd, Buf, sizeof(Buf)));
|
|
LxtCheckEqual(atoi(Buf), 2, "%d");
|
|
|
|
//
|
|
// Generate 2 inotify events, verify that there is no overflow.
|
|
//
|
|
|
|
LxtCheckErrno(Id = inotify_init());
|
|
LxtCheckErrno(Result = inotify_add_watch(Id, TestFile1, IN_ALL_EVENTS));
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDWR));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 2, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_CLOSE_WRITE, "%d");
|
|
|
|
//
|
|
// Generate 3 inotify events, verify that there is an overflow.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDWR));
|
|
LxtCheckErrnoZeroSuccess(fchmod(Fd, 0666));
|
|
LxtCheckErrnoZeroSuccess(fchmod(Fd, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 3, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_Q_OVERFLOW, "%d");
|
|
LxtCheckEqual(Events[2]->wd, -1, "%d");
|
|
LxtCheckEqual(Events[2]->cookie, 0, "%d");
|
|
LxtCheckEqual(Events[1]->len, 0, "%d");
|
|
|
|
//
|
|
// Restore the max_queued_events value to the original value read
|
|
// in the beginning, and verify.
|
|
//
|
|
|
|
sprintf(Buf, "%d", OriginalMaxQueuedEvents);
|
|
LxtCheckErrno(Result = write(ProcFd, Buf, strlen(Buf)));
|
|
LxtCheckErrno(Result = read(ProcFd, Buf, sizeof(Buf)));
|
|
LxtCheckEqual(atoi(Buf), OriginalMaxQueuedEvents, "%d");
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
close(Id);
|
|
close(Fd);
|
|
close(ProcFd);
|
|
unlink(TestFile1);
|
|
unlink(TestFile2);
|
|
unlink(TestFile1Hlink);
|
|
unlink(TestFile1Slink);
|
|
rmdir(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
return Result;
|
|
}
|
|
|
|
int TestInotifyEpollLxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
return LxtFsInotifyEpollCommon(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
}
|
|
|
|
int TestInotifyBasicLxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
int Id;
|
|
int Result;
|
|
int Wd[10];
|
|
|
|
//
|
|
// Test watching basic Lxfs paths.
|
|
//
|
|
|
|
LxtCheckErrno(Id = inotify_init());
|
|
LxtCheckErrno(Wd[0] = inotify_add_watch(Id, "/", IN_ALL_EVENTS));
|
|
LxtCheckErrno(Wd[1] = inotify_add_watch(Id, "/mnt", IN_ALL_EVENTS));
|
|
LxtCheckErrno(Wd[2] = inotify_add_watch(Id, "/mnt/", IN_ALL_EVENTS));
|
|
LxtCheckErrno(Wd[3] = inotify_add_watch(Id, "/proc", IN_ALL_EVENTS));
|
|
LxtCheckErrno(Wd[4] = inotify_add_watch(Id, "/sys", IN_ALL_EVENTS));
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
close(Id);
|
|
return Result;
|
|
}
|
|
|
|
int TestInotifyComprehensive1Lxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
return TestInotifyComprehensive1Common(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
}
|
|
|
|
int TestInotifyComprehensive1Common(char* BaseDir)
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
int Fd;
|
|
int Id1;
|
|
int Id2;
|
|
int Wd[10];
|
|
char Buf[10];
|
|
char InotifyBuf[500];
|
|
struct inotify_event* Events[INOTIFY_TEST_EVENTS_BUF_SIZE];
|
|
int NumEvents;
|
|
int Bytes;
|
|
int Result;
|
|
int Index;
|
|
int AttribEvent;
|
|
int CreateEvent;
|
|
char TestFile1[PATH_MAX];
|
|
char TestFile2[PATH_MAX];
|
|
char TestFile1Hlink[PATH_MAX];
|
|
char TestFile1Slink[PATH_MAX];
|
|
|
|
//
|
|
// Initialize and also do cleanup if the files have not been removed.
|
|
//
|
|
|
|
sprintf(TestFile1, "%s%s", BaseDir, INOTIFY_TEST_FILE1_NAME_ONLY);
|
|
sprintf(TestFile2, "%s%s", BaseDir, INOTIFY_TEST_FILE2_NAME_ONLY);
|
|
sprintf(TestFile1Hlink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_HLINK_NAME_ONLY);
|
|
sprintf(TestFile1Slink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_SLINK_NAME_ONLY);
|
|
unlink(TestFile1);
|
|
unlink(TestFile2);
|
|
unlink(TestFile1Hlink);
|
|
unlink(TestFile1Slink);
|
|
rmdir(BaseDir);
|
|
LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Setup inotify.
|
|
//
|
|
|
|
LxtCheckErrno(Id1 = inotify_init());
|
|
LxtCheckErrno(Id2 = inotify_init());
|
|
LxtCheckErrno(Wd[0] = inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS));
|
|
|
|
//
|
|
// Check that "output params" can also be specified as input.
|
|
//
|
|
|
|
LxtCheckErrno(Wd[1] = inotify_add_watch(Id1, BaseDir, IN_ALL_EVENTS | IN_IGNORED | IN_ISDIR | IN_Q_OVERFLOW | IN_UNMOUNT));
|
|
|
|
LxtCheckEqual(Wd[0], 1, "%d");
|
|
LxtCheckEqual(Wd[1], 2, "%d");
|
|
|
|
//
|
|
// Test IN_OPEN, IN_ATTRIB, IN_MODIFY, IN_ACCESS, IN_CLOSE_WRITE.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDWR));
|
|
LxtCheckErrnoZeroSuccess(fchmod(Fd, 0666));
|
|
LxtCheckErrno(Bytes = write(Fd, Buf, 10));
|
|
LxtCheckEqual(Bytes, 10, "%d");
|
|
LxtCheckErrno(Bytes = write(Fd, Buf, 10));
|
|
LxtCheckEqual(Bytes, 10, "%d");
|
|
LxtCheckErrnoZeroSuccess(lseek(Fd, 0, SEEK_SET));
|
|
LxtCheckErrno(Bytes = read(Fd, Buf, 10));
|
|
LxtCheckEqual(Bytes, 10, "%d");
|
|
LxtCheckErrno(Bytes = read(Fd, Buf, 10));
|
|
LxtCheckEqual(Bytes, 10, "%d");
|
|
LxtCheckErrnoZeroSuccess(fchmod(Fd, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 16, "%d");
|
|
for (Index = 0; Index < 2; Index++)
|
|
{
|
|
LxtCheckEqual(Events[0 + Index]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[2 + Index]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[4 + Index]->mask, IN_MODIFY, "%d");
|
|
LxtCheckEqual(Events[6 + Index]->mask, IN_MODIFY, "%d");
|
|
LxtCheckEqual(Events[8 + Index]->mask, IN_ACCESS, "%d");
|
|
LxtCheckEqual(Events[10 + Index]->mask, IN_ACCESS, "%d");
|
|
LxtCheckEqual(Events[12 + Index]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[14 + Index]->mask, IN_CLOSE_WRITE, "%d");
|
|
}
|
|
|
|
for (Index = 0; Index < NumEvents; Index++)
|
|
{
|
|
LxtCheckEqual(Events[Index]->cookie, 0, "%d");
|
|
if ((Index % 2) == 0)
|
|
{
|
|
|
|
//
|
|
// The parent directory.
|
|
//
|
|
|
|
LxtCheckEqual(Events[Index]->wd, 2, "%d");
|
|
LxtCheckTrue(strcmp(Events[Index]->name, INOTIFY_TEST_FILE1_NAME_ONLY) == 0);
|
|
LxtCheckNotEqual(Events[Index]->len, 0, "%d");
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// The file (child).
|
|
//
|
|
|
|
LxtCheckEqual(Events[Index]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[Index]->len, 0, "%d");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Test IN_CLOSE_NOWRITE.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDONLY));
|
|
LxtCheckErrno(Bytes = read(Fd, Buf, 10));
|
|
LxtCheckEqual(Bytes, 10, "%d");
|
|
LxtCheckErrno(Bytes = read(Fd, Buf, 10));
|
|
LxtCheckEqual(Bytes, 10, "%d");
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 8, "%d");
|
|
|
|
//
|
|
// Test that opening an existing file with O_TRUNC generates IN_MODIFY,
|
|
// even if the open is for read-only access.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDONLY | O_TRUNC));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 6, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_MODIFY, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_MODIFY, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[4]->mask, IN_CLOSE_NOWRITE, "%d");
|
|
LxtCheckEqual(Events[5]->mask, IN_CLOSE_NOWRITE, "%d");
|
|
|
|
//
|
|
// Test that opening an existing file with only O_PATH generates IN_OPEN.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_PATH));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 4, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_CLOSE_NOWRITE, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_CLOSE_NOWRITE, "%d");
|
|
|
|
//
|
|
// Test IN_MOVED_FROM, IN_MOVED_TO, IN_MOVE_SELF
|
|
// (rename with no overwrite).
|
|
//
|
|
|
|
LxtCheckErrnoZeroSuccess(rename(TestFile1, TestFile2));
|
|
LxtCheckErrnoZeroSuccess(rename(TestFile2, TestFile1));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 6, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_MOVED_FROM, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_MOVED_TO, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_MOVE_SELF, "%d");
|
|
LxtCheckEqual(Events[0]->cookie, Events[1]->cookie, "%d");
|
|
LxtCheckTrue(strcmp(Events[0]->name, INOTIFY_TEST_FILE1_NAME_ONLY) == 0);
|
|
LxtCheckTrue(strcmp(Events[1]->name, INOTIFY_TEST_FILE2_NAME_ONLY) == 0);
|
|
|
|
//
|
|
// Test IN_DELETE and IN_DELETE_SELF.
|
|
//
|
|
|
|
LxtCheckErrnoZeroSuccess(unlink(TestFile1));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 4, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_DELETE_SELF, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_IGNORED, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_DELETE, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[1]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[2]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[3]->wd, 2, "%d");
|
|
//
|
|
// Test IN_CREATE, and that inotify_rm_watch() generates IN_IGNORED.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrno(Wd[0] = inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS));
|
|
LxtCheckErrnoZeroSuccess(inotify_rm_watch(Id1, Wd[0]));
|
|
LxtCheckErrnoZeroSuccess(inotify_rm_watch(Id1, Wd[1]));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 5, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_CREATE, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_CLOSE_WRITE, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_IGNORED, "%d");
|
|
LxtCheckEqual(Events[4]->mask, IN_IGNORED, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[1]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[2]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[3]->wd, 3, "%d");
|
|
LxtCheckEqual(Events[4]->wd, 2, "%d");
|
|
|
|
//
|
|
// Test that IN_ONESHOT generates only one event and then IN_IGNORED.
|
|
//
|
|
|
|
LxtCheckErrno(Wd[0] = inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS | IN_ONESHOT));
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDONLY));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 2, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_IGNORED, "%d");
|
|
|
|
//
|
|
// Test IN_ONLYDIR on file, should fail.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(Wd[1] = inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS | IN_ONLYDIR), ENOTDIR);
|
|
|
|
//
|
|
// Test operations on directories.
|
|
//
|
|
|
|
LxtCheckErrno(Wd[1] = inotify_add_watch(Id1, BaseDir, IN_ALL_EVENTS | IN_ONLYDIR));
|
|
|
|
LxtCheckErrno(Fd = open(BaseDir, O_RDONLY));
|
|
LxtCheckErrnoZeroSuccess(fchmod(Fd, 0666));
|
|
LxtCheckErrnoZeroSuccess(fchmod(Fd, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 3, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN | IN_ISDIR, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_ATTRIB | IN_ISDIR, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_CLOSE_NOWRITE | IN_ISDIR, "%d");
|
|
|
|
//
|
|
// Test creating a symbolic link.
|
|
//
|
|
|
|
LxtCheckErrno(Wd[0] = inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS));
|
|
LxtCheckErrnoZeroSuccess(symlink(TestFile1, TestFile1Slink));
|
|
|
|
//
|
|
// Verify.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 1, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_CREATE, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 5, "%d");
|
|
LxtCheckTrue(strcmp(Events[0]->name, INOTIFY_TEST_FILE1_SLINK_NAME_ONLY) == 0);
|
|
|
|
//
|
|
// Test creating a hard link.
|
|
//
|
|
|
|
LxtCheckErrnoZeroSuccess(link(TestFile1, TestFile1Hlink));
|
|
|
|
//
|
|
// Verify. Note that Ubuntu generates 2 events, whereas WSL generates 4 events.
|
|
// This is due to WSL performing unnecessary file opens, which will be fixed
|
|
// in the future. Also, the ordering of the events differs between Ubuntu and WSL.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckTrue((NumEvents == 2) || (NumEvents == 4));
|
|
if (Events[0]->mask == IN_ATTRIB)
|
|
{
|
|
AttribEvent = 0;
|
|
CreateEvent = 1;
|
|
}
|
|
else
|
|
{
|
|
AttribEvent = 1;
|
|
CreateEvent = 0;
|
|
}
|
|
|
|
LxtCheckEqual(Events[AttribEvent]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[AttribEvent]->wd, 6, "%d");
|
|
LxtCheckEqual(Events[CreateEvent]->mask, IN_CREATE, "%d");
|
|
LxtCheckEqual(Events[CreateEvent]->wd, 5, "%d");
|
|
LxtCheckTrue(strcmp(Events[CreateEvent]->name, INOTIFY_TEST_FILE1_HLINK_NAME_ONLY) == 0);
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
close(Id1);
|
|
close(Id2);
|
|
close(Fd);
|
|
unlink(TestFile1);
|
|
unlink(TestFile2);
|
|
unlink(TestFile1Hlink);
|
|
unlink(TestFile1Slink);
|
|
rmdir(BaseDir);
|
|
return Result;
|
|
}
|
|
|
|
int TestInotifyComprehensive2Lxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
return TestInotifyComprehensive2Common(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
}
|
|
|
|
int TestInotifyComprehensive2Common(char* BaseDir)
|
|
|
|
/*++
|
|
--*/
|
|
|
|
{
|
|
|
|
int Fd;
|
|
int Id1;
|
|
int Id2;
|
|
int Wd[10];
|
|
char Buf[10];
|
|
char InotifyBuf[500];
|
|
struct inotify_event* Events[INOTIFY_TEST_EVENTS_BUF_SIZE];
|
|
int NumEvents;
|
|
int Bytes;
|
|
int Result;
|
|
char TestFile1[PATH_MAX];
|
|
char TestFile2[PATH_MAX];
|
|
char TestFile1Hlink[PATH_MAX];
|
|
char TestFile1Slink[PATH_MAX];
|
|
|
|
//
|
|
// Initialize and also do cleanup if the files have not been removed.
|
|
//
|
|
|
|
sprintf(TestFile1, "%s%s", BaseDir, INOTIFY_TEST_FILE1_NAME_ONLY);
|
|
sprintf(TestFile2, "%s%s", BaseDir, INOTIFY_TEST_FILE2_NAME_ONLY);
|
|
sprintf(TestFile1Hlink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_HLINK_NAME_ONLY);
|
|
sprintf(TestFile1Slink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_SLINK_NAME_ONLY);
|
|
unlink(TestFile1);
|
|
unlink(TestFile2);
|
|
unlink(TestFile1Hlink);
|
|
unlink(TestFile1Slink);
|
|
rmdir(BaseDir);
|
|
LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Setup inotify.
|
|
//
|
|
|
|
LxtCheckErrno(Id1 = inotify_init());
|
|
LxtCheckErrno(Id2 = inotify_init());
|
|
|
|
//
|
|
// Test IN_EXCL_UNLINK on both the directory and the file to be unlinked.
|
|
// Also test deleting a file that has open handles to it.
|
|
//
|
|
|
|
LxtCheckErrno(
|
|
Wd[0] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS | IN_EXCL_UNLINK));
|
|
|
|
LxtCheckErrno(
|
|
Wd[1] = // wd: 2
|
|
inotify_add_watch(Id1, BaseDir, IN_ALL_EVENTS | IN_EXCL_UNLINK));
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDWR));
|
|
unlink(TestFile1);
|
|
LxtCheckErrno(Bytes = write(Fd, Buf, 10));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify. Note that the write and close on the unlinked file did not
|
|
// generate any events on either the directory or the file since the
|
|
// IN_EXCL_UNLINK flag was set on both.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 6, "%d");
|
|
LxtCheckEqual(Wd[0], 1, "%d");
|
|
LxtCheckEqual(Wd[1], 2, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_DELETE, "%d");
|
|
LxtCheckEqual(Events[4]->mask, IN_DELETE_SELF, "%d");
|
|
LxtCheckEqual(Events[5]->mask, IN_IGNORED, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[1]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[2]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[3]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[4]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[5]->wd, 1, "%d");
|
|
|
|
//
|
|
// Test IN_EXCL_UNLINK on the directory only.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrnoZeroSuccess(close(Id1));
|
|
LxtCheckErrno(Id1 = inotify_init());
|
|
LxtCheckErrno(
|
|
Wd[0] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS));
|
|
|
|
LxtCheckErrno(
|
|
Wd[1] = // wd: 2
|
|
inotify_add_watch(Id1, BaseDir, IN_ALL_EVENTS | IN_EXCL_UNLINK));
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDWR));
|
|
unlink(TestFile1);
|
|
LxtCheckErrno(Bytes = write(Fd, Buf, 10));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify. Note that the file events are still generated even though it was
|
|
// unlinked, because the file does not have the IN_EXCL_UNLINK flag set.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 8, "%d");
|
|
LxtCheckEqual(Wd[0], 1, "%d");
|
|
LxtCheckEqual(Wd[1], 2, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_DELETE, "%d");
|
|
LxtCheckEqual(Events[4]->mask, IN_MODIFY, "%d");
|
|
LxtCheckEqual(Events[5]->mask, IN_CLOSE_WRITE, "%d");
|
|
LxtCheckEqual(Events[6]->mask, IN_DELETE_SELF, "%d");
|
|
LxtCheckEqual(Events[7]->mask, IN_IGNORED, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[1]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[2]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[3]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[4]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[5]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[6]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[7]->wd, 1, "%d");
|
|
|
|
//
|
|
// Test IN_EXCL_UNLINK on the unlinked file only.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrnoZeroSuccess(close(Id1));
|
|
LxtCheckErrno(Id1 = inotify_init());
|
|
LxtCheckErrno(
|
|
Wd[0] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_ALL_EVENTS | IN_EXCL_UNLINK));
|
|
|
|
LxtCheckErrno(
|
|
Wd[1] = // wd: 2
|
|
inotify_add_watch(Id1, BaseDir, IN_ALL_EVENTS));
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDWR));
|
|
unlink(TestFile1);
|
|
LxtCheckErrno(Bytes = write(Fd, Buf, 10));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify. Note that the directory still receives the events from the unlinked
|
|
// child, because the directory does not have the IN_EXCL_UNLINK flag set.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 8, "%d");
|
|
LxtCheckEqual(Wd[0], 1, "%d");
|
|
LxtCheckEqual(Wd[1], 2, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[2]->mask, IN_ATTRIB, "%d");
|
|
LxtCheckEqual(Events[3]->mask, IN_DELETE, "%d");
|
|
LxtCheckEqual(Events[4]->mask, IN_MODIFY, "%d");
|
|
LxtCheckEqual(Events[5]->mask, IN_CLOSE_WRITE, "%d");
|
|
LxtCheckEqual(Events[6]->mask, IN_DELETE_SELF, "%d");
|
|
LxtCheckEqual(Events[7]->mask, IN_IGNORED, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[1]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[2]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[3]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[4]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[5]->wd, 2, "%d");
|
|
LxtCheckEqual(Events[6]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[7]->wd, 1, "%d");
|
|
|
|
//
|
|
// Test watching the same file twice.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrnoZeroSuccess(close(Id1));
|
|
LxtCheckErrno(Id1 = inotify_init());
|
|
LxtCheckErrno(
|
|
Wd[0] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_OPEN));
|
|
|
|
LxtCheckErrno(
|
|
Wd[1] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_CLOSE));
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_WRONLY));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify that IN_CLOSE_WRITE is received, and that IN_OPEN is not received.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 1, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_CLOSE_WRITE, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 1, "%d");
|
|
LxtCheckEqual(Wd[0], Wd[1], "%d");
|
|
|
|
//
|
|
// Test watching the same file twice, but with IN_MASK_ADD.
|
|
//
|
|
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
LxtCheckErrnoZeroSuccess(close(Id1));
|
|
LxtCheckErrno(Id1 = inotify_init());
|
|
LxtCheckErrno(
|
|
Wd[0] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_OPEN));
|
|
|
|
LxtCheckErrno(
|
|
Wd[1] = // wd: 1
|
|
inotify_add_watch(Id1, TestFile1, IN_CLOSE | IN_MASK_ADD));
|
|
|
|
LxtCheckErrno(Fd = open(TestFile1, O_RDONLY));
|
|
LxtCheckErrnoZeroSuccess(close(Fd));
|
|
|
|
//
|
|
// Verify that both IN_OPEN and IN_CLOSE_NOWRITE are received.
|
|
//
|
|
|
|
LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
|
|
|
|
LxtCheckEqual(NumEvents, 2, "%d");
|
|
LxtCheckEqual(Events[0]->mask, IN_OPEN, "%d");
|
|
LxtCheckEqual(Events[1]->mask, IN_CLOSE_NOWRITE, "%d");
|
|
LxtCheckEqual(Events[0]->wd, 1, "%d");
|
|
LxtCheckEqual(Events[1]->wd, 1, "%d");
|
|
LxtCheckEqual(Wd[0], Wd[1], "%d");
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
close(Id1);
|
|
close(Id2);
|
|
close(Fd);
|
|
unlink(TestFile1);
|
|
rmdir(BaseDir);
|
|
return Result;
|
|
}
|
|
|
|
int TestInotifyPosixUnlinkRenameLxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
return LxtFsInotifyPosixUnlinkRenameCommon(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
}
|
|
|
|
int TestInotifyUnmountBindLxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
return LxtFsInotifyUnmountBindCommon(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
}
|
|
|
|
int TestInotifyFtruncateLxfs(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
int ChildPid;
|
|
int Fd;
|
|
struct pollfd PollFd;
|
|
int Result;
|
|
char TestFile1[PATH_MAX];
|
|
|
|
ChildPid = -1;
|
|
Fd = -1;
|
|
|
|
//
|
|
// Initialize and also do cleanup if the files have not been removed.
|
|
//
|
|
|
|
sprintf(TestFile1, "%s%s", INOTIFY_TEST_BASE_DIR_LXFS, INOTIFY_TEST_FILE1_NAME_ONLY);
|
|
|
|
unlink(TestFile1);
|
|
rmdir(INOTIFY_TEST_BASE_DIR_LXFS);
|
|
LxtCheckErrnoZeroSuccess(mkdir(INOTIFY_TEST_BASE_DIR_LXFS, 0777));
|
|
LxtCheckErrno(Fd = creat(TestFile1, 0777));
|
|
LxtCheckErrno(ftruncate(Fd, 1024));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
sleep(2);
|
|
LxtCheckErrno(ftruncate(Fd, 1024));
|
|
fsync(Fd);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
int Id = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
|
LxtCheckErrno(inotify_add_watch(Id, TestFile1, IN_ALL_EVENTS));
|
|
PollFd.fd = Id;
|
|
PollFd.events = POLLIN;
|
|
LxtCheckErrno(ppoll(&PollFd, 1, NULL, NULL));
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (Fd != -1)
|
|
{
|
|
LxtClose(Fd);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int TestInotifyPseudoPlugin(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
int Id;
|
|
int Result;
|
|
|
|
LxtCheckErrno(Id = inotify_init());
|
|
LxtCheckErrno(inotify_add_watch(Id, "/proc/self/ns/pid", IN_ALL_EVENTS));
|
|
|
|
ErrorExit:
|
|
if (Id != -1)
|
|
{
|
|
LxtClose(Id);
|
|
}
|
|
|
|
return Result;
|
|
}
|