sys: notify implementation

This commit is contained in:
Bill Zissimopoulos 2020-10-08 20:49:24 -07:00
parent 88edf5723e
commit a004e4be10
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
4 changed files with 141 additions and 20 deletions

View File

@ -1699,6 +1699,28 @@ UINT32 FspFileSystemGetEaPackedSize(PFILE_FULL_EA_INFORMATION SingleEa)
/* magic computations are courtesy of NTFS */ /* magic computations are courtesy of NTFS */
return 5 + SingleEa->EaNameLength + SingleEa->EaValueLength; return 5 + SingleEa->EaNameLength + SingleEa->EaValueLength;
} }
/**
* Add notify information to a buffer.
*
* This is a helper for filling a buffer to use with FspFileSystemNotify.
*
* @param NotifyInfo
* The notify information to add.
* @param Buffer
* Pointer to a buffer that will receive the notify information.
* @param Length
* Length of buffer.
* @param PBytesTransferred [out]
* Pointer to a memory location that will receive the actual number of bytes stored. This should
* be initialized to 0 prior to the first call to FspFileSystemAddNotifyInfo for a particular
* buffer.
* @return
* TRUE if the notify information was added, FALSE if there was not enough space to add it.
* @see
* FspFileSystemNotify
*/
FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred);
/* /*
* Directory buffering * Directory buffering

View File

@ -1866,3 +1866,9 @@ FSP_API BOOLEAN FspFileSystemAddEa(PFILE_FULL_EA_INFORMATION SingleEa,
return TRUE; return TRUE;
} }
FSP_API BOOLEAN FspFileSystemAddNotifyInfo(FSP_FSCTL_NOTIFY_INFO *NotifyInfo,
PVOID Buffer, ULONG Length, PULONG PBytesTransferred)
{
return FspFileSystemAddXxxInfo(NotifyInfo, Buffer, Length, PBytesTransferred);
}

View File

@ -1068,10 +1068,10 @@ NTSTATUS FspVolumeStop(
typedef struct typedef struct
{ {
PDEVICE_OBJECT FsvolDeviceObject;
PVOID InputBuffer;
ULONG InputBufferLength;
WORK_QUEUE_ITEM WorkItem; WORK_QUEUE_ITEM WorkItem;
PDEVICE_OBJECT FsvolDeviceObject;
ULONG InputBufferLength;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 InputBuffer[];
} FSP_VOLUME_NOTIFY_WORK_ITEM; } FSP_VOLUME_NOTIFY_WORK_ITEM;
NTSTATUS FspVolumeNotify( NTSTATUS FspVolumeNotify(
@ -1108,22 +1108,14 @@ NTSTATUS FspVolumeNotify(
if (!FspDeviceReference(FsvolDeviceObject)) if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED; return STATUS_CANCELLED;
NotifyWorkItem = FspAllocNonPaged(sizeof *NotifyWorkItem); NotifyWorkItem = FspAllocNonPaged(
FIELD_OFFSET(FSP_VOLUME_NOTIFY_WORK_ITEM, InputBuffer) + InputBufferLength);
if (0 == NotifyWorkItem) if (0 == NotifyWorkItem)
{ {
Result = STATUS_INSUFFICIENT_RESOURCES; Result = STATUS_INSUFFICIENT_RESOURCES;
goto fail; goto fail;
} }
NotifyWorkItem->FsvolDeviceObject = FsvolDeviceObject;
NotifyWorkItem->InputBuffer = FspAllocNonPaged(InputBufferLength);
if (0 == NotifyWorkItem->InputBuffer)
{
Result = STATUS_INSUFFICIENT_RESOURCES;
goto fail;
}
try try
{ {
ProbeForRead(InputBuffer, InputBufferLength, 1); ProbeForRead(InputBuffer, InputBufferLength, 1);
@ -1138,17 +1130,14 @@ NTSTATUS FspVolumeNotify(
} }
ExInitializeWorkItem(&NotifyWorkItem->WorkItem, FspVolumeNotifyWork, NotifyWorkItem); ExInitializeWorkItem(&NotifyWorkItem->WorkItem, FspVolumeNotifyWork, NotifyWorkItem);
NotifyWorkItem->FsvolDeviceObject = FsvolDeviceObject;
ExQueueWorkItem(&NotifyWorkItem->WorkItem, DelayedWorkQueue); ExQueueWorkItem(&NotifyWorkItem->WorkItem, DelayedWorkQueue);
return STATUS_SUCCESS; return STATUS_SUCCESS;
fail: fail:
if (0 != NotifyWorkItem) if (0 != NotifyWorkItem)
{
if (0 != NotifyWorkItem->InputBuffer)
FspFree(NotifyWorkItem->InputBuffer);
FspFree(NotifyWorkItem); FspFree(NotifyWorkItem);
}
FspDeviceDereference(FsvolDeviceObject); FspDeviceDereference(FsvolDeviceObject);
@ -1202,7 +1191,7 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
FSP_VOLUME_NOTIFY_WORK_ITEM *NotifyWorkItem = NotifyWorkItem0; FSP_VOLUME_NOTIFY_WORK_ITEM *NotifyWorkItem = NotifyWorkItem0;
PDEVICE_OBJECT FsvolDeviceObject = NotifyWorkItem->FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject = NotifyWorkItem->FsvolDeviceObject;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
FSP_FSCTL_NOTIFY_INFO *NotifyInfo = NotifyWorkItem->InputBuffer; FSP_FSCTL_NOTIFY_INFO *NotifyInfo = (PVOID)NotifyWorkItem->InputBuffer;
PUINT8 NotifyInfoEnd = (PUINT8)NotifyInfo + NotifyWorkItem->InputBufferLength; PUINT8 NotifyInfoEnd = (PUINT8)NotifyInfo + NotifyWorkItem->InputBufferLength;
ULONG NotifyInfoSize; ULONG NotifyInfoSize;
UNICODE_STRING FileName = { 0 }, StreamPart = { 0 }, AbsFileName = { 0 }, FullFileName = { 0 }; UNICODE_STRING FileName = { 0 }, StreamPart = { 0 }, AbsFileName = { 0 }, FullFileName = { 0 };
@ -1217,6 +1206,7 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
if (sizeof(FSP_FSCTL_NOTIFY_INFO) > NotifyInfoSize) if (sizeof(FSP_FSCTL_NOTIFY_INFO) > NotifyInfoSize)
{ {
/* !!!: we should wait until all pending notify work is done! */
if (1 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 0, 1)) if (1 == InterlockedCompareExchange(&FsvolDeviceExtension->VolumeNotifyLock, 0, 1))
FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, FsvolDeviceObject); FspFsvolDeviceFileRenameReleaseOwner(FsvolDeviceObject, FsvolDeviceObject);
break; break;
@ -1257,7 +1247,7 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
{ {
if (sizeof(WCHAR) * 2/* not empty or root */ <= AbsFileName.Length && if (sizeof(WCHAR) * 2/* not empty or root */ <= AbsFileName.Length &&
L'\\' == AbsFileName.Buffer[AbsFileName.Length / sizeof(WCHAR) - 1]) L'\\' != AbsFileName.Buffer[AbsFileName.Length / sizeof(WCHAR) - 1])
Result = RtlAppendUnicodeToString(&FullFileName, L"\\"); Result = RtlAppendUnicodeToString(&FullFileName, L"\\");
} }
if (NT_SUCCESS(Result)) if (NT_SUCCESS(Result))
@ -1273,7 +1263,6 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
if (0 != FullFileName.Buffer) if (0 != FullFileName.Buffer)
FspFree(FullFileName.Buffer); FspFree(FullFileName.Buffer);
FspFree(NotifyWorkItem->InputBuffer);
FspFree(NotifyWorkItem); FspFree(NotifyWorkItem);
FspDeviceDereference(FsvolDeviceObject); FspDeviceDereference(FsvolDeviceObject);

