📄 dirctl.c
字号:
}
VOID
RfsdNotifyReportChange (
IN PRFSD_IRP_CONTEXT IrpContext,
IN PRFSD_VCB Vcb,
IN PRFSD_FCB Fcb,
IN ULONG Filter,
IN ULONG Action )
{
PUNICODE_STRING FullName;
USHORT Offset;
FullName = &Fcb->LongName;
// ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
if (FullName->Buffer == NULL) {
if (!RfsdGetFullFileName(Fcb->RfsdMcb, FullName)) {
/*Status = STATUS_INSUFFICIENT_RESOURCES;*/
return;
}
}
Offset = (USHORT) ( FullName->Length -
Fcb->RfsdMcb->ShortName.Length);
FsRtlNotifyFullReportChange( Vcb->NotifySync,
&(Vcb->NotifyList),
(PSTRING) (FullName),
(USHORT) Offset,
(PSTRING)NULL,
(PSTRING) NULL,
(ULONG) Filter,
(ULONG) Action,
(PVOID) NULL );
// ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
}
NTSTATUS
RfsdDirectoryControl (IN PRFSD_IRP_CONTEXT IrpContext)
{
NTSTATUS Status;
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
switch (IrpContext->MinorFunction) {
case IRP_MN_QUERY_DIRECTORY:
Status = RfsdQueryDirectory(IrpContext);
break;
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
Status = RfsdNotifyChangeDirectory(IrpContext);
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
RfsdCompleteIrpContext(IrpContext, Status);
}
return Status;
}
#if DISABLE
BOOLEAN RfsdIsDirectoryEmpty (
PRFSD_VCB Vcb,
PRFSD_FCB Dcb )
{
DbgBreak();
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRFSD_DIR_ENTRY2 pTarget = NULL;
ULONG dwBytes = 0;
ULONG dwRet;
BOOLEAN bRet = FALSE;
if (!IsFlagOn(Dcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
return TRUE;
}
__try {
pTarget = (PRFSD_DIR_ENTRY2) ExAllocatePool(PagedPool,
RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
if (!pTarget) {
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
dwBytes = 0;
bRet = TRUE;
while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart) {
RtlZeroMemory(pTarget, RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
Status = RfsdReadInode(
NULL,
Vcb,
&(Dcb->RfsdMcb->Key),
Dcb->Inode,
dwBytes,
(PVOID)pTarget,
RFSD_DIR_REC_LEN(RFSD_NAME_LEN),
&dwRet);
if (!NT_SUCCESS(Status)) {
RfsdPrint((DBG_ERROR, "RfsdRemoveEntry: Reading Directory Content error.\n"));
bRet = FALSE;
__leave;
}
if (pTarget->inode) {
if (pTarget->name_len == 1 && pTarget->name[0] == '.') {
} else if (pTarget->name_len == 2 && pTarget->name[0] == '.' &&
pTarget->name[1] == '.') {
} else {
bRet = FALSE;
break;
}
} else {
break;
}
dwBytes += pTarget->rec_len;
}
} __finally {
if (pTarget != NULL) {
ExFreePool(pTarget);
}
}
return bRet;
}
#endif
/**
This callback is triggered when the FS tree parser hits a leaf node that may contain a directory item.
The function then reads each dentry in the item, and is reponsible for sending them into to ProcessDirEntry.
The callback is doing work on behalf of QueryDir -- the context given is from there.
*/
// NOTE: This signature has to be changed here, at the top decleration, and in the RFSD_CALLBACK macro definition
NTSTATUS
RfsdDirectoryCallback(
ULONG BlockNumber,
PVOID pContext)
{
PRFSD_CALLBACK_CONTEXT pCallbackContext = (PRFSD_CALLBACK_CONTEXT) pContext;
RFSD_KEY_IN_MEMORY DirectoryKey;
PUCHAR pBlockBuffer = NULL;
PRFSD_ITEM_HEAD pDirectoryItemHeader = NULL;
PUCHAR pDirectoryItemBuffer = NULL;
NTSTATUS Status;
UNICODE_STRING InodeFileName;
InodeFileName.Buffer = NULL;
RfsdPrint((DBG_FUNC, __FUNCTION__ " invoked on block %i\n", BlockNumber));
// Load the block
pBlockBuffer = RfsdAllocateAndLoadBlock(pCallbackContext->Vcb, BlockNumber);
if (!pBlockBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; goto out; }
// Construct the item key to search for
DirectoryKey = *(pCallbackContext->pDirectoryKey);
DirectoryKey.k_type = RFSD_KEY_TYPE_v2_DIRENTRY;
// Get the item header and its information
Status = RfsdFindItemHeaderInBlock(
pCallbackContext->Vcb, &DirectoryKey, pBlockBuffer,
( &pDirectoryItemHeader ), //<
&CompareKeysWithoutOffset
);
// If this block doesn't happen to contain a directory item, skip it.
if ( (Status == STATUS_NO_SUCH_MEMBER) || !pDirectoryItemHeader )
{
KdPrint(("Block %i did not contain the appropriate diritem header\n", BlockNumber));
Status = STATUS_SUCCESS; goto out;
}
RfsdPrint((DBG_INFO, "Found %i dentries in block\n", pDirectoryItemHeader->u.ih_entry_count));
// Calculate if the requested result will be from this dentry span
// If the end of this span is not greater than the requested start, it can be skipped.
if ( !( (pCallbackContext->idxCurrentDentry + (USHORT)(pDirectoryItemHeader->u.ih_entry_count)) > pCallbackContext->idxStartingDentry ) )
{
RfsdPrint((DBG_TRACE, "SKIPPING block\n"));
pCallbackContext->idxCurrentDentry += pDirectoryItemHeader->u.ih_entry_count;
Status = STATUS_SUCCESS;
goto out;
}
// Otherwise, Read out each dentry, and call ProcessDirEntry on it.
{
BOOLEAN bRun = TRUE;
PRFSD_DENTRY_HEAD pPrevDentry = NULL;
ULONG offsetDentry_toSequentialSpan; // The byte offset of this dentry, relative to the dentry spans, as though only their DENTRY_HEADs were stitched together sequentially
// Skip ahead to the starting dentry in this span.
ULONG idxDentryInSpan = pCallbackContext->idxStartingDentry - pCallbackContext->idxCurrentDentry;
pCallbackContext->idxCurrentDentry += idxDentryInSpan;
RfsdPrint((DBG_TRACE, "Sarting dentry: %i. skipped to %i dentry in span\n", pCallbackContext->idxStartingDentry, idxDentryInSpan));
offsetDentry_toSequentialSpan = pCallbackContext->idxCurrentDentry * sizeof(RFSD_DENTRY_HEAD);
// Setup the item buffer
pDirectoryItemBuffer = (PUCHAR) pBlockBuffer + pDirectoryItemHeader->ih_item_location;
while (bRun
&& ( *(pCallbackContext->pUsedLength) < (pCallbackContext->BufferLength) )
&& (idxDentryInSpan < (pDirectoryItemHeader->u.ih_entry_count)) )
{
STRING OemName; // FUTURE: does this support codepages?
PRFSD_DENTRY_HEAD pCurrentDentry;
USHORT InodeFileNameLength = 0;
// Read a directory entry from the buffered directory item (from the file associated with the filled inode)
pCurrentDentry = (PRFSD_DENTRY_HEAD) (pDirectoryItemBuffer + (idxDentryInSpan * sizeof(RFSD_DENTRY_HEAD) ));
// Skip the directory entry for the parent of the root directory (because it should not be shown, and has no stat data)
// (NOTE: Any change made here should also be mirrored in RfsdScanDirCallback)
if (pCurrentDentry->deh_dir_id == 0 /*&& pCurrentDentry->deh_objectid == 1*/)
{ goto ProcessNextEntry; }
// Pull the name of the file out from the buffer.
// NOTE: The filename is not gauranteed to be null-terminated, and so the end may implicitly be the start of the previous entry.
OemName.Buffer = (PUCHAR) pDirectoryItemBuffer + pCurrentDentry->deh_location;
OemName.MaximumLength = (pPrevDentry ? pPrevDentry->deh_location : // The end of this entry is the start of the previous
pDirectoryItemHeader->ih_item_len // Otherwise this is the first entry, the end of which is the end of the item.
) - pCurrentDentry->deh_location;
if (!pPrevDentry && pCallbackContext->idxStartingDentry > 1 && pCallbackContext->Ccb->deh_location)
{
if (OemName.MaximumLength != pCallbackContext->Ccb->deh_location - pCurrentDentry->deh_location)
{
//KdPrint(("Changed MaximumLength from %d to %d for {%.*s}\n", OemName.MaximumLength, pCallbackContext->Ccb->deh_location - pCurrentDentry->deh_location, RfsdStringLength(OemName.Buffer, pCallbackContext->Ccb->deh_location - pCurrentDentry->deh_location), OemName.Buffer));
}
OemName.MaximumLength = pCallbackContext->Ccb->deh_location - pCurrentDentry->deh_location;
}
OemName.Length = RfsdStringLength(OemName.Buffer, OemName.MaximumLength);
// Calculate the name's unicode length, allocate memory, and convert the codepaged name to unicode
InodeFileNameLength = (USHORT) RfsdOEMToUnicodeSize(&OemName);
InodeFileName.Length = 0;
InodeFileName.MaximumLength = InodeFileNameLength + 2;
if (InodeFileNameLength <= 0)
{ break; }
InodeFileName.Buffer = ExAllocatePool(
PagedPool,
InodeFileNameLength + 2);
if (!InodeFileName.Buffer) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto out;
}
RtlZeroMemory(InodeFileName.Buffer, InodeFileNameLength + 2);
Status = RfsdOEMToUnicode( &InodeFileName, &OemName );
if (!NT_SUCCESS(Status)) { Status = STATUS_INTERNAL_ERROR; goto out; } // TODO: CHECK IF TIHS OK
////////////// END OF MY PART
if (FsRtlDoesNameContainWildCards(
&(pCallbackContext->Ccb->DirectorySearchPattern)) ?
FsRtlIsNameInExpression(
&(pCallbackContext->Ccb->DirectorySearchPattern),
&InodeFileName,
TRUE,
NULL) :
!RtlCompareUnicodeString(
&(pCallbackContext->Ccb->DirectorySearchPattern),
&InodeFileName,
TRUE) ) {
// The name either contains wild cards, or matches the directory search pattern...
{
ULONG dwBytesWritten;
dwBytesWritten = RfsdProcessDirEntry(
pCallbackContext->Vcb, pCallbackContext->FileInformationClass,
pCurrentDentry->deh_dir_id,
pCurrentDentry->deh_objectid,
pCallbackContext->Buffer,
*(pCallbackContext->pUsedLength),
pCallbackContext->BufferLength - *(pCallbackContext->pUsedLength), // The remaining length in the user's buffer
offsetDentry_toSequentialSpan,
&InodeFileName,
pCallbackContext->ReturnSingleEntry,
pCallbackContext->pPreviousEntry);
if (dwBytesWritten <= 0) {
Status = STATUS_EVENT_DONE;
bRun = FALSE;
pCallbackContext->Ccb->deh_location = pPrevDentry ? pPrevDentry->deh_location : 0;
} else {
pCallbackContext->Ccb->deh_location = 0;
pCallbackContext->pPreviousEntry = (PUCHAR) (pCallbackContext->Buffer) + *(pCallbackContext->pUsedLength);
*(pCallbackContext->pUsedLength) += dwBytesWritten;
}
}
}
if (InodeFileName.Buffer) {
ExFreePool(InodeFileName.Buffer);
InodeFileName.Buffer = NULL;
}
ProcessNextEntry:
pPrevDentry = pCurrentDentry;
if (bRun)
{
++idxDentryInSpan;
++(pCallbackContext->idxCurrentDentry);
++(pCallbackContext->idxStartingDentry);
offsetDentry_toSequentialSpan += sizeof(RFSD_DENTRY_HEAD);
// Store the current position, so that it will be available for the next call
pCallbackContext->Ccb->CurrentByteOffset = offsetDentry_toSequentialSpan;
}
if ( ( *(pCallbackContext->pUsedLength) > 0) && pCallbackContext->ReturnSingleEntry) {
Status = STATUS_EVENT_DONE;
break;
}
}
}
out:
if (pBlockBuffer) ExFreePool(pBlockBuffer);
if (InodeFileName.Buffer) ExFreePool(InodeFileName.Buffer);
return Status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -