Пример #1
0
NTSTATUS
NdFatCommonFlushBuffers (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for flushing a buffer.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;

    PIO_STACK_LOCATION IrpSp;

    PFILE_OBJECT FileObject;

    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    BOOLEAN VcbAcquired = FALSE;
    BOOLEAN FcbAcquired = FALSE;

    PDIRENT Dirent;
    PBCB DirentBcb = NULL;

	PVOLUME_DEVICE_OBJECT		volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb );
	BOOLEAN						secondarySessionResourceAcquired = FALSE;

	PSECONDARY_REQUEST			secondaryRequest = NULL;

	PNDFS_REQUEST_HEADER		ndfsRequestHeader;
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader;
	PNDFS_WINXP_REPLY_HEADER	ndfsWinxpReplytHeader;

	LARGE_INTEGER				timeOut;



    PAGED_CODE();

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "->FileObject  = %08lx\n", IrpSp->FileObject);

	
	//
    //  Extract and decode the file object
    //

    FileObject = IrpSp->FileObject;
    TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );

    //
    //  CcFlushCache is always synchronous, so if we can't wait enqueue
    //  the irp to the Fsp.
    //

    if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {

        Status = FatFsdPostRequest( IrpContext, Irp );

        DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status );
        return Status;
    }

    Status = STATUS_SUCCESS;

    try {

		if (!FlagOn(Ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) {

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

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

					PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp );
					FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );	
				}

				secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 );

				if (secondaryRequest == NULL) {
	
					Status = STATUS_INSUFFICIENT_RESOURCES;
					break;
				}

				ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader;

				INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 );

				ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);
				ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData );

				INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, 
													  IrpContext->OriginatingIrp, 
													  IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), 
													  Ccb->PrimaryFileHandle );
				
				ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) );	

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

				timeOut.QuadPart = -NDFAT_TIME_OUT;		
				Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut );
			
				if (Status != STATUS_SUCCESS) {

					ASSERT( NDFAT_BUG );
					break;
				}

				KeClearEvent (&secondaryRequest->CompleteEvent);

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

					FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
				}

				if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) {

					ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData;
					ASSERT(ndfsWinxpReplytHeader->Status == STATUS_SUCCESS);
				}

				if (secondaryRequest) {

					DereferenceSecondaryRequest( secondaryRequest );
					secondaryRequest = NULL;
				}

				if ( secondarySessionResourceAcquired == TRUE ) {
					
					SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource );		
					secondarySessionResourceAcquired = FALSE;
				}

				break;

			} while(0);
		} 

		Status = STATUS_SUCCESS;

        //
        //  Case on the type of open that we are trying to flush
        //

        switch (TypeOfOpen) {

        case VirtualVolumeFile:
        case EaFile:
        case DirectoryFile:

            DebugTrace(0, Dbg, "Flush that does nothing\n", 0);
            break;

        case UserFileOpen:

            DebugTrace(0, Dbg, "Flush User File Open\n", 0);

            (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );

            FcbAcquired = TRUE;

            FatVerifyFcb( IrpContext, Fcb );

            //
            //  If the file is cached then flush its cache
            //

            Status = FatFlushFile( IrpContext, Fcb, Flush );

            //
            //  Also update and flush the file's dirent in the parent directory if the
            //  file flush worked.
            //

            if (NT_SUCCESS( Status )) {

                //
                //  Insure that we get the filesize to disk correctly.  This is
                //  benign if it was already good.
                //
                //  (why do we need to do this?)
                //

                SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
#if 0
                FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
#endif                
                //
                //  Flush the volume file to get any allocation information
                //  updates to disk.
                //

                if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {

                    Status = FatFlushFat( IrpContext, Vcb );

                    ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT);
                }

                //
                //  Set the write through bit so that these modifications
                //  will be completed with the request.
                //

                SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
            }

            break;

        case UserDirectoryOpen:

            //
            //  If the user had opened the root directory then we'll
            //  oblige by flushing the volume.
            //

            if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {

                DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0);
                break;
            }

        case UserVolumeOpen:

            DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0);

            //
            //  Acquire exclusive access to the Vcb.
            //

            {
                BOOLEAN Finished;
                Finished = FatAcquireExclusiveSecondaryVcb( IrpContext, Vcb );
                ASSERT( Finished );
            }

            VcbAcquired = TRUE;

            //
            //  Mark the volume clean and then flush the volume file,
            //  and then all directories
            //

            Status = FatFlushVolume( IrpContext, Vcb, Flush );

            //
            //  If the volume was dirty, do the processing that the delayed
            //  callback would have done.
            //

            if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {

                //
                //  Cancel any pending clean volumes.
                //

                (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
                (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );

                //
                //  The volume is now clean, note it.
                //

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

                    FatMarkVolume( IrpContext, Vcb, VolumeClean );
                    ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
                }

                //
                //  Unlock the volume if it is removable.
                //

                if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
                    !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {

                    FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
                }
            }

            break;

        default:

            FatBugCheck( TypeOfOpen, 0, 0 );
        }

        FatUnpinBcb( IrpContext, DirentBcb );

        FatUnpinRepinnedBcbs( IrpContext );

    } finally {

        DebugUnwind( FatCommonFlushBuffers );

		if (secondaryRequest)
			DereferenceSecondaryRequest( secondaryRequest );

		if (secondarySessionResourceAcquired) {

			SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource );		
		}

        FatUnpinBcb( IrpContext, DirentBcb );

        if (VcbAcquired) { FatReleaseSecondaryVcb( IrpContext, Vcb ); }

        if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }

        //
        //  If this is a normal termination then pass the request on
        //  to the target device object.
        //

        if (!AbnormalTermination()) {

            NTSTATUS DriverStatus;
            PIO_STACK_LOCATION NextIrpSp;

            //
            //  Get the next stack location, and copy over the stack location
            //

            NextIrpSp = IoGetNextIrpStackLocation( Irp );

            *NextIrpSp = *IrpSp;

            //
            //  Set up the completion routine
            //

            IoSetCompletionRoutine( Irp,
                                    FatFlushCompletionRoutine,
                                    ULongToPtr( Status ),
                                    TRUE,
                                    TRUE,
                                    TRUE );

            //
            //  Send the request.
            //

            DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);

            Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
                     Status : DriverStatus;

            //
            //  Free the IrpContext and return to the caller.
            //

            FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS );
        }

        DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status);
    }

    return Status;
}
Пример #2
0
NTSTATUS
FatCommonSetVolumeInfo (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for setting Volume Information called by both
    the fsd and fsp threads.

Arguments:

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;
    TYPE_OF_OPEN TypeOfOpen;

    ULONG Length;
    FS_INFORMATION_CLASS FsInformationClass;
    PVOID Buffer;

    //
    //  Get the current stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonSetVolumeInfo...\n", 0);
    DebugTrace( 0, Dbg, "Irp                  = %08lx\n", Irp );
    DebugTrace( 0, Dbg, "->Length             = %08lx\n", IrpSp->Parameters.SetVolume.Length);
    DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.SetVolume.FsInformationClass);
    DebugTrace( 0, Dbg, "->Buffer             = %08lx\n", Irp->AssociatedIrp.SystemBuffer);

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

    Length = IrpSp->Parameters.SetVolume.Length;
    FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
    Buffer = Irp->AssociatedIrp.SystemBuffer;

    //
    //  Decode the file object to get the Vcb
    //

    TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );

    if (TypeOfOpen != UserVolumeOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );

        DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> STATUS_ACCESS_DENIED\n", 0);

        return STATUS_ACCESS_DENIED;
    }

    //
    //  Acquire exclusive access to the Vcb and enqueue the Irp if we didn't
    //  get access
    //

    if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {

        DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);

        Status = FatFsdPostRequest( IrpContext, Irp );

        DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status );
        return Status;
    }

    try {

        //
        //  Make sure the vcb is in a usable condition.  This will raise
        //  and error condition if the volume is unusable
        //
        //  Also verify the Root Dcb since we need info from there.
        //

        FatVerifyFcb( IrpContext, Vcb->RootDcb );

        //
        //  Based on the information class we'll do different actions.  Each
        //  of the procedures that we're calling performs the action if
        //  possible and returns true if it successful and false if it couldn't
        //  wait for any I/O to complete.
        //

        switch (FsInformationClass) {

        case FileFsLabelInformation:

            Status = FatSetFsLabelInfo( IrpContext, Vcb, Buffer );
            break;

        default:

            Status = STATUS_INVALID_PARAMETER;
            break;
        }

        FatUnpinRepinnedBcbs( IrpContext );

    } finally {

        DebugUnwind( FatCommonSetVolumeInfo );

        FatReleaseVcb( IrpContext, Vcb );

        if (!AbnormalTermination()) {

            FatCompleteRequest( IrpContext, Irp, Status );
        }

        DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status);
    }

    return Status;
}
Пример #3
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 {
Пример #4
0
NTSTATUS
FatCommonQueryVolumeInfo (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for querying volume information called by both
    the fsd and fsp threads.

Arguments:

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    ULONG Length;
    FS_INFORMATION_CLASS FsInformationClass;
    PVOID Buffer;

    BOOLEAN WeAcquiredVcb = FALSE;

    //
    //  Get the current stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonQueryVolumeInfo...\n", 0);
    DebugTrace( 0, Dbg, "Irp                  = %08lx\n", Irp );
    DebugTrace( 0, Dbg, "->Length             = %08lx\n", IrpSp->Parameters.QueryVolume.Length);
    DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
    DebugTrace( 0, Dbg, "->Buffer             = %08lx\n", Irp->AssociatedIrp.SystemBuffer);

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

    Length = IrpSp->Parameters.QueryVolume.Length;
    FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
    Buffer = Irp->AssociatedIrp.SystemBuffer;

    //
    //  Decode the file object to get the Vcb
    //

    (VOID) FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );

    ASSERT( Vcb != NULL );

    try {

        //
        //  Make sure the vcb is in a usable condition.  This will raise
        //  and error condition if the volume is unusable
        //
        //  Also verify the Root Dcb since we need info from there.
        //

        FatVerifyFcb( IrpContext, Vcb->RootDcb );

        //
        //  Based on the information class we'll do different actions.  Each
        //  of the procedures that we're calling fills up the output buffer
        //  if possible and returns true if it successfully filled the buffer
        //  and false if it couldn't wait for any I/O to complete.
        //

        switch (FsInformationClass) {

        case FileFsVolumeInformation:

            //
            //  This is the only routine we need the Vcb shared because of
            //  copying the volume label.  All other routines copy fields that
            //  cannot change or are just manifest constants.
            //

            if (!FatAcquireSharedVcb( IrpContext, Vcb )) {

                DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);

                Status = FatFsdPostRequest( IrpContext, Irp );
                IrpContext = NULL;
                Irp = NULL;

            } else {

                WeAcquiredVcb = TRUE;
                
                Status = FatQueryFsVolumeInfo( IrpContext, Vcb, Buffer, &Length );
            }

            break;

        case FileFsSizeInformation:

            Status = FatQueryFsSizeInfo( IrpContext, Vcb, Buffer, &Length );
            break;

        case FileFsDeviceInformation:

            Status = FatQueryFsDeviceInfo( IrpContext, Vcb, Buffer, &Length );
            break;

        case FileFsAttributeInformation:

            Status = FatQueryFsAttributeInfo( IrpContext, Vcb, Buffer, &Length );
            break;

        case FileFsFullSizeInformation:

            Status = FatQueryFsFullSizeInfo( IrpContext, Vcb, Buffer, &Length );
            break;

        default:

            Status = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        //  Set the information field to the number of bytes actually filled in.
        //

        if (Irp != NULL) {
            
            Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
        }

    } finally {

        DebugUnwind( FatCommonQueryVolumeInfo );

        if ( WeAcquiredVcb ) { FatReleaseVcb( IrpContext, Vcb ); }

        if (!AbnormalTermination()) {

            FatCompleteRequest( IrpContext, Irp, Status );
        }

        DebugTrace(-1, Dbg, "FatCommonQueryVolumeInfo -> %08lx\n", Status);
    }

    return Status;
}