VOID PrimarySessionThreadProc ( IN PPRIMARY_SESSION PrimarySession ) { BOOLEAN primarySessionTerminate = FALSE; NTSTATUS status; _U16 slotIndex; PLIST_ENTRY primarySessionRequestEntry; ASSERT( SESSION_SLOT_COUNT == 1 ); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); DebugTrace2( 0, Dbg2, ("PrimarySessionThreadProc: Start PrimarySession = %p\n", PrimarySession) ); PrimarySession_Reference( PrimarySession ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_INITIALIZING ); InitializeListHead( &PrimarySession->Thread.OpenedFileQueue ); KeInitializeSpinLock( &PrimarySession->Thread.OpenedFileQSpinLock ); KeInitializeEvent( &PrimarySession->Thread.WorkCompletionEvent, NotificationEvent, FALSE ); PrimarySession->SessionContext.SessionSlotCount = SESSION_SLOT_COUNT; for (slotIndex = 0; slotIndex < PrimarySession->SessionContext.SessionSlotCount; slotIndex ++) { PrimarySession->Thread.SessionSlot[slotIndex].State = SLOT_WAIT; PrimarySession->Thread.IdleSlotCount ++; } ClearFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_INITIALIZING ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_START ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_CONNECTED ); KeSetEvent( &PrimarySession->ReadyEvent, IO_DISK_INCREMENT, FALSE ); status = LpxTdiRecvWithCompletionEvent( PrimarySession->ConnectionFileObject, &PrimarySession->Thread.TdiReceiveContext, (PUCHAR)&PrimarySession->Thread.NdfsRequestHeader, sizeof(NDFS_REQUEST_HEADER), 0, NULL, NULL ); if (NT_SUCCESS(status)) { PrimarySession->Thread.TdiReceiving = TRUE; } else { ASSERT( NDASFAT_BUG ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR ); primarySessionTerminate = TRUE; } while (primarySessionTerminate == FALSE) { PKEVENT events[3]; LONG eventCount; NTSTATUS eventStatus; LARGE_INTEGER timeOut; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); eventCount = 0; events[eventCount++] = &PrimarySession->RequestEvent; if (!FlagOn(PrimarySession->Flags, PRIMARY_SESSION_FLAG_STOPPING)) { events[eventCount++] = &PrimarySession->Thread.WorkCompletionEvent; if (FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN)) { if (PrimarySession->Thread.IdleSlotCount == PrimarySession->SessionContext.SessionSlotCount) { CloseOpenFiles( PrimarySession, TRUE ); KeSetEvent( &PrimarySession->Thread.ShutdownPrimarySessionRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN_WAIT ); ClearFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN ); } } if (!FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN_WAIT)) { if (PrimarySession->Thread.TdiReceiving == TRUE) { ASSERT( PrimarySession->Thread.IdleSlotCount != 0 ); events[eventCount++] = &PrimarySession->Thread.TdiReceiveContext.CompletionEvent; } } ASSERT( eventCount <= THREAD_WAIT_OBJECTS ); } timeOut.QuadPart = -5*HZ; eventStatus = KeWaitForMultipleObjects( eventCount, events, WaitAny, Executive, KernelMode, TRUE, &timeOut, NULL ); #if 0 if (!FlagOn(PrimarySession->Flags, PRIMARY_SESSION_FLAG_STOPPING)) { if (eventStatus == STATUS_TIMEOUT || eventStatus == 2) { if (PrimarySession->Thread.SessionState == SESSION_TREE_CONNECT) { ASSERT( PrimarySession->NetdiskPartition ); if (!(PrimarySession->NetdiskPartition->NetdiskVolume[NETDISK_PRIMARY].VolumeState == VolumeMounted || PrimarySession->NetdiskPartition->NetdiskVolume[NETDISK_SECONDARY2PRIMARY].VolumeState == VolumeMounted)) { DebugTrace2( 0, Dbg2, ("Netdisk Volume is unmounted\n") ); if (!FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN_WAIT)) primarySessionTerminate = TRUE; continue; } } } } #endif if (eventStatus == STATUS_TIMEOUT) { continue; } if (!NT_SUCCESS(eventStatus) || eventStatus >= eventCount) { NDASFAT_ASSERT( FALSE ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR ); primarySessionTerminate = TRUE; continue; } KeClearEvent( events[eventStatus] ); if (eventStatus == 0) { while (primarySessionRequestEntry = ExInterlockedRemoveHeadList( &PrimarySession->RequestQueue, &PrimarySession->RequestQSpinLock)) { PPRIMARY_SESSION_REQUEST primarySessionRequest; primarySessionRequest = CONTAINING_RECORD( primarySessionRequestEntry, PRIMARY_SESSION_REQUEST, ListEntry ); if (primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_DISCONNECT || primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_DISCONNECT_AND_TERMINATE) { DebugTrace2( 0, Dbg2, ((primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_DISCONNECT) ? ("PRIMARY_SESSION_REQ_DISCONNECT: DisconnectFromSecondary\n") : ("PRIMARY_SESSION_REQ_DISCONNECT_AND_TERMINATE: DisconnectFromSecondary\n")) ); if (!FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED)) { DisconnectFromSecondary( PrimarySession ); ClearFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_CONNECTED ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED ); } if (primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_DISCONNECT_AND_TERMINATE) primarySessionTerminate = TRUE; if (primarySessionRequest->Synchronous == TRUE) KeSetEvent( &primarySessionRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferencePrimarySessionRequest( primarySessionRequest ); } else if (primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_DOWN) { SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_STOPED ); primarySessionTerminate = TRUE; if (primarySessionRequest->Synchronous == TRUE) KeSetEvent( &primarySessionRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferencePrimarySessionRequest( primarySessionRequest ); } else if (primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_SHUTDOWN) { DebugTrace2( 0, Dbg, ("PrimarySessionThreadProc: PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN\n") ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN ); ASSERT (primarySessionRequest->Synchronous == TRUE); PrimarySession->Thread.ShutdownPrimarySessionRequest = primarySessionRequest; if (!FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED)) { DisconnectFromSecondary( PrimarySession ); ClearFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_CONNECTED ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED ); } } else if (primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_STOPPING) { SetFlag( PrimarySession->Flags, PRIMARY_SESSION_FLAG_STOPPING ); if (PrimarySession->IsLocalAddress == FALSE) { CloseOpenFiles( PrimarySession, FALSE ); } if (primarySessionRequest->Synchronous == TRUE) KeSetEvent( &primarySessionRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferencePrimarySessionRequest( primarySessionRequest ); } else if (primarySessionRequest->RequestType == PRIMARY_SESSION_REQ_CANCEL_STOPPING) { ClearFlag( PrimarySession->Flags, PRIMARY_SESSION_FLAG_STOPPING ); if (primarySessionRequest->Synchronous == TRUE) KeSetEvent( &primarySessionRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferencePrimarySessionRequest( primarySessionRequest ); } else { ASSERT( NDASFAT_BUG ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR ); } } continue; } else if (eventStatus == 1) { while (TRUE) { for (slotIndex = 0; slotIndex < PrimarySession->SessionContext.SessionSlotCount; slotIndex ++) { if (PrimarySession->Thread.SessionSlot[slotIndex].State == SLOT_FINISH) break; } if (slotIndex == PrimarySession->SessionContext.SessionSlotCount) break; PrimarySession->Thread.SessionSlot[slotIndex].State = SLOT_WAIT; PrimarySession->Thread.IdleSlotCount ++; if (PrimarySession->Thread.SessionSlot[slotIndex].Status == STATUS_SUCCESS) { PNDFS_REPLY_HEADER ndfsReplyHeader; ndfsReplyHeader = (PNDFS_REPLY_HEADER)PrimarySession->Thread.SessionSlot[slotIndex].ReplyMessageBuffer; PrimarySession->Thread.SessionSlot[slotIndex].Status = SendNdfsWinxpMessage( PrimarySession, ndfsReplyHeader, PrimarySession->Thread.SessionSlot[slotIndex].NdfsWinxpReplyHeader, PrimarySession->Thread.SessionSlot[slotIndex].ReplyDataSize, slotIndex ); } if (PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpRequestMessagePool) { ExFreePool(PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpRequestMessagePool); PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpRequestMessagePool = NULL; PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePoolLength = 0; } if (PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePool) { ExFreePool(PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePool); PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePool = NULL; PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePoolLength = 0; } if (!(PrimarySession->Thread.SessionSlot[slotIndex].Status == STATUS_SUCCESS || PrimarySession->Thread.SessionSlot[slotIndex].Status == STATUS_PENDING)) { SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR ); #if 0 if (PrimarySession->NetdiskPartition) { NetdiskManager_ReturnPrimaryPartition( GlobalLfs.NetdiskManager, PrimarySession, PrimarySession->NetdiskPartition, PrimarySession->IsLocalAddress ); PrimarySession->NetdiskPartition = NULL; } #endif primarySessionTerminate = TRUE; break; } if (PrimarySession->Thread.SessionState == SESSION_CLOSED) { #if 0 if (PrimarySession->NetdiskPartition) { NetdiskManager_ReturnPrimaryPartition( GlobalLfs.NetdiskManager, PrimarySession, PrimarySession->NetdiskPartition, PrimarySession->IsLocalAddress ); PrimarySession->NetdiskPartition = NULL; } #endif primarySessionTerminate = TRUE; break; } if (PrimarySession->Thread.SessionSlot[slotIndex].Status == STATUS_SUCCESS) { if (PrimarySession->Thread.TdiReceiving == FALSE) { status = LpxTdiRecvWithCompletionEvent( PrimarySession->ConnectionFileObject, &PrimarySession->Thread.TdiReceiveContext, (PUCHAR)&PrimarySession->Thread.NdfsRequestHeader, sizeof(NDFS_REQUEST_HEADER), 0, NULL, NULL ); if (!NT_SUCCESS(status)) { ASSERT( NDASFAT_BUG ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR ); primarySessionTerminate = TRUE; break; } PrimarySession->Thread.TdiReceiving = TRUE; } } } continue; } else { ASSERT( eventStatus == 2 ); // Receive Event ASSERT( !FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN_WAIT) && !FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_SHUTDOWN) ); if (PrimarySession->Thread.TdiReceiveContext.Result != sizeof(NDFS_REQUEST_HEADER)) { DebugTrace2( 0, Dbg, ("DispatchRequest: Disconnected, PrimarySession = Data received:%d\n", PrimarySession->Thread.TdiReceiveContext.Result) ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED ); primarySessionTerminate = TRUE; continue; } PrimarySession->Thread.TdiReceiving = FALSE; #if 0 if (PrimarySession->NetdiskPartition) { PENABLED_NETDISK EnabledNetdisk = PrimarySession->NetdiskPartition->EnabledNetdisk; ASSERT( EnabledNetdisk ); if (NetdiskManager_IsStoppedNetdisk(GlobalLfs.NetdiskManager, EnabledNetdisk)) { DebugTrace2( 0, Dbg2, ("PrimarySessionThread: %p Netdisk is stopped\n", PrimarySession) ); DebugTrace2( 0, Dbg2, ("DispatchWinXpRequest: Netdisk is stopped.\n") ); if (!FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED)) { // no other way to notify secondary about unmount without break backward compatability. DebugTrace2( 0, Dbg2, ("IsStoppedNetdisk: DisconnectFromSecondary\n") ); DisconnectFromSecondary( PrimarySession ); ClearFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_CONNECTED ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED ); } primarySessionTerminate = TRUE; continue; } } #endif status = DispatchRequest( PrimarySession ); if (!(status == STATUS_SUCCESS || status == STATUS_PENDING)) { primarySessionTerminate = TRUE; continue; } if (PrimarySession->Thread.SessionState == SESSION_CLOSED) { primarySessionTerminate = TRUE; continue; } if (status == STATUS_SUCCESS) { if (PrimarySession->Thread.TdiReceiving == FALSE) { status = LpxTdiRecvWithCompletionEvent( PrimarySession->ConnectionFileObject, &PrimarySession->Thread.TdiReceiveContext, (PUCHAR)&PrimarySession->Thread.NdfsRequestHeader, sizeof(NDFS_REQUEST_HEADER), 0, NULL, NULL ); if (!NT_SUCCESS(status)) { SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR ); primarySessionTerminate = TRUE; } PrimarySession->Thread.TdiReceiving = TRUE; } } continue; } } ExAcquireFastMutexUnsafe( &PrimarySession->FastMutex ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_STOPED ); ExReleaseFastMutexUnsafe( &PrimarySession->FastMutex ); while (TRUE) { LARGE_INTEGER timeOut; NTSTATUS eventStatus; if (PrimarySession->Thread.IdleSlotCount == PrimarySession->SessionContext.SessionSlotCount) break; timeOut.QuadPart = -10*HZ; eventStatus = KeWaitForSingleObject( &PrimarySession->Thread.WorkCompletionEvent, Executive, KernelMode, FALSE, &timeOut ); KeClearEvent( &PrimarySession->Thread.WorkCompletionEvent ); if (eventStatus == STATUS_TIMEOUT) { ASSERT( NDASFAT_UNEXPECTED ); continue; } while (TRUE) { for (slotIndex = 0; slotIndex < PrimarySession->SessionContext.SessionSlotCount; slotIndex++) { if (PrimarySession->Thread.SessionSlot[slotIndex].State == SLOT_FINISH) break; } if (slotIndex == PrimarySession->SessionContext.SessionSlotCount) break; DebugTrace2( 0, Dbg, ("PrimarySessionThreadProc: eventStatus = %d\n", eventStatus) ); PrimarySession->Thread.SessionSlot[slotIndex].State = SLOT_WAIT; PrimarySession->Thread.IdleSlotCount++; if (PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpRequestMessagePool) { ExFreePool( PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpRequestMessagePool ); PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpRequestMessagePool = NULL; PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePoolLength = 0; } if (PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePool) { ExFreePool( PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePool ); PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePool = NULL; PrimarySession->Thread.SessionSlot[slotIndex].ExtendWinxpReplyMessagePoolLength = 0; } } } if (!FlagOn(PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED)) { DebugTrace2( 0, Dbg2, ("PsTerminateSystemThread: DisconnectFromSecondary\n") ); DisconnectFromSecondary( PrimarySession ); ClearFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_CONNECTED ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_DISCONNECTED ); } CloseOpenFiles( PrimarySession, TRUE ); while (primarySessionRequestEntry = ExInterlockedRemoveHeadList( &PrimarySession->RequestQueue, &PrimarySession->RequestQSpinLock)) { PPRIMARY_SESSION_REQUEST primarySessionRequest; primarySessionRequest = CONTAINING_RECORD( primarySessionRequestEntry, PRIMARY_SESSION_REQUEST, ListEntry ); if (primarySessionRequest->Synchronous == TRUE) KeSetEvent( &primarySessionRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferencePrimarySessionRequest( primarySessionRequest ); } #if 0 if (PrimarySession->NetdiskPartition) { NetdiskManager_ReturnPrimaryPartition( GlobalLfs.NetdiskManager, PrimarySession, PrimarySession->NetdiskPartition, PrimarySession->IsLocalAddress ); PrimarySession->NetdiskPartition = NULL; } #endif DebugTrace2( 0, Dbg2, ("PrimarySessionThreadProc: PsTerminateSystemThread PrimarySession = %p\n", PrimarySession) ); SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_TERMINATED ); PrimarySession_Dereference( PrimarySession ); PsTerminateSystemThread( STATUS_SUCCESS ); }
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 {
NTSTATUS NdasFatCommonFlushBuffers ( 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->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { do { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->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 ); 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 ); } secondaryRequest = AllocateWinxpSecondaryRequest( 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 = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); break; } KeClearEvent (&secondaryRequest->CompleteEvent); if (BooleanFlagOn(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 ); } 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->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 = FatAcquireExclusiveVcb( 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->SessionResource ); } FatUnpinBcb( IrpContext, DirentBcb ); if (VcbAcquired) { FatReleaseVcb( 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; }
NTSTATUS FatFsdCleanup ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of closing down a handle to a file object. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being Cleanup exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel; PAGED_CODE(); #if __NDAS_FAT__ if ((PVOID)FatControlDeviceObject == VolumeDeviceObject) { Status = Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return Status; } #endif // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS // if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } DebugTrace(+1, Dbg, "FatFsdCleanup\n", 0); // // Call the common Cleanup routine, with blocking allowed. // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); #if (__NDAS_FAT_PRIMARY__ || __NDAS_FAT_SECONDARY__) do { try { if (IrpContext == NULL) { IrpContext = FatCreateIrpContext( Irp, TRUE ); IrpContext->TopLevel = TopLevel; #if __NDAS_FAT_PRIMARY__ { ULONG_PTR stackBottom; ULONG_PTR stackTop; BOOLEAN validPrimaryRequest = FALSE; PPRIMARY_REQUEST_INFO primaryRequestInfo; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); //primaryRequestInfo = (PPRIMARY_REQUEST_INFO)FatGetTopLevelContext()->SavedTopLevelIrp; primaryRequestInfo = (PPRIMARY_REQUEST_INFO)IoGetTopLevelIrp(); IoGetStackLimits( &stackTop, &stackBottom ); if ( (ULONG_PTR)primaryRequestInfo <= stackBottom - sizeof(PRIMARY_REQUEST_INFO) && (ULONG_PTR) primaryRequestInfo >= stackTop && (!FlagOn( (ULONG_PTR) primaryRequestInfo, 0x3 )) && primaryRequestInfo->PrimaryTag == 0xe2027482) { validPrimaryRequest = TRUE; } if (validPrimaryRequest) { //ASSERT( FatIsTopLevelRequest(IrpContext) ); IoSetTopLevelIrp( NULL ); TopLevel = FatIsIrpTopLevel( Irp ); ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL ); if (IsListEmpty(&VolumeDeviceObject->PrimarySessionQueue)) { NDASFAT_ASSERT( FALSE ); } IrpContext->PrimaryRequestInfo = *primaryRequestInfo; DebugTrace2( 0, Dbg, ("primaryRequestInfo = %p\n", primaryRequestInfo) ); } } #endif } #if __NDAS_FAT_SECONDARY__ if (IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( FatIsTopLevelRequest(IrpContext) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); Status = STATUS_SUCCESS; while (TRUE) { ASSERT( secondaryRecoveryResourceAcquired == FALSE ); ASSERT( secondaryResourceAcquired == FALSE ); if (FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->RecoveryResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); try { SecondaryRecoverySessionStart( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (secondaryResourceAcquired == FALSE) { ASSERT( FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING) ); continue; } break; } if (Status == STATUS_SUCCESS) { try { Status = FatCommonCleanup( IrpContext, Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Resource ); } } } else Status = FatCommonCleanup( IrpContext, Irp ); #else Status = FatCommonCleanup( IrpContext, Irp ); #endif } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT);
NTSTATUS SecondaryRecoverySessionStart ( IN PSECONDARY Secondary, IN PIRP_CONTEXT IrpContext ) { NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; LARGE_INTEGER timeOut; if (Secondary->RecoveryThreadHandle) return STATUS_SUCCESS; ASSERT( ExIsResourceAcquiredExclusiveLite(&Secondary->VolDo->RecoveryResource) && ExIsResourceAcquiredExclusiveLite(&Secondary->VolDo->Resource) ); ASSERT( IrpContext != NULL ); ASSERT( FatIsTopLevelRequest(IrpContext) /*|| FatIsTopLevelFat( IrpContext) && FatGetTopLevelContext()->SavedTopLevelIrp == (PIRP)FSRTL_FSP_TOP_LEVEL_IRP || FlagOn(IrpContext->State, IRP_CONTEXT_STATE_IN_FSP)*/ ); if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "SecondaryRecoverySessionStart", NULL, IrpContext->OriginatingIrp ); if (FlagOn(Secondary->VolDo->NdasFatFlags, ND_FAT_DEVICE_FLAG_SHUTDOWN)) { //DebugTrace2( 0, Dbg2, ("SecondaryToPrimary ND_FAT_DEVICE_FLAG_SHUTDOWN\n") ); //DbgPrint( "SecondaryToPrimary ND_FAT_DEVICE_FLAG_SHUTDOWN\n" ); FatRaiseStatus( IrpContext, STATUS_TOO_LATE ); } InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); status = PsCreateSystemThread( &Secondary->RecoveryThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, SecondaryRecoveryThreadProc, Secondary ); if (!NT_SUCCESS(status)) { NDASFAT_ASSERT( FALSE ); return status; } timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &Secondary->RecoveryReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { NDASFAT_ASSERT( FALSE ); return status; } KeClearEvent( &Secondary->RecoveryReadyEvent ); if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "SecondaryRecoverySessionStart returned", NULL, IrpContext->OriginatingIrp ); //status = SecondaryRecoverySession( Secondary, IrpContext ); return status; }
VOID SecondaryRecoveryThreadProc ( IN PSECONDARY Secondary ) { NTSTATUS status; BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); DebugTrace2( 0, Dbg2, ("SecondaryRecoveryThreadProc: Start Secondary = %p\n", Secondary) ); Secondary_Reference( Secondary ); FsRtlEnterFileSystem(); KeSetEvent( &Secondary->RecoveryReadyEvent, IO_DISK_INCREMENT, FALSE ); try { secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( NULL, &Secondary->VolDo->RecoveryResource, TRUE ); if (!FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { NDASFAT_ASSERT( FALSE ); SecondaryReleaseResourceLite( NULL, &Secondary->VolDo->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; leave; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( NULL, &Secondary->VolDo->Resource, TRUE ); try { status = SecondaryRecoverySession( Secondary ); } finally { SecondaryReleaseResourceLite( NULL, &Secondary->VolDo->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( NULL, &Secondary->VolDo->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } } finally { if (secondaryResourceAcquired) SecondaryReleaseResourceLite( NULL, &Secondary->VolDo->Resource ); if (secondaryRecoveryResourceAcquired) SecondaryReleaseResourceLite( NULL, &Secondary->VolDo->RecoveryResource ); Secondary->RecoveryThreadHandle = NULL; FsRtlExitFileSystem(); Secondary_Dereference( Secondary ); DebugTrace2( 0, Dbg2, ("SecondaryRecoveryThreadProc: Terminated Secondary = %p\n", Secondary) ); } PsTerminateSystemThread( STATUS_SUCCESS ); }
NTSTATUS SecondaryRecoverySession ( IN PSECONDARY Secondary ) { NTSTATUS status; LONG slotIndex; LARGE_INTEGER timeOut; OBJECT_ATTRIBUTES objectAttributes; ULONG reconnectionTry; PLIST_ENTRY ccblistEntry; BOOLEAN isLocalAddress; DebugTrace2( 0, Dbg2, ("SecondaryRecoverySession: Called Secondary = %p\n", Secondary) ); SetFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); ASSERT( FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ); ASSERT( Secondary->ThreadHandle ); ASSERT( IsListEmpty(&Secondary->RequestQueue) ); for (slotIndex=0; slotIndex < Secondary->Thread.SessionContext.SessionSlotCount; slotIndex++) { ASSERT( Secondary->Thread.SessionSlot[slotIndex] == NULL ); } if (Secondary->ThreadHandle) { ASSERT( Secondary->ThreadObject ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { NDASFAT_ASSERT( FALSE ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return status; } DebugTrace2( 0, Dbg2, ("Secondary_Stop: thread stoped\n") ); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = 0; Secondary->ThreadObject = 0; RtlZeroMemory( &Secondary->Thread.Flags, sizeof(SECONDARY) - FIELD_OFFSET(SECONDARY, Thread.Flags) ); } for (status = STATUS_UNSUCCESSFUL, reconnectionTry = 0; reconnectionTry < MAX_RECONNECTION_TRY; reconnectionTry++) { if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_LOCKED)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->NdasFatFlags, ND_FAT_DEVICE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY) { status = STATUS_SUCCESS; } else { status = ((PVOLUME_DEVICE_OBJECT) FatData.DiskFileSystemDeviceObject)-> NdfsCallback.SecondaryToPrimary( Secondary->VolDo->Vcb.Vpb->RealDevice, TRUE ); if (status == STATUS_NO_SUCH_DEVICE) { NDASFAT_ASSERT( FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_LOCKED) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } } //FatDebugTraceLevel = 0; DebugTrace2( 0, Dbg2, ("SecondaryToPrimary status = %x\n", status) ); #if 0 if (queryResult == TRUE) { BOOLEAN result0, result1; IRP_CONTEXT IrpContext; ASSERT( Secondary->VolDo->Vcb.VirtualVolumeFile ); result0 = CcPurgeCacheSection( &Secondary->VolDo->Vcb.SectionObjectPointers, NULL, 0, FALSE ); ASSERT( Secondary->VolDo->Vcb.RootDcb->Specific.Dcb.DirectoryFile ); result1 = CcPurgeCacheSection( &Secondary->VolDo->Vcb.RootDcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE ); ASSERT( result0 == TRUE ); ASSERT( result1 == TRUE ); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT); FatTearDownAllocationSupport ( &IrpContext, &Secondary->VolDo->Vcb ); FatSetupAllocationSupport( &IrpContext, &Secondary->VolDo->Vcb ); FatCheckDirtyBit( &IrpContext, &Secondary->VolDo->Vcb ); ASSERT( IrpContext.Repinned.Bcb[0] == NULL ); FatUnpinRepinnedBcbs( &IrpContext ); Secondary->VolDo->NetdiskEnableMode = NETDISK_SECONDARY2PRIMARY; Secondary->VolDo->SecondaryState = CONNECT_TO_LOCAL_STATE; } #endif if (status == STATUS_SUCCESS) { PVCB vcb = &Secondary->VolDo->Vcb; #if 0 TOP_LEVEL_CONTEXT topLevelContext; PTOP_LEVEL_CONTEXT threadTopLevelContext; #endif IRP_CONTEXT tempIrpContext2; PIRP_CONTEXT tempIrpContext = NULL; SetFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->SecondaryResource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->SecondaryResource) ); //FatReleaseAllResources( IrpContext ); //ObReferenceObject( vcb->TargetDeviceObject ); DebugTrace2( 0, Dbg2, ("Vcb->State = %X\n", vcb->VcbState) ); DebugTrace2( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); tempIrpContext = NULL; #if 0 threadTopLevelContext = FatInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); FatInitializeIrpContext( NULL, TRUE, &tempIrpContext ); FatUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); #endif tempIrpContext = &tempIrpContext2; RtlZeroMemory( tempIrpContext, sizeof(IRP_CONTEXT) ); SetFlag( tempIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); SetFlag( tempIrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); try { status = STATUS_UNSUCCESSFUL; status = CleanUpVcb( tempIrpContext, vcb ); } finally { //FatCompleteRequest( tempIrpContext, NULL, 0 ); //ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); ASSERT( status == STATUS_SUCCESS ); //ASSERT( FlagOn(vcb->VcbState, VCB_STATE_MOUNT_COMPLETED) ); ASSERT( FlagOn(Secondary->VolDo->NdasFatFlags, ND_FAT_DEVICE_FLAG_MOUNTED) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->SecondaryResource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->SecondaryResource) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); DebugTrace2( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->OpenFileCount) ); #if 0 tempIrpContext = NULL; threadTopLevelContext = FatInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); FatInitializeIrpContext( NULL, TRUE, &tempIrpContext ); FatUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); #endif Secondary->VolDo->NetdiskEnableMode = NETDISK_SECONDARY2PRIMARY; tempIrpContext = &tempIrpContext2; RtlZeroMemory( tempIrpContext, sizeof(IRP_CONTEXT) ); SetFlag( tempIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); SetFlag( tempIrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; SetFlag( Secondary->Flags, SECONDARY_FLAG_REMOUNT_VOLUME ); try { status = STATUS_UNSUCCESSFUL; status = NdasFatMountVolume( tempIrpContext, vcb->TargetDeviceObject, vcb->Vpb, NULL ); } finally { //FatCompleteRequest( tempIrpContext, NULL, 0 ); //ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } //ObDereferenceObject( vcb->TargetDeviceObject ); //FatDebugTraceLevel = 0xFFFFFFFFFFFFFFFF; //FatDebugTraceLevel |= DEBUG_TRACE_CREATE; ClearFlag( Secondary->Flags, SECONDARY_FLAG_REMOUNT_VOLUME ); ASSERT( status == STATUS_SUCCESS ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); DebugTrace2( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->OpenFileCount) ); #if 0 if (vcb->MftScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->MftScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->MftScb->Header.Resource) ); } if (vcb->Mft2Scb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->Mft2Scb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->Mft2Scb->Header.Resource) ); } if (vcb->LogFileScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->LogFileScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->LogFileScb->Header.Resource) ); } if (vcb->VolumeDasdScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->VolumeDasdScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->VolumeDasdScb->Header.Resource) ); } if (vcb->AttributeDefTableScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->AttributeDefTableScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->AttributeDefTableScb->Header.Resource) ); } if (vcb->UpcaseTableScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->UpcaseTableScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->UpcaseTableScb->Header.Resource) ); } if (vcb->RootIndexScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->RootIndexScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->RootIndexScb->Header.Resource) ); } if (vcb->BitmapScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->BitmapScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->BitmapScb->Header.Resource) ); } if (vcb->BadClusterFileScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->BadClusterFileScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->BadClusterFileScb->Header.Resource) ); } if (vcb->MftBitmapScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->MftBitmapScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->MftBitmapScb->Header.Resource) ); } if (vcb->SecurityDescriptorStream) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityDescriptorStream->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityDescriptorStream->Header.Resource) ); } if (vcb->UsnJournal) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->UsnJournal->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->UsnJournal->Header.Resource) ); } if (vcb->ExtendDirectory) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->ExtendDirectory->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->ExtendDirectory->Header.Resource) ); } if (vcb->SecurityDescriptorHashIndex) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityDescriptorHashIndex->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityDescriptorHashIndex->Header.Resource) ); } if (vcb->SecurityIdIndex) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityIdIndex->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityIdIndex->Header.Resource) ); } #endif } status = ((PVOLUME_DEVICE_OBJECT) FatData.DiskFileSystemDeviceObject)-> NdfsCallback.QueryPrimaryAddress( &Secondary->VolDo->NetdiskPartitionInformation, &Secondary->PrimaryAddress, &isLocalAddress ); DebugTrace2( 0, Dbg2, ("RecoverSession: LfsTable_QueryPrimaryAddress status = %X\n", status) ); if (status == STATUS_SUCCESS && !(Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY && isLocalAddress)) { DebugTrace2( 0, Dbg, ("SecondaryRecoverySessionStart: Found PrimaryAddress :%02x:%02x:%02x:%02x:%02x:%02x/%d\n", Secondary->PrimaryAddress.Node[0], Secondary->PrimaryAddress.Node[1], Secondary->PrimaryAddress.Node[2], Secondary->PrimaryAddress.Node[3], Secondary->PrimaryAddress.Node[4], Secondary->PrimaryAddress.Node[5], NTOHS(Secondary->PrimaryAddress.Port)) ); } else { //ASSERT( FALSE ); continue; } KeInitializeEvent( &Secondary->ReadyEvent, NotificationEvent, FALSE ); KeInitializeEvent( &Secondary->RequestEvent, NotificationEvent, FALSE ); InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); status = PsCreateSystemThread( &Secondary->ThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, SecondaryThreadProc, Secondary ); if (!NT_SUCCESS(status)) { ASSERT( NDASFAT_UNEXPECTED ); break; } status = ObReferenceObjectByHandle( Secondary->ThreadHandle, FILE_READ_DATA, NULL, KernelMode, &Secondary->ThreadObject, NULL ); if (!NT_SUCCESS(status)) { ASSERT (NDASFAT_INSUFFICIENT_RESOURCES ); break; } timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &Secondary->ReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); break; } KeClearEvent( &Secondary->ReadyEvent ); InterlockedIncrement( &Secondary->SessionId ); ExAcquireFastMutex( &Secondary->FastMutex ); if (!FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_START) || FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_STOPED)) { ExReleaseFastMutex( &Secondary->FastMutex ); if (Secondary->Thread.SessionStatus == STATUS_DISK_CORRUPT_ERROR) { status = STATUS_SUCCESS; break; } timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); return status; } DebugTrace2( 0, Dbg, ("Secondary_Stop: thread stoped\n") ); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = 0; Secondary->ThreadObject = 0; RtlZeroMemory( &Secondary->Thread.Flags, sizeof(SECONDARY) - FIELD_OFFSET(SECONDARY, Thread.Flags) ); continue; } ExReleaseFastMutex( &Secondary->FastMutex ); status = STATUS_SUCCESS; DebugTrace2( 0, Dbg2, ("SecondaryRecoverySession Success Secondary = %p\n", Secondary) ); break; }
NTSTATUS FatProcessException ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN NTSTATUS ExceptionCode ) /*++ Routine Description: This routine process an exception. It either completes the request with the saved exception status or it sends it off to IoRaiseHardError() Arguments: Irp - Supplies the Irp being processed ExceptionCode - Supplies the normalized exception status being handled Return Value: NTSTATUS - Returns the results of either posting the Irp or the saved completion status. --*/ { PVCB Vcb; PIO_STACK_LOCATION IrpSp; FAT_VOLUME_STATE TransitionState = VolumeDirty; ULONG SavedFlags; PAGED_CODE(); DebugTrace(0, Dbg, "FatProcessException\n", 0); // // If there is not an irp context, we must have had insufficient resources. // if ( !ARGUMENT_PRESENT( IrpContext ) ) { FatCompleteRequest( FatNull, Irp, ExceptionCode ); return ExceptionCode; } // // Get the real exception status from IrpContext->ExceptionStatus, and // reset it. // ExceptionCode = IrpContext->ExceptionStatus; FatResetExceptionState( IrpContext ); // // If this is an Mdl write request, then take care of the Mdl // here so that things get cleaned up properly. Cc now leaves // the MDL in place so a filesystem can retry after clearing an // internal condition (FAT does not). // #if __NDAS_FAT_WIN2K_SUPPORT__ if (NdasFatCcMdlWriteAbort && (IrpContext->MajorFunction == IRP_MJ_WRITE) && (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) && (Irp->MdlAddress != NULL)) { PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp); NdasFatCcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress ); Irp->MdlAddress = NULL; } #else if ((IrpContext->MajorFunction == IRP_MJ_WRITE) && (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) && (Irp->MdlAddress != NULL)) { PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp); CcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress ); Irp->MdlAddress = NULL; } #endif // // If we are going to post the request, we may have to lock down the // user's buffer, so do it here in a try except so that we failed the // request if the LockPages fails. // // Also unpin any repinned Bcbs, protected by the try {} except {} filter. // try { SavedFlags = IrpContext->Flags; // // Make sure we don't try to write through Bcbs // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH); FatUnpinRepinnedBcbs( IrpContext ); IrpContext->Flags = SavedFlags; // // If we will have to post the request, do it here. Note // that the last thing FatPrePostIrp() does is mark the Irp pending, // so it is critical that we actually return PENDING. Nothing // from this point to return can fail, so we are OK. // // We cannot do a verify operations at APC level because we // have to wait for Io operations to complete. // #if __NDAS_FAT__ if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) && (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (NdasFatKeAreAllApcsDisabled ? NdasFatKeAreAllApcsDisabled() : KeGetCurrentIrql() >= APC_LEVEL)) || !FlagOn(IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST) && (ExceptionCode == STATUS_CANT_WAIT))) { NDASFAT_ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); ExceptionCode = FatFsdPostRequest( IrpContext, Irp ); } #else if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) && (((ExceptionCode == STATUS_VERIFY_REQUIRED) && KeAreAllApcsDisabled()) || (ExceptionCode == STATUS_CANT_WAIT))) { ExceptionCode = FatFsdPostRequest( IrpContext, Irp ); } #endif } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) { ExceptionCode = IrpContext->ExceptionStatus; IrpContext->ExceptionStatus = 0; IrpContext->Flags = SavedFlags; } // // If we posted the request, just return here. // if (ExceptionCode == STATUS_PENDING) { return ExceptionCode; } #if (__NDAS_FAT_PRIMARY__ || __NDAS_FAT_SECONDARY__) if (ExceptionCode == STATUS_CANT_WAIT) { IrpContext->OriginalIrpIoStatus = Irp->IoStatus; } #endif Irp->IoStatus.Status = ExceptionCode; // // If this request is not a "top-level" irp, just complete it. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) { // // If there is a cache operation above us, commute verify // to a lock conflict. This will cause retries so that // we have a chance of getting through without needing // to return an unaesthetic error for the operation. // if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP && ExceptionCode == STATUS_VERIFY_REQUIRED) { ExceptionCode = STATUS_FILE_LOCK_CONFLICT; } FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } if (IoIsErrorUserInduced(ExceptionCode)) { // // Check for the various error conditions that can be caused by, // and possibly resolved by the user. // if (ExceptionCode == STATUS_VERIFY_REQUIRED) { PDEVICE_OBJECT Device; DebugTrace(0, Dbg, "Perform Verify Operation\n", 0); // // Now we are at the top level file system entry point. // // Grab the device to verify from the thread local storage // and stick it in the information field for transportation // to the fsp. We also clear the field at this time. // Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread ); IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL ); if ( Device == NULL ) { Device = IoGetDeviceToVerify( PsGetCurrentThread() ); IoSetDeviceToVerify( PsGetCurrentThread(), NULL ); ASSERT( Device != NULL ); } // // Let's not BugCheck just because the driver messed up. // if (Device == NULL) { ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR; FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } // // FatPerformVerify() will do the right thing with the Irp. return FatPerformVerify( IrpContext, Irp, Device ); } // // The other user induced conditions generate an error unless // they have been disabled for this request. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS)) { FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } else { // // Generate a pop-up // PDEVICE_OBJECT RealDevice; PVPB Vpb; PETHREAD Thread; if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL) { Vpb = IoGetCurrentIrpStackLocation(Irp)->FileObject->Vpb; } else { Vpb = NULL; } // // The device to verify is either in my thread local storage // or that of the thread that owns the Irp. // Thread = Irp->Tail.Overlay.Thread; RealDevice = IoGetDeviceToVerify( Thread ); if ( RealDevice == NULL ) { Thread = PsGetCurrentThread(); RealDevice = IoGetDeviceToVerify( Thread ); ASSERT( RealDevice != NULL ); } // // Let's not BugCheck just because the driver messed up. // if (RealDevice == NULL) { FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } // // This routine actually causes the pop-up. It usually // does this by queuing an APC to the callers thread, // but in some cases it will complete the request immediately, // so it is very important to IoMarkIrpPending() first. // IoMarkIrpPending( Irp ); IoRaiseHardError( Irp, Vpb, RealDevice ); // // We will be handing control back to the caller here, so // reset the saved device object. // IoSetDeviceToVerify( Thread, NULL ); // // The Irp will be completed by Io or resubmitted. In either // case we must clean up the IrpContext here. // FatDeleteIrpContext( IrpContext ); return STATUS_PENDING; } } // // This is just a run of the mill error. If is a STATUS that we // raised ourselves, and the information would be use for the // user, raise an informational pop-up. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); Vcb = IrpContext->Vcb; // // Now, if the Vcb is unknown to us this means that the error was raised // in the process of a mount and before we even had a chance to build // a full Vcb - and was really handled there. // if (Vcb != NULL) { if ( !FatDeviceIsFatFsdo( IrpSp->DeviceObject) && !NT_SUCCESS(ExceptionCode) && !FsRtlIsTotalDeviceFailure(ExceptionCode) ) { TransitionState = VolumeDirtyWithSurfaceTest; } // // If this was a STATUS_FILE_CORRUPT or similar error indicating some // nastiness out on the media, then mark the volume permanently dirty. // if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS) && ( TransitionState == VolumeDirtyWithSurfaceTest || (ExceptionCode == STATUS_FILE_CORRUPT_ERROR) || (ExceptionCode == STATUS_DISK_CORRUPT_ERROR) || (ExceptionCode == STATUS_EA_CORRUPT_ERROR) || (ExceptionCode == STATUS_INVALID_EA_NAME) || (ExceptionCode == STATUS_EA_LIST_INCONSISTENT) || (ExceptionCode == STATUS_NO_EAS_ON_FILE) )) { ASSERT( NodeType(Vcb) == FAT_NTC_VCB ); ASSERT( !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)); SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); // // Do the "dirty" work, ignoring any error. We need to take the Vcb here // to synchronize against the verify path tearing things down, since // we dropped all synchronization when backing up due to the exception. // FatAcquireExclusiveVcbNoOpCheck( IrpContext, Vcb); try { if (VcbGood == Vcb->VcbCondition) { FatMarkVolume( IrpContext, Vcb, TransitionState ); } } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) { NOTHING; } FatReleaseVcb( IrpContext, Vcb); } }