Example #1
0
PVOID
RadixAllocateElement (
    IN PRTL_GENERIC_TABLE   Table,
    IN CLONG                Size
    )
{
    return FsRtlAllocatePoolWithTag(NonPagedPool,Size, TAG_RADIX_TABLE);
}
PVOID
xixfs_FCBTLBAllocateEntry(
	IN PRTL_GENERIC_TABLE Table,
	IN uint32 ByteSize
)
{
	PAGED_CODE();
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CREATE|DEBUG_TARGET_CLOSE| DEBUG_TARGET_FCB),
		("Enter xixfs_FCBTLBAllocateEntry \n" ));  

	return (FsRtlAllocatePoolWithTag(PagedPool, ByteSize, TAG_G_TABLE));
}
Example #3
0
PPCB
UdfCreatePcb (
    IN ULONG NumberOfPartitions
    )

/*++

Routine Description:

    This routine creates a new Pcb of the indicated size.

Arguments:

    NumberOfPartitions - Number of partitions this Pcb will describe

Return Value:

    PPCB - the Pcb created

--*/

{
    PPCB Pcb;
    ULONG Size = sizeof(PCB) + sizeof(PARTITION)*NumberOfPartitions;

    PAGED_CODE();

    ASSERT( NumberOfPartitions );
    ASSERT( NumberOfPartitions < MAXUSHORT );

    Pcb = (PPCB) FsRtlAllocatePoolWithTag( UdfPagedPool,
                                           Size,
                                           TAG_PCB );

    RtlZeroMemory( Pcb, Size );

    Pcb->NodeTypeCode = UDFS_NTC_PCB;
    Pcb->NodeByteSize = (USHORT) Size;

    Pcb->Partitions = (USHORT)NumberOfPartitions;

    return Pcb;
}
Example #4
0
VOID
MsInitializeData(
    VOID
    )

/*++

Routine Description:

    This function initializes all MSFS global data.

Arguments:

    None.

Return Value:

    None.

--*/

{
    PAGED_CODE();
#ifdef MSDBG
    MsDebugTraceLevel = 0;
    MsDebugTraceIndent = 0;
#endif

    MsGlobalResource = FsRtlAllocatePoolWithTag (NonPagedPoolMustSucceed,
                                                 sizeof(ERESOURCE) * 3,
                                                 'sFsM');
    MsPrefixTableResource = MsGlobalResource + 1;
    MsCcbListResource = MsGlobalResource + 2;

    ExInitializeResource ( MsGlobalResource );
    ExInitializeResource ( MsPrefixTableResource );
    ExInitializeResource ( MsCcbListResource );

}
Example #5
0
PPRIMARY_SESSION
PrimarySession_Create (
	IN  PPRIMARY					Primary,
	IN	HANDLE						ListenFileHandle,
	IN  PFILE_OBJECT				ListenFileObject,
	IN  PLPXTDI_OVERLAPPED_CONTEXT	ListenOverlapped,
	IN  ULONG						ListenSocketIndex,
	IN  PLPX_ADDRESS				RemoteAddress
	)
{
	PPRIMARY_SESSION	primarySession;
 	OBJECT_ATTRIBUTES	objectAttributes;
	NTSTATUS			status;
	LARGE_INTEGER		timeOut;

		
	NDAS_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );

	Primary_Reference( Primary );

	primarySession = FsRtlAllocatePoolWithTag( NonPagedPool, sizeof(PRIMARY_SESSION), LFS_ALLOC_TAG );
	
	if (primarySession == NULL) {

		NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES );

		Primary_Dereference( Primary );
		return NULL;
	}

	try {
	
		RtlZeroMemory( primarySession, sizeof(PRIMARY_SESSION) );

		primarySession->Flags = PRIMARY_SESSION_FLAG_INITIALIZING;

		primarySession->ReferenceCount = 1;
		primarySession->Primary = Primary;
		
		ExInitializeFastMutex( &primarySession->FastMutex );
		
		InitializeListHead( &primarySession->ListEntry );

		KeInitializeEvent( &primarySession->ReadyEvent, NotificationEvent, FALSE );
	
		InitializeListHead( &primarySession->RequestQueue );
		KeInitializeSpinLock( &primarySession->RequestQSpinLock );
		KeInitializeEvent( &primarySession->RequestEvent, NotificationEvent, FALSE );

		InitializeListHead( &primarySession->NetdiskPartitionListEntry );

		primarySession->ThreadHandle = 0;
		primarySession->ThreadObject = NULL;

		NdasFcInitialize( &primarySession->SendNdasFcStatistics );
		NdasFcInitialize( &primarySession->RecvNdasFcStatistics );

		primarySession->ConnectionFileHandle	= ListenFileHandle;
		primarySession->ConnectionFileObject	= ListenFileObject;
		
		LpxTdiV2MoveOverlappedContext( &primarySession->ReceiveOverlapped, ListenOverlapped );

		RtlCopyMemory( &primarySession->RemoteAddress, RemoteAddress, sizeof(LPX_ADDRESS) );
		primarySession->IsLocalAddress			= Lfs_IsLocalAddress(RemoteAddress);

		SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("primarySession->ConnectionFileHandle = %p\n", primarySession->ConnectionFileHandle) );

		primarySession->Thread.SessionState = SESSION_CLOSE;
		primarySession->SessionContext.SessionKey = (UINT32)PtrToUlong(primarySession);

		primarySession->SessionContext.PrimaryMaxDataSize = (LfsRegistry.MaxDataTransferPri < DEFAULT_MAX_DATA_SIZE)
													? LfsRegistry.MaxDataTransferPri:DEFAULT_MAX_DATA_SIZE;

		primarySession->SessionContext.SecondaryMaxDataSize = (LfsRegistry.MaxDataTransferSec < DEFAULT_MAX_DATA_SIZE)
													? LfsRegistry.MaxDataTransferSec:DEFAULT_MAX_DATA_SIZE;

		//
		//	Initialize transport context for traffic control
		//

		InitTransCtx( &primarySession->Thread.TransportCtx, primarySession->SessionContext.SecondaryMaxDataSize );

		SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("PrimarySession_Create: PriMaxData:%08u SecMaxData:%08u\n",
												  primarySession->SessionContext.PrimaryMaxDataSize,
												  primarySession->SessionContext.SecondaryMaxDataSize) );

		ExAcquireFastMutex( &GlobalLfs.FastMutex );
		primarySession->SessionContext.Uid = GlobalLfs.Uid++;
		ExReleaseFastMutex( &GlobalLfs.FastMutex );

		InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );

		status = PsCreateSystemThread( &primarySession->ThreadHandle,
									   THREAD_ALL_ACCESS,
									   &objectAttributes,
									   NULL,
									   NULL,
									   PrimarySessionThreadProc,
									   primarySession );
	
		if (!NT_SUCCESS(status)) {

			leave;
		}

		status = ObReferenceObjectByHandle( primarySession->ThreadHandle,
											FILE_READ_DATA,
											NULL,
											KernelMode,
											&primarySession->ThreadObject,
											NULL );

		if (!NT_SUCCESS(status)) {

			leave;
		}

		timeOut.QuadPart = -LFS_TIME_OUT;
		status = KeWaitForSingleObject( &primarySession->ReadyEvent,
										Executive,
										KernelMode,
										FALSE,
										&timeOut );


		if (!NT_SUCCESS(status)) {

			leave;
		}

		KeClearEvent( &primarySession->ReadyEvent );

		ExInterlockedInsertTailList( &Primary->PrimarySessionQueue[ListenSocketIndex],
									 &primarySession->ListEntry,
									 &Primary->PrimarySessionQSpinLock[ListenSocketIndex] );

		SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("PrimarySession_Create: The primary thread are ready\n") );
		SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("Fat PrimarySession_Create: primarySession = %p\n", primarySession) );
	
	} finally {

		if (AbnormalTermination()) {

			status = STATUS_UNSUCCESSFUL;
		}

		if (!NT_SUCCESS(status)) {

			ASSERT( LFS_UNEXPECTED );
			PrimarySession_Close( primarySession );
			primarySession = NULL;
		}
	}

	return primarySession;
}
Example #6
0
NTSTATUS
NdasFatSecondaryQueryDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs the query directory operation.  It is responsible
    for either completing of enqueuing the input Irp.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PVCB Vcb;
    PDCB Dcb;
    PCCB Ccb;
    PBCB Bcb;

    ULONG i;
    PUCHAR Buffer;
    CLONG UserBufferLength;

    PUNICODE_STRING UniArgFileName;
    WCHAR LongFileNameBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
    UNICODE_STRING LongFileName;
    FILE_INFORMATION_CLASS FileInformationClass;
    ULONG FileIndex;
    BOOLEAN RestartScan;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN IndexSpecified;

    BOOLEAN InitialQuery;
    VBO CurrentVbo;
    BOOLEAN UpdateCcb;
    PDIRENT Dirent;
    UCHAR Fat8Dot3Buffer[12];
    OEM_STRING Fat8Dot3String;
    ULONG DiskAllocSize;

    ULONG NextEntry;
    ULONG LastEntry;

    PFILE_DIRECTORY_INFORMATION DirInfo;
    PFILE_FULL_DIR_INFORMATION FullDirInfo;
    PFILE_BOTH_DIR_INFORMATION BothDirInfo;
    PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
    PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;
    PFILE_NAMES_INFORMATION NamesInfo;

#if 1

	PVOLUME_DEVICE_OBJECT		volDo;
	BOOLEAN						secondarySessionResourceAcquired = FALSE;

	PSECONDARY_REQUEST			secondaryRequest = NULL;

	PNDFS_REQUEST_HEADER		ndfsRequestHeader;
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader;
	PNDFS_WINXP_REPLY_HEADER	ndfsWinxpReplytHeader;
	_U8							*ndfsWinxpRequestData;

	LARGE_INTEGER				timeOut;

	struct QueryDirectory		queryDirectory;
	PVOID						inputBuffer;
	ULONG						inputBufferLength;

	ULONG						returnedDataSize;

#endif

    PAGED_CODE();

    //
    //  Get the current Stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    //
    //  Display the input values.
    //
    DebugTrace(+1, Dbg, "FatQueryDirectory...\n", 0);
    DebugTrace( 0, Dbg, " Wait                   = %08lx\n", FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
    DebugTrace( 0, Dbg, " Irp                    = %08lx\n", Irp);
    DebugTrace( 0, Dbg, " ->Length               = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
    DebugTrace( 0, Dbg, " ->FileName             = %08lx\n", IrpSp->Parameters.QueryDirectory.FileName);
    DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
    DebugTrace( 0, Dbg, " ->FileIndex            = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
    DebugTrace( 0, Dbg, " ->UserBuffer           = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
    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 ));

    //
    //  Reference our input parameters to make things easier
    //

    UserBufferLength = IrpSp->Parameters.QueryDirectory.Length;

    FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
    FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;

    UniArgFileName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName;

    RestartScan       = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
    ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
    IndexSpecified    = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);

    //
    //  Check on the type of open.  We return invalid parameter for all
    //  but UserDirectoryOpens.  Also check that the filename is a valid
    //  UNICODE string.
    //
    
    if (FatDecodeFileObject( IrpSp->FileObject,
                             &Vcb,
                             &Dcb,
                             &Ccb) != UserDirectoryOpen ||
        (UniArgFileName &&
         UniArgFileName->Length % sizeof(WCHAR))) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
        DebugTrace(-1, Dbg, "FatQueryDirectory -> STATUS_INVALID_PARAMETER\n", 0);

        return STATUS_INVALID_PARAMETER;
    }

#if 1

	 if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) {

		 ASSERT( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) );

		 FatCompleteRequest( IrpContext, Irp, STATUS_FILE_CORRUPT_ERROR );

		 DebugTrace2( -1, Dbg, ("NtfsCommonDirectoryControl -> STATUS_FILE_CORRUPT_ERROR\n") );
		 return STATUS_FILE_CORRUPT_ERROR;
	 }

#endif


    //
    //  Initialize the local variables.
    //

    Bcb = NULL;
    UpdateCcb = TRUE;
    Dirent = NULL;

    Fat8Dot3String.MaximumLength = 12;
    Fat8Dot3String.Buffer = Fat8Dot3Buffer;

    LongFileName.Length = 0;
    LongFileName.MaximumLength = sizeof( LongFileNameBuffer);
    LongFileName.Buffer = LongFileNameBuffer;

    InitialQuery = (BOOLEAN)((Ccb->UnicodeQueryTemplate.Buffer == NULL) &&
                             !FlagOn(Ccb->Flags, CCB_FLAG_MATCH_ALL));
    Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    DiskAllocSize = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;

    //
    //  If this is the initial query, then grab exclusive access in
    //  order to update the search string in the Ccb.  We may
    //  discover that we are not the initial query once we grab the Fcb
    //  and downgrade our status.
    //

    if (InitialQuery) {

        if (!FatAcquireExclusiveFcb( IrpContext, Dcb )) {

            DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0);
            Status = FatFsdPostRequest( IrpContext, Irp );
            DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status);

            return Status;
        }

        if (Ccb->UnicodeQueryTemplate.Buffer != NULL) {

            InitialQuery = FALSE;

            FatConvertToSharedFcb( IrpContext, Dcb );
        }

    } else {

        if (!FatAcquireSharedFcb( IrpContext, Dcb )) {

            DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0);
            Status = FatFsdPostRequest( IrpContext, Irp );
            DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status);

            return Status;

        }
    }

    try {

        ULONG BaseLength;
        ULONG BytesConverted;

        //
        // If we are in the Fsp now because we had to wait earlier,
        // we must map the user buffer, otherwise we can use the
        // user's buffer directly.
        //

        Buffer = FatMapUserBuffer( IrpContext, Irp );

#if 1

		volDo = CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb );

		secondarySessionResourceAcquired 
			= SecondaryAcquireResourceExclusiveLite( IrpContext, 
													 &volDo->SessionResource, 
													 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );

		
		if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) {

			NDASFAT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
			SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST );
			FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
		}

		queryDirectory.FileIndex			= IrpSp->Parameters.QueryDirectory.FileIndex;
		queryDirectory.FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
		queryDirectory.FileName				= IrpSp->Parameters.QueryDirectory.FileName;
		queryDirectory.Length				= IrpSp->Parameters.QueryDirectory.Length;

		inputBuffer			= (queryDirectory.FileName) ? (queryDirectory.FileName->Buffer) : NULL;
		inputBufferLength	= (queryDirectory.FileName) ? (queryDirectory.FileName->Length) : 0;

		if (queryDirectory.FileName) {

			DebugTrace2( 0, Dbg, ("NdNtfsSecondaryQueryDirectory: queryFileName = %wZ\n", queryDirectory.FileName) );
		}

		ASSERT( inputBufferLength <= volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize );
		ASSERT( UserBufferLength <= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize );

		secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, 
														  IRP_MJ_DIRECTORY_CONTROL,
														  ((inputBufferLength > UserBufferLength) ? inputBufferLength : UserBufferLength) );

		if (secondaryRequest == NULL) {

			try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
		}

		ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader;
		INITIALIZE_NDFS_REQUEST_HEADER(	ndfsRequestHeader, 
										NDFS_COMMAND_EXECUTE, 
										volDo->Secondary, 
										IRP_MJ_DIRECTORY_CONTROL, 
										inputBufferLength );

		ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);
		ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData );
		INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, Irp, IrpSp, Ccb->PrimaryFileHandle );

		ndfsWinxpRequestHeader->QueryDirectory.Length				= UserBufferLength;
		ndfsWinxpRequestHeader->QueryDirectory.FileInformationClass	= queryDirectory.FileInformationClass;
		ndfsWinxpRequestHeader->QueryDirectory.FileIndex			= queryDirectory.FileIndex;

		ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1);
		if (inputBufferLength)
			RtlCopyMemory( ndfsWinxpRequestData, inputBuffer, inputBufferLength );

		secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE;
		QueueingSecondaryRequest( volDo->Secondary, secondaryRequest );

		timeOut.QuadPart = -NDASFAT_TIME_OUT;		
		Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut );
		
		KeClearEvent( &secondaryRequest->CompleteEvent );

		if (Status != STATUS_SUCCESS) {

			secondaryRequest = NULL;
			try_return( Status = STATUS_IO_DEVICE_ERROR );
		}

		SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource );		
		secondarySessionResourceAcquired = FALSE;

		if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) {

			if (IrpContext->OriginatingIrp)
				PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp );
			DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) );

			NDASFAT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
			SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST );
			FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
		}

		ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData;
		Status = Irp->IoStatus.Status = ndfsWinxpReplytHeader->Status;
		Irp->IoStatus.Information = ndfsWinxpReplytHeader->Information;
		
		returnedDataSize = secondaryRequest->NdfsReplyHeader.MessageSize - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REPLY_HEADER);

		if (returnedDataSize) {

			ASSERT( ndfsWinxpReplytHeader->Information != 0 );
			ASSERT(returnedDataSize <= ADD_ALIGN8(queryDirectory.Length));
			ASSERT( Buffer );

			RtlCopyMemory( Buffer,
						   (_U8 *)(ndfsWinxpReplytHeader+1),
						   (returnedDataSize < queryDirectory.Length) ? returnedDataSize : queryDirectory.Length );
		}

#endif

#if 0

        //
        //  Make sure the Dcb is still good.
        //

        FatVerifyFcb( IrpContext, Dcb );

        //
        //  Determine where to start the scan.  Highest priority is given
        //  to the file index.  Lower priority is the restart flag.  If
        //  neither of these is specified, then the Vbo offset field in the
        //  Ccb is used.
        //

        if (IndexSpecified) {

            CurrentVbo = FileIndex + sizeof( DIRENT );

        } else if (RestartScan) {

            CurrentVbo = 0;

        } else {

            CurrentVbo = Ccb->OffsetToStartSearchFrom;

        }

        //
        //  If this is the first try then allocate a buffer for the file
        //  name.
        //

        if (InitialQuery) {

            //
            //  If either:
            //
            //  - No name was specified
            //  - An empty name was specified
            //  - We received a '*'
            //  - The user specified the DOS equivolent of ????????.???
            //
            //  then match all names.
            //

            if ((UniArgFileName == NULL) ||
                (UniArgFileName->Length == 0) ||
                (UniArgFileName->Buffer == NULL) ||
                ((UniArgFileName->Length == sizeof(WCHAR)) &&
                 (UniArgFileName->Buffer[0] == L'*')) ||
                ((UniArgFileName->Length == 12*sizeof(WCHAR)) &&
                 (RtlEqualMemory( UniArgFileName->Buffer,
                                  Fat8QMdot3QM,
                                  12*sizeof(WCHAR) )))) {

                Ccb->ContainsWildCards = TRUE;

                SetFlag( Ccb->Flags, CCB_FLAG_MATCH_ALL );

            } else {

                BOOLEAN ExtendedName = FALSE;
                OEM_STRING LocalBestFit;

                //
                //  First and formost, see if the name has wild cards.
                //

                Ccb->ContainsWildCards =
                    FsRtlDoesNameContainWildCards( UniArgFileName );

                //
                //  Now check to see if the name contains any extended
                //  characters
                //

                for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) {

                    if (UniArgFileName->Buffer[i] >= 0x80) {

                        ExtendedName = TRUE;
                        break;
                    }
                }

                //
                //  OK, now do the conversions we need.
                //

                if (ExtendedName) {

                    Status = RtlUpcaseUnicodeString( &Ccb->UnicodeQueryTemplate,
                                                     UniArgFileName,
                                                     TRUE );

                    if (!NT_SUCCESS(Status)) {

                        try_return( Status );
                    }

                    SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE );

                    //
                    //  Upcase the name and convert it to the Oem code page.
                    //

                    Status = RtlUpcaseUnicodeStringToCountedOemString( &LocalBestFit,
                                                                       UniArgFileName,
                                                                       TRUE );

                    //
                    //  If this conversion failed for any reason other than
                    //  an unmappable character fail the request.
                    //

                    if (!NT_SUCCESS(Status)) {

                        if (Status == STATUS_UNMAPPABLE_CHARACTER) {

                            SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE );

                        } else {

                            try_return( Status );
                        }

                    } else {

                        SetFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT );
                    }

                } else {

                    PVOID Buffers;

                    //
                    //  This case is optimized because I know I only have to
                    //  worry about a-z.
                    //

                    Buffers = FsRtlAllocatePoolWithTag( PagedPool,
                                                        UniArgFileName->Length +
                                                        UniArgFileName->Length / sizeof(WCHAR),
                                                        TAG_FILENAME_BUFFER );

                    Ccb->UnicodeQueryTemplate.Buffer = Buffers;
                    Ccb->UnicodeQueryTemplate.Length = UniArgFileName->Length;
                    Ccb->UnicodeQueryTemplate.MaximumLength = UniArgFileName->Length;

                    LocalBestFit.Buffer = (PUCHAR)Buffers + UniArgFileName->Length;
                    LocalBestFit.Length = UniArgFileName->Length / sizeof(WCHAR);
                    LocalBestFit.MaximumLength = LocalBestFit.Length;

                    SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE );

                    for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) {

                        WCHAR c = UniArgFileName->Buffer[i];

                        LocalBestFit.Buffer[i] = (UCHAR)
                        (Ccb->UnicodeQueryTemplate.Buffer[i] =
                             (c < 'a' ? c : c <= 'z' ? c - ('a' - 'A') : c));
                    }
                }

                //
                //  At this point we now have the upcased unicode name,
                //  and the two Oem names if they could be represented in
                //  this code page.
                //
                //  Now determine if the Oem names are legal for what we
                //  going to try and do.  Mark them as not usable is they
                //  are not legal.  Note that we can optimize extended names
                //  since they are actually both the same string.
                //

                if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ) &&
                    !FatIsNameShortOemValid( IrpContext,
                                             LocalBestFit,
                                             Ccb->ContainsWildCards,
                                             FALSE,
                                             FALSE )) {

                    if (ExtendedName) {

                        RtlFreeOemString( &LocalBestFit );
                        ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT );
                    }

                    SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE );
                }

                //
                //  OK, now both locals oem strings correctly reflect their
                //  usability.  Now we want to load up the Ccb structure.
                //
                //  Now we will branch on two paths of wheather the name
                //  is wild or not.
                //

                if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE )) {

                    if (Ccb->ContainsWildCards) {

                        Ccb->OemQueryTemplate.Wild = LocalBestFit;

                    } else {

                        FatStringTo8dot3( IrpContext,
                                          LocalBestFit,
                                          &Ccb->OemQueryTemplate.Constant );

                        if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT)) {

                            RtlFreeOemString( &LocalBestFit );
                            ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT );
                        }
                    }
                }
            }

            //
            //  We convert to shared access.
            //

            FatConvertToSharedFcb( IrpContext, Dcb );
        }

        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 FileIdFullDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_ID_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;

        case FileIdBothDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
                                       FileName[0] );
            break;

        default:

            try_return( Status = STATUS_INVALID_INFO_CLASS );
        }

        //
        //  At this point we are about to enter our query loop.  We have
        //  determined the index into the directory file to begin the
        //  search.  LastEntry and NextEntry are used to index into the user
        //  buffer.  LastEntry is the last entry we've added, NextEntry is
        //  current one we're working on.  If NextEntry is non-zero, then
        //  at least one entry was added.
        //

        while ( TRUE ) {

            VBO NextVbo;
            ULONG FileNameLength;
            ULONG BytesRemainingInBuffer;


            DebugTrace(0, Dbg, "FatQueryDirectory -> Top of loop\n", 0);

            //
            //  If the user had requested only a single match and we have
            //  returned that, then we stop at this point.
            //

            if (ReturnSingleEntry && NextEntry != 0) {

                try_return( Status );
            }

            //
            //  We call FatLocateDirent to lock down the next matching dirent.
            //

            FatLocateDirent( IrpContext,
                             Dcb,
                             Ccb,
                             CurrentVbo,
                             &Dirent,
                             &Bcb,
                             &NextVbo,
                             NULL,
                             &LongFileName);

            //
            //  If we didn't receive a dirent, then we are at the end of the
            //  directory.  If we have returned any files, we exit with
            //  success, otherwise we return STATUS_NO_MORE_FILES.
            //

            if (!Dirent) {

                DebugTrace(0, Dbg, "FatQueryDirectory -> No dirent\n", 0);

                if (NextEntry == 0) {

                    UpdateCcb = FALSE;

                    if (InitialQuery) {

                        Status = STATUS_NO_SUCH_FILE;

                    } else {

                        Status = STATUS_NO_MORE_FILES;
                    }
                }

                try_return( Status );
            }

            //
            //  Protect access to the user buffer with an exception handler.
            //  Since (at our request) IO doesn't buffer these requests, we have
            //  to guard against a user messing with the page protection and other
            //  such trickery.
            //
            
            try {
                
                if (LongFileName.Length == 0) {

                    //
                    //  Now we have an entry to return to our caller.  We'll convert
                    //  the name from the form in the dirent to a <name>.<ext> form.
                    //  We'll case on the type of information requested and fill up
                    //  the user buffer if everything fits.
                    //

                    Fat8dot3ToString( IrpContext, Dirent, TRUE, &Fat8Dot3String );
    
                    //
                    //  Determine the UNICODE length of the file name.
                    //
    
                    FileNameLength = RtlOemStringToCountedUnicodeSize(&Fat8Dot3String);

                    //
                    //  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 = UserBufferLength - NextEntry;
    
                    if ( (NextEntry != 0) &&
                         ( (BaseLength + FileNameLength > BytesRemainingInBuffer) ||
                           (UserBufferLength < NextEntry) ) ) {
    
                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
    
                        try_return( Status = STATUS_SUCCESS );
                    }
    
                    ASSERT( BytesRemainingInBuffer >= BaseLength );

                    //
                    //  Zero the base part of the structure.
                    //

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    switch ( FileInformationClass ) {
    
                    //
                    //  Now fill the base parts of the strucure that are applicable.
                    //
    
                    case FileBothDirectoryInformation:
                    case FileFullDirectoryInformation:
                    case FileIdBothDirectoryInformation:
                    case FileIdFullDirectoryInformation:

                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0);
    
                        //
                        //  Get the Ea file length.
                        //
    
                        FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry];
    
                        //
                        //  If the EAs are corrupt, ignore the error.  We don't want
                        //  to abort the directory query.
                        //
    
                        try {
    
                            FatGetEaLength( IrpContext,
                                            Vcb,
                                            Dirent,
                                            &FullDirInfo->EaSize );
    
                        } except(EXCEPTION_EXECUTE_HANDLER) {
    
                              FatResetExceptionState( IrpContext );
                              FullDirInfo->EaSize = 0;
                        }
                        
                    case FileDirectoryInformation:
    
                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];
    
                        FatGetDirTimes( IrpContext, Dirent, DirInfo );
    
                        DirInfo->EndOfFile.QuadPart = Dirent->FileSize;
    
                        if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
    
                            DirInfo->AllocationSize.QuadPart =
                               (((Dirent->FileSize + DiskAllocSize - 1) / DiskAllocSize) *
                                DiskAllocSize );
                        }
    
                        DirInfo->FileAttributes = Dirent->Attributes != 0 ?
                                                  Dirent->Attributes :
                                                  FILE_ATTRIBUTE_NORMAL;
    
                        DirInfo->FileIndex = NextVbo;
    
                        DirInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String);
    
                        break;
    
                    case FileNamesInformation:
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0);
    
                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];
    
                        NamesInfo->FileIndex = NextVbo;
    
                        NamesInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String );
    
                        break;
    
                    default:
    
                        FatBugCheck( FileInformationClass, 0, 0 );
                    }

                    BytesConverted = 0;
    
                    Status = RtlOemToUnicodeN( (PWCH)&Buffer[NextEntry + BaseLength],
                                               BytesRemainingInBuffer - BaseLength,
                                               &BytesConverted,
                                               Fat8Dot3String.Buffer,
                                               Fat8Dot3String.Length );
                    
                    //
                    //  Check for the case that a single entry doesn't fit.
                    //  This should only get this far on the first entry
                    //
    
                    if (BytesConverted < FileNameLength) {
    
                        ASSERT( NextEntry == 0 );
                        Status = STATUS_BUFFER_OVERFLOW;
                    }
    
                    //
                    //  Set up the previous next entry offset
                    //
    
                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;
    
                    //
                    //  And indicate how much of the user buffer we have currently
                    //  used up.  We must compute this value before we long align
                    //  ourselves for the next entry
                    //
    
                    Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) +
                                                BaseLength + BytesConverted;
    
                    //
                    //  If something happened with the conversion, bail here.
                    //
    
                    if ( !NT_SUCCESS( Status ) ) {
    
                        try_return( NOTHING );
                    }

                } else {

                    ULONG ShortNameLength;
    
                    FileNameLength = LongFileName.Length;
    
                    //
                    //  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 = UserBufferLength - NextEntry;
    
                    if ( (NextEntry != 0) &&
                         ( (BaseLength + FileNameLength > BytesRemainingInBuffer) ||
                           (UserBufferLength < NextEntry) ) ) {
    
                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
    
                        try_return( Status = STATUS_SUCCESS );
                    }
    
                    ASSERT( BytesRemainingInBuffer >= BaseLength );
    
                    //
                    //  Zero the base part of the structure.
                    //

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    switch ( FileInformationClass ) {
    
                    //
                    //  Now fill the base parts of the strucure that are applicable.
                    //
    
                    case FileBothDirectoryInformation:
                    case FileIdBothDirectoryInformation:
    
                        BothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&Buffer[NextEntry];
    
                        //
                        //  Now we have an entry to return to our caller.  We'll convert
                        //  the name from the form in the dirent to a <name>.<ext> form.
                        //  We'll case on the type of information requested and fill up
                        //  the user buffer if everything fits.
                        //
    
                        Fat8dot3ToString( IrpContext, Dirent, FALSE, &Fat8Dot3String );
    
                        ASSERT( Fat8Dot3String.Length <= 12 );
    
                        Status = RtlOemToUnicodeN( &BothDirInfo->ShortName[0],
                                                   12*sizeof(WCHAR),
                                                   &ShortNameLength,
                                                   Fat8Dot3String.Buffer,
                                                   Fat8Dot3String.Length );
    
                        ASSERT( Status != STATUS_BUFFER_OVERFLOW );
                        ASSERT( ShortNameLength <= 12*sizeof(WCHAR) );
    
                        //
                        //  Copy the length into the dirinfo structure.  Note
                        //  that the LHS below is a USHORT, so it can not
                        //  be specificed as the OUT parameter above.
                        //
    
                        BothDirInfo->ShortNameLength = (UCHAR)ShortNameLength;
    
                        //
                        //  If something happened with the conversion, bail here.
                        //
    
                        if ( !NT_SUCCESS( Status ) ) {
    
                            try_return( NOTHING );
                        }
    
                    case FileFullDirectoryInformation:
                    case FileIdFullDirectoryInformation:
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0);
    
                        //
                        //  Get the Ea file length.
                        //
    
                        FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry];
    
                        //
                        //  If the EAs are corrupt, ignore the error.  We don't want
                        //  to abort the directory query.
                        //
    
                        try {
    
                            FatGetEaLength( IrpContext,
                                            Vcb,
                                            Dirent,
                                            &FullDirInfo->EaSize );
    
                        } except(EXCEPTION_EXECUTE_HANDLER) {
    
                              FatResetExceptionState( IrpContext );
                              FullDirInfo->EaSize = 0;
                        }
    
                    case FileDirectoryInformation:
    
                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];
    
                        FatGetDirTimes( IrpContext, Dirent, DirInfo );
    
                        DirInfo->EndOfFile.QuadPart = Dirent->FileSize;
    
                        if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
    
                            DirInfo->AllocationSize.QuadPart = (
                                                            (( Dirent->FileSize
                                                               + DiskAllocSize - 1 )
                                                             / DiskAllocSize )
                                                            * DiskAllocSize );
                        }
    
                        DirInfo->FileAttributes = Dirent->Attributes != 0 ?
                                                  Dirent->Attributes :
                                                  FILE_ATTRIBUTE_NORMAL;
    
                        DirInfo->FileIndex = NextVbo;
    
                        DirInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String);
    
                        break;
    
                    case FileNamesInformation:
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0);
    
                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];
    
                        NamesInfo->FileIndex = NextVbo;
    
                        NamesInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String );
    
                        break;
    
                    default:
    
                        FatBugCheck( FileInformationClass, 0, 0 );
                    }

                    BytesConverted = BytesRemainingInBuffer - BaseLength >= FileNameLength ?
                                     FileNameLength :
                                     BytesRemainingInBuffer - BaseLength;
    
                    RtlCopyMemory( &Buffer[NextEntry + BaseLength],
                                   &LongFileName.Buffer[0],
                                   BytesConverted );
    
                    //
                    //  Set up the previous next entry offset
                    //
    
                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;

                    //
                    //  And indicate how much of the user buffer we have currently
                    //  used up.  We must compute this value before we long align
                    //  ourselves for the next entry
                    //
    
                    Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) +
                                                BaseLength + BytesConverted;

                    //
                    //  Check for the case that a single entry doesn't fit.
                    //  This should only get this far on the first entry.
                    //

                    if (BytesConverted < FileNameLength) {

                        ASSERT( NextEntry == 0 );

                        try_return( Status = STATUS_BUFFER_OVERFLOW );
                    }
                }

                //
                //  Finish up by filling in the FileId
                //

                switch ( FileInformationClass ) {

                case FileIdBothDirectoryInformation:

                    IdBothDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)&Buffer[NextEntry];
                    IdBothDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo );
                    break;

                case FileIdFullDirectoryInformation:

                    IdFullDirInfo = (PFILE_ID_FULL_DIR_INFORMATION)&Buffer[NextEntry];
                    IdFullDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo );
                    break;

                default:
                    break;
                }
            
            }  except (EXCEPTION_EXECUTE_HANDLER) {

                  //
                  //  We had a problem filling in the user's buffer, so stop and
                  //  fail this request.  This is the only reason any exception
                  //  would have occured at this level.
                  //
                  
                  Irp->IoStatus.Information = 0;
                  UpdateCcb = FALSE;
                  try_return( Status = GetExceptionCode());
            }

            //
            //  Set ourselves up for the next iteration
            //

            LastEntry = NextEntry;
            NextEntry += (ULONG)QuadAlign(BaseLength + BytesConverted);

            CurrentVbo = NextVbo + sizeof( DIRENT );
        }

#endif

    try_exit: NOTHING;
    } finally {
Example #7
0
VOID
CdInitializeEnumeration (
    __in PIRP_CONTEXT IrpContext,
    __in PIO_STACK_LOCATION IrpSp,
    __in PFCB Fcb,
    __inout PCCB Ccb,
    __inout PFILE_ENUM_CONTEXT FileContext,
    __out PBOOLEAN ReturnNextEntry,
    __out PBOOLEAN ReturnSingleEntry,
    __out PBOOLEAN InitialQuery
    )

/*++

Routine Description:

    This routine is called to initialize the enumeration variables and structures.
    We look at the state of a previous enumeration from the Ccb as well as any
    input values from the user.  On exit we will position the FileContext at
    a file in the directory and let the caller know whether this entry or the
    next entry should be returned.

Arguments:

    IrpSp - Irp stack location for this request.

    Fcb - Fcb for this directory.

    Ccb - Ccb for the directory handle.

    FileContext - FileContext to use for this enumeration.

    ReturnNextEntry - Address to store whether we should return the entry at
        the FileContext position or the next entry.

    ReturnSingleEntry - Address to store whether we should only return
        a single entry.

    InitialQuery - Address to store whether this is the first enumeration
        query on this handle.

Return Value:

    None.

--*/

{
    NTSTATUS Status;

    PUNICODE_STRING FileName;
    CD_NAME WildCardName;
    CD_NAME SearchExpression;

    ULONG CcbFlags;

    ULONG DirentOffset;
    ULONG LastDirentOffset;
    BOOLEAN KnownOffset;

    BOOLEAN Found;

    PAGED_CODE();

    //
    //  If this is the initial query then build a search expression from the input
    //  file name.
    //

    if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {

        FileName = IrpSp->Parameters.QueryDirectory.FileName;

        CcbFlags = 0;

        //
        //  If the filename is not specified or is a single '*' then we will
        //  match all names.
        //

        if ((FileName == NULL) ||
            (FileName->Buffer == NULL) ||
            (FileName->Length == 0) ||
            ((FileName->Length == sizeof( WCHAR )) &&
             (FileName->Buffer[0] == L'*'))) {

            SetFlag( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL );
            RtlZeroMemory( &SearchExpression, sizeof( SearchExpression ));

        //
        //  Otherwise build the CdName from the name in the stack location.
        //  This involves building both the name and version portions and
        //  checking for wild card characters.  We also upcase the string if
        //  this is a case-insensitive search.
        //

        } else {

            //
            //  Create a CdName to check for wild cards.
            //

            WildCardName.FileName = *FileName;

            CdConvertNameToCdName( IrpContext, &WildCardName );

            //
            //  The name better have at least one character.
            //

            if (WildCardName.FileName.Length == 0) {

                CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER );
            }

            //
            //  Check for wildcards in the separate components.
            //

            if (FsRtlDoesNameContainWildCards( &WildCardName.FileName)) {

                SetFlag( CcbFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD );
            }

            if ((WildCardName.VersionString.Length != 0) &&
                (FsRtlDoesNameContainWildCards( &WildCardName.VersionString ))) {

                SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD );

                //
                //  Check if this is a wild card only and match all version
                //  strings.
                //

                if ((WildCardName.VersionString.Length == sizeof( WCHAR )) &&
                    (WildCardName.VersionString.Buffer[0] == L'*')) {

                    SetFlag( CcbFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL );
                }
            }

            //
            //  Now create the search expression to store in the Ccb.
            //

            SearchExpression.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
                                                                         FileName->Length,
                                                                         TAG_ENUM_EXPRESSION );

            SearchExpression.FileName.MaximumLength = FileName->Length;

            //
            //  Either copy the name directly or perform the upcase.
            //

            if (FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE )) {

                Status = RtlUpcaseUnicodeString( (PUNICODE_STRING) &SearchExpression.FileName,
                                                 FileName,
                                                 FALSE );

                //
                //  This should never fail.
                //
                __analysis_assert( Status == STATUS_SUCCESS );
                ASSERT( Status == STATUS_SUCCESS );

            } else {

                RtlCopyMemory( SearchExpression.FileName.Buffer,
                               FileName->Buffer,
                               FileName->Length );
            }

            //
            //  Now split into the separate name and version components.
            //

            SearchExpression.FileName.Length = WildCardName.FileName.Length;
            SearchExpression.VersionString.Length = WildCardName.VersionString.Length;
            SearchExpression.VersionString.MaximumLength = WildCardName.VersionString.MaximumLength;

            SearchExpression.VersionString.Buffer = Add2Ptr( SearchExpression.FileName.Buffer,
                                                             SearchExpression.FileName.Length + sizeof( WCHAR ),
                                                             PWCHAR );
        }

        //
        //  But we do not want to return the constant "." and ".." entries for
        //  the root directory, for consistency with the rest of Microsoft's
        //  filesystems.
        //

        if (Fcb == Fcb->Vcb->RootIndexFcb) {

            SetFlag( CcbFlags, CCB_FLAG_ENUM_NOMATCH_CONSTANT_ENTRY );
        }

        //
        //  Now lock the Fcb in order to update the Ccb with the inital
        //  enumeration values.
        //

        CdLockFcb( IrpContext, Fcb );

        //
        //  Check again that this is the initial search.
        //

        if (!FlagOn( Ccb->Flags, CCB_FLAG_ENUM_INITIALIZED )) {

            //
            //  Update the values in the Ccb.
            //

            Ccb->CurrentDirentOffset = Fcb->StreamOffset;
            Ccb->SearchExpression = SearchExpression;

            //
            //  Set the appropriate flags in the Ccb.
            //

            SetFlag( Ccb->Flags, CcbFlags | CCB_FLAG_ENUM_INITIALIZED );

        //
        //  Otherwise cleanup any buffer allocated here.
        //

        } else {

            if (!FlagOn( CcbFlags, CCB_FLAG_ENUM_MATCH_ALL )) {

                CdFreePool( &SearchExpression.FileName.Buffer );
            }
        }

    //
    //  Otherwise lock the Fcb so we can read the current enumeration values.
    //

    } else {

        CdLockFcb( IrpContext, Fcb );
    }

    //
    //  Capture the current state of the enumeration.
    //
    //  If the user specified an index then use his offset.  We always
    //  return the next entry in this case.
    //

    if (FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )) {

        KnownOffset = FALSE;
        DirentOffset = IrpSp->Parameters.QueryDirectory.FileIndex;
        *ReturnNextEntry = TRUE;

    //
    //  If we are restarting the scan then go from the self entry.
    //

    } else if (FlagOn( IrpSp->Flags, SL_RESTART_SCAN )) {

        KnownOffset = TRUE;
        DirentOffset = Fcb->StreamOffset;
        *ReturnNextEntry = FALSE;

    //
    //  Otherwise use the values from the Ccb.
    //

    } else {

        KnownOffset = TRUE;
        DirentOffset = Ccb->CurrentDirentOffset;
        *ReturnNextEntry = BooleanFlagOn( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
    }

    //
    //  Unlock the Fcb.
    //

    CdUnlockFcb( IrpContext, Fcb );

    //
    //  We have the starting offset in the directory and whether to return
    //  that entry or the next.  If we are at the beginning of the directory
    //  and are returning that entry, then tell our caller this is the
    //  initial query.
    //

    *InitialQuery = FALSE;

    if ((DirentOffset == Fcb->StreamOffset) &&
        !(*ReturnNextEntry)) {

        *InitialQuery = TRUE;
    }

    //
    //  If there is no file object then create it now.
    //

    CdVerifyOrCreateDirStreamFile( IrpContext, Fcb);

    //
    //  Determine the offset in the stream to position the FileContext and
    //  whether this offset is known to be a file offset.
    //
    //  If this offset is known to be safe then go ahead and position the
    //  file context.  This handles the cases where the offset is the beginning
    //  of the stream, the offset is from a previous search or this is the
    //  initial query.
    //

    if (KnownOffset) {

        CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, DirentOffset );

    //
    //  Otherwise we walk through the directory from the beginning until
    //  we reach the entry which contains this offset.
    //

    } else {

        LastDirentOffset = Fcb->StreamOffset;
        Found = TRUE;

        CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );

        //
        //  If the requested offset is prior to the beginning offset in the stream
        //  then don't return the next entry.
        //

        if (DirentOffset < LastDirentOffset) {

            *ReturnNextEntry = FALSE;

        //
        //  Else look for the last entry which ends past the desired index.
        //

        } else {

            //
            //  Keep walking through the directory until we run out of
            //  entries or we find an entry which ends beyond the input
            //  index value.
            //

            do {

                //
                //  If we have passed the index value then exit.
                //

                if (FileContext->InitialDirent->Dirent.DirentOffset > DirentOffset) {

                    Found = FALSE;
                    break;
                }

                //
                //  Remember the current position in case we need to go back.
                //

                LastDirentOffset = FileContext->InitialDirent->Dirent.DirentOffset;

                //
                //  Exit if the next entry is beyond the desired index value.
                //

                if (LastDirentOffset + FileContext->InitialDirent->Dirent.DirentLength > DirentOffset) {

                    break;
                }

                Found = CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext );

            } while (Found);

            //
            //  If we didn't find the entry then go back to the last known entry.
            //  This can happen if the index lies in the unused range at the
            //  end of a sector.
            //

            if (!Found) {

                CdCleanupFileContext( IrpContext, FileContext );
                CdInitializeFileContext( IrpContext, FileContext );

                CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, LastDirentOffset );
            }
        }
    }

    //
    //  Only update the dirent name if we will need it for some reason.
    //  Don't update this name if we are returning the next entry and
    //  the search string has a version component.
    //

    FileContext->ShortName.FileName.Length = 0;

    if (!(*ReturnNextEntry) ||
        (Ccb->SearchExpression.VersionString.Length == 0)) {

        //
        //  Update the name in the dirent into filename and version components.
        //

        CdUpdateDirentName( IrpContext,
                            &FileContext->InitialDirent->Dirent,
                            FlagOn( Ccb->Flags, CCB_FLAG_IGNORE_CASE ));
    }

    //
    //  Look at the flag in the IrpSp indicating whether to return just
    //  one entry.
    //

    *ReturnSingleEntry = FALSE;

    if (FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )) {

        *ReturnSingleEntry = TRUE;
    }

    return;
}
Example #8
0
NTSTATUS
UdfInitializePcb (
    IN PIRP_CONTEXT IrpContext,
    IN PVCB Vcb,
    IN OUT PPCB *Pcb,
    IN PNSR_LVOL LVD
    )