View File

@ -151,6 +151,109 @@ void notify_timeout_test(void)
notify_timeout_dotest(MemfsNet); notify_timeout_dotest(MemfsNet);
} }
static
void notify_change_dotest(ULONG Flags)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[1024];
} Buffer;
ULONG Length = 0;
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[sizeof(FSP_FSCTL_NOTIFY_INFO) + MAX_PATH * sizeof(WCHAR)];
} NotifyInfo;
PWSTR FileName;
NTSTATUS Result;
Result = FspFileSystemNotifyBegin(FileSystem, 0);
ASSERT(STATUS_SUCCESS == Result);
FileName = L"\\";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"bar";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"baz";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"\\foo";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"bar";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"baz";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"\\foo\\";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"bar";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
FileName = L"baz";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = 0;
NotifyInfo.V.Action = 0;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
FspFileSystemAddNotifyInfo(&NotifyInfo.V, &Buffer, sizeof Buffer, &Length);
Result = FspFileSystemNotify(FileSystem, &Buffer.V, Length);
ASSERT(STATUS_SUCCESS == Result);
Result = FspFileSystemNotifyEnd(FileSystem);
ASSERT(STATUS_SUCCESS == Result);
memfs_stop(memfs);
}
static
void notify_change_test(void)
{
if (WinFspDiskTests)
notify_change_dotest(MemfsDisk);
if (WinFspNetTests)
notify_change_dotest(MemfsNet);
}
void notify_tests(void) void notify_tests(void)
{ {
if (!OptExternal) if (!OptExternal)
@ -158,5 +261,6 @@ void notify_tests(void)
TEST(notify_abandon_test); TEST(notify_abandon_test);
TEST(notify_abandon_rename_test); TEST(notify_abandon_rename_test);
TEST(notify_timeout_test); TEST(notify_timeout_test);
TEST(notify_change_test);
} }
} }