__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; }
ULONG NTAPI BasepOemStringToUnicodeSize(IN PANSI_STRING String) { return RtlOemStringToUnicodeSize(String); }