/*++

Routine Description:

    This routine walks through the partition map of a Logical Volume Descriptor
    and builds an intializing Pcb from it.  The Pcb will be ready to be used
    in searching for the partition descriptors of a volume.

Arguments:

    Vcb - The volume this Pcb will pertain to

    Pcb - Caller's pointer to the Pcb

    LVD - The Logical Volume Descriptor being used

Return Value:

    STATUS_SUCCESS if the partition map is good and the Pcb is built

    STATUS_DISK_CORRUPT_ERROR if corrupt maps are found

    STATUS_UNRECOGNIZED_VOLUME if noncompliant maps are found

--*/

{
    PPARTMAP_UDF_GENERIC Map;
    PPARTITION Partition;

    BOOLEAN Found;

    PAGED_CODE();

    //
    //  Check the input parameters
    //

    ASSERT_OPTIONAL_PCB( *Pcb );

    DebugTrace(( +1, Dbg,
                 "UdfInitializePcb, Lvd %08x\n",
                 LVD ));

    //
    //  Delete a pre-existing (partially initialized from a failed
    //  crawl of a VDS) Pcb.
    //

    if (*Pcb != NULL) {

        UdfDeletePcb( *Pcb );
        *Pcb = NULL;
    }

    *Pcb = UdfCreatePcb( LVD->MapTableCount );

    //
    //  Walk the table of partition maps intializing the Pcb for the descriptor
    //  initialization pass.
    //

    for (Map = (PPARTMAP_UDF_GENERIC) LVD->MapTable,
         Partition = (*Pcb)->Partition;

         Partition < &(*Pcb)->Partition[(*Pcb)->Partitions];

         Map = Add2Ptr( Map, Map->Length, PPARTMAP_UDF_GENERIC ),
         Partition++) {

        //
        //  Now check that this LVD can actually contain this map entry.  First check that
        //  the descriptor can contain the first few fields, then check that it can hold
        //  all of the bytes claimed by the descriptor.
        //

        if (Add2Ptr( Map, sizeof( PARTMAP_GENERIC ), PCHAR ) > Add2Ptr( LVD, ISONsrLvolSize( LVD ), PCHAR ) ||
            Add2Ptr( Map, Map->Length,               PCHAR ) > Add2Ptr( LVD, ISONsrLvolSize( LVD ), PCHAR )) {

            DebugTrace(( 0, Dbg,
                         "UdfInitializePcb, map at +%04x beyond Lvd size %04x\n",
                         (PCHAR) Map - (PCHAR) LVD,
                         ISONsrLvolSize( LVD )));

            DebugTrace(( -1, Dbg,
                         "UdfInitializePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));

            return STATUS_DISK_CORRUPT_ERROR;
        }

        //
        //  Now load up this map entry.
        //

        switch (Map->Type) {

            case PARTMAP_TYPE_PHYSICAL:

                {
                    PPARTMAP_PHYSICAL MapPhysical = (PPARTMAP_PHYSICAL) Map;

                    //
                    //  Type 1 - Physical Partition
                    //

                    DebugTrace(( 0, Dbg,
                                 "UdfInitializePcb, map reference %02x is Physical (Partition # %08x)\n",
                                 (Partition - (*Pcb)->Partition)/sizeof(PARTITION),
                                 MapPhysical->Partition ));

                    //
                    //  It must be the case that the volume the partition is on is the first
                    //  one since we only do single disc UDF.  This will have already been
                    //  checked by the caller.
                    //

                    if (MapPhysical->VolSetSeq > 1) {

                        DebugTrace(( 0, Dbg,
                                     "UdfInitializePcb, ... but physical partition resides on volume set volume # %08x (> 1)!\n",
                                     MapPhysical->VolSetSeq ));

                        DebugTrace(( -1, Dbg,
                                     "UdfInitializePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));

                        return STATUS_DISK_CORRUPT_ERROR;
                    }

                    SetFlag( (*Pcb)->Flags, PCB_FLAG_PHYSICAL_PARTITION );
                    Partition->Type = Physical;
                    Partition->Physical.PartitionNumber = MapPhysical->Partition;
                }

                break;

            case PARTMAP_TYPE_PROXY:

                //
                //  Type 2 - a Proxy Partition, something not explicitly physical.
                //

                DebugTrace(( 0, Dbg,
                             "UdfInitializePcb, map reference %02x is a proxy\n",
                             (Partition - (*Pcb)->Partition)/sizeof(PARTITION)));

                //
                //  Handle the various types of proxy partitions we recognize
                //

                if (UdfDomainIdentifierContained( &Map->PartID,
                                                  &UdfVirtualPartitionDomainIdentifier,
                                                  UDF_VERSION_150,
                                                  UDF_VERSION_RECOGNIZED )) {

                    {
                        PPARTMAP_VIRTUAL MapVirtual = (PPARTMAP_VIRTUAL) Map;

                        //
                        //  Only one of these guys can exist, since there can be only one VAT per media surface.
                        //

                        if (FlagOn( (*Pcb)->Flags, PCB_FLAG_VIRTUAL_PARTITION )) {

                            DebugTrace(( 0, Dbg,
                                         "UdfInitializePcb, ... but this is a second virtual partition!?!!\n" ));

                            DebugTrace(( -1, Dbg,
                                         "UdfInitializePcb -> STATUS_UNCRECOGNIZED_VOLUME\n" ));

                            return STATUS_UNRECOGNIZED_VOLUME;
                        }

                        DebugTrace(( 0, Dbg,
                                     "UdfInitializePcb, ... Virtual (Partition # %08x)\n",
                                     MapVirtual->Partition ));

                        SetFlag( (*Pcb)->Flags, PCB_FLAG_VIRTUAL_PARTITION );
                        Partition->Type = Virtual;

                        //
                        //  We will convert the partition number to a partition reference
                        //  before returning.
                        //

                        Partition->Virtual.RelatedReference = MapVirtual->Partition;
                    }

                } else if (UdfDomainIdentifierContained( &Map->PartID,
                                                         &UdfSparablePartitionDomainIdentifier,
                                                         UDF_VERSION_150,
                                                         UDF_VERSION_RECOGNIZED )) {

                    {
                        NTSTATUS Status;
                        PPARTMAP_SPARABLE MapSparable = (PPARTMAP_SPARABLE) Map;

                        //
                        //  It must be the case that the volume the partition is on is the first
                        //  one since we only do single disc UDF.  This will have already been
                        //  checked by the caller.
                        //

                        if (MapSparable->VolSetSeq > 1) {

                            DebugTrace(( 0, Dbg,
                                         "UdfInitializePcb, ... but sparable partition resides on volume set volume # %08x (> 1)!\n",
                                         MapSparable->VolSetSeq ));

                            DebugTrace(( -1, Dbg,
                                         "UdfInitializePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));

                            return STATUS_DISK_CORRUPT_ERROR;
                        }

                        DebugTrace(( 0, Dbg,
                                     "UdfInitializePcb, ... Sparable (Partition # %08x)\n",
                                     MapSparable->Partition ));

                        //
                        //  We pretend that sparable partitions are basically the same as
                        //  physical partitions.  Since we are not r/w (and will never be
                        //  on media that requires host-based sparing in any case), this
                        //  is a good simplification.
                        //

                        SetFlag( (*Pcb)->Flags, PCB_FLAG_SPARABLE_PARTITION );
                        Partition->Type = Physical;
                        Partition->Physical.PartitionNumber = MapSparable->Partition;

                        //
                        //  Save this map for use when the partition descriptor is found.
                        //  We can't load the sparing table at this time because we have
                        //  to turn the Lbn->Psn mapping into a Psn->Psn mapping.  UDF
                        //  believes that the way sparing will be used in concert with
                        //  the Lbn->Psn mapping engine (like UdfLookupPsnOfExtent).
                        //
                        //  Unfortunately, this would be a bit painful at this time.
                        //  The users of UdfLookupPsnOfExtent would need to iterate
                        //  over a new interface (not so bad) but the Vmcb package
                        //  would need to be turned inside out so that it didn't do
                        //  the page-filling alignment of blocks in the metadata
                        //  stream - instead, UdfLookupMetaVsnOfExtent would need to
                        //  do this itself.  I choose to lay the sparing engine into
                        //  the read path and raw sector read engine instead.
                        //

                        Partition->Physical.SparingMap = FsRtlAllocatePoolWithTag( PagedPool,
                                                                                   sizeof(PARTMAP_SPARABLE),
                                                                                   TAG_NSR_FSD);
                        RtlCopyMemory( Partition->Physical.SparingMap,
                                       MapSparable,
                                       sizeof(PARTMAP_SPARABLE));
                    }

                } else {

                    DebugTrace(( 0, Dbg,
                                 "UdfInitializePcb, ... but we don't recognize this proxy!\n" ));

                    DebugTrace(( -1, Dbg,
                                 "UdfInitializePcb -> STATUS_UNRECOGNIZED_VOLUME\n" ));

                    return STATUS_UNRECOGNIZED_VOLUME;
                }

                break;

            default:

                DebugTrace(( 0, Dbg,
                             "UdfInitializePcb, map reference %02x is of unknown type %02x\n",
                             Map->Type ));

                DebugTrace(( -1, Dbg,
                             "UdfInitializePcb -> STATUS_UNRECOGNIZED_VOLUME\n" ));

                return STATUS_UNRECOGNIZED_VOLUME;
                break;
        }
    }

    if (!FlagOn( (*Pcb)->Flags, PCB_FLAG_PHYSICAL_PARTITION | PCB_FLAG_SPARABLE_PARTITION )) {

        DebugTrace(( 0, Dbg,
                     "UdfInitializePcb, no physical partition seen on this logical volume!\n" ));

        DebugTrace(( -1, Dbg,
                     "UdfInitializePcb -> STATUS_UNRECOGNIZED_VOLUME\n" ));

        return STATUS_UNRECOGNIZED_VOLUME;
    }

    if (FlagOn( (*Pcb)->Flags, PCB_FLAG_VIRTUAL_PARTITION )) {

        PPARTITION Host;

        //
        //  Confirm the validity of any type 2 virtual maps on this volume
        //  and convert partition numbers to partition references that will
        //  immediately index an element of the Pcb.
        //

        for (Partition = (*Pcb)->Partition;
             Partition < &(*Pcb)->Partition[(*Pcb)->Partitions];
             Partition++) {

            if (Partition->Type == Virtual) {

                //
                //  Go find the partition this thing is talking about
                //

                Found = FALSE;

                for (Host = (*Pcb)->Partition;
                     Host < &(*Pcb)->Partition[(*Pcb)->Partitions];
                     Host++) {

                    if (Host->Type == Physical &&
                        Host->Physical.PartitionNumber ==
                        Partition->Virtual.RelatedReference) {

                        Partition->Virtual.RelatedReference =
                            (USHORT)(Host - (*Pcb)->Partition)/sizeof(PARTITION);
                        Found = TRUE;
                        break;
                    }
                }

                //
                //  Failure to find a physical partition for this virtual guy
                //  is not a good sign.
                //

                if (!Found) {

                    return STATUS_DISK_CORRUPT_ERROR;
                }
            }
        }
    }

    DebugTrace(( -1, Dbg,
             "UdfInitializePcb -> STATUS_SUCCESS\n" ));

    return STATUS_SUCCESS;
}
Example #9
0
PPRIMARY_SESSION
PrimarySession_Create (
	IN  PIRP_CONTEXT			IrpContext,  
	IN	PVOLUME_DEVICE_OBJECT	VolDo,		 
	IN  PSESSION_INFORMATION	SessionInformation,
	IN  PIRP					Irp
	)
{
	PPRIMARY_SESSION	primarySession;
 	OBJECT_ATTRIBUTES	objectAttributes;
	NTSTATUS			status;
	LARGE_INTEGER		timeOut;

		
	ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );

	VolDo_Reference( VolDo );

	primarySession = FsRtlAllocatePoolWithTag( NonPagedPool, sizeof(PRIMARY_SESSION), NDFAT_ALLOC_TAG );
	
	if (primarySession == NULL) {

		ASSERT( NDASFAT_INSUFFICIENT_RESOURCES );
		VolDo_Dereference( VolDo );
		return NULL;
	}

	try {
	
		RtlZeroMemory( primarySession, sizeof(PRIMARY_SESSION) );

		primarySession->Flags = PRIMARY_SESSION_FLAG_INITIALIZING;

		primarySession->ReferenceCount = 1;
		primarySession->VolDo = VolDo;
		
		ExInitializeFastMutex( &primarySession->FastMutex )
		
		InitializeListHead( &primarySession->ListEntry );

		primarySession->NetdiskPartitionInformation = SessionInformation->NetdiskPartitionInformation;
	
		RtlInitEmptyUnicodeString( &primarySession->NetdiskPartitionInformation.VolumeName,
								   primarySession->NetdiskPartitionInformation.VolumeNameBuffer,
								   sizeof(primarySession->NetdiskPartitionInformation.VolumeNameBuffer) );

		if (RtlAppendUnicodeStringToString( &primarySession->NetdiskPartitionInformation.VolumeName,
											&SessionInformation->NetdiskPartitionInformation.VolumeName) != STATUS_SUCCESS) {

			ASSERT( NDASFAT_UNEXPECTED );
		}

		ASSERT( primarySession->NetdiskPartitionInformation.VolumeName.Buffer == primarySession->NetdiskPartitionInformation.VolumeNameBuffer );

		primarySession->ConnectionFileHandle		= SessionInformation->ConnectionFileHandle;
		primarySession->ConnectionFileObject		= SessionInformation->ConnectionFileObject;

		primarySession->RemoteAddress				= SessionInformation->RemoteAddress;
		primarySession->IsLocalAddress				= SessionInformation->IsLocalAddress;

		primarySession->Irp									= Irp;

		primarySession->SessionContext = SessionInformation->SessionContext;

		primarySession->SessionContext.PrimaryMaxDataSize	= DEFAULT_NDAS_MAX_DATA_SIZE; //SessionInformation->PrimaryMaxDataSize;
		primarySession->SessionContext.SecondaryMaxDataSize	= DEFAULT_NDAS_MAX_DATA_SIZE; // SessionInformation->SecondaryMaxDataSize;

		DebugTrace2( 0, Dbg2, ("primarySession->ConnectionFileHandle = %x " 
							   "primarySession->SessionContext.PrimaryMaxDataSize = %x primarySession->SessionContext.SecondaryMaxDataSize = %x\n", 
							    primarySession->ConnectionFileHandle, primarySession->SessionContext.PrimaryMaxDataSize, primarySession->SessionContext.SecondaryMaxDataSize) );

		KeInitializeEvent( &primarySession->ReadyEvent, NotificationEvent, FALSE );
	
		InitializeListHead( &primarySession->RequestQueue );
		KeInitializeSpinLock( &primarySession->RequestQSpinLock );
		KeInitializeEvent( &primarySession->RequestEvent, NotificationEvent, FALSE );

		primarySession->ThreadHandle = 0;
		primarySession->ThreadObject = NULL;

		primarySession->Thread.TdiReceiveContext.Irp = NULL;
		KeInitializeEvent( &primarySession->Thread.TdiReceiveContext.CompletionEvent, NotificationEvent, FALSE );

		InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );

		primarySession->Thread.SessionState = SESSION_TREE_CONNECT;
	
		ExInterlockedInsertTailList( &VolDo->PrimarySessionQueue,
									 &primarySession->ListEntry,
									 &VolDo->PrimarySessionQSpinLock );

		status = PsCreateSystemThread( &primarySession->ThreadHandle,
									   THREAD_ALL_ACCESS,
									   &objectAttributes,
									   NULL,
									   NULL,
									   PrimarySessionThreadProc,
									   primarySession );
	
		if (!NT_SUCCESS(status)) {

			leave;
		}

		status = ObReferenceObjectByHandle( primarySession->ThreadHandle,
											FILE_READ_DATA,
											NULL,
											KernelMode,
											&primarySession->ThreadObject,
											NULL );

		if (!NT_SUCCESS(status)) {

			leave;
		}

		timeOut.QuadPart = -NDASFAT_TIME_OUT;
		status = KeWaitForSingleObject( &primarySession->ReadyEvent,
										Executive,
										KernelMode,
										FALSE,
										&timeOut );


		if (!NT_SUCCESS(status)) {

			leave;
		}

		KeClearEvent( &primarySession->ReadyEvent );

		DebugTrace2( 0, Dbg, ("PrimarySession_Create: The primary thread are ready\n") );
	
		DebugTrace2( 0, Dbg2, ("Fat PrimarySession_Create: primarySession = %p\n", primarySession) );
	
	} finally {

		if (AbnormalTermination()) {

			status = IrpContext->ExceptionStatus;
		}

		if (!NT_SUCCESS(status)) {

			ASSERT( NDASFAT_UNEXPECTED );
			PrimarySession_Close( primarySession );
			primarySession = NULL;
		}
	}

	return primarySession;
}
Example #10
0
VOID
NTAPI
FatCreateRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
                 IN PVCB Vcb)
{
    PFCB Dcb;

    /* Make sure it's not already created */
    ASSERT(!Vcb->RootDcb);

    /* Allocate the DCB */
    Dcb = FsRtlAllocatePoolWithTag(NonPagedPool,
                                   sizeof(FCB),
                                   TAG_FCB);

    /* Zero it */
    RtlZeroMemory(Dcb, sizeof(FCB));

    /* Assign it to the VCB */
    Vcb->RootDcb = Dcb;

    /* Set its header */
    Dcb->Header.NodeTypeCode = FAT_NTC_ROOT_DCB;
    Dcb->Header.NodeByteSize = sizeof(FCB);

    /* FCB is in a good condition */
    Dcb->Condition = FcbGood;

    /* Initialize FCB's resource */
    Dcb->Header.Resource = &Dcb->Resource;
    ExInitializeResourceLite(&Dcb->Resource);

    /* Initialize Paging Io resource*/
    Dcb->Header.PagingIoResource = &Dcb->PagingIoResource;
    ExInitializeResourceLite(&Dcb->PagingIoResource);

    /* Initialize a list of parent DCBs*/
    InitializeListHead(&Dcb->ParentDcbLinks);

    /* Set VCB */
    Dcb->Vcb = Vcb;

    /* Initialize parent's DCB list */
    InitializeListHead(&Dcb->Dcb.ParentDcbList);

    /* Initialize the full file name */
    Dcb->FullFileName.Buffer = L"\\";
    Dcb->FullFileName.Length = 1 * sizeof(WCHAR);
    Dcb->FullFileName.MaximumLength = 2 * sizeof(WCHAR);

    Dcb->ShortName.Name.Ansi.Buffer = "\\";
    Dcb->ShortName.Name.Ansi.Length = 1;
    Dcb->ShortName.Name.Ansi.MaximumLength = 2 * sizeof(CHAR);

    /* Fill dirent attribute byte copy */
    Dcb->DirentFatFlags = FILE_ATTRIBUTE_DIRECTORY;

    /* Initialize advanced FCB header fields */
    ExInitializeFastMutex(&Dcb->HeaderMutex);
    FsRtlSetupAdvancedHeader(&Dcb->Header, &Dcb->HeaderMutex);

    /* Set up first cluster field depending on FAT type */
    if (TRUE/*FatIsFat32(Vcb)*/)
    {
        /* First cluster is really the first cluster of this volume */
        Dcb->FirstClusterOfFile = Vcb->Bpb.RootDirFirstCluster;

        /* Calculate size of FAT32 root dir */
        Dcb->Header.AllocationSize.LowPart = 0xFFFFFFFF;
        //FatLookupFileAllocationSize(IrpContext, Dcb);
        DPRINT1("Calculation of a size of a root dir is missing!\n");

        Dcb->Header.FileSize.QuadPart = Dcb->Header.AllocationSize.QuadPart;
    }
    else
    {
#if 0
        /* Add MCB entry */
        FatAddMcbEntry(Vcb,
                       &Dcb->Mcb,
                       0,
                       FatRootDirectoryLbo(&Vcb->Bpb),
                       FatRootDirectorySize(&Vcb->Bpb));

        /* Set a real size of the root directory */
        Dcb->Header.FileSize.QuadPart = FatRootDirectorySize(&Vcb->Bpb);
        Dcb->Header.AllocationSize.QuadPart = Dcb->Header.FileSize.QuadPart;
#endif
        UNIMPLEMENTED;
    }
}
Example #11
0
BOOLEAN
FsRtlFindInTunnelCache (
    IN PTUNNEL Cache,
    IN ULONGLONG DirKey,
    IN PUNICODE_STRING Name,
    OUT PUNICODE_STRING ShortName,
    OUT PUNICODE_STRING LongName,
    IN OUT PULONG  DataLength,
    OUT PVOID Data
    )
/*++

Routine Description:

    Looks up the key

        DirKey ## Name

    in the tunnel cache and removes it. As a side effect, this routine will initiate
    expiration of the aged entries in the tunnel cache.

Arguments:

    Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache()

    DirKey - the key value of the directory the name will appear in

    Name - the name of the entry

    ShortName - return string to hold the short name of the tunneled file. Must
        already be allocated and large enough for max 8.3 name

    LongName -  return string to hold the long name of the tunneled file. If
        already allocated, may be grown if not large enough. Caller is
        responsible for noticing this and freeing data regardless of return value.

    DataLength - provides the length of the buffer avaliable to hold the
        tunneling information, returns the size of the tunneled information
        read out

Return Value:

    Boolean true if found, false otherwise

--*/
{
    PRTL_SPLAY_LINKS Links;
    PTUNNEL_NODE Node;
    LONG Compare;
    LIST_ENTRY FreePoolList;

    BOOLEAN Status = FALSE;

    PAGED_CODE();

    //
    //  If MaxEntries is 0 then tunneling is disabled.
    //

    if (TunnelMaxEntries == 0) return FALSE;

    InitializeListHead(&FreePoolList);

#ifdef KEYVIEW
    DbgPrint("++\nSearching for %wZ , %08x%08x\n--\n", Name, DblHex64(DirKey));
#endif

    ExAcquireFastMutex(&Cache->Mutex);

    //
    //  Expire aged entries first so we don't grab old data
    //

    FsRtlPruneTunnelCache(Cache, &FreePoolList);

    Links = Cache->Cache;

    while (Links) {

        Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks);

        Compare = FsRtlCompareNodeAndKey(Node, DirKey, Name);

        if (Compare > 0) {

            Links = RtlLeftChild(&Node->CacheLinks);

        } else {

            if (Compare < 0) {

                Links = RtlRightChild(&Node->CacheLinks);

            } else {

                //
                //  Found tunneling information
                //

#if defined(TUNNELTEST) || defined(KEYVIEW)
                DbgPrint("FsRtlFindInTunnelCache:\n");
                DumpNode(Node, 1);
#ifndef KEYVIEW
                DumpTunnel(Cache);
#endif
#endif // TUNNELTEST

                break;
            }
        }
    }

    try {

        if (Links) {
    
            //
            //  Copy node data into caller's area
            //
    
            ASSERT(ShortName->MaximumLength >= (8+1+3)*sizeof(WCHAR));
            RtlCopyUnicodeString(ShortName, &Node->ShortName);
    
            if (LongName->MaximumLength >= Node->LongName.Length) {
    
                RtlCopyUnicodeString(LongName, &Node->LongName);
    
            } else {
    
                //
                //  Need to allocate more memory for the long name
                //
    
                LongName->Buffer = FsRtlAllocatePoolWithTag(PagedPool, Node->LongName.Length, '4nuT');
                LongName->Length = LongName->MaximumLength = Node->LongName.Length;
    
                RtlCopyMemory(LongName->Buffer, Node->LongName.Buffer, Node->LongName.Length);
            }
    
            ASSERT(*DataLength >= Node->TunnelDataLength);
            RtlCopyMemory(Data, Node->TunnelData, Node->TunnelDataLength);
            *DataLength = Node->TunnelDataLength;
    
            Status = TRUE;
        }

    } finally {

        ExReleaseFastMutex(&Cache->Mutex);
    
        FsRtlEmptyFreePoolList(&FreePoolList);
    }
    
    return Status;
}
Example #12
0
VOID
NTAPI
FatSetFcbNames(IN PFAT_IRP_CONTEXT IrpContext,
               IN PFCB Fcb)
{
    FF_DIRENT DirEnt;
    FF_ERROR Err;
    POEM_STRING ShortName;
    CHAR ShortNameRaw[13];
    UCHAR EntryBuffer[32];
    UCHAR NumLFNs;
    PUNICODE_STRING UnicodeName;
    OEM_STRING LongNameOem;
    NTSTATUS Status;

    /* Get the dir entry */
    Err = FF_GetEntry(Fcb->Vcb->Ioman,
                      Fcb->FatHandle->DirEntry,
                      Fcb->FatHandle->DirCluster,
                      &DirEnt);

    if (Err != FF_ERR_NONE)
    {
        DPRINT1("Error %d getting dirent of a file\n", Err);
        return;
    }

    /* Read the dirent to fetch the raw short name */
    FF_FetchEntry(Fcb->Vcb->Ioman,
                  Fcb->FatHandle->DirCluster,
                  Fcb->FatHandle->DirEntry,
                  EntryBuffer);
    NumLFNs = (UCHAR)(EntryBuffer[0] & ~0x40);
    RtlCopyMemory(ShortNameRaw, EntryBuffer, 11);

    /* Initialize short name string */
    ShortName = &Fcb->ShortName.Name.Ansi;
    ShortName->Buffer = Fcb->ShortNameBuffer;
    ShortName->Length = 0;
    ShortName->MaximumLength = sizeof(Fcb->ShortNameBuffer);

    /* Convert raw short name to a proper string */
    Fati8dot3ToString(ShortNameRaw, FALSE, ShortName);

    /* Add the short name link */
    FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksAnsi, &Fcb->ShortName);
    Fcb->ShortName.Fcb = Fcb;

    /* Get the long file name (if any) */
    if (NumLFNs > 0)
    {
        /* Prepare the oem string */
        LongNameOem.Buffer = DirEnt.FileName;
        LongNameOem.MaximumLength = FF_MAX_FILENAME;
        LongNameOem.Length = strlen(DirEnt.FileName);

        /* Prepare the unicode string */
        UnicodeName = &Fcb->LongName.Name.String;
        UnicodeName->Length = (LongNameOem.Length + 1) * sizeof(WCHAR);
        UnicodeName->MaximumLength = UnicodeName->Length;
        UnicodeName->Buffer = FsRtlAllocatePool(PagedPool, UnicodeName->Length);

        /* Convert it to unicode */
        Status = RtlOemStringToUnicodeString(UnicodeName, &LongNameOem, FALSE);
        if (!NT_SUCCESS(Status))
        {
            ASSERT(FALSE);
        }

        /* Set its length */
        Fcb->FileNameLength = UnicodeName->Length;

        /* Save case-preserved copy */
        Fcb->ExactCaseLongName.Length = UnicodeName->Length;
        Fcb->ExactCaseLongName.MaximumLength = UnicodeName->Length;
        Fcb->ExactCaseLongName.Buffer =
            FsRtlAllocatePoolWithTag(PagedPool, UnicodeName->Length, TAG_FILENAME);

        RtlCopyMemory(Fcb->ExactCaseLongName.Buffer,
                      UnicodeName->Buffer,
                      UnicodeName->Length);

        /* Perform a trick which is done by MS's FASTFAT driver to monocase
           the filename */
        RtlDowncaseUnicodeString(UnicodeName, UnicodeName, FALSE);
        RtlUpcaseUnicodeString(UnicodeName, UnicodeName, FALSE);

        DPRINT("Converted long name: %wZ\n", UnicodeName);

        /* Add the long unicode name link */
        FatInsertName(IrpContext, &Fcb->ParentFcb->Dcb.SplayLinksUnicode, &Fcb->LongName);
        Fcb->LongName.Fcb = Fcb;

        /* Indicate that this FCB has a unicode long name */
        SetFlag(Fcb->State, FCB_STATE_HAS_UNICODE_NAME);
    }
    else
    {
        /* No LFN, set exact case name to 0 length */
        Fcb->ExactCaseLongName.Length = 0;
        Fcb->ExactCaseLongName.MaximumLength = 0;

        /* Set the length based on the short name */
        Fcb->FileNameLength = RtlOemStringToCountedUnicodeSize(ShortName);
    }

    /* Mark the fact that names were added to splay trees*/
    SetFlag(Fcb->State, FCB_STATE_HAS_NAMES);
}
Example #13
0
VOID
NTAPI
FatSetFullFileNameInFcb(IN PFAT_IRP_CONTEXT IrpContext,
                        IN PFCB Fcb)
{
    UNICODE_STRING LongName;
    PFCB CurFcb = Fcb;
    PFCB StopFcb;
    PWCHAR TmpBuffer;
    ULONG PathLength = 0;

    /* Do nothing if it's already set */
    if (Fcb->FullFileName.Buffer) return;

    /* Allocate a temporary buffer */
    LongName.Length = 0;
    LongName.MaximumLength = FF_MAX_FILENAME * sizeof(WCHAR);
    LongName.Buffer =
        FsRtlAllocatePoolWithTag(PagedPool,
                                 FF_MAX_FILENAME * sizeof(WCHAR),
                                 TAG_FILENAME);

    /* Go through all parents to calculate needed length */
    while (CurFcb != Fcb->Vcb->RootDcb)
    {
        /* Does current FCB have FullFileName set? */
        if (CurFcb != Fcb &&
            CurFcb->FullFileName.Buffer)
        {
            /* Yes, just use it! */
            PathLength += CurFcb->FullFileName.Length;

            Fcb->FullFileName.Buffer =
                FsRtlAllocatePoolWithTag(PagedPool,
                                         PathLength,
                                         TAG_FILENAME);

            RtlCopyMemory(Fcb->FullFileName.Buffer,
                          CurFcb->FullFileName.Buffer,
                          CurFcb->FullFileName.Length);

            break;
        }

        /* Sum up length of a current item */
        PathLength += CurFcb->FileNameLength + sizeof(WCHAR);

        /* Go to the parent */
        CurFcb = CurFcb->ParentFcb;
    }

    /* Allocate FullFileName if it wasn't already allocated above */
    if (!Fcb->FullFileName.Buffer)
    {
        Fcb->FullFileName.Buffer =
            FsRtlAllocatePoolWithTag(PagedPool,
                                     PathLength,
                                     TAG_FILENAME);
    }

    StopFcb = CurFcb;

    CurFcb = Fcb;
    TmpBuffer =  Fcb->FullFileName.Buffer + PathLength / sizeof(WCHAR);

    /* Set lengths */
    Fcb->FullFileName.Length = PathLength;
    Fcb->FullFileName.MaximumLength = PathLength;

    while (CurFcb != StopFcb)
    {
        /* Get its unicode name */
        FatGetFcbUnicodeName(IrpContext,
                             CurFcb,
                             &LongName);

        /* Copy it */
        TmpBuffer -= LongName.Length / sizeof(WCHAR);
        RtlCopyMemory(TmpBuffer, LongName.Buffer, LongName.Length);

        /* Append with a backslash */
        TmpBuffer -= 1;
        *TmpBuffer = L'\\';

        /* Go to the parent */
        CurFcb = CurFcb->ParentFcb;
    }

    /* Free the temp buffer */
    ExFreePool(LongName.Buffer);
}
Example #14
0
VOID
NTAPI
FatSetFullNameInFcb(PFCB Fcb,
                    PUNICODE_STRING Name)
{
    PUNICODE_STRING ParentName;

    /* Make sure this FCB's name wasn't already set */
    ASSERT(Fcb->FullFileName.Buffer == NULL);

    /* First of all, check exact case name */
    if (Fcb->ExactCaseLongName.Buffer)
    {
        ASSERT(Fcb->ExactCaseLongName.Length != 0);

        /* Use exact case name */
        Name = &Fcb->ExactCaseLongName;
    }

    /* Treat root dir different */
    if (FatNodeType(Fcb->ParentFcb) == FAT_NTC_ROOT_DCB)
    {
        /* Set lengths */
        Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + Name->Length;
        Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength;

        /* Allocate a buffer */
        Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool,
                                                            Fcb->FullFileName.Length,
                                                            TAG_FILENAME);

        /* Prefix with a backslash */
        Fcb->FullFileName.Buffer[0] = L'\\';

        /* Copy the name here */
        RtlCopyMemory(&Fcb->FullFileName.Buffer[1],
                      &Name->Buffer[0],
                       Name->Length );
    }
    else
    {
        ParentName = &Fcb->ParentFcb->FullFileName;

        /* Check if parent's name is set */
        if (!ParentName->Buffer)
            return;

        /* Set lengths */
        Fcb->FullFileName.MaximumLength =
            ParentName->Length + sizeof(WCHAR) + Name->Length;
        Fcb->FullFileName.Length = Fcb->FullFileName.MaximumLength;

        /* Allocate a buffer */
        Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag(PagedPool,
                                                            Fcb->FullFileName.Length,
                                                            TAG_FILENAME );

        /* Copy parent's name here */
        RtlCopyMemory(&Fcb->FullFileName.Buffer[0],
                      &ParentName->Buffer[0],
                      ParentName->Length );

        /* Add a backslash */
        Fcb->FullFileName.Buffer[ParentName->Length / sizeof(WCHAR)] = L'\\';

        /* Copy given name here */
        RtlCopyMemory(&Fcb->FullFileName.Buffer[(ParentName->Length / sizeof(WCHAR)) + 1],
                      &Name->Buffer[0],
                      Name->Length );
    }
}
Example #15
0
PNDAS_FCB
ReadonlyAllocateFcb (
	IN PFILESPY_DEVICE_EXTENSION	DevExt,
	IN PUNICODE_STRING				FullFileName,
	IN BOOLEAN						IsPagingFile
    )
{
    PNDAS_FCB fcb;

	
    fcb = FsRtlAllocatePoolWithTag( NonPagedPool,
									sizeof(NDAS_FCB),
									LFS_FCB_TAG );
	
	if (fcb == NULL) {
	
		SPY_LOG_PRINT( LFS_DEBUG_READONLY_ERROR, ("ReadonlyAllocateFcb: failed to allocate fcb\n") );
		return NULL;
	}
	
	RtlZeroMemory( fcb, sizeof(NDAS_FCB) );

    fcb->NonPaged = LfsAllocateNonPagedFcb();
	
	if (fcb->NonPaged == NULL) {
	
		SPY_LOG_PRINT( LFS_DEBUG_READONLY_ERROR, ("ReadonlyAllocateFcb: failed to allocate fcb->NonPaged\n") );
		ExFreePool( fcb );
		
		return NULL;
	}

    RtlZeroMemory( fcb->NonPaged, sizeof(NON_PAGED_FCB) );

#define FAT_NTC_FCB                      (0x0502)
	
	fcb->Header.NodeTypeCode = FAT_NTC_FCB;
	fcb->Header.IsFastIoPossible = FastIoIsPossible;
    fcb->Header.Resource = LfsAllocateResource();
	fcb->Header.PagingIoResource = NULL; //fcb->Header.Resource;
	
	if (fcb->Header.Resource == NULL) {
	
		SPY_LOG_PRINT( LFS_DEBUG_READONLY_ERROR, ("ReadonlyAllocateFcb: failed to allocate fcb->Header.Resource\n") );
		ExFreePool( fcb->NonPaged );
		ExFreePool( fcb );
		return NULL;
	}

	if (LfsFsRtlTeardownPerStreamContexts) {

		ExInitializeFastMutex( &fcb->NonPaged->AdvancedFcbHeaderMutex );
		FsRtlSetupAdvancedHeader( &fcb->Header, &fcb->NonPaged->AdvancedFcbHeaderMutex );

		if (IsPagingFile) {

			ClearFlag( fcb->Header.Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS );
		}
	}

	FsRtlInitializeFileLock( &fcb->FileLock, NULL, NULL );

	fcb->ReferenceCount = 1;
	InitializeListHead( &fcb->ListEntry );

	fcb->Readonly = DevExt->LfsDeviceExt.Readonly;

    RtlInitEmptyUnicodeString( &fcb->FullFileName,
							   fcb->FullFileNameBuffer,
							   sizeof(fcb->FullFileNameBuffer) );

	RtlCopyUnicodeString( &fcb->FullFileName, FullFileName );

    RtlInitEmptyUnicodeString( &fcb->CaseInSensitiveFullFileName,
							   fcb->CaseInSensitiveFullFileNameBuffer,
							   sizeof(fcb->CaseInSensitiveFullFileNameBuffer) );

	RtlDowncaseUnicodeString( &fcb->CaseInSensitiveFullFileName,
							  &fcb->FullFileName,
							  FALSE );

	if(FullFileName->Length)
		if(FullFileName->Buffer[0] != L'\\')
			ASSERT( LFS_BUG );
	
	return fcb;
}
Example #16
0
NTSTATUS
UdfLoadSparingTables(
    PIRP_CONTEXT IrpContext,
    PVCB Vcb,
    PPCB Pcb,
    ULONG Reference
    )

/*++

Routine Description:

    This routine reads the sparing tables for a partition and fills
    in the sparing Mcb.

Arguments:

    Vcb - the volume hosting the spared partition

    Pcb - the partion block corresponding to the volume

    Reference - the partition reference being pulled in

Return Value:

    NTSTATUS according to whether the sparing tables were loaded

--*/

{
    NTSTATUS Status;

    ULONG SparingTable;
    PULONG SectorBuffer;
    ULONG Psn;

    ULONG RemainingBytes;
    ULONG ByteOffset;
    ULONG TotalBytes;

    BOOLEAN Complete;

    PSPARING_TABLE_HEADER Header;
    PSPARING_TABLE_ENTRY Entry;

    PPARTITION Partition = &Pcb->Partition[Reference];
    PPARTMAP_SPARABLE Map = Partition->Physical.SparingMap;

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_VCB( Vcb );

    ASSERT( Map != NULL );

    DebugTrace(( +1, Dbg, "UdfLoadSparingTables, Vcb %08x, PcbPartition %08x, Map @ %08x\n", Vcb, Partition, Map ));

    DebugTrace(( 0, Dbg, "UdfLoadSparingTables, Map sez: PacketLen %u, NTables %u, TableSize %u\n",
                         Map->PacketLength,
                         Map->NumSparingTables,
                         Map->TableSize));


    //
    //  Check that the sparale map appears sane.  If there are no sparing tables that
    //  is pretty OK, and it'll wind up looking like a regular physical partition.
    //

    if (Map->NumSparingTables == 0) {

        DebugTrace((  0, Dbg, "UdfLoadSparingTables, no sparing tables claimed!\n" ));
        DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_SUCCESS\n" ));
        return STATUS_SUCCESS;
    }

    if (Map->NumSparingTables > sizeof(Map->TableLocation)/sizeof(ULONG)) {

        DebugTrace((  0, Dbg, "UdfLoadSparingTables, too many claimed tables to fit! (max %u)\n",
                              sizeof(Map->TableLocation)/sizeof(ULONG)));
        DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_DISK_CORRUPT_ERROR\n" ));
        return  STATUS_DISK_CORRUPT_ERROR;
    }

    if (Map->PacketLength != UDF_SPARING_PACKET_LENGTH) {

        DebugTrace((  0, Dbg, "UdfLoadSparingTables, packet size is %u (not %u!\n",
                              Map->PacketLength,
                              UDF_SPARING_PACKET_LENGTH ));
        DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_DISK_CORRUPT_ERROR\n" ));
        return  STATUS_DISK_CORRUPT_ERROR;
    }

    if (Map->TableSize < sizeof(SPARING_TABLE_HEADER) ||
        (Map->TableSize - sizeof(SPARING_TABLE_HEADER)) % sizeof(SPARING_TABLE_ENTRY) != 0) {

        DebugTrace((  0, Dbg, "UdfLoadSparingTables, sparing table size is too small or unaligned!\n" ));
        DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_DISK_CORRUPT_ERROR\n" ));
        return  STATUS_DISK_CORRUPT_ERROR;
    }

#ifdef UDF_SANITY
    DebugTrace(( 0, Dbg, "UdfLoadSparingTables" ));
    for (SparingTable = 0; SparingTable < Map->NumSparingTables; SparingTable++) {

        DebugTrace(( 0, Dbg, ", Table %u @ %x", SparingTable, Map->TableLocation[SparingTable] ));
    }
    DebugTrace(( 0, Dbg, "\n" ));
#endif

    //
    //  If a sparing mcb doesn't exist, manufacture one.
    //

    if (Pcb->SparingMcb == NULL) {

        Pcb->SparingMcb = FsRtlAllocatePoolWithTag( PagedPool, sizeof(LARGE_MCB), TAG_SPARING_MCB );
        FsRtlInitializeLargeMcb( Pcb->SparingMcb, PagedPool );
    }

    SectorBuffer = FsRtlAllocatePoolWithTag( PagedPool, PAGE_SIZE, TAG_NSR_FSD );

    //
    //  Now loop across the sparing tables and pull the data in.
    //

    try {

        for (Complete = FALSE, SparingTable = 0;

             SparingTable < Map->NumSparingTables;

             SparingTable++) {

            DebugTrace((  0, Dbg, "UdfLoadSparingTables, loading sparing table %u!\n",
                                  SparingTable ));

            ByteOffset = 0;
            TotalBytes = 0;
            RemainingBytes = 0;

            do {

                if (RemainingBytes == 0) {

                    (VOID) UdfReadSectors( IrpContext,
                                           BytesFromSectors( Vcb, Map->TableLocation[SparingTable] ) + ByteOffset,
                                           SectorSize( Vcb ),
                                           FALSE,
                                           SectorBuffer,
                                           Vcb->TargetDeviceObject );

                    //
                    //  Verify the descriptor at the head of the sparing table.  If it is not
                    //  valid, we just break out for a chance at the next table, if any.
                    //

                    if (ByteOffset == 0) {

                        Header = (PSPARING_TABLE_HEADER) SectorBuffer;

                        if (!UdfVerifyDescriptor( IrpContext,
                                                  &Header->Destag,
                                                  0,
                                                  SectorSize( Vcb ),
                                                  Header->Destag.Lbn,
                                                  TRUE )) {

                            DebugTrace((  0, Dbg, "UdfLoadSparingTables, sparing table %u didn't verify destag!\n",
                                                  SparingTable ));
                            break;
                        }

                        if (!UdfUdfIdentifierContained( &Header->RegID,
                                                        &UdfSparingTableIdentifier,
                                                        UDF_VERSION_150,
                                                        UDF_VERSION_RECOGNIZED,
                                                        OSCLASS_INVALID,
                                                        OSIDENTIFIER_INVALID)) {

                            DebugTrace((  0, Dbg, "UdfLoadSparingTables, sparing table %u didn't verify regid!\n",
                                                  SparingTable ));
                            break;
                        }

                        //
                        //  Calculate the total number bytes this map spans and check it against what
                        //  we were told the sparing table sizes are.
                        //

                        DebugTrace(( 0, Dbg, "UdfLoadSparingTables, Sparing table %u has %u entries\n",
                                             SparingTable,
                                             Header->TableEntries ));

                        TotalBytes = sizeof(SPARING_TABLE_HEADER) + Header->TableEntries * sizeof(SPARING_TABLE_ENTRY);

                        if (Map->TableSize < TotalBytes) {

                            DebugTrace((  0, Dbg, "UdfLoadSparingTables, sparing table #ents %u overflows allocation!\n",
                                                  Header->TableEntries ));
                            break;
                        }

                        //
                        //  So far so good, advance past the header.
                        //

                        ByteOffset = sizeof(SPARING_TABLE_HEADER);
                        Entry = Add2Ptr( SectorBuffer, sizeof(SPARING_TABLE_HEADER), PSPARING_TABLE_ENTRY );

                    } else {

                        //
                        //  Pick up in the new sector.
                        //

                        Entry = (PSPARING_TABLE_ENTRY) SectorBuffer;
                    }

                    RemainingBytes = Min( SectorSize( Vcb ), TotalBytes - ByteOffset );
                }

                //
                //  Add the mapping.  Since sparing tables are an Lbn->Psn mapping,
                //  very odd, and I want to simplify things by putting the sparing
                //  in right at IO dispatch, translate this to a Psn->Psn mapping.
                //

                if (Entry->Original != UDF_SPARING_AVALIABLE &&
                    Entry->Original != UDF_SPARING_DEFECTIVE) {

                    Psn = Partition->Physical.Start + SectorsFromBlocks( Vcb, Entry->Original );

                    DebugTrace((  0, Dbg, "UdfLoadSparingTables, mapping from Psn %x (Lbn %x) -> Psn %x\n",
                                          Psn,
                                          Entry->Original,
                                          Entry->Mapped ));

                    FsRtlAddLargeMcbEntry( Pcb->SparingMcb,
                                           Psn,
                                           Entry->Mapped,
                                           UDF_SPARING_PACKET_LENGTH );
                }

                //
                //  Advance to the next, and drop out if we've hit the end.
                //

                ByteOffset += sizeof(SPARING_TABLE_ENTRY);
                RemainingBytes -= sizeof(SPARING_TABLE_ENTRY);
                Entry++;

            } while ( ByteOffset < TotalBytes );
        }

    } finally {

        DebugUnwind( UdfLoadSparingTables );

        UdfFreePool( &SectorBuffer );
    }

    DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_SUCCESS\n" ));

    return STATUS_SUCCESS;
}
Example #17
0
VOID
FatSetFullFileNameInFcb (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb
    )

