diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/cdfs/read.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/cdfs/read.c')
-rw-r--r-- | private/ntos/cdfs/read.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/private/ntos/cdfs/read.c b/private/ntos/cdfs/read.c new file mode 100644 index 000000000..bbc374a1d --- /dev/null +++ b/private/ntos/cdfs/read.c @@ -0,0 +1,539 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + Read.c + +Abstract: + + This module implements the File Read routine for Read called by the + Fsd/Fsp dispatch drivers. + +Author: + + Brian Andrew [BrianAn] 01-July-1995 + +Revision History: + +--*/ + +#include "CdProcs.h" + +// +// The Bug check file id for this module +// + +#define BugCheckFileId (CDFS_BUG_CHECK_READ) + +// +// VOID +// SafeZeroMemory ( +// IN PUCHAR At, +// IN ULONG ByteCount +// ); +// + +// +// This macro just puts a nice little try-except around RtlZeroMemory +// + +#define SafeZeroMemory(IC,AT,BYTE_COUNT) { \ + try { \ + RtlZeroMemory( (AT), (BYTE_COUNT) ); \ + } except( EXCEPTION_EXECUTE_HANDLER ) { \ + CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \ + } \ +} + +// +// Read ahead amount used for normal data files +// + +#define READ_AHEAD_GRANULARITY (0x10000) + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, CdCommonRead) +#endif + + +NTSTATUS +CdCommonRead ( + IN PIRP_CONTEXT IrpContext, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This is the common entry point for NtReadFile calls. For synchronous requests, + CommonRead will complete the request in the current thread. If not + synchronous the request will be passed to the Fsp if there is a need to + block. + +Arguments: + + Irp - Supplies the Irp to process + +Return Value: + + NTSTATUS - The result of this operation. + +--*/ + +{ + NTSTATUS Status; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + TYPE_OF_OPEN TypeOfOpen; + PFCB Fcb; + PCCB Ccb; + + BOOLEAN Wait; + ULONG PagingIo; + ULONG SynchronousIo; + ULONG NonCachedIo; + + LONGLONG StartingOffset; + LONGLONG ByteRange; + ULONG ByteCount; + ULONG ReadByteCount; + ULONG OriginalByteCount; + + PVOID SystemBuffer; + + BOOLEAN ReleaseFile = TRUE; + + CD_IO_CONTEXT LocalIoContext; + + PAGED_CODE(); + + // + // If this is a zero length read then return SUCCESS immediately. + // + + if (IrpSp->Parameters.Read.Length == 0) { + + CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); + return STATUS_SUCCESS; + } + + // + // Decode the file object and verify we support read on this. It + // must be a user file, stream file or volume file (for a data disk). + // + + TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ); + + if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_RAW_DISK ) || + (TypeOfOpen == UnopenedFileObject) || + (TypeOfOpen == UserDirectoryOpen)) { + + CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Examine our input parameters to determine if this is noncached and/or + // a paging io operation. + // + + Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); + PagingIo = FlagOn( Irp->Flags, IRP_PAGING_IO ); + NonCachedIo = FlagOn( Irp->Flags, IRP_NOCACHE ); + SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO ); + + + // + // Extract the range of the Io. + // + + StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart; + OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length; + + ByteRange = StartingOffset + ByteCount; + + // + // Make sure that Dasd access is always non-cached. + // + + if (TypeOfOpen == UserVolumeOpen) { + + NonCachedIo = TRUE; + } + + // + // Acquire the file shared to perform the read. + // + + CdAcquireFileShared( IrpContext, Fcb ); + + // + // Use a try-finally to facilitate cleanup. + // + + try { + + // + // Verify the Fcb. + // + + CdVerifyFcbOperation( IrpContext, Fcb ); + + // + // If this is a non-cached then check whether we need to post this + // request if this thread can't block. + // + + if (!Wait && NonCachedIo) { + + // + // XA requests must always be waitable. + // Also limit the number of times this thread can acquire the + // resource. + // + + if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK ) || + (ExIsResourceAcquiredShared( Fcb->Resource ) > MAX_FCB_ASYNC_ACQUIRE)) { + + SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); + try_return( Status = STATUS_CANT_WAIT ); + } + } + + // + // If this is a user request then verify the oplock and filelock state. + // + + if (TypeOfOpen == UserFileOpen) { + + // + // We check whether we can proceed + // based on the state of the file oplocks. + // + + Status = FsRtlCheckOplock( &Fcb->Oplock, + Irp, + IrpContext, + CdOplockComplete, + CdPrePostIrp ); + + // + // If the result is not STATUS_SUCCESS then the Irp was completed + // elsewhere. + // + + if (Status != STATUS_SUCCESS) { + + Irp = NULL; + IrpContext = NULL; + + try_return( NOTHING ); + } + + if (!PagingIo && + (Fcb->FileLock != NULL) && + !FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) { + + try_return( Status = STATUS_FILE_LOCK_CONFLICT ); + } + } + + // + // Complete the request if it begins beyond the end of file. + // + + if (StartingOffset >= Fcb->FileSize.QuadPart) { + + try_return( Status = STATUS_END_OF_FILE ); + } + + // + // Truncate the read if it extends beyond the end of the file. + // + + if (ByteRange > Fcb->FileSize.QuadPart) { + + ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset); + ByteRange = Fcb->FileSize.QuadPart; + } + + // + // Handle the non-cached read first. + // + + if (NonCachedIo) { + + // + // If we have an unaligned transfer then post this request if + // we can't wait. Unaligned means that the starting offset + // is not on a sector boundary or the read is not integral + // sectors. + // + + ReadByteCount = BlockAlign( Fcb->Vcb, ByteCount ); + + if (SectorOffset( StartingOffset ) || + SectorOffset( ReadByteCount ) || + (ReadByteCount > OriginalByteCount)) { + + if (!Wait) { + + CdRaiseStatus( IrpContext, STATUS_CANT_WAIT ); + } + + // + // Make sure we don't overwrite the buffer. + // + + ReadByteCount = ByteCount; + } + + // + // Initialize the IoContext for the read. + // If there is a context pointer, we need to make sure it was + // allocated and not a stale stack pointer. + // + + if (IrpContext->IoContext == NULL || + !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) { + + // + // If we can wait, use the context on the stack. Otherwise + // we need to allocate one. + // + + if (Wait) { + + IrpContext->IoContext = &LocalIoContext; + ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); + + } else { + + IrpContext->IoContext = CdAllocateIoContext(); + SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); + } + } + + RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT )); + + // + // Store whether we allocated this context structure in the structure + // itself. + // + + IrpContext->IoContext->AllocatedContext = + BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); + + if (Wait) { + + KeInitializeEvent( &IrpContext->IoContext->SyncEvent, + NotificationEvent, + FALSE ); + + } else { + + IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread(); + IrpContext->IoContext->Resource = Fcb->Resource; + IrpContext->IoContext->RequestedByteCount = ByteCount; + } + + Irp->IoStatus.Information = ReadByteCount; + + // + // Call one of the NonCacheIo routines to perform the actual + // read. + // + + if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) { + + Status = CdNonCachedXARead( IrpContext, Fcb, StartingOffset, ReadByteCount ); + + } else { + + Status = CdNonCachedRead( IrpContext, Fcb, StartingOffset, ReadByteCount ); + } + + // + // Don't complete this request now if STATUS_PENDING was returned. + // + + if (Status == STATUS_PENDING) { + + Irp = NULL; + ReleaseFile = FALSE; + + // + // Test is we should zero part of the buffer or update the + // synchronous file position. + // + + } else { + + // + // Convert any unknown error code to IO_ERROR. + // + + if (!NT_SUCCESS( Status )) { + + // + // Set the information field to zero. + // + + Irp->IoStatus.Information = 0; + + // + // Raise if this is a user induced error. + // + + if (IoIsErrorUserInduced( Status )) { + + CdRaiseStatus( IrpContext, Status ); + } + + Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR ); + + // + // Check if there is any portion of the user's buffer to zero. + // + + } else if (ReadByteCount != ByteCount) { + + SafeZeroMemory( IrpContext, + Add2Ptr( CdMapUserBuffer( IrpContext ), + ByteCount, + PVOID ), + ReadByteCount - ByteCount ); + + Irp->IoStatus.Information = ByteCount; + } + + // + // Update the file position if this is a synchronous request. + // + + if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) { + + IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange; + } + } + + try_return( NOTHING ); + } + + // + // Handle the cached case. Start by initializing the private + // cache map. + // + + if (IrpSp->FileObject->PrivateCacheMap == NULL) { + + // + // Now initialize the cache map. + // + + CcInitializeCacheMap( IrpSp->FileObject, + (PCC_FILE_SIZES) &Fcb->AllocationSize, + FALSE, + &CdData.CacheManagerCallbacks, + Fcb ); + + CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY ); + } + + // + // Read from the cache if this is not an Mdl read. + // + + if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) { + + // + // 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. + // + + SystemBuffer = CdMapUserBuffer( IrpContext ); + + // + // Now try to do the copy. + // + + if (!CcCopyRead( IrpSp->FileObject, + (PLARGE_INTEGER) &StartingOffset, + ByteCount, + Wait, + SystemBuffer, + &Irp->IoStatus )) { + + try_return( Status = STATUS_CANT_WAIT ); + } + + // + // If the call didn't succeed, raise the error status + // + + if (!NT_SUCCESS( Irp->IoStatus.Status )) { + + CdNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status ); + } + + // + // Otherwise perform the MdlRead operation. + // + + } else { + + CcMdlRead( IrpSp->FileObject, + (PLARGE_INTEGER) &StartingOffset, + ByteCount, + &Irp->MdlAddress, + &Irp->IoStatus ); + + Status = Irp->IoStatus.Status; + } + + // + // Update the current file position in the user file object. + // + + if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) { + + IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange; + } + + try_exit: NOTHING; + } finally { + + // + // Release the Fcb. + // + + if (ReleaseFile) { + + CdReleaseFile( IrpContext, Fcb ); + } + } + + // + // Post the request if we got CANT_WAIT. + // + + if (Status == STATUS_CANT_WAIT) { + + Status = CdFsdPostRequest( IrpContext, Irp ); + + // + // Otherwise complete the request. + // + + } else { + + CdCompleteRequest( IrpContext, Irp, Status ); + } + + return Status; +} + |