BOOLEAN SpyIsWatchedPath(_In_ PUNICODE_STRING path) { BOOLEAN result = FALSE; if (!InterlockedExchange(&MiniFSWatcherData.WatchPathInUse, TRUE)) { result = FsRtlIsNameInExpression(&MiniFSWatcherData.WatchPath, path, TRUE, NULL); MiniFSWatcherData.WatchPathInUse = FALSE; } return result; }
// Checks if the export is listed as a hook target, and if so install a hook. _Use_decl_annotations_ EXTERN_C static bool DdimonpEnumExportedSymbolsCallback( ULONG index, ULONG_PTR base_address, PIMAGE_EXPORT_DIRECTORY directory, ULONG_PTR directory_base, ULONG_PTR directory_end, void* context) { PAGED_CODE(); if (!context) { return false; } auto functions = reinterpret_cast<ULONG*>(base_address + directory->AddressOfFunctions); auto ordinals = reinterpret_cast<USHORT*>(base_address + directory->AddressOfNameOrdinals); auto names = reinterpret_cast<ULONG*>(base_address + directory->AddressOfNames); auto ord = ordinals[index]; auto export_address = base_address + functions[ord]; auto export_name = reinterpret_cast<const char*>(base_address + names[index]); // Check if an export is forwared one? If so, ignore it. if (UtilIsInBounds(export_address, directory_base, directory_end)) { return true; } // convert the name to UNICODE_STRING wchar_t name[100]; auto status = RtlStringCchPrintfW(name, RTL_NUMBER_OF(name), L"%S", export_name); if (!NT_SUCCESS(status)) { return true; } UNICODE_STRING name_u = {}; RtlInitUnicodeString(&name_u, name); for (auto& target : g_ddimonp_hook_targets) { // Is this export listed as a target if (!FsRtlIsNameInExpression(&target.target_name, &name_u, TRUE, nullptr)) { continue; } // Yes, install a hook to the export if (!ShInstallHook(reinterpret_cast<SharedShadowHookData*>(context), reinterpret_cast<void*>(export_address), &target)) { // This is an error which should not happen DdimonpFreeAllocatedTrampolineRegions(); return false; } HYPERPLATFORM_LOG_INFO("Hook has been installed at %p %s.", export_address, export_name); } return true; }
EXTERN_C static bool ScvnpIsWhiteListedFile( _In_ PUNICODE_STRING TargetFileName) { PAGED_CODE(); UNICODE_STRING WHITE_LIST[] = { RTL_CONSTANT_STRING( L"\\DEVICE\\HARDDISKVOLUME?\\*" L"\\APPDATA\\LOCAL\\MICROSOFT\\WINDOWS\\EXPLORER\\THUMBCACHE_*.DB"), }; for (auto i = 0; i < RTL_NUMBER_OF(WHITE_LIST); ++i) { if (FsRtlIsNameInExpression(&WHITE_LIST[i], TargetFileName, TRUE, nullptr)) { return true; } } return false; }
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch) { BOOLEAN Ret, Alloc = FALSE; UNICODE_STRING EntryName; EntryName.Buffer = IndexEntry->FileName.Name; EntryName.Length = EntryName.MaximumLength = IndexEntry->FileName.NameLength * sizeof(WCHAR); if (DirSearch) { UNICODE_STRING IntFileName; if (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX) { NT_VERIFY(NT_SUCCESS(RtlUpcaseUnicodeString(&IntFileName, FileName, TRUE))); Alloc = TRUE; } else { IntFileName = *FileName; } Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX), NULL); if (Alloc) { RtlFreeUnicodeString(&IntFileName); } return Ret; } else { return (RtlCompareUnicodeString(FileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)) == 0); } }
static VOID FsRtlIsNameInExpressionTest() { ULONG i; for (i = 0; i < sizeof(Tests) / sizeof(Tests[0]); i++) { BOOLEAN TestResult; UNICODE_STRING Expression; UNICODE_STRING Name; /* Don't run Tests which are known to assert in checked builds */ if (KmtIsCheckedBuild && Tests[i].AssertsInChecked) continue; RtlInitUnicodeString(&Expression, Tests[i].Expression); RtlInitUnicodeString(&Name, Tests[i].Name); TestResult = FsRtlIsNameInExpression(&Expression, &Name, Tests[i].IgnoreCase, NULL); ok(TestResult == Tests[i].Expected, "FsRtlIsNameInExpression(%wZ,%wZ,%s,NULL): Expected %s, got %s\n", &Expression, &Name, Tests[i].IgnoreCase ? "TRUE" : "FALSE", Tests[i].Expected ? "TRUE" : "FALSE", TestResult ? "TRUE" : "FALSE"); } /* TODO: test UpcaseTable */ }
NTSTATUS CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt, PFCB DirectoryFcb, PUNICODE_STRING FileToFind, PFCB *FoundFCB) { UNICODE_STRING TempName; WCHAR Name[256]; PVOID Block; ULONG DirSize; PDIR_RECORD Record; ULONG Offset; ULONG BlockOffset; NTSTATUS Status; LARGE_INTEGER StreamOffset, OffsetOfEntry; PVOID Context; WCHAR ShortNameBuffer[13]; UNICODE_STRING ShortName; UNICODE_STRING LongName; UNICODE_STRING FileToFindUpcase; ASSERT(DeviceExt); ASSERT(DirectoryFcb); ASSERT(FileToFind); DPRINT("CdfsDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n", DeviceExt, DirectoryFcb, FileToFind); DPRINT("Dir Path:%S\n", DirectoryFcb->PathName); /* default to '.' if no filename specified */ if (FileToFind->Length == 0) { RtlInitUnicodeString(&TempName, L"."); FileToFind = &TempName; } DirSize = DirectoryFcb->Entry.DataLengthL; StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return STATUS_UNSUCCESSFUL; } Offset = 0; BlockOffset = 0; Record = (PDIR_RECORD)Block; /* Upper case the expression for FsRtlIsNameInExpression */ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE); if (!NT_SUCCESS(Status)) { return Status; } while(TRUE) { if (Record->RecordLength == 0) { DPRINT("RecordLength == 0 Stopped!\n"); break; } DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); CdfsGetDirEntryName(DeviceExt, Record, Name); DPRINT ("Name '%S'\n", Name); DPRINT ("Sector %lu\n", DirectoryFcb->Entry.ExtentLocationL); DPRINT ("Offset %lu\n", Offset); RtlInitUnicodeString(&LongName, Name); ShortName.Length = 0; ShortName.MaximumLength = 26; ShortName.Buffer = ShortNameBuffer; memset(ShortNameBuffer, 0, 26); OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset; CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName); DPRINT("ShortName '%wZ'\n", &ShortName); if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) || FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL)) { DPRINT("Match found, %S\n", Name); Status = CdfsMakeFCBFromDirEntry(DeviceExt, DirectoryFcb, Name, ShortNameBuffer, Record, DirectoryFcb->Entry.ExtentLocationL, Offset, FoundFCB); RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return(Status); } Offset += Record->RecordLength; BlockOffset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset); if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(Context); StreamOffset.QuadPart += BLOCKSIZE; Offset = ROUND_UP(Offset, BLOCKSIZE); BlockOffset = 0; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); RtlFreeUnicodeString(&FileToFindUpcase); return(STATUS_UNSUCCESSFUL); } Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset); } if (Offset >= DirSize) break; } RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return(STATUS_OBJECT_NAME_NOT_FOUND); }
NTSTATUS DoMatchExpression(PUNICODE_STRING Path) { // 是否需要在这里判断是否在重定向根目录内 // 这里要先判断链表是否为空 if (IsListEmpty(&MatchExpressionList.HeadList)) return STATUS_NOT_FOUND; UNICODE_STRING tmpPath; RtlZeroMemory(&tmpPath, sizeof(UNICODE_STRING)); tmpPath.MaximumLength = sizeof(WCHAR) * 260; tmpPath.Buffer = (PWSTR)ExAllocatePool(NonPagedPool, tmpPath.MaximumLength); if (tmpPath.Buffer == NULL) return STATUS_NOT_FOUND; RtlCopyUnicodeString(&tmpPath, Path); KIRQL irql; KeAcquireSpinLock(&MatchExpressionList.Lock, &irql); // 链表头 PLIST_ENTRY pList = MatchExpressionList.HeadList.Flink; BOOLEAN isMatched = FALSE; while (pList != &MatchExpressionList.HeadList) { PMATCH_EXPRESSION element = CONTAINING_RECORD(pList, MATCH_EXPRESSION, ListEntry); // 注意,这里这样申请内存其实还挺频繁的 // 如果这里还是有问题,可能就要用Looksaide结构来处理内存问题了 UNICODE_STRING Expression; RtlZeroMemory(&Expression, sizeof(UNICODE_STRING)); Expression.MaximumLength = sizeof(WCHAR) * 260; Expression.Buffer = (PWSTR)ExAllocatePool(NonPagedPool, Expression.MaximumLength); if (Expression.Buffer == NULL) { KdPrint(("[ISISandBox] DoMatchExpression -> Alloc pool for Expression string buffer failed.\n")); pList = pList->Flink; continue; } RtlUnicodeStringCbCopyStringN(&Expression, element->Expression, sizeof(WCHAR) * 260); Expression.Length = (USHORT)element->Length; KdPrint(("[ISISandBox] Current expression : %wZ %u\n", &Expression, Expression.Length)); KdPrint(("[ISISandBox] Current path : %wZ\n", &tmpPath)); // 注意:这里经常触发蓝屏,最近一次是因为 DRIVER_CORRUPTED_EXPOOL (C5) // 说明此处对内存的读写性要求比较高,应该使用灵活度更高的内存空间 // 所以这两个字符串所在内存都是在此函数中动态申请的非分页内存,应该能解决问题 BOOLEAN ret = FsRtlIsNameInExpression(&Expression, &tmpPath, TRUE, NULL); ExFreePool(Expression.Buffer); if (ret) { KdPrint(("[ISISandBox] Match Expression OK : %wZ.\n", &tmpPath)); isMatched = TRUE; break; } pList = pList->Flink; } KeReleaseSpinLock(&MatchExpressionList.Lock, irql); ExFreePool(tmpPath.Buffer); if (isMatched) return STATUS_SUCCESS; else { //KdPrint(("[ISISandBox] CheckMatchExpression Cannot find Expression : %wZ.\n", Expression)); return STATUS_NOT_FOUND; } }
__drv_mustHoldCriticalRegion NTSTATUS FFSQueryDirectory( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = 0; PFILE_OBJECT FileObject; PFFS_FCB Fcb = 0; PFFS_CCB Ccb; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FILE_INFORMATION_CLASS FileInformationClass; ULONG Length; PUNICODE_STRING FileName; ULONG FileIndex; BOOLEAN RestartScan; BOOLEAN ReturnSingleEntry; BOOLEAN IndexSpecified; PUCHAR Buffer; BOOLEAN FirstQuery; PFFSv1_INODE dinode1 = NULL; PFFSv2_INODE dinode2 = NULL; BOOLEAN FcbResourceAcquired = FALSE; ULONG UsedLength = 0; USHORT InodeFileNameLength; UNICODE_STRING InodeFileName; PFFS_DIR_ENTRY pDir = NULL; ULONG dwBytes; ULONG dwTemp = 0; ULONG dwSize = 0; ULONG dwReturn = 0; BOOLEAN bRun = TRUE; ULONG ByteOffset; PAGED_CODE(); InodeFileName.Buffer = NULL; _SEH2_TRY { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); ASSERT(IsMounted(Vcb)); FileObject = IrpContext->FileObject; Fcb = (PFFS_FCB)FileObject->FsContext; ASSERT(Fcb); // // This request is not allowed on volumes // if (Fcb->Identifier.Type == FFSVCB) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); if (!IsDirectory(Fcb)) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } Ccb = (PFFS_CCB)FileObject->FsContext2; ASSERT(Ccb); ASSERT((Ccb->Identifier.Type == FFSCCB) && (Ccb->Identifier.Size == sizeof(FFS_CCB))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); #if !defined(_GNU_NTIFS_) || defined(__REACTOS__) FileInformationClass = IoStackLocation->Parameters.QueryDirectory.FileInformationClass; Length = IoStackLocation->Parameters.QueryDirectory.Length; FileName = IoStackLocation->Parameters.QueryDirectory.FileName; FileIndex = IoStackLocation->Parameters.QueryDirectory.FileIndex; #else // _GNU_NTIFS_ FileInformationClass = ((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Parameters.QueryDirectory.FileInformationClass; Length = ((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Parameters.QueryDirectory.Length; FileName = ((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Parameters.QueryDirectory.FileName; FileIndex = ((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Parameters.QueryDirectory.FileIndex; #endif // _GNU_NTIFS_ RestartScan = FlagOn(IoStackLocation->Flags, SL_RESTART_SCAN); ReturnSingleEntry = FlagOn(IoStackLocation->Flags, SL_RETURN_SINGLE_ENTRY); IndexSpecified = FlagOn(IoStackLocation->Flags, SL_INDEX_SPECIFIED); /* if (!Irp->MdlAddress && Irp->UserBuffer) { ProbeForWrite(Irp->UserBuffer, Length, 1); } */ Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; _SEH2_LEAVE; } if (!IrpContext->IsSynchronous) { Status = STATUS_PENDING; _SEH2_LEAVE; } if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbResourceAcquired = TRUE; if (FileName != NULL) { if (Ccb->DirectorySearchPattern.Buffer != NULL) { FirstQuery = FALSE; } else { FirstQuery = TRUE; Ccb->DirectorySearchPattern.Length = Ccb->DirectorySearchPattern.MaximumLength = FileName->Length; Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(PagedPool, FileName->Length, FFS_POOL_TAG); if (Ccb->DirectorySearchPattern.Buffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } Status = RtlUpcaseUnicodeString( &(Ccb->DirectorySearchPattern), FileName, FALSE); if (!NT_SUCCESS(Status)) _SEH2_LEAVE; } } else if (Ccb->DirectorySearchPattern.Buffer != NULL) { FirstQuery = FALSE; FileName = &Ccb->DirectorySearchPattern; } else { FirstQuery = TRUE; Ccb->DirectorySearchPattern.Length = Ccb->DirectorySearchPattern.MaximumLength = 2; Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(PagedPool, 2, FFS_POOL_TAG); if (Ccb->DirectorySearchPattern.Buffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } RtlCopyMemory( Ccb->DirectorySearchPattern.Buffer, L"*\0", 2); } if (!IndexSpecified) { if (RestartScan || FirstQuery) { FileIndex = Fcb->FFSMcb->DeOffset = 0; } else { FileIndex = Ccb->CurrentByteOffset; } } if (FS_VERSION == 1) { dinode1 = (PFFSv1_INODE)ExAllocatePoolWithTag( PagedPool, DINODE1_SIZE, FFS_POOL_TAG); if (dinode1 == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } RtlZeroMemory(Buffer, Length); if (Fcb->dinode1->di_size <= FileIndex) { Status = STATUS_NO_MORE_FILES; _SEH2_LEAVE; } } else { dinode2 = (PFFSv2_INODE)ExAllocatePoolWithTag( PagedPool, DINODE2_SIZE, FFS_POOL_TAG); if (dinode2 == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } RtlZeroMemory(Buffer, Length); if (Fcb->dinode2->di_size <= FileIndex) { Status = STATUS_NO_MORE_FILES; _SEH2_LEAVE; } } pDir = ExAllocatePoolWithTag(PagedPool, sizeof(FFS_DIR_ENTRY), FFS_POOL_TAG); if (!pDir) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } if (FS_VERSION == 1) { dwBytes = 0; dwSize = (ULONG)Fcb->dinode1->di_size - FileIndex - (sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1); ByteOffset = FileIndex; dwTemp = 0; while (bRun && UsedLength < Length && dwBytes < dwSize) { OEM_STRING OemName; RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY)); Status = FFSv1ReadInode( NULL, Vcb, Fcb->dinode1, ByteOffset, (PVOID)pDir, sizeof(FFS_DIR_ENTRY), &dwReturn); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } if (!pDir->d_ino) { if (pDir->d_reclen == 0) { FFSBreakPoint(); _SEH2_LEAVE; } goto ProcessNextEntryv1; } OemName.Buffer = pDir->d_name; OemName.Length = (pDir->d_namlen & 0xff); OemName.MaximumLength = OemName.Length; #if 0 /* // // We could not filter the files: "." and ".." // if ((OemName.Length >) 1 && OemName.Buffer[0] == '.') { if ( OemName.Length == 2 && OemName.Buffer[1] == '.') { } else { goto ProcessNextEntry1; } } */ #endif InodeFileNameLength = (USHORT) RtlOemStringToUnicodeSize(&OemName); InodeFileName.Length = 0; InodeFileName.MaximumLength = InodeFileNameLength + 2; if (InodeFileNameLength <= 0) { break; } InodeFileName.Buffer = ExAllocatePoolWithTag( PagedPool, InodeFileNameLength + 2, FFS_POOL_TAG); if (!InodeFileName.Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } RtlZeroMemory( InodeFileName.Buffer, InodeFileNameLength + 2); Status = FFSOEMToUnicode(&InodeFileName, &OemName); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } if (FsRtlDoesNameContainWildCards( &(Ccb->DirectorySearchPattern)) ? FsRtlIsNameInExpression( &(Ccb->DirectorySearchPattern), &InodeFileName, TRUE, NULL) : !RtlCompareUnicodeString( &(Ccb->DirectorySearchPattern), &InodeFileName, TRUE)) { dwReturn = FFSProcessDirEntry( Vcb, FileInformationClass, pDir->d_ino, Buffer, UsedLength, Length - UsedLength, (FileIndex + dwBytes), &InodeFileName, ReturnSingleEntry); if (dwReturn <= 0) { bRun = FALSE; } else { dwTemp = UsedLength; UsedLength += dwReturn; } } if (InodeFileName.Buffer != NULL) { ExFreePool(InodeFileName.Buffer); InodeFileName.Buffer = NULL; } ProcessNextEntryv1: if (bRun) { dwBytes +=pDir->d_reclen; Ccb->CurrentByteOffset = FileIndex + dwBytes; } if (UsedLength && ReturnSingleEntry) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } ByteOffset = FileIndex + dwBytes; } } else { dwBytes = 0; dwSize = (ULONG)Fcb->dinode2->di_size - FileIndex - (sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1); ByteOffset = FileIndex; dwTemp = 0; while (bRun && UsedLength < Length && dwBytes < dwSize) { OEM_STRING OemName; RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY)); Status = FFSv2ReadInode( NULL, Vcb, Fcb->dinode2, ByteOffset, (PVOID)pDir, sizeof(FFS_DIR_ENTRY), &dwReturn); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } if (!pDir->d_ino) { if (pDir->d_reclen == 0) { FFSBreakPoint(); _SEH2_LEAVE; } goto ProcessNextEntryv2; } OemName.Buffer = pDir->d_name; OemName.Length = (pDir->d_namlen & 0xff); OemName.MaximumLength = OemName.Length; #if 0 /* // // We could not filter the files: "." and ".." // if ((OemName.Length >) 1 && OemName.Buffer[0] == '.') { if ( OemName.Length == 2 && OemName.Buffer[1] == '.') { } else { goto ProcessNextEntry2; } } */ #endif InodeFileNameLength = (USHORT) RtlOemStringToUnicodeSize(&OemName); InodeFileName.Length = 0; InodeFileName.MaximumLength = InodeFileNameLength + 2; if (InodeFileNameLength <= 0) { break; } InodeFileName.Buffer = ExAllocatePoolWithTag( PagedPool, InodeFileNameLength + 2, FFS_POOL_TAG); if (!InodeFileName.Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } RtlZeroMemory( InodeFileName.Buffer, InodeFileNameLength + 2); Status = FFSOEMToUnicode(&InodeFileName, &OemName); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } if (FsRtlDoesNameContainWildCards( &(Ccb->DirectorySearchPattern)) ? FsRtlIsNameInExpression( &(Ccb->DirectorySearchPattern), &InodeFileName, TRUE, NULL) : !RtlCompareUnicodeString( &(Ccb->DirectorySearchPattern), &InodeFileName, TRUE)) { dwReturn = FFSProcessDirEntry( Vcb, FileInformationClass, pDir->d_ino, Buffer, UsedLength, Length - UsedLength, (FileIndex + dwBytes), &InodeFileName, ReturnSingleEntry); if (dwReturn <= 0) { bRun = FALSE; } else { dwTemp = UsedLength; UsedLength += dwReturn; } } if (InodeFileName.Buffer != NULL) { ExFreePool(InodeFileName.Buffer); InodeFileName.Buffer = NULL; } ProcessNextEntryv2: if (bRun) { dwBytes +=pDir->d_reclen; Ccb->CurrentByteOffset = FileIndex + dwBytes; } if (UsedLength && ReturnSingleEntry) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } ByteOffset = FileIndex + dwBytes; } } FileIndex += dwBytes; ((PULONG)((PUCHAR)Buffer + dwTemp)) [0] = 0; if (!UsedLength) { if (FirstQuery) { Status = STATUS_NO_SUCH_FILE; } else { Status = STATUS_NO_MORE_FILES; } } else { Status = STATUS_SUCCESS; } } _SEH2_FINALLY { if (FcbResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (FS_VERSION == 1) { if (dinode1 != NULL) { ExFreePool(dinode1); } } else { if (dinode2 != NULL) { ExFreePool(dinode2); } } if (pDir != NULL) { ExFreePool(pDir); pDir = NULL; } if (InodeFileName.Buffer != NULL) { ExFreePool(InodeFileName.Buffer); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoWriteAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } else { IrpContext->Irp->IoStatus.Information = UsedLength; FFSCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
/* * FUNCTION: Find a file */ static NTSTATUS CdfsFindFile(PDEVICE_EXTENSION DeviceExt, PFCB Fcb, PFCB Parent, PUNICODE_STRING FileToFind, PULONG pDirIndex, PULONG pOffset) { WCHAR name[256]; WCHAR ShortNameBuffer[13]; UNICODE_STRING TempString; UNICODE_STRING ShortName; UNICODE_STRING LongName; UNICODE_STRING FileToFindUpcase; PVOID Block; NTSTATUS Status; ULONG len; ULONG DirIndex; ULONG Offset = 0; BOOLEAN IsRoot; PVOID Context = NULL; ULONG DirSize; PDIR_RECORD Record; LARGE_INTEGER StreamOffset, OffsetOfEntry; DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n", Parent, FileToFind, pDirIndex ? *pDirIndex : 0); DPRINT("FindFile: old Pathname %p, old Objectname %p)\n", Fcb->PathName, Fcb->ObjectName); IsRoot = FALSE; DirIndex = 0; if (FileToFind == NULL || FileToFind->Length == 0) { RtlInitUnicodeString(&TempString, L"."); FileToFind = &TempString; } if (Parent) { if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart) { IsRoot = TRUE; } } else { IsRoot = TRUE; } if (IsRoot == TRUE) { StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE; DirSize = DeviceExt->CdInfo.RootSize; if (FileToFind->Buffer[0] == 0 || (FileToFind->Buffer[0] == '\\' && FileToFind->Buffer[1] == 0) || (FileToFind->Buffer[0] == '.' && FileToFind->Buffer[1] == 0)) { /* it's root : complete essentials fields then return ok */ RtlZeroMemory(Fcb, sizeof(FCB)); RtlInitEmptyUnicodeString(&Fcb->PathName, Fcb->PathNameBuffer, sizeof(Fcb->PathNameBuffer)); Fcb->PathNameBuffer[0] = '\\'; Fcb->PathName.Length = sizeof(WCHAR); Fcb->ObjectName = &Fcb->PathNameBuffer[1]; Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart; Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize; Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY; if (pDirIndex) *pDirIndex = 0; if (pOffset) *pOffset = 0; DPRINT("CdfsFindFile: new Pathname %wZ, new Objectname %S)\n",&Fcb->PathName, Fcb->ObjectName); return STATUS_SUCCESS; } } else { StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; DirSize = Parent->Entry.DataLengthL; } DPRINT("StreamOffset %I64d DirSize %u\n", StreamOffset.QuadPart, DirSize); if (pDirIndex && (*pDirIndex)) DirIndex = *pDirIndex; if (pOffset && (*pOffset)) { Offset = *pOffset; StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE); } if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return STATUS_UNSUCCESSFUL; } Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE); if (Offset) { Offset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength); } /* Upper case the expression for FsRtlIsNameInExpression */ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE); if (!NT_SUCCESS(Status)) { return Status; } while(TRUE) { DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); Status = CdfsGetEntryName (DeviceExt, &Context, &Block, &StreamOffset, DirSize, (PVOID*)&Record, name, &DirIndex, &Offset); if (Status == STATUS_NO_MORE_ENTRIES) { break; } else if (Status == STATUS_UNSUCCESSFUL || Status == STATUS_DISK_CORRUPT_ERROR) { /* Note: the directory cache has already been unpinned */ RtlFreeUnicodeString(&FileToFindUpcase); return Status; } DPRINT("Name '%S'\n", name); RtlInitUnicodeString(&LongName, name); ShortName.Length = 0; ShortName.MaximumLength = 26; ShortName.Buffer = ShortNameBuffer; OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset; CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName); DPRINT("ShortName '%wZ'\n", &ShortName); if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) || FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL)) { if (Parent->PathName.Buffer[0]) { RtlCopyUnicodeString(&Fcb->PathName, &Parent->PathName); len = Parent->PathName.Length / sizeof(WCHAR); Fcb->ObjectName=&Fcb->PathName.Buffer[len]; if (len != 1 || Fcb->PathName.Buffer[0] != '\\') { Fcb->ObjectName[0] = '\\'; Fcb->ObjectName = &Fcb->ObjectName[1]; } } else { Fcb->ObjectName=Fcb->PathName.Buffer; Fcb->ObjectName[0]='\\'; Fcb->ObjectName=&Fcb->ObjectName[1]; } DPRINT("PathName '%wZ' ObjectName '%S'\n", &Fcb->PathName, Fcb->ObjectName); memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD)); wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1, MAX_PATH - (Fcb->PathName.Length / sizeof(WCHAR)) + wcslen(Fcb->ObjectName))); /* Copy short name */ Fcb->ShortNameU.Length = ShortName.Length; Fcb->ShortNameU.MaximumLength = ShortName.Length; Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer; memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length); if (pDirIndex) *pDirIndex = DirIndex; if (pOffset) *pOffset = Offset; DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n", &Fcb->PathName, Fcb->ObjectName, DirIndex); RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return STATUS_SUCCESS; } Offset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength); DirIndex++; } RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); if (pDirIndex) *pDirIndex = DirIndex; if (pOffset) *pOffset = Offset; return STATUS_UNSUCCESSFUL; }
NTSTATUS NcEnumerateDirectorySetupInjection ( _Inout_ PNC_DIR_QRY_CONTEXT DirQryCtx, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PNC_INSTANCE_CONTEXT InstanceContext, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ FILE_INFORMATION_CLASS InformationClass ) /*++ Routine Description: Sets up directory enumeration context cache so that we are ready to perform injection. Arguments: DirQryCtx - Pointer to directory query context (on the stream handle.) FltObjects - FltObjects structure for this operation. InstanceContext - Instance Context for this operation. Offsets - Offsets structure for this information class. InformationClass - The information class for this operation. Return Value: Returns STATUS_SUCCESS on success, otherwise an appropriate error code. --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES RealParentAttributes; HANDLE RealParentHandle = 0; //close always PFILE_OBJECT RealParentFileObj = NULL; IO_STATUS_BLOCK RealParentStatusBlock; char * QueryBuffer = NULL; //free on error, when no injection ULONG QueryBufferLength = 0; USHORT NameLength; ULONG QueryBufferLengthRead; BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, FO_OPENED_CASE_SENSITIVE ); PAGED_CODE(); // // If the user has specified a search string, and if our user mapping // should not be returned in this search string, return success. We // don't need to inject anything. // if (DirQryCtx->SearchString.Length > 0 && !FsRtlIsNameInExpression( &DirQryCtx->SearchString, &InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName, IgnoreCase, NULL ) && !FsRtlIsNameInExpression( &DirQryCtx->SearchString, &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName, IgnoreCase, NULL )) { Status = STATUS_SUCCESS; goto NcEnumerateDirectorySetupCleanup; } // // Initialize insertion info. // // We have to insert the final component of the real mapping // as the final component of the user mapping. To do this we // will open the parent of the real mapping, and query the real // mapping. // Then we will overwrite the real mapping's name with // the final component of the user mapping. This data will be // stored in the DirQryCtx for later injection. // // // Open parent of real mapping. // InitializeObjectAttributes( &RealParentAttributes, &InstanceContext->Mapping.RealMapping.LongNamePath.ParentPath, OBJ_KERNEL_HANDLE, NULL, NULL); Status = NcCreateFileHelper( NcGlobalData.FilterHandle, // Filter FltObjects->Instance, // InstanceOffsets &RealParentHandle, // Returned Handle &RealParentFileObj, // Returned FileObject FILE_LIST_DIRECTORY|FILE_TRAVERSE, // Desired Access &RealParentAttributes, // object attributes &RealParentStatusBlock, // Returned IOStatusBlock 0, // Allocation Size FILE_ATTRIBUTE_NORMAL, // File Attributes 0, // Share Access FILE_OPEN, // Create Disposition FILE_DIRECTORY_FILE, // Create Options NULL, // Ea Buffer 0, // EA Length IO_IGNORE_SHARE_ACCESS_CHECK, // Flags FltObjects->FileObject ); // Transaction state if (!NT_SUCCESS( Status )) { goto NcEnumerateDirectorySetupCleanup; } // // Allocate Buffer to store mapping data. // NameLength = Max( InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName.Length, InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length ); QueryBufferLength = Offsets->FileNameDist + NameLength; QueryBuffer = ExAllocatePoolWithTag( PagedPool, QueryBufferLength, NC_DIR_QRY_CACHE_TAG ); if (QueryBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto NcEnumerateDirectorySetupCleanup; } // // Query the information from the parent of the real mapping. // Status = NcQueryDirectoryFile( FltObjects->Instance, RealParentFileObj, QueryBuffer, QueryBufferLength, InformationClass, TRUE,//Return single entry &InstanceContext->Mapping.RealMapping.LongNamePath.FinalComponentName, FALSE,//restart scan &QueryBufferLengthRead); if (Status == STATUS_NO_SUCH_FILE) { // // The user mapping does not exist, this is allowed. It means we // have nothing to inject. // DirQryCtx->InjectionEntry.Buffer = NULL; DirQryCtx->InjectionEntry.CurrentOffset = 0; ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG ); QueryBuffer = NULL; Status = STATUS_SUCCESS; } else if (!NT_SUCCESS( Status )) { // // An unexpected error occurred, return code. // goto NcEnumerateDirectorySetupCleanup; } else { // // Now we have to munge the real mapping directory entry into a // user mapping directory entry. // NcSetFileName( QueryBuffer, InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Buffer, InstanceContext->Mapping.UserMapping.LongNamePath.FinalComponentName.Length, Offsets, TRUE ); NcSetShortName( QueryBuffer, InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Buffer, InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName.Length, Offsets ); FLT_ASSERT( DirQryCtx->InjectionEntry.Buffer == NULL ); // // Set the injection entry up in the cache. // DirQryCtx->InjectionEntry.Buffer = QueryBuffer; DirQryCtx->InjectionEntry.CurrentOffset = 0; } NcEnumerateDirectorySetupCleanup: if (!NT_SUCCESS( Status )) { if(QueryBuffer != NULL) { ExFreePoolWithTag( QueryBuffer, NC_DIR_QRY_CACHE_TAG ); } } if (RealParentHandle != NULL) { FltClose( RealParentHandle ); } if (RealParentFileObj != NULL) { ObDereferenceObject( RealParentFileObj ); } return Status; }
/************************************************************************* * * Function: Ext2QueryDirectory() * * Description: * Query directory request. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: STATUS_SUCCESS/Error * *************************************************************************/ NTSTATUS NTAPI Ext2QueryDirectory( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, #ifdef _GNU_NTIFS_ PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, #else PIO_STACK_LOCATION PtrIoStackLocation, #endif PFILE_OBJECT PtrFileObject, PtrExt2FCB PtrFCB, PtrExt2CCB PtrCCB) { NTSTATUS RC = STATUS_SUCCESS; BOOLEAN PostRequest = FALSE; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; BOOLEAN CanWait = FALSE; PtrExt2VCB PtrVCB = NULL; BOOLEAN AcquiredFCB = FALSE; unsigned long BufferLength = 0; unsigned long BufferIndex = 0; unsigned long FileIndex = 0; PUNICODE_STRING PtrSearchPattern = NULL; FILE_INFORMATION_CLASS FileInformationClass; BOOLEAN RestartScan = FALSE; BOOLEAN ReturnSingleEntry = FALSE; BOOLEAN IndexSpecified = FALSE; unsigned char *Buffer = NULL; BOOLEAN FirstTimeQuery = FALSE; unsigned long StartingIndexForSearch = 0; unsigned long BytesReturned = 0; BOOLEAN BufferUsedup = FALSE; BOOLEAN SearchWithWildCards = FALSE; PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL; PEXT2_DIR_ENTRY PtrDirEntry = NULL; PEXT2_INODE PtrInode = NULL; unsigned long LogicalBlockSize; unsigned long ThisBlock; // The starting Physical Block No... //LARGE_INTEGER StartPhysicalBlock; LARGE_INTEGER StartBufferOffset ; ULONG PinBufferLength; // Buffer Control Block PBCB PtrBCB = NULL; BYTE * PtrPinnedBlockBuffer = NULL; unsigned int j; DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer ); try { // Validate the sent-in FCB if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { // We will only allow notify requests on directories. RC = STATUS_INVALID_PARAMETER; } PtrReqdFCB = &(PtrFCB->NTRequiredFCB); CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); PtrVCB = PtrFCB->PtrVCB; // // Asynchronous IO requested // Posting request... // /* * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL * requests aren't handled in the worker thread yet. I tried * adding handling of them to the worked routine, but there * were problems with accessing the PtrIoStackLocation-> * Parameters.QueryDirectory.FileName variable. * -- Filip Navara, 18/08/2004 */ #if 0 if (!CanWait) { PostRequest = TRUE; try_return(RC = STATUS_PENDING); } #endif // Obtain the callers parameters BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length; PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName; FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass; FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex; // Some additional arguments that affect the FSD behavior RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN); ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY); IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED); // // Acquiring exclusive access to the FCB. // This is not mandatory // DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); AcquiredFCB = TRUE; // We must determine the buffer pointer to be used. Since this // routine could either be invoked directly in the context of the // calling thread, or in the context of a worker thread, here is // a general way of determining what we should use. Buffer = Ext2GetCallersBuffer ( PtrIrp ); // The method of determining where to look from and what to look for is // unfortunately extremely confusing. However, here is a methodology you // you can broadly adopt: // (a) You have to maintain a search buffer per CCB structure. // (b) This search buffer is initialized the very first time // a query directory operation is performed using the file object. // (For the sample FSD, the search buffer is stored in the // DirectorySearchPattern field) // However, the caller still has the option of "overriding" this stored // search pattern by supplying a new one in a query directory operation. // if( PtrCCB->DirectorySearchPattern.Length ) { if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0); } DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); } if (PtrSearchPattern != NULL) { // User has supplied a search pattern // Now validate that the search pattern is legitimate if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This must be the very first query request. FirstTimeQuery = TRUE; } else { // We should ignore the search pattern in the CCB and instead, // use the user-supplied pattern for this particular query // directory request. Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); } // Now, allocate enough memory to contain the caller // supplied search pattern and fill in the DirectorySearchPattern // field in the CCB Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern ); /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) ); */ } else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This MUST be the first directory query operation (else the // DirectorySearchPattern field would never be empty. Also, the caller // has neglected to provide a pattern so we MUST invent one. // Use "*" (following NT conventions) as your search pattern // and store it in the PtrCCB->DirectorySearchPattern field. /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/ Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" ); FirstTimeQuery = TRUE; } else { // The caller has not supplied any search pattern... // Using previously supplied pattern PtrSearchPattern = &PtrCCB->DirectorySearchPattern; } if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 ); } DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern ); // There is one other piece of information that your FSD must store // in the CCB structure for query directory support. This is the index // value (i.e. the offset in your on-disk directory structure) from // which you should start searching. // However, the flags supplied with the IRP can make us override this // as well. if (FileIndex) { // Caller has told us wherefrom to begin. // You may need to round this to an appropriate directory entry // entry alignment value. StartingIndexForSearch = FileIndex; } else if (RestartScan) { StartingIndexForSearch = 0; } else { // Get the starting offset from the CCB. StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart; } // Read in the file inode if it hasn't already been read... Ext2InitializeFCBInodeInfo( PtrFCB ); if (PtrFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), TRUE, // We will utilize pin access for directories &(Ext2GlobalData.CacheMgrCallBacks), // callbacks PtrCCB); // The context used in callbacks } // // Read in the next Data Block of this directory // LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize ); StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary... PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart; if ( !CcMapData( PtrFileObject, &StartBufferOffset, PinBufferLength, TRUE, &PtrBCB, (PVOID*)&PtrPinnedBlockBuffer ) ) { // Read Failure DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0); try_return(); } else { DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); } PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) ); // // Walking through the directory entries... for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; ) { PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ]; StartingIndexForSearch += PtrDirEntry->rec_len; PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch; if( PtrDirEntry->inode == 0 ) { continue; } if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 ) { // // This should not happen // Hqw can this be so!!! // Ext2BreakPoint(); if( BothDirInformation ) { BothDirInformation->NextEntryOffset = 0; } if( !BytesReturned ) { if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; } break; } // Does this entry match the search criterian? // Checking // { UNICODE_STRING FileName; LONG Matched = 0; // Constructing a counted Unicode string out of PtrDirEntry Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len ); if ( SearchWithWildCards ) { Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL ); } else { Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE ); } Ext2DeallocateUnicodeString( &FileName ); if( !Matched ) { continue; } } switch( FileInformationClass ) { case FileBothDirectoryInformation: DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( BothDirInformation ) BothDirInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) ); BothDirInformation->EaSize = 0; BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size; BothDirInformation->ChangeTime.QuadPart = 0; BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } BothDirInformation->FileIndex = StartingIndexForSearch; BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; BothDirInformation->ShortNameLength = 0; BothDirInformation->ShortName[0] = 0; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j]; BothDirInformation->FileName[ j ] = PtrDirEntry->name[j]; // if( j < 11 ) // BothDirInformation->ShortName[j] = PtrDirEntry->name[j]; } /* if( j < 11 ) { BothDirInformation->ShortNameLength = j * 2 + 2; BothDirInformation->ShortName[ j ] = 0; } else { BothDirInformation->ShortNameLength = 24; BothDirInformation->ShortName[ 11 ] = 0; }*/ BothDirInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) BothDirInformation->NextEntryOffset = ThisBlock; else BothDirInformation->NextEntryOffset = 0; break; case FileDirectoryInformation: // DirectoryInformation DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( DirectoryInformation ) DirectoryInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) ); DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size; DirectoryInformation->ChangeTime.QuadPart = 0; DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } DirectoryInformation->FileIndex = StartingIndexForSearch; DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j]; } DirectoryInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) DirectoryInformation->NextEntryOffset = ThisBlock; else DirectoryInformation->NextEntryOffset = 0; break; case FileFullDirectoryInformation: // FullDirInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 ); try_return(); case FileNamesInformation: // NamesInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 ); try_return(); default: DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 ); try_return( RC = STATUS_INVALID_INFO_CLASS ); } if( ReturnSingleEntry ) { break; } }// end of for... if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) ) { Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); PtrCCB->CurrentByteOffset.QuadPart = 0; if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; try_return(); } else if( BytesReturned ) { BothDirInformation->NextEntryOffset = 0; } try_exit: NOTHING; } finally { if( PtrInode ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode ); ExFreePool( PtrInode ); } if( PtrBCB ) { CcUnpinData( PtrBCB ); PtrBCB = NULL; } if (PostRequest) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Map the users buffer and then post the request. RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength); ASSERT(NT_SUCCESS(RC)); RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Complete the request. PtrIrp->IoStatus.Status = RC; PtrIrp->IoStatus.Information = BytesReturned; // Free up the Irp Context Ext2ReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); } // Flush the saved BCBs... // Ext2FlushSavedBCBs ( PtrIrpContext ); } return(RC); }
NTSTATUS NpQueryDirectory ( IN PROOT_DCB RootDcb, IN PROOT_DCB_CCB Ccb, IN PIRP Irp ) /*++ Routine Description: This is the work routine for querying a directory. Arugments: RootDcb - Supplies the dcb being queried Ccb - Supplies the context of the caller Irp - Supplies the Irp being processed Return Value: NTSTATUS - The return status for the operation. --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PUCHAR Buffer; CLONG SystemBufferLength; UNICODE_STRING FileName; ULONG FileIndex; FILE_INFORMATION_CLASS FileInformationClass; BOOLEAN RestartScan; BOOLEAN ReturnSingleEntry; BOOLEAN IndexSpecified; static WCHAR Star = L'*'; BOOLEAN CaseInsensitive = TRUE; //*** Make searches case insensitive ULONG CurrentIndex; ULONG LastEntry; ULONG NextEntry; PLIST_ENTRY Links; PFCB Fcb; PFILE_DIRECTORY_INFORMATION DirInfo; PFILE_NAMES_INFORMATION NamesInfo; PAGED_CODE(); // // Get the current stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "NpQueryDirectory\n", 0 ); DebugTrace( 0, Dbg, "RootDcb = %08lx\n", RootDcb); DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb); DebugTrace( 0, Dbg, "SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer); DebugTrace( 0, Dbg, "Length = %08lx\n", IrpSp->Parameters.QueryDirectory.Length); DebugTrace( 0, Dbg, "FileName = %Z\n", IrpSp->Parameters.QueryDirectory.FileName); DebugTrace( 0, Dbg, "FileIndex = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex); DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass); DebugTrace( 0, Dbg, "RestartScan = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN)); DebugTrace( 0, Dbg, "ReturnSingleEntry = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY)); DebugTrace( 0, Dbg, "IndexSpecified = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED)); // // Save references to the input parameters within the Irp // SystemBufferLength = IrpSp->Parameters.QueryDirectory.Length; FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN); ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED); if (IrpSp->Parameters.QueryDirectory.FileName != NULL) { FileName = *(PUNICODE_STRING)IrpSp->Parameters.QueryDirectory.FileName; } else { FileName.Length = 0; FileName.Buffer = NULL; } // // Check if the ccb already has a query template attached. If it // does not already have one then we either use the string we are // given or we attach our own containing "*" // if (Ccb->QueryTemplate == NULL) { // // This is our first time calling query directory so we need // to either set the query template to the user specified string // or to "*" // if (FileName.Buffer == NULL) { DebugTrace(0, Dbg, "Set template to *\n", 0); FileName.Length = 2; FileName.Buffer = ⋆ } DebugTrace(0, Dbg, "Set query template -> %Z\n", &FileName); // // Allocate space for the query template // Ccb->QueryTemplate = FsRtlAllocatePool( PagedPool, sizeof(UNICODE_STRING) + FileName.Length ); // // Initialize the query template and copy over the string // Ccb->QueryTemplate->Length = FileName.Length; Ccb->QueryTemplate->Buffer = (PWCH)Ccb->QueryTemplate + sizeof(UNICODE_STRING) / sizeof(WCHAR); RtlCopyMemory( Ccb->QueryTemplate->Buffer, FileName.Buffer, FileName.Length ); // // Now zero out the FileName so we won't think we're to use it // as a subsearch string. // FileName.Length = 0; FileName.Buffer = NULL; } // // Check if we were given an index to start with or if we need to // restart the scan or if we should use the index that was saved in // the ccb // if (RestartScan) { FileIndex = 0; } else if (!IndexSpecified) { FileIndex = Ccb->IndexOfLastCcbReturned + 1; } // // Now we are committed to completing the Irp, we do that in // the finally clause of the following try. // try { ULONG BaseLength; ULONG LengthAdded; // // Map the user buffer. // Buffer = NpMapUserBuffer( Irp ); // // At this point we are about to enter our query loop. We have // already decided which Fcb index we need to return. The variables // LastEntry and NextEntry are used to index into the user buffer. // LastEntry is the last entry we added to the user buffer, and // NextEntry is the current one we're working on. CurrentIndex // is the Fcb index that we are looking at next. Logically the // way the loop works is as follows. // // Scan all of the Fcb in the directory // // if the Fcb matches the query template then // // if the CurrentIndex is >= the FileIndex then // // process this fcb, and decide if we should // continue the main loop // // end if // // Increment the current index // // end if // // end scan // CurrentIndex = 0; LastEntry = 0; NextEntry =0; switch (FileInformationClass) { case FileDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); break; case FileFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); break; case FileNamesInformation: BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); break; case FileBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); break; default: try_return( Status = STATUS_INVALID_INFO_CLASS ); } for (Links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &RootDcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) { Fcb = CONTAINING_RECORD(Links, FCB, ParentDcbLinks); ASSERT(Fcb->NodeTypeCode == NPFS_NTC_FCB); DebugTrace(0, Dbg, "Top of Loop\n", 0); DebugTrace(0, Dbg, "Fcb = %08lx\n", Fcb); DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", CurrentIndex); DebugTrace(0, Dbg, "FileIndex = %08lx\n", FileIndex); DebugTrace(0, Dbg, "LastEntry = %08lx\n", LastEntry); DebugTrace(0, Dbg, "NextEntry = %08lx\n", NextEntry); // // Check if the Fcb represents a named pipe that is part of // our query template // if (FsRtlIsNameInExpression( Ccb->QueryTemplate, &Fcb->LastFileName, CaseInsensitive, NULL )) { // // The fcb is in the query template so now check if // this is the index we should start returning // if (CurrentIndex >= FileIndex) { ULONG BytesToCopy; ULONG BytesRemainingInBuffer; // // Here are the rules concerning filling up the buffer: // // 1. The Io system garentees that there will always be // enough room for at least one base record. // // 2. If the full first record (including file name) cannot // fit, as much of the name as possible is copied and // STATUS_BUFFER_OVERFLOW is returned. // // 3. If a subsequent record cannot completely fit into the // buffer, none of it (as in 0 bytes) is copied, and // STATUS_SUCCESS is returned. A subsequent query will // pick up with this record. // BytesRemainingInBuffer = SystemBufferLength - NextEntry; if ( (NextEntry != 0) && ( (BaseLength + Fcb->LastFileName.Length > BytesRemainingInBuffer) || (SystemBufferLength < NextEntry) ) ) { DebugTrace(0, Dbg, "Next entry won't fit\n", 0); try_return( Status = STATUS_SUCCESS ); } ASSERT( BytesRemainingInBuffer >= BaseLength ); // // See how much of the name we will be able to copy into // the system buffer. This also dictates out return // value. // if ( BaseLength + Fcb->LastFileName.Length <= BytesRemainingInBuffer ) { BytesToCopy = Fcb->LastFileName.Length; Status = STATUS_SUCCESS; } else { BytesToCopy = BytesRemainingInBuffer - BaseLength; Status = STATUS_BUFFER_OVERFLOW; } // // Note how much of buffer we are consuming and zero // the base part of the structure. // LengthAdded = BaseLength + BytesToCopy; RtlZeroMemory( &Buffer[NextEntry], BaseLength ); // // Now fill the base parts of the strucure that are // applicable. // switch (FileInformationClass) { case FileBothDirectoryInformation: // // We don't need short name // DebugTrace(0, Dbg, "Getting directory full information\n", 0); case FileFullDirectoryInformation: // // We don't use EaLength, so fill in nothing here. // DebugTrace(0, Dbg, "Getting directory full information\n", 0); case FileDirectoryInformation: DebugTrace(0, Dbg, "Getting directory information\n", 0); // // The eof indicates the number of instances and // allocation size is the maximum allowed // DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry]; DirInfo->EndOfFile.QuadPart = Fcb->OpenCount; DirInfo->AllocationSize.QuadPart = Fcb->Specific.Fcb.MaximumInstances; DirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL; DirInfo->FileNameLength = Fcb->LastFileName.Length; break; case FileNamesInformation: DebugTrace(0, Dbg, "Getting names information\n", 0); NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry]; NamesInfo->FileNameLength = Fcb->LastFileName.Length; break; default: NpBugCheck( FileInformationClass, 0, 0 ); } RtlCopyMemory( &Buffer[NextEntry + BaseLength], Fcb->LastFileName.Buffer, BytesToCopy ); // // Update the ccb to the index we've just used // Ccb->IndexOfLastCcbReturned = CurrentIndex; // // And indicate how much of the system buffer we have // currently used up. We must compute this value before // we long align outselves for the next entry // Irp->IoStatus.Information = NextEntry + LengthAdded; // // Setup the previous next entry offset // *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry; // // Check if the last entry didn't completely fit // if ( Status == STATUS_BUFFER_OVERFLOW ) { try_return( NOTHING ); } // // Check if we are only to return a single entry // if (ReturnSingleEntry) { try_return( Status = STATUS_SUCCESS ); } // // Set ourselves up for the next iteration // LastEntry = NextEntry; NextEntry += (ULONG)QuadAlign( LengthAdded ); } // // Increment the current index by one // CurrentIndex += 1; } } // // At this point we've scanned the entire list of Fcb so if // the NextEntry is zero then we haven't found anything so we // will return no more files, otherwise we return success. // if (NextEntry == 0) { Status = STATUS_NO_MORE_FILES; } else { Status = STATUS_SUCCESS; } try_exit: NOTHING; } finally { if (!AbnormalTermination()) { NpCompleteRequest( Irp, Status ); } DebugTrace(-1, Dbg, "NpQueryDirectory -> %08lx\n", Status); } return Status; }
BOOLEAN CdIsNameInExpression ( IN PIRP_CONTEXT IrpContext, IN PCD_NAME CurrentName, IN PCD_NAME SearchExpression, IN ULONG WildcardFlags, IN BOOLEAN CheckVersion ) /*++ Routine Description: This routine will compare two CdName strings. We assume that if this is to be a case-insensitive search then they are already upcased. We compare the filename portions of the name and if they match we compare the version strings if requested. Arguments: CurrentName - Filename from the disk. SearchExpression - Filename expression to use for match. WildcardFlags - Flags field which indicates which parts of the search expression might have wildcards. These flags are the same as in the Ccb flags field. CheckVersion - Indicates whether we should check both the name and the version strings or just the name. Return Value: BOOLEAN - TRUE if the expressions match, FALSE otherwise. --*/ { BOOLEAN Match = TRUE; PAGED_CODE(); // // If there are wildcards in the expression then we call the // appropriate FsRtlRoutine. // if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD )) { Match = FsRtlIsNameInExpression( &SearchExpression->FileName, &CurrentName->FileName, FALSE, NULL ); // // Otherwise do a direct memory comparison for the name string. // } else { if ((CurrentName->FileName.Length != SearchExpression->FileName.Length) || (!RtlEqualMemory( CurrentName->FileName.Buffer, SearchExpression->FileName.Buffer, CurrentName->FileName.Length ))) { Match = FALSE; } } // // Check the version numbers if requested by the user and we have a // match on the name and the version number is present. // if (Match && CheckVersion && SearchExpression->VersionString.Length && !FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL )) { // // If there are wildcards in the expression then call the // appropriate search expression. // if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD )) { Match = FsRtlIsNameInExpression( &SearchExpression->VersionString, &CurrentName->VersionString, FALSE, NULL ); // // Otherwise do a direct memory comparison for the name string. // } else { if ((CurrentName->VersionString.Length != SearchExpression->VersionString.Length) || (!RtlEqualMemory( CurrentName->VersionString.Buffer, SearchExpression->VersionString.Buffer, CurrentName->VersionString.Length ))) { Match = FALSE; } } } return Match; }