mirror of
https://github.com/reactos/reactos.git
synced 2025-04-20 12:29:56 +00:00
init. work on a notify-directory impl.
svn path=/trunk/; revision=13790
This commit is contained in:
parent
2093306969
commit
926067bd87
3 changed files with 292 additions and 111 deletions
|
@ -1102,10 +1102,11 @@ typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct _FILE_NOTIFY_INFORMATION {
|
typedef struct _FILE_NOTIFY_INFORMATION {
|
||||||
|
ULONG NextEntryOffset;
|
||||||
ULONG Action;
|
ULONG Action;
|
||||||
ULONG FileNameLength;
|
ULONG NameLength;
|
||||||
WCHAR FileName[0];
|
WCHAR Name[1];
|
||||||
} FILE_NOTIFY_INFORMATION;
|
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
|
||||||
|
|
||||||
#define FSCTL_GET_VOLUME_BITMAP 0x9006F
|
#define FSCTL_GET_VOLUME_BITMAP 0x9006F
|
||||||
#define FSCTL_GET_RETRIEVAL_POINTERS 0x90073
|
#define FSCTL_GET_RETRIEVAL_POINTERS 0x90073
|
||||||
|
|
|
@ -9,36 +9,36 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
#define NDEBUG
|
|
||||||
|
//#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
|
||||||
PAGED_LOOKASIDE_LIST NotifyEntryLookaside;
|
PAGED_LOOKASIDE_LIST NotifyEntryLookaside;
|
||||||
|
|
||||||
|
#define FSRTL_NOTIFY_TAG TAG('N','O','T','I')
|
||||||
|
|
||||||
typedef struct _NOTIFY_ENTRY
|
typedef struct _NOTIFY_ENTRY
|
||||||
{
|
{
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
PSTRING FullDirectoryName;
|
PSTRING FullDirectoryName;
|
||||||
BOOLEAN WatchTree;
|
BOOLEAN WatchTree;
|
||||||
BOOLEAN IgnoreBuffer;
|
BOOLEAN IgnoreBuffer;
|
||||||
|
BOOLEAN PendingChanges;
|
||||||
ULONG CompletionFilter;
|
ULONG CompletionFilter;
|
||||||
LIST_ENTRY IrpQueue;
|
LIST_ENTRY IrpQueue;
|
||||||
PVOID Fcb;
|
PVOID Fcb;
|
||||||
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback;
|
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback;
|
||||||
PSECURITY_SUBJECT_CONTEXT SubjectContext;
|
PSECURITY_SUBJECT_CONTEXT SubjectContext;
|
||||||
PVOID FsContext;
|
PVOID FsContext;
|
||||||
LIST_ENTRY BufferedChangesList;
|
BOOLEAN Unicode;
|
||||||
|
BOOLEAN BufferExhausted;
|
||||||
|
PVOID Buffer; /* Buffer == NULL equals IgnoreBuffer == TRUE */
|
||||||
|
ULONG BufferSize;
|
||||||
|
ULONG NextEntryOffset;
|
||||||
|
PFILE_NOTIFY_INFORMATION PrevEntry;
|
||||||
} NOTIFY_ENTRY, *PNOTIFY_ENTRY;
|
} NOTIFY_ENTRY, *PNOTIFY_ENTRY;
|
||||||
|
|
||||||
typedef struct _BUFFERED_CHANGE
|
|
||||||
{
|
|
||||||
LIST_ENTRY ListEntry;
|
|
||||||
ULONG Action;
|
|
||||||
USHORT NameLen;
|
|
||||||
WCHAR RelativeName[1];
|
|
||||||
|
|
||||||
} BUFFERED_CHANGE, *PBUFFERED_CHANGE;
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* NAME PRIVATE
|
* NAME PRIVATE
|
||||||
|
@ -54,7 +54,7 @@ FsRtlpInitNotifyImplementation(VOID)
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
sizeof(NOTIFY_ENTRY),
|
sizeof(NOTIFY_ENTRY),
|
||||||
0 /* FSRTL_NOTIFY_TAG*/,
|
FSRTL_NOTIFY_TAG,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -63,6 +63,21 @@ FsRtlpInitNotifyImplementation(VOID)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
BOOLEAN
|
||||||
|
FsRtlpIsUnicodePath(
|
||||||
|
PSTRING Path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ASSERT(Path->Length);
|
||||||
|
|
||||||
|
if (Path->Length == 1) return FALSE;
|
||||||
|
|
||||||
|
if (*(WCHAR*)Path->Buffer == '\\') return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
@ -188,7 +203,6 @@ FsRtlNotifyCleanup (
|
||||||
PNOTIFY_ENTRY NotifyEntry;
|
PNOTIFY_ENTRY NotifyEntry;
|
||||||
LIST_ENTRY CompletedListHead;
|
LIST_ENTRY CompletedListHead;
|
||||||
PLIST_ENTRY TmpEntry;
|
PLIST_ENTRY TmpEntry;
|
||||||
PBUFFERED_CHANGE BufferedChange;
|
|
||||||
PIRP Irp;
|
PIRP Irp;
|
||||||
|
|
||||||
InitializeListHead(&CompletedListHead);
|
InitializeListHead(&CompletedListHead);
|
||||||
|
@ -200,11 +214,9 @@ FsRtlNotifyCleanup (
|
||||||
if (NotifyEntry)
|
if (NotifyEntry)
|
||||||
{
|
{
|
||||||
/* free buffered changes */
|
/* free buffered changes */
|
||||||
while (!IsListEmpty(&NotifyEntry->BufferedChangesList))
|
if (NotifyEntry->Buffer)
|
||||||
{
|
{
|
||||||
TmpEntry = RemoveHeadList(&NotifyEntry->BufferedChangesList);
|
ExFreePool(NotifyEntry->Buffer);
|
||||||
BufferedChange = CONTAINING_RECORD(TmpEntry , BUFFERED_CHANGE, ListEntry);
|
|
||||||
ExFreePool(BufferedChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cancel(?) pending irps */
|
/* cancel(?) pending irps */
|
||||||
|
@ -303,7 +315,6 @@ FsRtlpWatchedDirectoryWasDeleted(
|
||||||
LIST_ENTRY CompletedListHead;
|
LIST_ENTRY CompletedListHead;
|
||||||
PLIST_ENTRY EnumEntry, TmpEntry;
|
PLIST_ENTRY EnumEntry, TmpEntry;
|
||||||
PNOTIFY_ENTRY NotifyEntry;
|
PNOTIFY_ENTRY NotifyEntry;
|
||||||
PBUFFERED_CHANGE BufferedChange;
|
|
||||||
PIRP Irp;
|
PIRP Irp;
|
||||||
|
|
||||||
InitializeListHead(&CompletedListHead);
|
InitializeListHead(&CompletedListHead);
|
||||||
|
@ -317,14 +328,12 @@ FsRtlpWatchedDirectoryWasDeleted(
|
||||||
RemoveEntryList(&NotifyEntry->ListEntry);
|
RemoveEntryList(&NotifyEntry->ListEntry);
|
||||||
|
|
||||||
/* free buffered changes */
|
/* free buffered changes */
|
||||||
while (!IsListEmpty(&NotifyEntry->BufferedChangesList))
|
if (NotifyEntry->Buffer)
|
||||||
{
|
{
|
||||||
TmpEntry = RemoveHeadList(&NotifyEntry->BufferedChangesList);
|
ExFreePool(NotifyEntry->Buffer);
|
||||||
BufferedChange = CONTAINING_RECORD(TmpEntry , BUFFERED_CHANGE, ListEntry);
|
|
||||||
ExFreePool(BufferedChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cancel(?) pending irps */
|
/* cleanup pending irps */
|
||||||
while (!IsListEmpty(&NotifyEntry->IrpQueue))
|
while (!IsListEmpty(&NotifyEntry->IrpQueue))
|
||||||
{
|
{
|
||||||
TmpEntry = RemoveHeadList(&NotifyEntry->IrpQueue);
|
TmpEntry = RemoveHeadList(&NotifyEntry->IrpQueue);
|
||||||
|
@ -338,7 +347,7 @@ FsRtlpWatchedDirectoryWasDeleted(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Irp->IoStatus.Status = STATUS_NOTIFY_CLEANUP; /* FIXME: correct status? */
|
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
|
|
||||||
/* avoid holding lock while completing irp */
|
/* avoid holding lock while completing irp */
|
||||||
|
@ -359,6 +368,11 @@ FsRtlpWatchedDirectoryWasDeleted(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* NAME EXPORTED
|
* NAME EXPORTED
|
||||||
* FsRtlNotifyFullChangeDirectory@40
|
* FsRtlNotifyFullChangeDirectory@40
|
||||||
|
@ -388,8 +402,7 @@ FsRtlNotifyFullChangeDirectory (
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IrpStack;
|
PIO_STACK_LOCATION IrpStack;
|
||||||
PNOTIFY_ENTRY NotifyEntry;
|
PNOTIFY_ENTRY NotifyEntry;
|
||||||
PBUFFERED_CHANGE BufferedChange;
|
ULONG IrpBuffLen;
|
||||||
PLIST_ENTRY TmpEntry;
|
|
||||||
|
|
||||||
if (!NotifyIrp)
|
if (!NotifyIrp)
|
||||||
{
|
{
|
||||||
|
@ -398,6 +411,8 @@ FsRtlNotifyFullChangeDirectory (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DPRINT("FullDirectoryName: %wZ\n", FullDirectoryName);
|
||||||
|
|
||||||
ExAcquireFastMutex((PFAST_MUTEX)NotifySync);
|
ExAcquireFastMutex((PFAST_MUTEX)NotifySync);
|
||||||
|
|
||||||
IrpStack = IoGetCurrentIrpStackLocation(NotifyIrp);
|
IrpStack = IoGetCurrentIrpStackLocation(NotifyIrp);
|
||||||
|
@ -411,39 +426,61 @@ FsRtlNotifyFullChangeDirectory (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IrpBuffLen = IrpStack->Parameters.NotifyDirectory.Length;
|
||||||
|
|
||||||
NotifyEntry = FsRtlpFindNotifyEntry(NotifyList, FsContext);
|
NotifyEntry = FsRtlpFindNotifyEntry(NotifyList, FsContext);
|
||||||
|
|
||||||
if (!NotifyEntry)
|
if (!NotifyEntry)
|
||||||
{
|
{
|
||||||
/* No NotifyStruct for this FileObject existed */
|
/* No NotifyStruct for this FileObject existed */
|
||||||
|
|
||||||
|
/* The first request for this FileObject set the standards.
|
||||||
|
* For subsequent requests, these params will be ignored.
|
||||||
|
* Ref: Windows NT File System Internals page 516
|
||||||
|
*/
|
||||||
|
|
||||||
NotifyEntry = ExAllocateFromPagedLookasideList(&NotifyEntryLookaside);
|
NotifyEntry = ExAllocateFromPagedLookasideList(&NotifyEntryLookaside);
|
||||||
|
|
||||||
|
RtlZeroMemory(NotifyEntry, sizeof(NOTIFY_ENTRY));
|
||||||
|
|
||||||
NotifyEntry->FsContext = FsContext;
|
NotifyEntry->FsContext = FsContext;
|
||||||
NotifyEntry->FullDirectoryName = FullDirectoryName;
|
NotifyEntry->FullDirectoryName = FullDirectoryName;
|
||||||
NotifyEntry->WatchTree = WatchTree;
|
NotifyEntry->WatchTree = WatchTree;
|
||||||
NotifyEntry->IgnoreBuffer = IgnoreBuffer;
|
|
||||||
NotifyEntry->CompletionFilter = CompletionFilter;
|
NotifyEntry->CompletionFilter = CompletionFilter;
|
||||||
NotifyEntry->TraverseCallback = TraverseCallback;
|
NotifyEntry->TraverseCallback = TraverseCallback;
|
||||||
NotifyEntry->SubjectContext = SubjectContext;
|
NotifyEntry->SubjectContext = SubjectContext;
|
||||||
NotifyEntry->Fcb = IrpStack->FileObject->FsContext;
|
NotifyEntry->Fcb = IrpStack->FileObject->FsContext;
|
||||||
|
NotifyEntry->Unicode = FsRtlpIsUnicodePath(FullDirectoryName);
|
||||||
|
|
||||||
|
/* Init. buffer */
|
||||||
|
if (IrpBuffLen && !IgnoreBuffer)
|
||||||
|
{
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
NotifyEntry->Buffer = ExAllocatePoolWithQuotaTag(
|
||||||
|
PagedPool,
|
||||||
|
IrpBuffLen,
|
||||||
|
FSRTL_NOTIFY_TAG
|
||||||
|
);
|
||||||
|
|
||||||
|
NotifyEntry->PrevEntry = NotifyEntry->Buffer;
|
||||||
|
NotifyEntry->BufferSize = IrpBuffLen;
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
/* ExAllocatePoolWithQuotaTag raised exception */
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
}
|
||||||
|
|
||||||
InitializeListHead(&NotifyEntry->IrpQueue);
|
InitializeListHead(&NotifyEntry->IrpQueue);
|
||||||
InitializeListHead(&NotifyEntry->BufferedChangesList);
|
|
||||||
|
|
||||||
InsertTailList(NotifyList, &NotifyEntry->ListEntry);
|
InsertTailList(NotifyList, &NotifyEntry->ListEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: this NotifyStruct allready have values for WatchTree, CompletionFilter etc.
|
|
||||||
* What if the WatchTree, CompletionFilter etc. params are different from
|
|
||||||
* those in the NotifyStruct? Should the params be ignored or should the params overwrite
|
|
||||||
* the "old" values in the NotifyStruct??
|
|
||||||
* STATUS: Currently we ignore these params for subsequesnt request.
|
|
||||||
*
|
|
||||||
* -Gunnar
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (IsListEmpty(&NotifyEntry->BufferedChangesList))
|
|
||||||
|
if (!NotifyEntry->PendingChanges)
|
||||||
{
|
{
|
||||||
/* No changes are pending. Queue the irp */
|
/* No changes are pending. Queue the irp */
|
||||||
|
|
||||||
|
@ -474,46 +511,44 @@ FsRtlNotifyFullChangeDirectory (
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Pending changes exist */
|
||||||
|
|
||||||
|
if (NotifyEntry->Buffer == NULL ||
|
||||||
/*
|
NotifyEntry->BufferExhausted ||
|
||||||
typedef struct _FILE_NOTIFY_INFORMATION {
|
IrpBuffLen < NotifyEntry->NextEntryOffset)
|
||||||
ULONG NextEntryOffset;
|
|
||||||
ULONG Action;
|
|
||||||
ULONG NameLength;
|
|
||||||
WCHAR Name[1];
|
|
||||||
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Buffered changes exist */
|
|
||||||
|
|
||||||
|
|
||||||
/* Copy as much buffered data as available/the buffer can hold */
|
|
||||||
while (!IsListEmpty(&NotifyEntry->BufferedChangesList))
|
|
||||||
{
|
{
|
||||||
TmpEntry = RemoveHeadList(&NotifyEntry->BufferedChangesList);
|
/*
|
||||||
BufferedChange = CONTAINING_RECORD(TmpEntry, BUFFERED_CHANGE, ListEntry);
|
Can't return detailed changes to user cause:
|
||||||
|
-No buffer exist, OR
|
||||||
/* FIXME:
|
-Buffer were overflowed, OR
|
||||||
Fill user-buffer with recorded events until full. If user buffer is too small to hold even
|
-Current irp buff was not large enough
|
||||||
a single record or can only hold some of the events, what should we do????????????
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* FIXME: implement this (copy data to user) */
|
NotifyIrp->IoStatus.Information = 0;
|
||||||
|
NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR;
|
||||||
// BufferedChange->Action = Action;
|
|
||||||
// RecordedChange->Name
|
|
||||||
// RecordedChange->NameLength
|
|
||||||
|
|
||||||
ExFreePool(BufferedChange);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* terminate last entry */
|
||||||
|
NotifyEntry->PrevEntry->NextEntryOffset = 0;
|
||||||
|
|
||||||
|
//FIXME: copy data correctly to user
|
||||||
|
memcpy(NotifyIrp->UserBuffer, NotifyEntry->Buffer, NotifyEntry->NextEntryOffset);
|
||||||
|
|
||||||
|
NotifyIrp->IoStatus.Information = NotifyEntry->NextEntryOffset;
|
||||||
|
NotifyIrp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset buffer */
|
||||||
|
NotifyEntry->PrevEntry = NotifyEntry->Buffer;
|
||||||
|
NotifyEntry->NextEntryOffset = 0;
|
||||||
|
NotifyEntry->BufferExhausted = FALSE;
|
||||||
|
|
||||||
|
NotifyEntry->PendingChanges = FALSE;
|
||||||
|
|
||||||
ExReleaseFastMutex((PFAST_MUTEX)NotifySync);
|
ExReleaseFastMutex((PFAST_MUTEX)NotifySync);
|
||||||
|
|
||||||
NotifyIrp->IoStatus.Information = 0; //<- FIXME
|
|
||||||
NotifyIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
||||||
IoCompleteRequest(NotifyIrp, IO_NO_INCREMENT);
|
IoCompleteRequest(NotifyIrp, IO_NO_INCREMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,8 +565,8 @@ FsRtlpGetNextIrp(PNOTIFY_ENTRY NotifyEntry)
|
||||||
/* Loop to get a non-canceled irp */
|
/* Loop to get a non-canceled irp */
|
||||||
while (!IsListEmpty(&NotifyEntry->IrpQueue))
|
while (!IsListEmpty(&NotifyEntry->IrpQueue))
|
||||||
{
|
{
|
||||||
/* If we have queued irp(s) we can't possibly have buffered changes too */
|
/* If we have queued irp(s) we can't possibly have pending changes too */
|
||||||
ASSERT(IsListEmpty(&NotifyEntry->BufferedChangesList));
|
ASSERT(!NotifyEntry->PendingChanges);
|
||||||
|
|
||||||
TmpEntry = RemoveHeadList(&NotifyEntry->IrpQueue);
|
TmpEntry = RemoveHeadList(&NotifyEntry->IrpQueue);
|
||||||
Irp = CONTAINING_RECORD(TmpEntry , IRP, Tail.Overlay.ListEntry);
|
Irp = CONTAINING_RECORD(TmpEntry , IRP, Tail.Overlay.ListEntry);
|
||||||
|
@ -552,8 +587,35 @@ FsRtlpGetNextIrp(PNOTIFY_ENTRY NotifyEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
VOID
|
||||||
|
FsRtlpCopyName(
|
||||||
|
PFILE_NOTIFY_INFORMATION CurrentEntry,
|
||||||
|
BOOLEAN Unicode,
|
||||||
|
PSTRING RelativeName,
|
||||||
|
PSTRING StreamName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Buffer size is allready probed, so just copy the data */
|
||||||
|
|
||||||
|
if (Unicode)
|
||||||
|
{
|
||||||
|
memcpy(CurrentEntry->Name, RelativeName->Buffer, RelativeName->Length);
|
||||||
|
if (StreamName)
|
||||||
|
{
|
||||||
|
CurrentEntry->Name[RelativeName->Length/sizeof(WCHAR)] = ':';
|
||||||
|
memcpy(&CurrentEntry ->Name[(RelativeName->Length/sizeof(WCHAR))+1],
|
||||||
|
StreamName->Buffer,
|
||||||
|
StreamName->Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//FIXME: convert to unicode etc.
|
||||||
|
DPRINT1("FIXME: ansi strings in notify impl. not supported yet\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
@ -573,75 +635,188 @@ STDCALL
|
||||||
FsRtlNotifyFullReportChange (
|
FsRtlNotifyFullReportChange (
|
||||||
IN PNOTIFY_SYNC NotifySync,
|
IN PNOTIFY_SYNC NotifySync,
|
||||||
IN PLIST_ENTRY NotifyList,
|
IN PLIST_ENTRY NotifyList,
|
||||||
IN PSTRING FullTargetName,
|
IN PSTRING FullTargetName, /* can include short names! */
|
||||||
IN USHORT TargetNameOffset, /* in bytes */
|
IN USHORT TargetNameOffset, /* in bytes */
|
||||||
IN PSTRING StreamName OPTIONAL,
|
IN PSTRING StreamName OPTIONAL,
|
||||||
IN PSTRING NormalizedParentName OPTIONAL,
|
IN PSTRING NormalizedParentName OPTIONAL, /* same as FullTargetName, but with long names */
|
||||||
IN ULONG FilterMatch,
|
IN ULONG FilterMatch,
|
||||||
IN ULONG Action,
|
IN ULONG Action,
|
||||||
IN PVOID TargetContext
|
IN PVOID TargetContext
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UNICODE_STRING FullDirName;
|
USHORT FullDirLen;
|
||||||
UNICODE_STRING TargetName;
|
STRING RelativeName;
|
||||||
PLIST_ENTRY EnumEntry;
|
PLIST_ENTRY EnumEntry;
|
||||||
PNOTIFY_ENTRY NotifyEntry;
|
PNOTIFY_ENTRY NotifyEntry;
|
||||||
PBUFFERED_CHANGE BufferedChange;
|
|
||||||
PIRP Irp;
|
PIRP Irp;
|
||||||
LIST_ENTRY CompletedListHead;
|
LIST_ENTRY CompletedListHead;
|
||||||
|
USHORT NameLenU;
|
||||||
|
ULONG RecordLen;
|
||||||
|
PFILE_NOTIFY_INFORMATION CurrentEntry;
|
||||||
|
|
||||||
InitializeListHead(&CompletedListHead);
|
InitializeListHead(&CompletedListHead);
|
||||||
|
|
||||||
FullDirName.Buffer = (WCHAR*)FullTargetName->Buffer;
|
DPRINT("FullTargetName: %wZ\n", FullTargetName);
|
||||||
FullDirName.MaximumLength = FullDirName.Length = TargetNameOffset - sizeof(WCHAR);
|
|
||||||
|
/*
|
||||||
|
I think FullTargetName can include/be a short file name! What the heck do i do with this?
|
||||||
|
Dont think this apply to FsRtlNotifyFullChangeDirectory's FullDirectoryName.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
TargetName.Buffer = (WCHAR*)(FullTargetName->Buffer + TargetNameOffset);
|
|
||||||
TargetName.MaximumLength = TargetName.Length = FullTargetName->Length - TargetNameOffset;
|
|
||||||
|
|
||||||
|
|
||||||
ExAcquireFastMutex((PFAST_MUTEX)NotifySync);
|
ExAcquireFastMutex((PFAST_MUTEX)NotifySync);
|
||||||
|
|
||||||
LIST_FOR_EACH_SAFE(EnumEntry, NotifyList, NotifyEntry, NOTIFY_ENTRY, ListEntry )
|
LIST_FOR_EACH_SAFE(EnumEntry, NotifyList, NotifyEntry, NOTIFY_ENTRY, ListEntry )
|
||||||
{
|
{
|
||||||
|
ASSERT(NotifyEntry->Unicode == FsRtlpIsUnicodePath(FullTargetName));
|
||||||
|
|
||||||
/* rule out some easy cases */
|
/* rule out some easy cases */
|
||||||
/* FIXME: short vs. long names??? */
|
/* FIXME: short vs. long names??? */
|
||||||
if (FilterMatch != NotifyEntry->CompletionFilter) continue;
|
if (!(FilterMatch & NotifyEntry->CompletionFilter)) continue;
|
||||||
|
|
||||||
if (FullDirName.Length < NotifyEntry->FullDirectoryName->Length) continue;
|
FullDirLen = TargetNameOffset - (NotifyEntry->Unicode?sizeof(WCHAR):sizeof(char));
|
||||||
|
|
||||||
if (!NotifyEntry->WatchTree && FullDirName.Length != NotifyEntry->FullDirectoryName->Length) continue;
|
|
||||||
|
|
||||||
if (wcsncmp((WCHAR*)NotifyEntry->FullDirectoryName->Buffer,
|
if (FullDirLen < NotifyEntry->FullDirectoryName->Length) continue;
|
||||||
FullDirName.Buffer,
|
|
||||||
NotifyEntry->FullDirectoryName->Length/sizeof(WCHAR)) != 0) continue;
|
if (!NotifyEntry->WatchTree && FullDirLen != NotifyEntry->FullDirectoryName->Length) continue;
|
||||||
|
|
||||||
|
DPRINT("NotifyEntry->FullDirectoryName: %wZ\n", NotifyEntry->FullDirectoryName);
|
||||||
|
|
||||||
|
if (memcmp(NotifyEntry->FullDirectoryName->Buffer,
|
||||||
|
FullTargetName->Buffer,
|
||||||
|
NotifyEntry->FullDirectoryName->Length) != 0) continue;
|
||||||
|
|
||||||
|
|
||||||
|
if (NotifyEntry->WatchTree &&
|
||||||
|
NotifyEntry->TraverseCallback &&
|
||||||
|
FullDirLen != NotifyEntry->FullDirectoryName->Length)
|
||||||
|
{
|
||||||
|
/* change happend in a subdir. ask caller if we are allowed in here */
|
||||||
|
NTSTATUS Status = NotifyEntry->TraverseCallback(NotifyEntry->FsContext,
|
||||||
|
TargetContext,
|
||||||
|
NotifyEntry->SubjectContext);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status)) continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
FIXME: notify-dir impl. should release and free the SubjectContext
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("Found match\n");
|
||||||
|
|
||||||
/* Found a valid change */
|
/* Found a valid change */
|
||||||
|
|
||||||
|
RelativeName.Buffer = FullTargetName->Buffer + TargetNameOffset;
|
||||||
|
RelativeName.MaximumLength =
|
||||||
|
RelativeName.Length =
|
||||||
|
FullTargetName->Length - TargetNameOffset;
|
||||||
|
|
||||||
|
DPRINT("RelativeName: %wZ\n",&RelativeName);
|
||||||
|
|
||||||
|
/* calculate unicode bytes of relative-name + stream-name */
|
||||||
|
if (NotifyEntry->Unicode)
|
||||||
|
{
|
||||||
|
NameLenU = RelativeName.Length + (StreamName ? (StreamName->Length + sizeof(WCHAR)) : 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NameLenU = RelativeName.Length * sizeof(WCHAR) +
|
||||||
|
(StreamName ? ((StreamName->Length * sizeof(WCHAR)) + sizeof(WCHAR)) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordLen = FIELD_OFFSET(FILE_NOTIFY_INFORMATION, Name) + NameLenU;
|
||||||
|
|
||||||
if ((Irp = FsRtlpGetNextIrp(NotifyEntry)))
|
if ((Irp = FsRtlpGetNextIrp(NotifyEntry)))
|
||||||
{
|
{
|
||||||
//FIXME: copy data to user
|
PIO_STACK_LOCATION IrpStack;
|
||||||
|
ULONG IrpBuffLen;
|
||||||
|
|
||||||
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
|
IrpBuffLen = IrpStack->Parameters.NotifyDirectory.Length;
|
||||||
|
|
||||||
|
DPRINT("Got pending irp\n");
|
||||||
|
|
||||||
|
ASSERT(!NotifyEntry->PendingChanges);
|
||||||
|
|
||||||
|
if (NotifyEntry->Buffer == NULL || /* aka. IgnoreBuffer */
|
||||||
|
RecordLen > IrpBuffLen)
|
||||||
|
{
|
||||||
|
/* ignore buffer / buffer not large enough */
|
||||||
|
Irp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR;
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//FIXME: copy data to user correctly
|
||||||
|
CurrentEntry = (PFILE_NOTIFY_INFORMATION)Irp->UserBuffer;
|
||||||
|
|
||||||
|
CurrentEntry->Action = Action;
|
||||||
|
CurrentEntry->NameLength = NameLenU;
|
||||||
|
CurrentEntry->NextEntryOffset = 0;
|
||||||
|
|
||||||
|
FsRtlpCopyName(
|
||||||
|
CurrentEntry,
|
||||||
|
NotifyEntry->Unicode,
|
||||||
|
&RelativeName,
|
||||||
|
StreamName
|
||||||
|
);
|
||||||
|
|
||||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = RecordLen;
|
||||||
|
}
|
||||||
|
|
||||||
/* avoid holding lock while completing irp */
|
/* avoid holding lock while completing irp */
|
||||||
InsertTailList(&CompletedListHead, &Irp->Tail.Overlay.ListEntry);
|
InsertTailList(&CompletedListHead, &Irp->Tail.Overlay.ListEntry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* No irp in queue. Buffer changes */
|
DPRINT("No irp\n");
|
||||||
/* FIXME: how much stuff should we buffer?
|
|
||||||
-Should we alloc with quotas?
|
NotifyEntry->PendingChanges = TRUE;
|
||||||
-Should we use a hardcoded limit?
|
|
||||||
-Should we use a time-out? (drop changes if they are not retrieved in x seconds?
|
if (NotifyEntry->Buffer == NULL || NotifyEntry->BufferExhausted) continue;
|
||||||
|
|
||||||
|
if (RecordLen > NotifyEntry->BufferSize - NotifyEntry->NextEntryOffset)
|
||||||
|
{
|
||||||
|
/* overflow. drop these changes and stop buffering any other changes too */
|
||||||
|
NotifyEntry->BufferExhausted = TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The buffer has enough room for the changes.
|
||||||
|
* Copy data to buffer.
|
||||||
*/
|
*/
|
||||||
BufferedChange = ExAllocatePool(PagedPool, FIELD_OFFSET(BUFFERED_CHANGE, RelativeName) + TargetName.Length);
|
|
||||||
|
|
||||||
BufferedChange->Action = Action;
|
CurrentEntry = (PFILE_NOTIFY_INFORMATION)NotifyEntry->Buffer;
|
||||||
BufferedChange->NameLen = TargetName.Length;
|
|
||||||
memcpy(BufferedChange->RelativeName, TargetName.Buffer, TargetName.Length);
|
CurrentEntry->Action = Action;
|
||||||
|
CurrentEntry->NameLength = NameLenU;
|
||||||
|
CurrentEntry->NextEntryOffset = 0;
|
||||||
|
|
||||||
|
FsRtlpCopyName(CurrentEntry,
|
||||||
|
NotifyEntry->Unicode,
|
||||||
|
&RelativeName,
|
||||||
|
StreamName
|
||||||
|
);
|
||||||
|
|
||||||
|
/* adjust buffer */
|
||||||
|
NotifyEntry->PrevEntry->NextEntryOffset = (char*)CurrentEntry - (char*)NotifyEntry->PrevEntry;
|
||||||
|
NotifyEntry->PrevEntry = CurrentEntry;
|
||||||
|
NotifyEntry->NextEntryOffset += RecordLen;
|
||||||
|
|
||||||
|
|
||||||
|
// {
|
||||||
|
// UNICODE_STRING TmpStr;
|
||||||
|
// TmpStr.Buffer = BufferedChange->RelativeName;
|
||||||
|
// TmpStr.MaximumLength = TmpStr.Length = BufferedChange->NameLen;
|
||||||
|
// DPRINT("BufferedChange->RelativeName: %wZ\n", &TmpStr);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
InsertTailList(&NotifyEntry->BufferedChangesList, &BufferedChange->ListEntry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,7 +852,7 @@ FsRtlNotifyInitializeSync (
|
||||||
IN PNOTIFY_SYNC *NotifySync
|
IN PNOTIFY_SYNC *NotifySync
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
*NotifySync = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), 0/*FSRTL_NOTIFY_TAG*/ );
|
*NotifySync = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), FSRTL_NOTIFY_TAG );
|
||||||
ExInitializeFastMutex((PFAST_MUTEX)*NotifySync);
|
ExInitializeFastMutex((PFAST_MUTEX)*NotifySync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
/* Look for "FSrt" in mem view */
|
/* Look for "FSrt" in mem view */
|
||||||
#define IFS_POOL_TAG 0x74725346
|
#define IFS_POOL_TAG 0x74725346
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL INIT_FUNCTION
|
||||||
|
FsRtlpInitNotifyImplementation(VOID);
|
||||||
|
|
||||||
|
|
||||||
VOID STDCALL
|
VOID STDCALL
|
||||||
FsRtlpInitFileLockingImplementation(VOID);
|
FsRtlpInitFileLockingImplementation(VOID);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue