📄 dirctl.c
字号:
RestartScan = FlagOn(((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Flags, SL_RESTART_SCAN);
ReturnSingleEntry = FlagOn(((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Flags, SL_RETURN_SINGLE_ENTRY);
IndexSpecified = FlagOn(((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Flags, SL_INDEX_SPECIFIED);
/*
if (!Irp->MdlAddress && Irp->UserBuffer) {
ProbeForWrite(Irp->UserBuffer, Length, 1);
}
*/
// Check that the user's buffer for the output is valid..
Buffer = RfsdGetUserBuffer(Irp);
if (Buffer == NULL) {
DbgBreak();
Status = STATUS_INVALID_USER_BUFFER;
__leave;
}
// Check if we have a synchronous or asynchronous request...
if (!IrpContext->IsSynchronous) {
Status = STATUS_PENDING;
__leave;
}
if (!ExAcquireResourceSharedLite(
&Fcb->MainResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
__leave;
}
FcbResourceAcquired = TRUE;
if (FileName != NULL) {
// The caller provided a FileName to search on...
if (Ccb->DirectorySearchPattern.Buffer != NULL) {
FirstQuery = FALSE;
} else {
FirstQuery = TRUE;
// Set up the DirectorySearchPattern to simply be an uppercase copy of the FileName.
Ccb->DirectorySearchPattern.Length =
Ccb->DirectorySearchPattern.MaximumLength =
FileName->Length;
Ccb->DirectorySearchPattern.Buffer =
ExAllocatePool(PagedPool, FileName->Length);
if (Ccb->DirectorySearchPattern.Buffer == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
Status = RtlUpcaseUnicodeString(
&(Ccb->DirectorySearchPattern),
FileName,
FALSE);
if (!NT_SUCCESS(Status))
__leave;
}
} else if (Ccb->DirectorySearchPattern.Buffer != NULL) {
FirstQuery = FALSE;
FileName = &Ccb->DirectorySearchPattern;
} else {
// (The FileName and CCB's DirectorySearchPattern were null)
FirstQuery = TRUE;
Ccb->DirectorySearchPattern.Length =
Ccb->DirectorySearchPattern.MaximumLength = 2;
Ccb->DirectorySearchPattern.Buffer =
ExAllocatePool(PagedPool, 2);
if (Ccb->DirectorySearchPattern.Buffer == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
RtlCopyMemory(
Ccb->DirectorySearchPattern.Buffer,
L"*\0", 2);
}
if (!IndexSpecified) {
if (RestartScan || FirstQuery) {
FileIndex = Fcb->RfsdMcb->DeOffset = 0;
} else {
// If we are not starting/restaring a scan, then we must have already started.
// Retrieve the byte offset (in the directory . file) where we left off.
FileIndex = Ccb->CurrentByteOffset;
}
}
RtlZeroMemory(Buffer, Length);
// Leave if a previous query has already read the entire contents of the directory
if (Fcb->Inode->i_size <= FileIndex) {
Status = STATUS_NO_MORE_FILES;
__leave;
}
////////
// Construct a context for the call, and call to parse the entire file system tree.
// A callback will be triggered on any direntry span belonging to DirectoryKey.
// This callback will fill the requested section of the user buffer.
{
ULONG CurrentFileIndex;
RFSD_CALLBACK_CONTEXT CallbackContext;
CallbackContext.Vcb = Vcb;
CallbackContext.Ccb = Ccb;
CallbackContext.idxStartingDentry = FileIndex / sizeof(RFSD_DENTRY_HEAD);
CallbackContext.idxCurrentDentry = 0;
CallbackContext.pDirectoryKey = pQueryKey;
CallbackContext.FileInformationClass = FileInformationClass;
CallbackContext.Buffer = Buffer;
CallbackContext.BufferLength = Length;
CallbackContext.ReturnSingleEntry = ReturnSingleEntry;
CallbackContext.pUsedLength = &UsedLength;
CallbackContext.pPreviousEntry = NULL;
RfsdPrint((DBG_TRACE, "Calculated idxCurrentDentry to be %i\n", CallbackContext.idxStartingDentry));
RfsdParseFilesystemTree(Vcb, pQueryKey, Vcb->SuperBlock->s_root_block, &RfsdDirectoryCallback, &CallbackContext);
}
//================================================================
if (!UsedLength) {
// No amount of the dsetination buffer has been used (meaning there were no results)...
if (FirstQuery) {
Status = STATUS_NO_SUCH_FILE;
} else {
Status = STATUS_NO_MORE_FILES;
}
} else {
Status = STATUS_SUCCESS;
}
} __finally {
if (FcbResourceAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->MainResource,
ExGetCurrentResourceThread() );
}
if (!IrpContext->ExceptionInProgress) {
if (Status == STATUS_PENDING) {
Status = RfsdLockUserBuffer(
IrpContext->Irp,
Length,
IoWriteAccess );
if (NT_SUCCESS(Status)) {
Status = RfsdQueueRequest(IrpContext);
} else {
RfsdCompleteIrpContext(IrpContext, Status);
}
} else {
IrpContext->Irp->IoStatus.Information = UsedLength;
RfsdCompleteIrpContext(IrpContext, Status);
}
}
}
return Status;
}
NTSTATUS
RfsdNotifyChangeDirectory (
IN PRFSD_IRP_CONTEXT IrpContext
)
{
PDEVICE_OBJECT DeviceObject;
BOOLEAN CompleteRequest;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRFSD_VCB Vcb;
PFILE_OBJECT FileObject;
PRFSD_FCB Fcb;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
ULONG CompletionFilter;
BOOLEAN WatchTree;
BOOLEAN bFcbAcquired = FALSE;
PUNICODE_STRING FullName;
__try {
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
//
// Always set the wait flag in the Irp context for the original request.
//
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
DeviceObject = IrpContext->DeviceObject;
if (DeviceObject == RfsdGlobal->DeviceObject) {
CompleteRequest = TRUE;
Status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
ASSERT(IsMounted(Vcb));
FileObject = IrpContext->FileObject;
Fcb = (PRFSD_FCB) FileObject->FsContext;
ASSERT(Fcb);
if (Fcb->Identifier.Type == RFSDVCB) {
DbgBreak();
CompleteRequest = TRUE;
Status = STATUS_INVALID_PARAMETER;
__leave;
}
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
if (!IsDirectory(Fcb)) {
//- DbgBreak(); // NOTE: Windows (at least I've noticed it with the image previewer), will send this request oftentimes on a file!
CompleteRequest = TRUE;
Status = STATUS_INVALID_PARAMETER;
__leave;
}
if (ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
TRUE )) {
bFcbAcquired = TRUE;
} else {
Status = STATUS_PENDING;
__leave;
}
Irp = IrpContext->Irp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
#ifndef _GNU_NTIFS_
CompletionFilter =
IrpSp->Parameters.NotifyDirectory.CompletionFilter;
#else // _GNU_NTIFS_
CompletionFilter = ((PEXTENDED_IO_STACK_LOCATION)
IrpSp)->Parameters.NotifyDirectory.CompletionFilter;
#endif // _GNU_NTIFS_
WatchTree = IsFlagOn(IrpSp->Flags, SL_WATCH_TREE);
if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
Status = STATUS_DELETE_PENDING;
__leave;
}
FullName = &Fcb->LongName;
if (FullName->Buffer == NULL) {
if (!RfsdGetFullFileName(Fcb->RfsdMcb, FullName)) {
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
}
FsRtlNotifyFullChangeDirectory( Vcb->NotifySync,
&Vcb->NotifyList,
FileObject->FsContext2,
(PSTRING)FullName,
WatchTree,
FALSE,
CompletionFilter,
Irp,
NULL,
NULL );
CompleteRequest = FALSE;
Status = STATUS_PENDING;
/*
Currently the driver is read-only but here is an example on how to use the
FsRtl-functions to report a change:
ANSI_STRING TestString;
USHORT FileNamePartLength;
RtlInitAnsiString(&TestString, "\\ntifs.h");
FileNamePartLength = 7;
FsRtlNotifyReportChange(
Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
&Vcb->NotifyList, // PLIST_ENTRY NotifyList
&TestString, // PSTRING FullTargetName
&FileNamePartLength, // PUSHORT FileNamePartLength
FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch
);
or
ANSI_STRING TestString;
RtlInitAnsiString(&TestString, "\\ntifs.h");
FsRtlNotifyFullReportChange(
Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
&Vcb->NotifyList, // PLIST_ENTRY NotifyList
&TestString, // PSTRING FullTargetName
1, // USHORT TargetNameOffset
NULL, // PSTRING StreamName OPTIONAL
NULL, // PSTRING NormalizedParentName OPTIONAL
FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch
0, // ULONG Action
NULL // PVOID TargetContext
);
*/
} __finally {
if (bFcbAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->MainResource,
ExGetCurrentResourceThread());
}
if (!IrpContext->ExceptionInProgress) {
if (!CompleteRequest) {
IrpContext->Irp = NULL;
}
RfsdCompleteIrpContext(IrpContext, Status);
}
}
return Status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -