Пример #1
0
/*************************************************************************
*
* Function: Ext2MountVolume()
*
* Description:
*	This routine is used for querying the partition information.
*
* Expected Interrupt Level (for execution) :
*  IRQL_PASSIVE_LEVEL 
*
* Arguments:
*
*	TargetDeviceObject - The target of the query
*	PartitionInformation - Receives the result of the query
*
* Return Value:
*
*	NTSTATUS - The return status for the operation
*
*************************************************************************/
NTSTATUS
Ext2GetPartitionInfo (
    IN PDEVICE_OBJECT TargetDeviceObject,
    IN PPARTITION_INFORMATION PartitionInformation
    )
{
    PIRP Irp;
    KEVENT *PtrEvent = NULL;
    NTSTATUS Status;
    IO_STATUS_BLOCK Iosb;

    //
    //  Query the partition table
    //
	PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) )  );
	



    KeInitializeEvent( PtrEvent, NotificationEvent, FALSE );
	
    Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO,
                                         TargetDeviceObject,
                                         NULL,
                                         0,
                                         PartitionInformation,
                                         sizeof(PARTITION_INFORMATION),
                                         FALSE,
                                         PtrEvent,
                                         &Iosb );

    if ( Irp == NULL ) 
	{
		DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", PtrEvent);
		ExFreePool( PtrEvent );
		return 0;
    }

    Status = IoCallDriver( TargetDeviceObject, Irp );

    if ( Status == STATUS_PENDING ) {

        (VOID) KeWaitForSingleObject( PtrEvent,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      (PLARGE_INTEGER)NULL );

        Status = Iosb.Status;
    }
	DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", PtrEvent);
	ExFreePool( PtrEvent );
    return Status;
}
Пример #2
0
/*************************************************************************
*
* Function: Ext2MountVolume()
*
* Description:
*	This routine verifies and mounts the volume; 
*	Called by FSCTRL IRP handler to attempt a 
*		volume mount.
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL 
*
*
* Arguments:
*
*    Irp - Supplies the Irp being processed
*	 IrpSp - Irp Stack Location pointer
*
* Return Value: 
*
*   NTSTATUS - The Mount status
*
*************************************************************************/
NTSTATUS
Ext2MountVolume ( 
	IN PIRP Irp,
	IN PIO_STACK_LOCATION IrpSp )
{
	
	//	Volume Parameter Block
	PVPB PtrVPB;

	//	The target device object
	PDEVICE_OBJECT TargetDeviceObject = NULL;

	// The new volume device object (to be created if partition is Ext2)
	PDEVICE_OBJECT PtrVolumeDeviceObject = NULL;
	
	//	Return Status
	NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;

	// Number of bytes to read for Volume verification...
	unsigned long NumberOfBytesToRead = 0;
	
	//	Starting Offset for 'read'
	LONGLONG StartingOffset = 0;

	//	Boot Sector information...
	PPACKED_BOOT_SECTOR BootSector = NULL;
	
	//	Ext2 Super Block information...
	PEXT2_SUPER_BLOCK SuperBlock = NULL;

	//	Volume Control Block
	PtrExt2VCB			PtrVCB = NULL;

	//	The File Object for the root directory
	PFILE_OBJECT PtrRootFileObject = NULL;
	
	//	Flag
	int WeClearedVerifyRequiredBit;
	
	//	Used by a for loop...
	unsigned int i;
	
	//	
	LARGE_INTEGER VolumeByteOffset;

	unsigned long LogicalBlockSize = 0;

	//	Buffer Control Block
	PBCB PtrBCB = NULL;
			
	//	Cache Buffer - used for pinned access of volume...
	PVOID PtrCacheBuffer = NULL;
	
	PEXT2_GROUP_DESCRIPTOR	PtrGroupDescriptor = NULL;

	// Inititalising variables
	
	PtrVPB = IrpSp->Parameters.MountVolume.Vpb;
	TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
	
	try
	{
		//
		//	1. Reading in Volume meta data
		//

		//	Temporarily clear the DO_VERIFY_VOLUME Flag
		WeClearedVerifyRequiredBit = 0;
		if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) 
		{
            Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME );
            WeClearedVerifyRequiredBit = 1;
        }

		//	Allocating memory for reading in Boot Sector...
		NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize );
		BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead  );
		RtlZeroMemory( BootSector, NumberOfBytesToRead );

		//	Reading in Boot Sector
		StartingOffset = 0L;
		Ext2PerformVerifyDiskRead ( TargetDeviceObject,
			BootSector, StartingOffset, NumberOfBytesToRead );

		// Reject a volume that contains fat artifacts
		
		DebugTrace(DEBUG_TRACE_MOUNT, "OEM[%s]", BootSector->Oem);
		if (BootSector->Oem[0])
		{
		    try_return();
		}

		//	Allocating memory for reading in Super Block...
		
		SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead  );
		RtlZeroMemory( SuperBlock, NumberOfBytesToRead );
		StartingOffset = 1024;

		//	Reading in the Super Block...
		Ext2PerformVerifyDiskRead ( TargetDeviceObject,
			SuperBlock, StartingOffset, NumberOfBytesToRead );

		//	Resetting the DO_VERIFY_VOLUME Flag
		if( WeClearedVerifyRequiredBit ) 
		{
			PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME;
		}

		// Verifying the Super Block..
		if( SuperBlock->s_magic == EXT2_SUPER_MAGIC )
		{
			//
			//	Found a valid super block.
			//	No more tests for now.
			//	Assuming that this is an ext2 partition...
			//	Going ahead with mount.
			//
			DebugTrace(DEBUG_TRACE_MOUNT,   "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name);
			//
			//	2. Creating a volume device object
			//
	        if (!NT_SUCCESS( IoCreateDevice( 
					Ext2GlobalData.Ext2DriverObject,	//	(This) Driver object
					Ext2QuadAlign( sizeof(Ext2VCB) ),	//	Device Extension
                    NULL,								//	Device Name - no name ;)
                    FILE_DEVICE_DISK_FILE_SYSTEM,		//	Disk File System
                    0,									//	DeviceCharacteristics
                    FALSE,								//	Not an exclusive device
                    (PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) //	The Volume Device Object
					) 
			{
	            try_return();
			}

			//	
			//  Our alignment requirement is the larger of the processor alignment requirement
			//  already in the volume device object and that in the TargetDeviceObject
			//

			if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement) 
			{
				PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
			}
			
			//
			//	Clearing the Device Initialising Flag
			//
			Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);


			//
			//	Setting the Stack Size for the newly created Volume Device Object
			//
			PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
			

			//
			//	3. Creating the link between Target Device Object 
			//	and the Volume Device Object via the Volume Parameter Block
			//
			PtrVPB->DeviceObject = PtrVolumeDeviceObject;
			
			//	Remembring the Volume parameters in the VPB bock
			for( i = 0; i < 16 ; i++ )
			{
				PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i];
				if( SuperBlock->s_volume_name[i] == 0 )
					break;
			}
			PtrVPB->VolumeLabelLength = i * 2;
			PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0];
				
			//
			//	4. Initialise the Volume Comtrol Block
			//
			{
				LARGE_INTEGER AllocationSize;

				AllocationSize .QuadPart = 
					( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) * 
					SuperBlock->s_blocks_count;

				Ext2InitializeVCB(
					PtrVolumeDeviceObject, 
					TargetDeviceObject,
					PtrVPB,
					&AllocationSize);
				PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension);
				ASSERT( PtrVCB );
			}

			PtrVCB->InodesCount = SuperBlock->s_inodes_count;
			PtrVCB->BlocksCount = SuperBlock->s_blocks_count;
			PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count;
			PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count;
			PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count;
			PtrVCB->LogBlockSize = SuperBlock->s_log_block_size;
			PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group;
			PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group;
			PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block 
								+ SuperBlock->s_blocks_per_group - 1 ) 
								/ SuperBlock->s_blocks_per_group;
			if( SuperBlock->s_rev_level )
			{
				PtrVCB->InodeSize = SuperBlock->s_inode_size;
			}
			else
			{
				PtrVCB->InodeSize = sizeof( EXT2_INODE );
			}

			PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups  );
			
			RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups );

			//
			//	Attempting to Read in some matadata from the Cache...
			//	using pin access...
			//
			LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
	
			//
			//	Reading Group Descriptors...
			//
			if( PtrVCB->LogBlockSize )
			{
				//	First block contains the descriptors...
				VolumeByteOffset.QuadPart = LogicalBlockSize;
			}
			else
			{
				//	Second block contains the descriptors...
				VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
			}

			NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
			NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );

			if (!CcMapData( PtrVCB->PtrStreamFileObject,
                   &VolumeByteOffset,
                   NumberOfBytesToRead,
                   TRUE,
                   &PtrBCB,
                   &PtrCacheBuffer )) 
			{
				DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
				try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
			}
			else
			{
				//	
				//	Saving up Often Used Group Descriptor Information in the VCB...
				//
				unsigned int DescIndex ;

				DebugTrace(DEBUG_TRACE_MISC,   "Cache hit while reading in volume meta data", 0);
				PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer;
				for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ )
				{
					PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock 
						= PtrGroupDescriptor[ DescIndex ].bg_inode_table;

					PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock 
						= PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap
						;
					PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock 
						= PtrGroupDescriptor[ DescIndex ].bg_block_bitmap
						;
					PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount 
						= PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count;

					PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount 
						= PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count;
				}
				CcUnpinData( PtrBCB );
				PtrBCB = NULL;
			}

			//
			//	5. Creating a Root Directory FCB
			//
			PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject );
			if( !PtrRootFileObject )
			{
				try_return();
			}
			//
			//	Associate the file stream with the Volume parameter block...
			//	I do it now
			//
			PtrRootFileObject->Vpb = PtrVCB->PtrVPB;

			PtrRootFileObject->ReadAccess = TRUE;
			PtrRootFileObject->WriteAccess = TRUE;

			{
				PtrExt2ObjectName		PtrObjectName;
				LARGE_INTEGER ZeroSize;

				PtrObjectName = Ext2AllocateObjectName();
				RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" );
				Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" );


				ZeroSize.QuadPart = 0;
				if ( !NT_SUCCESS( Ext2CreateNewFCB( 
						&PtrVCB->PtrRootDirectoryFCB,	//	Root FCB
						ZeroSize,			//	AllocationSize,
						ZeroSize,			//	EndOfFile,
						PtrRootFileObject,		//	The Root Dircetory File Object
						PtrVCB,
						PtrObjectName  )  )  )
				{
					try_return();
				}
				

				PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY;


			}

			PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject;
			PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO;
			PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject);
			RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" );

			Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB );

			//	
			//	Initiating caching for root directory...
			//

			CcInitializeCacheMap(PtrRootFileObject, 
				(PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
				TRUE,		// We will utilize pin access for directories
				&(Ext2GlobalData.CacheMgrCallBacks), // callbacks
				PtrVCB->PtrRootDirectoryFCB );		// The context used in callbacks


			//
			//	6. Update the VCB Flags
			//
			PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ;	//	| EXT2_VCB_FLAGS_VOLUME_READ_ONLY;


			//
			//	7. Mount Success
			//
			Status = STATUS_SUCCESS;
			
			{
				//
				//	This block is for testing....
				//	To be removed...

				/*
				EXT2_INODE	Inode ;
				Ext2ReadInode( PtrVCB, 100, &Inode );
				DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size );
				Ext2DeallocInode( NULL, PtrVCB, 0xfb6 );
				*/
			}
			
			//	 ObDereferenceObject( TargetDeviceObject );
		}
		else
		{
			DebugTrace(DEBUG_TRACE_MOUNT,   "Failing mount. Partition not Ext2...", 0);
		}

		try_exit: NOTHING;
	}
	finally 
	{
		//	Freeing Allocated Memory...
		if( SuperBlock != NULL )
		{
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", SuperBlock );
			ExFreePool( SuperBlock );
		}
		if( BootSector != NULL )
		{
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", BootSector);
			ExFreePool( BootSector );
		}

		// start unwinding if we were unsuccessful
		if (!NT_SUCCESS( Status )) 
		{
						
		}
	}
	
	return Status;
}
Пример #3
0
NTSTATUS NTAPI Ext2PassDownSingleReadWriteIRP(
	PtrExt2IrpContext	PtrIrpContext,
	PIRP				PtrIrp, 
	PtrExt2VCB			PtrVCB,
	LARGE_INTEGER		ByteOffset, 
	uint32				ReadWriteLength, 
	BOOLEAN				SynchronousIo)
{
	NTSTATUS				RC = STATUS_SUCCESS;

	PEXT2_IO_CONTEXT		PtrIoContext = NULL;
	PKEVENT					PtrSyncEvent = NULL;

	PIO_STACK_LOCATION	PtrIrpNextSp = NULL;

	try
	{
		if( !PtrIrp->MdlAddress )
		{
			Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength );
		}


		if( SynchronousIo )
		{
			PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) )  );
			if ( !PtrSyncEvent )
			{
				RC = STATUS_INSUFFICIENT_RESOURCES;
				try_return();
			}
			KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
		}

		//
		//	Allocate and initialize a completion context
		//
		PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) )  );
		if ( !PtrIoContext )
		{
			RC = STATUS_INSUFFICIENT_RESOURCES;
			try_return();
		}

		RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) );
		PtrIoContext->Count = 1;
		PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT;
		PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT );
		PtrIoContext->PtrMasterIrp = NULL;
		PtrIoContext->PtrSyncEvent = PtrSyncEvent;
		PtrIoContext->ReadWriteLength = ReadWriteLength;

 		IoSetCompletionRoutine( PtrIrp, 
			SynchronousIo ?	
			Ext2SingleSyncCompletionRoutine: 
			Ext2SingleAsyncCompletionRoutine,
			PtrIoContext, TRUE, TRUE, TRUE );

		//
		//  Setup the next IRP stack location in the associated Irp for the disk
		//  driver beneath us.
		//
		PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp );

		//
		//  Setup the Stack location to do a read from the disk driver.
		//
		PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction;
		if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
		{
			PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength;
			PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset;
		}
		else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
		{
			PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength;
			PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset;
		}
		//
		//  Issue the read / write request
		//
		RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp);

		if( SynchronousIo )
		{
			//
			//	Wait for completion...
			//
			RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent,
						Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );

			RC = STATUS_SUCCESS;
		}
		else
		{
			RC = STATUS_PENDING;
		}

		try_exit:	NOTHING;
	}
	finally 
	{
		if( PtrSyncEvent )
		{
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrSyncEvent );
			ExFreePool( PtrSyncEvent );
		}
		if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
		{
			//
			//	This means we are getting out of 
			//	this function without doing a read / write
			//	due to an error, maybe...
			//
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrIoContext );
			ExFreePool( PtrIoContext );
		}
	}
	return RC;
}
Пример #4
0
/*************************************************************************
*
* Function: Ext2PassDownMultiReadWriteIRP()
*
* Description:
*	pass down multiple read IRPs as Associated IRPs
*
* Expected Interrupt Level (for execution) :
*
*  ?
*
* Return Value: STATUS_SUCCESS / STATUS_PENDING / Error
*
*************************************************************************/
NTSTATUS NTAPI Ext2PassDownMultiReadWriteIRP( 
	PEXT2_IO_RUN			PtrIoRuns, 
	UINT					Count, 
	ULONG					TotalReadWriteLength,
	PtrExt2IrpContext		PtrIrpContext,
	PtrExt2FCB				PtrFCB,
	BOOLEAN					SynchronousIo)
{
	PIRP				PtrMasterIrp;
	PIRP				PtrAssociatedIrp;
    PIO_STACK_LOCATION	PtrIrpSp;
    PMDL				PtrMdl;
	PtrExt2VCB			PtrVCB;
	UINT				i;
	ULONG				BufferOffset;
	PEXT2_IO_CONTEXT	PtrIoContext = NULL;
	PKEVENT				PtrSyncEvent = NULL;
	ULONG				LogicalBlockSize;
	ULONG				ReadWriteLength;

	NTSTATUS RC = STATUS_SUCCESS;

	PtrVCB = PtrFCB->PtrVCB;
	PtrMasterIrp = PtrIrpContext->Irp;
	LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;

	try
	{
		if( !SynchronousIo )
		{
			IoMarkIrpPending( PtrIrpContext->Irp );
			//	We will be returning STATUS_PENDING...
		}

		if( !PtrMasterIrp->MdlAddress )
		{
			Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength );
		}

		if( SynchronousIo )
		{
			PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) )  );
			if ( !PtrSyncEvent )
			{
				RC = STATUS_INSUFFICIENT_RESOURCES;
				try_return();
			}
			KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
		}
		//
		//	Allocate and initialize a completion context
		//
		PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) )  );
		if ( !PtrIoContext )
		{
			RC = STATUS_INSUFFICIENT_RESOURCES;
			try_return();
		}

		RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) );
		PtrIoContext->Count = Count;
		PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT;
		PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT );
		PtrIoContext->PtrMasterIrp = PtrMasterIrp;
		PtrIoContext->PtrSyncEvent = PtrSyncEvent;
		PtrIoContext->ReadWriteLength = TotalReadWriteLength;

		

		for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength )
		{
			
			ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset;
			
			//
			//	Allocating an Associated IRP...
			//
			PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp,
					(CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) );
			PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp;
			ASSERT ( PtrAssociatedIrp );
			PtrMasterIrp->AssociatedIrp.IrpCount ++;
			
			//
			//	Allocating a Memory Descriptor List...
			//
			PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, //	Virtual Address
				ReadWriteLength,	FALSE, FALSE, PtrAssociatedIrp );
			
			//
			//	and building a partial MDL...
			//
			IoBuildPartialMdl( PtrMasterIrp->MdlAddress,
				PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength );

			//
			//	Create an Irp stack location for ourselves...
			//
			IoSetNextIrpStackLocation( PtrAssociatedIrp );
			PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp );

			//
			//  Setup the Stack location to describe our read.
			//
			PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
			if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
			{
				PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = 
					PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}
			else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
			{
				PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = 
					PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}

			//	PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
			//	PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock;


			//
			//	Setup a completion routine...
			//
			IoSetCompletionRoutine( PtrAssociatedIrp, 
						SynchronousIo ?	
						Ext2MultiSyncCompletionRoutine : 
						Ext2MultiAsyncCompletionRoutine,
						PtrIoContext, TRUE, TRUE, TRUE );

			//
			//	Initialise the next stack location for the driver below us to use...
			//
			PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp );
			PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
			if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
			{
				PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}
			else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
			{
				PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
				PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
			}

			//	PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
			//	PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = 
			//	 	PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
		}

		for( i = 0; i < Count; i++ ) {
                    // DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i);
                    IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp );
                }

		if( SynchronousIo )
		{
			//
			//	Synchronous IO 
			//	Wait for the IO to complete...
			//
			DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql());
			KeWaitForSingleObject( PtrSyncEvent,
				Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
                        DbgPrint("DEADLY WAIT DONE\n");
			try_return();
		}
		else
		{
			//	Asynchronous IO...
			RC = STATUS_PENDING;
			try_return();
		}
	
		try_exit:	NOTHING;
	}
	finally 
	{
		if( PtrSyncEvent )
		{
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrSyncEvent );
			ExFreePool( PtrSyncEvent );
		}
		if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
		{
			//
			//	This means we are getting out of 
			//	this function without doing a read
			//	due to an error, maybe...
			//
			DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrIoContext);
			ExFreePool( PtrIoContext );
		}
	}
	return(RC);
}
Пример #5
0
/*************************************************************************
*
* 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);
}