1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 Read.c 8 9 Abstract: 10 11 This module implements the File Read routine for Read called by the 12 Fsd/Fsp dispatch drivers. 13 14 15 --*/ 16 17 #include "cdprocs.h" 18 19 // 20 // The Bug check file id for this module 21 // 22 23 #define BugCheckFileId (CDFS_BUG_CHECK_READ) 24 25 // 26 // VOID 27 // SafeZeroMemory ( 28 // _Out_ PUCHAR At, 29 // _In_ ULONG ByteCount 30 // ); 31 // 32 33 // 34 // This macro just puts a nice little try-except around RtlZeroMemory 35 // 36 37 #ifndef __REACTOS__ 38 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \ 39 _SEH2_TRY { \ 40 RtlZeroMemory( (AT), (BYTE_COUNT) ); \ 41 __pragma(warning(suppress: 6320)) \ 42 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \ 43 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \ 44 } _SEH2_END; \ 45 } 46 #else 47 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \ 48 _SEH2_TRY { \ 49 RtlZeroMemory( (AT), (BYTE_COUNT) ); \ 50 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { \ 51 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \ 52 } _SEH2_END; \ 53 } 54 #endif 55 56 // 57 // Read ahead amount used for normal data files 58 // 59 60 #define READ_AHEAD_GRANULARITY (0x10000) 61 62 #ifdef ALLOC_PRAGMA 63 #pragma alloc_text(PAGE, CdCommonRead) 64 #endif 65 66 67 68 _Requires_lock_held_(_Global_critical_region_) 69 NTSTATUS 70 CdCommonRead ( 71 _Inout_ PIRP_CONTEXT IrpContext, 72 _Inout_ PIRP Irp 73 ) 74 75 /*++ 76 77 Routine Description: 78 79 This is the common entry point for NtReadFile calls. For synchronous requests, 80 CommonRead will complete the request in the current thread. If not 81 synchronous the request will be passed to the Fsp if there is a need to 82 block. 83 84 Arguments: 85 86 Irp - Supplies the Irp to process 87 88 Return Value: 89 90 NTSTATUS - The result of this operation. 91 92 --*/ 93 94 { 95 NTSTATUS Status = STATUS_SUCCESS; 96 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 97 98 TYPE_OF_OPEN TypeOfOpen; 99 PFCB Fcb; 100 PCCB Ccb; 101 102 BOOLEAN Wait; 103 ULONG PagingIo; 104 ULONG SynchronousIo; 105 ULONG NonCachedIo; 106 PVOID UserBuffer; 107 108 LONGLONG StartingOffset; 109 LONGLONG ByteRange; 110 ULONG ByteCount; 111 ULONG ReadByteCount; 112 ULONG OriginalByteCount; 113 114 PVOID SystemBuffer; 115 116 BOOLEAN ReleaseFile = TRUE; 117 118 CD_IO_CONTEXT LocalIoContext; 119 120 PAGED_CODE(); 121 122 // 123 // If this is a zero length read then return SUCCESS immediately. 124 // 125 126 if (IrpSp->Parameters.Read.Length == 0) { 127 128 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 129 return STATUS_SUCCESS; 130 } 131 132 // 133 // Decode the file object and verify we support read on this. It 134 // must be a user file, stream file or volume file (for a data disk). 135 // 136 137 TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ); 138 139 // Internal lock object is acquired if return status is STATUS_PENDING 140 _Analysis_suppress_lock_checking_(Fcb->Resource); 141 142 if ((TypeOfOpen == UnopenedFileObject) || 143 (TypeOfOpen == UserDirectoryOpen)) { 144 145 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); 146 return STATUS_INVALID_DEVICE_REQUEST; 147 } 148 149 // 150 // Examine our input parameters to determine if this is noncached and/or 151 // a paging io operation. 152 // 153 154 Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); 155 PagingIo = FlagOn( Irp->Flags, IRP_PAGING_IO ); 156 NonCachedIo = FlagOn( Irp->Flags, IRP_NOCACHE ); 157 SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO ); 158 159 160 // 161 // Extract the range of the Io. 162 // 163 164 StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart; 165 OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length; 166 167 ByteRange = StartingOffset + ByteCount; 168 169 // 170 // Make sure that Dasd access is always non-cached. 171 // 172 173 if (TypeOfOpen == UserVolumeOpen) { 174 175 NonCachedIo = TRUE; 176 } 177 178 // 179 // Acquire the file shared to perform the read. If we are doing paging IO, 180 // it may be the case that we would have a deadlock imminent because we may 181 // block on shared access, so starve out any exclusive waiters. This requires 182 // a degree of caution - we believe that any paging IO bursts will recede and 183 // allow the exclusive waiter in. 184 // 185 186 if (PagingIo) { 187 188 CdAcquireFileSharedStarveExclusive( IrpContext, Fcb ); 189 190 } else { 191 192 CdAcquireFileShared( IrpContext, Fcb ); 193 } 194 195 // 196 // Use a try-finally to facilitate cleanup. 197 // 198 199 _SEH2_TRY { 200 201 // 202 // Verify the Fcb. Allow reads if this is a DASD handle that is 203 // dismounting the volume. 204 // 205 206 if ((TypeOfOpen != UserVolumeOpen) || (NULL == Ccb) || 207 !FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) { 208 209 CdVerifyFcbOperation( IrpContext, Fcb ); 210 } 211 212 // 213 // If this is a non-cached then check whether we need to post this 214 // request if this thread can't block. 215 // 216 217 if (!Wait && NonCachedIo) { 218 219 // 220 // XA requests must always be waitable. 221 // 222 223 if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) { 224 225 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST ); 226 try_return( Status = STATUS_CANT_WAIT ); 227 } 228 } 229 230 // 231 // If this is a user request then verify the oplock and filelock state. 232 // 233 234 if (TypeOfOpen == UserFileOpen) { 235 236 // 237 // We check whether we can proceed 238 // based on the state of the file oplocks. 239 // 240 241 Status = FsRtlCheckOplock( CdGetFcbOplock(Fcb), 242 Irp, 243 IrpContext, 244 (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */ 245 (PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */ 246 247 // 248 // If the result is not STATUS_SUCCESS then the Irp was completed 249 // elsewhere. 250 // 251 252 if (Status != STATUS_SUCCESS) { 253 254 Irp = NULL; 255 IrpContext = NULL; 256 257 try_return( NOTHING ); 258 } 259 260 if (!PagingIo && 261 (Fcb->FileLock != NULL) && 262 !FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) { 263 264 try_return( Status = STATUS_FILE_LOCK_CONFLICT ); 265 } 266 } 267 268 // 269 // Check request beyond end of file if this is not a read on a volume 270 // handle marked for extended DASD IO. 271 // 272 273 if ((TypeOfOpen != UserVolumeOpen) || 274 (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO ))) { 275 276 // 277 // Complete the request if it begins beyond the end of file. 278 // 279 280 if (StartingOffset >= Fcb->FileSize.QuadPart) { 281 282 try_return( Status = STATUS_END_OF_FILE ); 283 } 284 285 // 286 // Truncate the read if it extends beyond the end of the file. 287 // 288 289 if (ByteRange > Fcb->FileSize.QuadPart) { 290 291 ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset); 292 ByteRange = Fcb->FileSize.QuadPart; 293 } 294 } 295 296 // 297 // Handle the non-cached read first. 298 // 299 300 if (NonCachedIo) { 301 302 // 303 // If we have an unaligned transfer then post this request if 304 // we can't wait. Unaligned means that the starting offset 305 // is not on a sector boundary or the read is not integral 306 // sectors. 307 // 308 309 ReadByteCount = BlockAlign( Fcb->Vcb, ByteCount ); 310 311 if (SectorOffset( StartingOffset ) || 312 SectorOffset( ReadByteCount ) || 313 (ReadByteCount > OriginalByteCount)) { 314 315 if (!Wait) { 316 317 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT ); 318 } 319 320 // 321 // Make sure we don't overwrite the buffer. 322 // 323 324 ReadByteCount = ByteCount; 325 } 326 327 // 328 // Initialize the IoContext for the read. 329 // If there is a context pointer, we need to make sure it was 330 // allocated and not a stale stack pointer. 331 // 332 333 if (IrpContext->IoContext == NULL || 334 !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) { 335 336 // 337 // If we can wait, use the context on the stack. Otherwise 338 // we need to allocate one. 339 // 340 341 if (Wait) { 342 343 IrpContext->IoContext = &LocalIoContext; 344 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); 345 346 } else { 347 348 IrpContext->IoContext = CdAllocateIoContext(); 349 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); 350 } 351 } 352 353 RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT )); 354 355 // 356 // Store whether we allocated this context structure in the structure 357 // itself. 358 // 359 360 IrpContext->IoContext->AllocatedContext = 361 BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); 362 363 if (Wait) { 364 365 KeInitializeEvent( &IrpContext->IoContext->SyncEvent, 366 NotificationEvent, 367 FALSE ); 368 369 } else { 370 371 IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread(); 372 IrpContext->IoContext->Resource = Fcb->Resource; 373 IrpContext->IoContext->RequestedByteCount = ByteCount; 374 } 375 376 Irp->IoStatus.Information = ReadByteCount; 377 378 // 379 // Call one of the NonCacheIo routines to perform the actual 380 // read. 381 // 382 383 if (FlagOn( Fcb->FcbState, FCB_STATE_RAWSECTOR_MASK )) { 384 385 Status = CdNonCachedXARead( IrpContext, Fcb, StartingOffset, ReadByteCount ); 386 387 } else { 388 389 Status = CdNonCachedRead( IrpContext, Fcb, StartingOffset, ReadByteCount ); 390 } 391 392 // 393 // Don't complete this request now if STATUS_PENDING was returned. 394 // 395 396 if (Status == STATUS_PENDING) { 397 398 Irp = NULL; 399 ReleaseFile = FALSE; 400 401 // 402 // Test is we should zero part of the buffer or update the 403 // synchronous file position. 404 // 405 406 } else { 407 408 // 409 // Convert any unknown error code to IO_ERROR. 410 // 411 412 if (!NT_SUCCESS( Status )) { 413 414 // 415 // Set the information field to zero. 416 // 417 418 Irp->IoStatus.Information = 0; 419 420 // 421 // Raise if this is a user induced error. 422 // 423 424 if (IoIsErrorUserInduced( Status )) { 425 426 CdRaiseStatus( IrpContext, Status ); 427 } 428 429 Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR ); 430 431 // 432 // Check if there is any portion of the user's buffer to zero. 433 // 434 435 } else if (ReadByteCount != ByteCount) { 436 437 CdMapUserBuffer( IrpContext, &UserBuffer); 438 439 SafeZeroMemory( IrpContext, 440 Add2Ptr( UserBuffer, 441 ByteCount, 442 PVOID ), 443 ReadByteCount - ByteCount ); 444 445 Irp->IoStatus.Information = ByteCount; 446 } 447 448 // 449 // Update the file position if this is a synchronous request. 450 // 451 452 if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) { 453 454 IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange; 455 } 456 } 457 458 try_return( NOTHING ); 459 } 460 461 // 462 // Handle the cached case. Start by initializing the private 463 // cache map. 464 // 465 466 if (IrpSp->FileObject->PrivateCacheMap == NULL) { 467 468 // 469 // Now initialize the cache map. 470 // 471 472 CcInitializeCacheMap( IrpSp->FileObject, 473 (PCC_FILE_SIZES) &Fcb->AllocationSize, 474 FALSE, 475 &CdData.CacheManagerCallbacks, 476 Fcb ); 477 478 CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY ); 479 } 480 481 // 482 // Read from the cache if this is not an Mdl read. 483 // 484 485 if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) { 486 487 // 488 // If we are in the Fsp now because we had to wait earlier, 489 // we must map the user buffer, otherwise we can use the 490 // user's buffer directly. 491 // 492 493 CdMapUserBuffer( IrpContext, &SystemBuffer ); 494 495 // 496 // Now try to do the copy. 497 // 498 499 if (!CcCopyRead( IrpSp->FileObject, 500 (PLARGE_INTEGER) &StartingOffset, 501 ByteCount, 502 Wait, 503 SystemBuffer, 504 &Irp->IoStatus )) { 505 506 try_return( Status = STATUS_CANT_WAIT ); 507 } 508 509 // 510 // If the call didn't succeed, raise the error status 511 // 512 513 if (!NT_SUCCESS( Irp->IoStatus.Status )) { 514 515 CdNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status ); 516 } 517 518 // 519 // Otherwise perform the MdlRead operation. 520 // 521 522 } else { 523 524 CcMdlRead( IrpSp->FileObject, 525 (PLARGE_INTEGER) &StartingOffset, 526 ByteCount, 527 &Irp->MdlAddress, 528 &Irp->IoStatus ); 529 530 Status = Irp->IoStatus.Status; 531 } 532 533 // 534 // Update the current file position in the user file object. 535 // 536 537 if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) { 538 539 IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange; 540 } 541 542 try_exit: NOTHING; 543 } _SEH2_FINALLY { 544 545 // 546 // Release the Fcb. 547 // 548 549 if (ReleaseFile) { 550 551 CdReleaseFile( IrpContext, Fcb ); 552 } 553 } _SEH2_END; 554 555 // 556 // Post the request if we got CANT_WAIT. 557 // 558 559 if (Status == STATUS_CANT_WAIT) { 560 561 Status = CdFsdPostRequest( IrpContext, Irp ); 562 563 // 564 // Otherwise complete the request. 565 // 566 567 } else { 568 569 CdCompleteRequest( IrpContext, Irp, Status ); 570 } 571 572 return Status; 573 } 574 575 576 577