/*++

Routine Description:

    If the FullFileName field in the Fcb has not yet been filled in, we
    proceed to do so.

Arguments:

    Fcb - Supplies the file.

Return Value:

    None

--*/

{
    if (Fcb->FullFileName.Buffer == NULL) {

        UNICODE_STRING Lfn;
        PFCB TmpFcb = Fcb;
        PFCB StopFcb;
        PWCHAR TmpBuffer;
        ULONG PathLength = 0;

        //
        //  We will assume we do this infrequently enough, that it's OK to
        //  to a pool allocation here.
        //

        Lfn.Length = 0;
        Lfn.MaximumLength = MAX_LFN_CHARACTERS * sizeof(WCHAR);
        Lfn.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
                                               MAX_LFN_CHARACTERS * sizeof(WCHAR),
                                               TAG_FILENAME_BUFFER );

        try {

            //
            //  First determine how big the name will be.  If we find an
            //  ancestor with a FullFileName, our work is easier.
            //

            while (TmpFcb != Fcb->Vcb->RootDcb) {

                if ((TmpFcb != Fcb) && (TmpFcb->FullFileName.Buffer != NULL)) {

                    PathLength += TmpFcb->FullFileName.Length;

                    Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
                                                                         PathLength,
                                                                         TAG_FILENAME_BUFFER );

                    RtlCopyMemory( Fcb->FullFileName.Buffer,
                                   TmpFcb->FullFileName.Buffer,
                                   TmpFcb->FullFileName.Length );

                    break;
                }

                PathLength += TmpFcb->FinalNameLength + sizeof(WCHAR);

                TmpFcb = TmpFcb->ParentDcb;
            }

            //
            //  If FullFileName.Buffer is still NULL, allocate it.
            //

            if (Fcb->FullFileName.Buffer == NULL) {

                Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool,
                                                                     PathLength,
                                                                     TAG_FILENAME_BUFFER );
            }

            StopFcb = TmpFcb;

            TmpFcb = Fcb;
            TmpBuffer =  Fcb->FullFileName.Buffer + PathLength / sizeof(WCHAR);

            Fcb->FullFileName.Length =
            Fcb->FullFileName.MaximumLength = (USHORT)PathLength;

            while (TmpFcb != StopFcb) {

                FatGetUnicodeNameFromFcb( IrpContext,
                                          TmpFcb,
                                          &Lfn );

                TmpBuffer -= Lfn.Length / sizeof(WCHAR);

                RtlCopyMemory( TmpBuffer, Lfn.Buffer, Lfn.Length );

                TmpBuffer -= 1;

                *TmpBuffer = L'\\';

                TmpFcb = TmpFcb->ParentDcb;
            }

        } finally {

            if (AbnormalTermination()) {

                if (Fcb->FullFileName.Buffer) {

                    ExFreePool( Fcb->FullFileName.Buffer );
                    Fcb->FullFileName.Buffer = NULL;
                }
            }

            ExFreePool( Lfn.Buffer );
        }
    }
Example #18
0
NTSTATUS
FatCommonRead (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common read routine for NtReadFile, called from both
    the Fsd, or from the Fsp if a request could not be completed without
    blocking in the Fsd.  This routine has no code where it determines
    whether it is running in the Fsd or Fsp.  Instead, its actions are
    conditionalized by the Wait input parameter, which determines whether
    it is allowed to block or not.  If a blocking condition is encountered
    with Wait == FALSE, however, the request is posted to the Fsp, who
    always calls with WAIT == TRUE.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    PVCB Vcb;
    PFCB FcbOrDcb;
    PCCB Ccb;

    VBO StartingVbo;
    ULONG ByteCount;
    ULONG RequestedByteCount;

    PIO_STACK_LOCATION IrpSp;
    PFILE_OBJECT FileObject;
    TYPE_OF_OPEN TypeOfOpen;

    BOOLEAN PostIrp = FALSE;
    BOOLEAN OplockPostIrp = FALSE;

    BOOLEAN FcbOrDcbAcquired = FALSE;

    BOOLEAN Wait;
    BOOLEAN PagingIo;
    BOOLEAN NonCachedIo;
    BOOLEAN SynchronousIo;

    NTSTATUS Status;

    FAT_IO_CONTEXT StackFatIoContext;

    //
    // A system buffer is only used if we have to access the
    // buffer directly from the Fsp to clear a portion or to
    // do a synchronous I/O, or a cached transfer.  It is
    // possible that our caller may have already mapped a
    // system buffer, in which case we must remember this so
    // we do not unmap it on the way out.
    //

    PVOID SystemBuffer = NULL;

    LARGE_INTEGER StartingByte;

    PAGED_CODE();

    //
    // Get current Irp stack location.
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );
    FileObject = IrpSp->FileObject;

    //
    // Initialize the appropriate local variables.
    //

    Wait          = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
    PagingIo      = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
    NonCachedIo   = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
    SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);

    DebugTrace(+1, Dbg, "CommonRead\n", 0);
    DebugTrace( 0, Dbg, "  Irp                   = %8lx\n", Irp);
    DebugTrace( 0, Dbg, "  ->ByteCount           = %8lx\n", IrpSp->Parameters.Read.Length);
    DebugTrace( 0, Dbg, "  ->ByteOffset.LowPart  = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart);
    DebugTrace( 0, Dbg, "  ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart);

    //
    //  Extract starting Vbo and offset.
    //

    StartingByte = IrpSp->Parameters.Read.ByteOffset;

    StartingVbo = StartingByte.LowPart;

    ByteCount = IrpSp->Parameters.Read.Length;
    RequestedByteCount = ByteCount;

    //
    //  Check for a null request, and return immediately
    //

    if (ByteCount == 0) {

        Irp->IoStatus.Information = 0;
        FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
        return STATUS_SUCCESS;
    }

    //
    // Extract the nature of the read from the file object, and case on it
    //

    TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);

    ASSERT( Vcb != NULL );

    //
    //  Save callers who try to do cached IO to the raw volume from themselves.
    //

    if (TypeOfOpen == UserVolumeOpen) {

        NonCachedIo = TRUE;
    }

    ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));

    //
    // Collect interesting statistics.  The FLAG_USER_IO bit will indicate
    // what type of io we're doing in the FatNonCachedIo function.
    //

    if (PagingIo) {
        CollectReadStats(Vcb, TypeOfOpen, ByteCount);

        if (TypeOfOpen == UserFileOpen) {
            SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        } else {
            ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        }
    }

    ASSERT(!FlagOn( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ));

    //
    //  Allocate if necessary and initialize a FAT_IO_CONTEXT block for
    //  all non cached Io.  For synchronous Io we use stack storage,
    //  otherwise we allocate pool.
    //

    if (NonCachedIo) {

        if (IrpContext->FatIoContext == NULL) {

            if (!Wait) {

                IrpContext->FatIoContext =
                    FsRtlAllocatePoolWithTag( NonPagedPool,
                                              sizeof(FAT_IO_CONTEXT),
                                              TAG_FAT_IO_CONTEXT );

            } else {

                IrpContext->FatIoContext = &StackFatIoContext;

                SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
            }
        }

        RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );

        if (Wait) {

            KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
                               NotificationEvent,
                               FALSE );

        } else {

            IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
                ExGetCurrentResourceThread();

            IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
                ByteCount;

            IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
        }
    }


    //
    // These two cases correspond to either a general opened volume, ie.
    // open ("a:"), or a read of the volume file (boot sector + fat(s))
    //

    if ((TypeOfOpen == VirtualVolumeFile) ||
        (TypeOfOpen == UserVolumeOpen)) {

        LBO StartingLbo;

        StartingLbo = StartingByte.QuadPart;

        DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0);

        if (TypeOfOpen == UserVolumeOpen) {

            //
            //  Verify that the volume for this handle is still valid
            //

            //
            //  Verify that the volume for this handle is still valid, permitting
            //  operations to proceed on dismounted volumes via the handle which
            //  performed the dismount.
            //

            if (!FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT | CCB_FLAG_SENT_FORMAT_UNIT )) {

                FatQuickVerifyVcb( IrpContext, Vcb );
            }

            //
            //  If the caller previously sent a format unit command, then we will allow
            //  their read/write requests to ignore the verify flag on the device, since some
            //  devices send a media change event after format unit, but we don't want to 
            //  process it yet since we're probably in the process of formatting the
            //  media.
            //

            if (FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) {

                SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY );
            }

            if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) {

                (VOID)ExAcquireResourceExclusiveLite( &Vcb->Resource, TRUE );

                try {

                    //
                    //  If the volume isn't locked, flush it.
                    //

                    if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {

                        FatFlushVolume( IrpContext, Vcb, Flush );
                    }

                } finally {

                    ExReleaseResourceLite( &Vcb->Resource );
                }

                SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE );
            }

            if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {

                LBO VolumeSize;

                //
                //  Make sure we don't try to read past end of volume,
                //  reducing the byte count if necessary.
                //

                VolumeSize = (LBO) Vcb->Bpb.BytesPerSector *
                             (Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
                                                      Vcb->Bpb.LargeSectors);

                if (StartingLbo >= VolumeSize) {
                    Irp->IoStatus.Information = 0;
                    FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
                    return STATUS_END_OF_FILE;
                }

                if (ByteCount > VolumeSize - StartingLbo) {

                    ByteCount = RequestedByteCount = (ULONG) (VolumeSize - StartingLbo);

                    //
                    //  For async reads we had set the byte count in the FatIoContext
                    //  above, so fix that here.
                    //

                    if (!Wait) {

                        IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
                            ByteCount;
                    }
                }
            }

            //
            //  For DASD we have to probe and lock the user's buffer
            //

            FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, ByteCount );


        } else {
Example #19
0
VOID
CdAddAllocationFromDirent (
    __in PIRP_CONTEXT IrpContext,
    __inout PFCB Fcb,
    __in ULONG McbEntryOffset,
    __in LONGLONG StartingFileOffset,
    __in PDIRENT Dirent
    )

/*++

Routine Description:

    This routine is called to add an entry into the Cd Mcb.  We grow the Mcb
    as necessary and update the new entry.

    NOTE - The Fcb has already been locked prior to makeing this call.

Arguments:

    Fcb - Fcb containing the Mcb to update.

    McbEntryOffset - Offset into the Mcb array to add this data.

    StartingFileOffset - Offset in bytes from the start of the file.

    Dirent - Dirent containing the on-disk data for this entry.

Return Value:

    None

--*/

{
    ULONG NewArraySize;
    PVOID NewMcbArray;
    PCD_MCB_ENTRY McbEntry;

    PAGED_CODE();

    UNREFERENCED_PARAMETER( IrpContext );

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_FCB( Fcb );
    ASSERT_LOCKED_FCB( Fcb );

    //
    //  If we need to grow the Mcb then do it now.
    //

    if (McbEntryOffset >= Fcb->Mcb.MaximumEntryCount) {

        //
        //  Allocate a new buffer and copy the old data over.
        //

        NewArraySize = Fcb->Mcb.MaximumEntryCount * 2 * sizeof( CD_MCB_ENTRY );

        NewMcbArray = FsRtlAllocatePoolWithTag( CdPagedPool,
                                                NewArraySize,
                                                TAG_MCB_ARRAY );

        RtlZeroMemory( NewMcbArray, NewArraySize );
        RtlCopyMemory( NewMcbArray,
                       Fcb->Mcb.McbArray,
                       Fcb->Mcb.MaximumEntryCount * sizeof( CD_MCB_ENTRY ));

        //
        //  Deallocate the current array unless it is embedded in the Fcb.
        //

        if (Fcb->Mcb.MaximumEntryCount != 1) {

            CdFreePool( &Fcb->Mcb.McbArray );
        }

        //
        //  Now update the Mcb with the new array.
        //

        Fcb->Mcb.MaximumEntryCount *= 2;
        Fcb->Mcb.McbArray = NewMcbArray;
    }

    //
    //  Update the new entry with the input data.
    //

    McbEntry = Fcb->Mcb.McbArray + McbEntryOffset;

    //
    //  Start with the location and length on disk.
    //

    McbEntry->DiskOffset = LlBytesFromBlocks( Fcb->Vcb, Dirent->StartingOffset );
    McbEntry->ByteCount = Dirent->DataLength;

    //
    //  Round the byte count up to a logical block boundary if this is
    //  the last extent.
    //

    if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_MULTI )) {

        McbEntry->ByteCount = BlockAlign( Fcb->Vcb, McbEntry->ByteCount );
    }

    //
    //  The file offset is the logical position within this file.
    //  We know this is correct regardless of whether we bias the
    //  file size or disk offset.
    //

    McbEntry->FileOffset = StartingFileOffset;

    //
    //  Convert the interleave information from logical blocks to
    //  bytes.
    //

    if (Dirent->FileUnitSize != 0) {

        McbEntry->DataBlockByteCount = LlBytesFromBlocks( Fcb->Vcb, Dirent->FileUnitSize );
        McbEntry->TotalBlockByteCount = McbEntry->DataBlockByteCount +
                                        LlBytesFromBlocks( Fcb->Vcb, Dirent->InterleaveGapSize );

    //
    //  If the file is not interleaved then the size of the data block
    //  and total block are the same as the byte count.
    //

    } else {

        McbEntry->DataBlockByteCount =
        McbEntry->TotalBlockByteCount = McbEntry->ByteCount;
    }

    //
    //  Update the number of entries in the Mcb.  The Mcb is never sparse
    //  so whenever we add an entry it becomes the last entry in the Mcb.
    //

    Fcb->Mcb.CurrentEntryCount = McbEntryOffset + 1;

    return;
}