1 /* 2 * PROJECT: VFAT Filesystem 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Reading and writing routines 5 * COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com> 6 * Copyright 2008-2018 Pierre Schweitzer <pierre@reactos.org> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include "vfat.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* 17 * Uncomment to enable strict verification of cluster/offset pair 18 * caching. If this option is enabled you lose all the benefits of 19 * the caching and the read/write operations will actually be 20 * slower. It's meant only for debugging!!! 21 * - Filip Navara, 26/07/2004 22 */ 23 /* #define DEBUG_VERIFY_OFFSET_CACHING */ 24 25 /* Arbitrary, taken from MS FastFAT, should be 26 * refined given what we experience in common 27 * out of stack operations 28 */ 29 #define OVERFLOW_READ_THRESHHOLD 0xE00 30 31 /* FUNCTIONS *****************************************************************/ 32 33 /* 34 * Return the next cluster in a FAT chain, possibly extending the chain if 35 * necessary 36 */ 37 NTSTATUS 38 NextCluster( 39 PDEVICE_EXTENSION DeviceExt, 40 ULONG FirstCluster, 41 PULONG CurrentCluster, 42 BOOLEAN Extend) 43 { 44 if (FirstCluster == 1) 45 { 46 (*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster; 47 return STATUS_SUCCESS; 48 } 49 else 50 { 51 if (Extend) 52 return GetNextClusterExtend(DeviceExt, (*CurrentCluster), CurrentCluster); 53 else 54 return GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster); 55 } 56 } 57 58 NTSTATUS 59 OffsetToCluster( 60 PDEVICE_EXTENSION DeviceExt, 61 ULONG FirstCluster, 62 ULONG FileOffset, 63 PULONG Cluster, 64 BOOLEAN Extend) 65 { 66 ULONG CurrentCluster; 67 ULONG i; 68 NTSTATUS Status; 69 /* 70 DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x," 71 " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt, 72 Fcb, FirstCluster, FileOffset, Cluster, Extend); 73 */ 74 if (FirstCluster == 0) 75 { 76 DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n"); 77 ASSERT(FALSE); 78 } 79 80 if (FirstCluster == 1) 81 { 82 /* root of FAT16 or FAT12 */ 83 *Cluster = DeviceExt->FatInfo.rootStart + FileOffset 84 / (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster; 85 return STATUS_SUCCESS; 86 } 87 else 88 { 89 CurrentCluster = FirstCluster; 90 if (Extend) 91 { 92 for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++) 93 { 94 Status = GetNextClusterExtend (DeviceExt, CurrentCluster, &CurrentCluster); 95 if (!NT_SUCCESS(Status)) 96 return Status; 97 } 98 *Cluster = CurrentCluster; 99 } 100 else 101 { 102 for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++) 103 { 104 Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster); 105 if (!NT_SUCCESS(Status)) 106 return Status; 107 } 108 *Cluster = CurrentCluster; 109 } 110 return STATUS_SUCCESS; 111 } 112 } 113 114 /* 115 * FUNCTION: Reads data from a file 116 */ 117 static 118 NTSTATUS 119 VfatReadFileData( 120 PVFAT_IRP_CONTEXT IrpContext, 121 ULONG Length, 122 LARGE_INTEGER ReadOffset, 123 PULONG LengthRead) 124 { 125 ULONG CurrentCluster; 126 ULONG FirstCluster; 127 ULONG StartCluster; 128 ULONG ClusterCount; 129 LARGE_INTEGER StartOffset; 130 PDEVICE_EXTENSION DeviceExt; 131 BOOLEAN First = TRUE; 132 PVFATFCB Fcb; 133 NTSTATUS Status; 134 ULONG BytesDone; 135 ULONG BytesPerSector; 136 ULONG BytesPerCluster; 137 ULONG LastCluster; 138 ULONG LastOffset; 139 140 /* PRECONDITION */ 141 ASSERT(IrpContext); 142 DeviceExt = IrpContext->DeviceExt; 143 ASSERT(DeviceExt); 144 ASSERT(DeviceExt->FatInfo.BytesPerCluster); 145 ASSERT(IrpContext->FileObject); 146 ASSERT(IrpContext->FileObject->FsContext2 != NULL); 147 148 DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, " 149 "Length %u, ReadOffset 0x%I64x)\n", DeviceExt, 150 IrpContext->FileObject, Length, ReadOffset.QuadPart); 151 152 *LengthRead = 0; 153 154 Fcb = IrpContext->FileObject->FsContext; 155 BytesPerSector = DeviceExt->FatInfo.BytesPerSector; 156 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster; 157 158 ASSERT(ReadOffset.QuadPart + Length <= ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)); 159 ASSERT(ReadOffset.u.LowPart % BytesPerSector == 0); 160 ASSERT(Length % BytesPerSector == 0); 161 162 /* Is this a read of the FAT? */ 163 if (BooleanFlagOn(Fcb->Flags, FCB_IS_FAT)) 164 { 165 ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector; 166 Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE); 167 168 if (NT_SUCCESS(Status)) 169 { 170 *LengthRead = Length; 171 } 172 else 173 { 174 DPRINT1("FAT reading failed, Status %x\n", Status); 175 } 176 return Status; 177 } 178 179 /* Is this a read of the Volume ? */ 180 if (BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME)) 181 { 182 Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE); 183 if (NT_SUCCESS(Status)) 184 { 185 *LengthRead = Length; 186 } 187 else 188 { 189 DPRINT1("Volume reading failed, Status %x\n", Status); 190 } 191 return Status; 192 } 193 194 /* Find the first cluster */ 195 FirstCluster = 196 CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry); 197 198 if (FirstCluster == 1) 199 { 200 /* Directory of FAT12/16 needs a special handling */ 201 if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector) 202 { 203 Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart; 204 } 205 ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector; 206 207 /* Fire up the read command */ 208 Status = VfatReadDiskPartial (IrpContext, &ReadOffset, Length, 0, TRUE); 209 if (NT_SUCCESS(Status)) 210 { 211 *LengthRead = Length; 212 } 213 return Status; 214 } 215 216 ExAcquireFastMutex(&Fcb->LastMutex); 217 LastCluster = Fcb->LastCluster; 218 LastOffset = Fcb->LastOffset; 219 ExReleaseFastMutex(&Fcb->LastMutex); 220 221 /* Find the cluster to start the read from */ 222 if (LastCluster > 0 && ReadOffset.u.LowPart >= LastOffset) 223 { 224 Status = OffsetToCluster(DeviceExt, LastCluster, 225 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) - 226 LastOffset, 227 &CurrentCluster, FALSE); 228 #ifdef DEBUG_VERIFY_OFFSET_CACHING 229 /* DEBUG VERIFICATION */ 230 { 231 ULONG CorrectCluster; 232 OffsetToCluster(DeviceExt, FirstCluster, 233 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster), 234 &CorrectCluster, FALSE); 235 if (CorrectCluster != CurrentCluster) 236 KeBugCheck(FAT_FILE_SYSTEM); 237 } 238 #endif 239 } 240 else 241 { 242 Status = OffsetToCluster(DeviceExt, FirstCluster, 243 ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster), 244 &CurrentCluster, FALSE); 245 } 246 247 if (!NT_SUCCESS(Status)) 248 { 249 return Status; 250 } 251 252 ExAcquireFastMutex(&Fcb->LastMutex); 253 Fcb->LastCluster = CurrentCluster; 254 Fcb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster); 255 ExReleaseFastMutex(&Fcb->LastMutex); 256 257 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); 258 IrpContext->RefCount = 1; 259 260 while (Length > 0 && CurrentCluster != 0xffffffff) 261 { 262 StartCluster = CurrentCluster; 263 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector; 264 BytesDone = 0; 265 ClusterCount = 0; 266 267 do 268 { 269 ClusterCount++; 270 if (First) 271 { 272 BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster)); 273 StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster; 274 First = FALSE; 275 } 276 else 277 { 278 if (Length - BytesDone > BytesPerCluster) 279 { 280 BytesDone += BytesPerCluster; 281 } 282 else 283 { 284 BytesDone = Length; 285 } 286 } 287 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE); 288 } 289 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone); 290 DPRINT("start %08x, next %08x, count %u\n", 291 StartCluster, CurrentCluster, ClusterCount); 292 293 ExAcquireFastMutex(&Fcb->LastMutex); 294 Fcb->LastCluster = StartCluster + (ClusterCount - 1); 295 Fcb->LastOffset = ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster; 296 ExReleaseFastMutex(&Fcb->LastMutex); 297 298 /* Fire up the read command */ 299 Status = VfatReadDiskPartial (IrpContext, &StartOffset, BytesDone, *LengthRead, FALSE); 300 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) 301 { 302 break; 303 } 304 *LengthRead += BytesDone; 305 Length -= BytesDone; 306 ReadOffset.u.LowPart += BytesDone; 307 } 308 309 if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0) 310 { 311 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); 312 } 313 314 if (NT_SUCCESS(Status) || Status == STATUS_PENDING) 315 { 316 if (Length > 0) 317 { 318 Status = STATUS_UNSUCCESSFUL; 319 } 320 else 321 { 322 Status = IrpContext->Irp->IoStatus.Status; 323 } 324 } 325 326 return Status; 327 } 328 329 static 330 NTSTATUS 331 VfatWriteFileData( 332 PVFAT_IRP_CONTEXT IrpContext, 333 ULONG Length, 334 LARGE_INTEGER WriteOffset) 335 { 336 PDEVICE_EXTENSION DeviceExt; 337 PVFATFCB Fcb; 338 ULONG Count; 339 ULONG FirstCluster; 340 ULONG CurrentCluster; 341 ULONG BytesDone; 342 ULONG StartCluster; 343 ULONG ClusterCount; 344 NTSTATUS Status = STATUS_SUCCESS; 345 BOOLEAN First = TRUE; 346 ULONG BytesPerSector; 347 ULONG BytesPerCluster; 348 LARGE_INTEGER StartOffset; 349 ULONG BufferOffset; 350 ULONG LastCluster; 351 ULONG LastOffset; 352 353 /* PRECONDITION */ 354 ASSERT(IrpContext); 355 DeviceExt = IrpContext->DeviceExt; 356 ASSERT(DeviceExt); 357 ASSERT(DeviceExt->FatInfo.BytesPerCluster); 358 ASSERT(IrpContext->FileObject); 359 ASSERT(IrpContext->FileObject->FsContext2 != NULL); 360 361 Fcb = IrpContext->FileObject->FsContext; 362 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster; 363 BytesPerSector = DeviceExt->FatInfo.BytesPerSector; 364 365 DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, " 366 "Length %u, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt, 367 IrpContext->FileObject, Length, WriteOffset.QuadPart, 368 &Fcb->PathNameU); 369 370 ASSERT(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart); 371 ASSERT(WriteOffset.u.LowPart % BytesPerSector == 0); 372 ASSERT(Length % BytesPerSector == 0); 373 374 /* Is this a write of the volume? */ 375 if (BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME)) 376 { 377 Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, TRUE); 378 if (!NT_SUCCESS(Status)) 379 { 380 DPRINT1("Volume writing failed, Status %x\n", Status); 381 } 382 return Status; 383 } 384 385 /* Is this a write to the FAT? */ 386 if (BooleanFlagOn(Fcb->Flags, FCB_IS_FAT)) 387 { 388 WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector; 389 IrpContext->RefCount = 1; 390 for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++) 391 { 392 Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, FALSE); 393 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) 394 { 395 DPRINT1("FAT writing failed, Status %x\n", Status); 396 break; 397 } 398 WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart; 399 } 400 401 if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0) 402 { 403 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); 404 } 405 406 if (NT_SUCCESS(Status) || Status == STATUS_PENDING) 407 { 408 Status = IrpContext->Irp->IoStatus.Status; 409 } 410 return Status; 411 } 412 413 /* 414 * Find the first cluster 415 */ 416 FirstCluster = 417 CurrentCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry); 418 419 if (FirstCluster == 1) 420 { 421 ASSERT(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector); 422 // Directory of FAT12/16 needs a special handling 423 WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector; 424 // Fire up the write command 425 Status = VfatWriteDiskPartial (IrpContext, &WriteOffset, Length, 0, TRUE); 426 return Status; 427 } 428 429 ExAcquireFastMutex(&Fcb->LastMutex); 430 LastCluster = Fcb->LastCluster; 431 LastOffset = Fcb->LastOffset; 432 ExReleaseFastMutex(&Fcb->LastMutex); 433 434 /* 435 * Find the cluster to start the write from 436 */ 437 if (LastCluster > 0 && WriteOffset.u.LowPart >= LastOffset) 438 { 439 Status = OffsetToCluster(DeviceExt, LastCluster, 440 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) - 441 LastOffset, 442 &CurrentCluster, FALSE); 443 #ifdef DEBUG_VERIFY_OFFSET_CACHING 444 /* DEBUG VERIFICATION */ 445 { 446 ULONG CorrectCluster; 447 OffsetToCluster(DeviceExt, FirstCluster, 448 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster), 449 &CorrectCluster, FALSE); 450 if (CorrectCluster != CurrentCluster) 451 KeBugCheck(FAT_FILE_SYSTEM); 452 } 453 #endif 454 } 455 else 456 { 457 Status = OffsetToCluster(DeviceExt, FirstCluster, 458 ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster), 459 &CurrentCluster, FALSE); 460 } 461 462 if (!NT_SUCCESS(Status)) 463 { 464 return Status; 465 } 466 467 ExAcquireFastMutex(&Fcb->LastMutex); 468 Fcb->LastCluster = CurrentCluster; 469 Fcb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster); 470 ExReleaseFastMutex(&Fcb->LastMutex); 471 472 IrpContext->RefCount = 1; 473 BufferOffset = 0; 474 475 while (Length > 0 && CurrentCluster != 0xffffffff) 476 { 477 StartCluster = CurrentCluster; 478 StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector; 479 BytesDone = 0; 480 ClusterCount = 0; 481 482 do 483 { 484 ClusterCount++; 485 if (First) 486 { 487 BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster)); 488 StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster; 489 First = FALSE; 490 } 491 else 492 { 493 if (Length - BytesDone > BytesPerCluster) 494 { 495 BytesDone += BytesPerCluster; 496 } 497 else 498 { 499 BytesDone = Length; 500 } 501 } 502 Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE); 503 } 504 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone); 505 DPRINT("start %08x, next %08x, count %u\n", 506 StartCluster, CurrentCluster, ClusterCount); 507 508 ExAcquireFastMutex(&Fcb->LastMutex); 509 Fcb->LastCluster = StartCluster + (ClusterCount - 1); 510 Fcb->LastOffset = ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster; 511 ExReleaseFastMutex(&Fcb->LastMutex); 512 513 // Fire up the write command 514 Status = VfatWriteDiskPartial (IrpContext, &StartOffset, BytesDone, BufferOffset, FALSE); 515 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) 516 { 517 break; 518 } 519 BufferOffset += BytesDone; 520 Length -= BytesDone; 521 WriteOffset.u.LowPart += BytesDone; 522 } 523 524 if (InterlockedDecrement((PLONG)&IrpContext->RefCount) != 0) 525 { 526 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); 527 } 528 529 if (NT_SUCCESS(Status) || Status == STATUS_PENDING) 530 { 531 if (Length > 0) 532 { 533 Status = STATUS_UNSUCCESSFUL; 534 } 535 else 536 { 537 Status = IrpContext->Irp->IoStatus.Status; 538 } 539 } 540 541 return Status; 542 } 543 544 NTSTATUS 545 VfatCommonRead( 546 PVFAT_IRP_CONTEXT IrpContext) 547 { 548 PVFATFCB Fcb; 549 PVOID Buffer; 550 NTSTATUS Status; 551 ULONG Length = 0; 552 ULONG BytesPerSector; 553 LARGE_INTEGER ByteOffset; 554 ULONG ReturnedLength = 0; 555 BOOLEAN PagingIo, CanWait, IsVolume, NoCache; 556 557 PagingIo = BooleanFlagOn(IrpContext->Irp->Flags, IRP_PAGING_IO); 558 CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT); 559 NoCache = BooleanFlagOn(IrpContext->Irp->Flags, IRP_NOCACHE); 560 Fcb = IrpContext->FileObject->FsContext; 561 IsVolume = BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME); 562 563 ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset; 564 Length = IrpContext->Stack->Parameters.Read.Length; 565 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; 566 567 if (!PagingIo && 568 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) 569 { 570 if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp)) 571 { 572 return STATUS_FILE_LOCK_CONFLICT; 573 } 574 } 575 576 Buffer = VfatGetUserBuffer(IrpContext->Irp, PagingIo); 577 578 if (!PagingIo && !NoCache && !IsVolume) 579 { 580 // cached read 581 Status = STATUS_SUCCESS; 582 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) 583 { 584 Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart; 585 Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS; 586 } 587 588 vfatAddToStat(IrpContext->DeviceExt, Base.UserFileReads, 1); 589 vfatAddToStat(IrpContext->DeviceExt, Base.UserFileReadBytes, Length); 590 591 _SEH2_TRY 592 { 593 if (IrpContext->FileObject->PrivateCacheMap == NULL) 594 { 595 CcInitializeCacheMap(IrpContext->FileObject, 596 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), 597 FALSE, 598 &(VfatGlobalData->CacheMgrCallbacks), 599 Fcb); 600 } 601 602 if (!CcCopyRead(IrpContext->FileObject, 603 &ByteOffset, 604 Length, 605 CanWait, 606 Buffer, 607 &IrpContext->Irp->IoStatus)) 608 { 609 ASSERT(!CanWait); 610 Status = STATUS_PENDING; 611 goto ByeBye; 612 } 613 } 614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 615 { 616 Status = _SEH2_GetExceptionCode(); 617 goto ByeBye; 618 } 619 _SEH2_END; 620 621 if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status)) 622 { 623 Status = IrpContext->Irp->IoStatus.Status; 624 } 625 } 626 else 627 { 628 // non cached read 629 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); 630 if (!NT_SUCCESS(Status)) 631 { 632 goto ByeBye; 633 } 634 635 if (ByteOffset.QuadPart + Length > ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)) 636 { 637 Length = (ULONG)(ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart); 638 } 639 640 if (!IsVolume) 641 { 642 vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedReads, 1); 643 vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedReadBytes, Length); 644 } 645 else 646 { 647 vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataReads, 1); 648 vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataReadBytes, Length); 649 } 650 651 Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength); 652 if (NT_SUCCESS(Status)) 653 { 654 IrpContext->Irp->IoStatus.Information = ReturnedLength; 655 } 656 } 657 658 ByeBye: 659 return Status; 660 } 661 662 VOID 663 NTAPI 664 VfatStackOverflowRead( 665 PVOID Context, 666 IN PKEVENT Event) 667 { 668 PVFAT_IRP_CONTEXT IrpContext; 669 670 IrpContext = Context; 671 /* In a separate thread, we can wait and resources got locked */ 672 SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT); 673 674 /* Perform the read operation */ 675 DPRINT1("Performing posted read\n"); 676 VfatCommonRead(IrpContext); 677 678 KeSetEvent(Event, 0, FALSE); 679 } 680 681 VOID 682 VfatPostRead( 683 PVFAT_IRP_CONTEXT IrpContext, 684 PERESOURCE Lock, 685 BOOLEAN PagingIo) 686 { 687 KEVENT Event; 688 689 KeInitializeEvent(&Event, NotificationEvent, FALSE); 690 691 ExAcquireResourceSharedLite(Lock, TRUE); 692 693 /* If paging IO, call the non failing but blocking routine */ 694 if (PagingIo) 695 { 696 FsRtlPostPagingFileStackOverflow(IrpContext, &Event, VfatStackOverflowRead); 697 } 698 else 699 { 700 FsRtlPostStackOverflow(IrpContext, &Event, VfatStackOverflowRead); 701 } 702 703 /* Wait till it's done */ 704 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 705 } 706 707 NTSTATUS 708 VfatRead( 709 PVFAT_IRP_CONTEXT IrpContext) 710 { 711 NTSTATUS Status; 712 PVFATFCB Fcb; 713 ULONG Length = 0; 714 PERESOURCE Resource = NULL; 715 LARGE_INTEGER ByteOffset; 716 ULONG BytesPerSector; 717 BOOLEAN PagingIo, CanWait, IsVolume, NoCache; 718 719 ASSERT(IrpContext); 720 721 DPRINT("VfatRead(IrpContext %p)\n", IrpContext); 722 723 ASSERT(IrpContext->DeviceObject); 724 725 PagingIo = BooleanFlagOn(IrpContext->Irp->Flags, IRP_PAGING_IO); 726 CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT); 727 NoCache = BooleanFlagOn(IrpContext->Irp->Flags, IRP_NOCACHE); 728 729 // This request is not allowed on the main device object 730 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) 731 { 732 DPRINT("VfatRead is called with the main device object.\n"); 733 Status = STATUS_INVALID_DEVICE_REQUEST; 734 goto ByeBye; 735 } 736 737 ASSERT(IrpContext->DeviceExt); 738 ASSERT(IrpContext->FileObject); 739 Fcb = IrpContext->FileObject->FsContext; 740 ASSERT(Fcb); 741 742 IsVolume = BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME); 743 744 if (BooleanFlagOn(Fcb->Flags, FCB_IS_PAGE_FILE)) 745 { 746 PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; 747 IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; 748 IoSkipCurrentIrpStackLocation(IrpContext->Irp); 749 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE; 750 DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart); 751 Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); 752 return Status; 753 } 754 755 DPRINT("<%wZ>\n", &Fcb->PathNameU); 756 757 ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset; 758 Length = IrpContext->Stack->Parameters.Read.Length; 759 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; 760 761 /* fail if file is a directory and no paged read */ 762 if (vfatFCBIsDirectory(Fcb) && !PagingIo) 763 { 764 Status = STATUS_INVALID_PARAMETER; 765 goto ByeBye; 766 } 767 768 DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length); 769 770 if (ByteOffset.u.HighPart && !IsVolume) 771 { 772 Status = STATUS_INVALID_PARAMETER; 773 goto ByeBye; 774 } 775 776 if (Length == 0) 777 { 778 IrpContext->Irp->IoStatus.Information = 0; 779 Status = STATUS_SUCCESS; 780 goto ByeBye; 781 } 782 783 if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart) 784 { 785 IrpContext->Irp->IoStatus.Information = 0; 786 Status = STATUS_END_OF_FILE; 787 goto ByeBye; 788 } 789 790 if (NoCache || PagingIo || IsVolume) 791 { 792 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) 793 { 794 DPRINT("%u %u\n", ByteOffset.u.LowPart, Length); 795 // non cached read must be sector aligned 796 Status = STATUS_INVALID_PARAMETER; 797 goto ByeBye; 798 } 799 } 800 801 if (IsVolume) 802 { 803 Resource = &IrpContext->DeviceExt->DirResource; 804 } 805 else if (PagingIo) 806 { 807 Resource = &Fcb->PagingIoResource; 808 } 809 else 810 { 811 Resource = &Fcb->MainResource; 812 } 813 814 /* Are we out of stack for the rest of the operation? */ 815 if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) 816 { 817 /* Lock the buffer */ 818 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); 819 if (!NT_SUCCESS(Status)) 820 { 821 return Status; 822 } 823 824 /* And post the read to the overflow thread */ 825 VfatPostRead(IrpContext, Resource, PagingIo); 826 827 /* Return the appropriate status */ 828 return IrpContext->Irp->IoStatus.Status; 829 } 830 831 if (!ExAcquireResourceSharedLite(Resource, CanWait)) 832 { 833 Resource = NULL; 834 Status = STATUS_PENDING; 835 goto ByeBye; 836 } 837 838 Status = VfatCommonRead(IrpContext); 839 840 ByeBye: 841 if (Resource) 842 { 843 ExReleaseResourceLite(Resource); 844 } 845 846 if (Status == STATUS_PENDING) 847 { 848 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); 849 if (NT_SUCCESS(Status)) 850 { 851 Status = VfatMarkIrpContextForQueue(IrpContext); 852 } 853 } 854 else 855 { 856 IrpContext->Irp->IoStatus.Status = Status; 857 if (BooleanFlagOn(IrpContext->FileObject->Flags, FO_SYNCHRONOUS_IO) && 858 !PagingIo && 859 (NT_SUCCESS(Status) || Status == STATUS_END_OF_FILE)) 860 { 861 IrpContext->FileObject->CurrentByteOffset.QuadPart = 862 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; 863 } 864 865 if (NT_SUCCESS(Status)) 866 IrpContext->PriorityBoost = IO_DISK_INCREMENT; 867 } 868 DPRINT("%x\n", Status); 869 return Status; 870 } 871 872 NTSTATUS 873 VfatWrite( 874 PVFAT_IRP_CONTEXT *pIrpContext) 875 { 876 PVFAT_IRP_CONTEXT IrpContext = *pIrpContext; 877 PVFATFCB Fcb; 878 PERESOURCE Resource = NULL; 879 LARGE_INTEGER ByteOffset; 880 LARGE_INTEGER OldFileSize; 881 NTSTATUS Status = STATUS_SUCCESS; 882 ULONG Length = 0; 883 PVOID Buffer; 884 ULONG BytesPerSector; 885 BOOLEAN PagingIo, CanWait, IsVolume, IsFAT, NoCache; 886 887 ASSERT(IrpContext); 888 889 DPRINT("VfatWrite(IrpContext %p)\n", IrpContext); 890 891 ASSERT(IrpContext->DeviceObject); 892 893 PagingIo = BooleanFlagOn(IrpContext->Irp->Flags, IRP_PAGING_IO); 894 CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT); 895 NoCache = BooleanFlagOn(IrpContext->Irp->Flags, IRP_NOCACHE); 896 897 // This request is not allowed on the main device object 898 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) 899 { 900 DPRINT("VfatWrite is called with the main device object.\n"); 901 Status = STATUS_INVALID_DEVICE_REQUEST; 902 goto ByeBye; 903 } 904 905 ASSERT(IrpContext->DeviceExt); 906 ASSERT(IrpContext->FileObject); 907 Fcb = IrpContext->FileObject->FsContext; 908 ASSERT(Fcb); 909 910 IsVolume = BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME); 911 IsFAT = BooleanFlagOn(Fcb->Flags, FCB_IS_FAT); 912 913 if (BooleanFlagOn(Fcb->Flags, FCB_IS_PAGE_FILE)) 914 { 915 PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; 916 IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; 917 IoSkipCurrentIrpStackLocation(IrpContext->Irp); 918 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE; 919 DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart); 920 Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); 921 return Status; 922 } 923 924 DPRINT("<%wZ>\n", &Fcb->PathNameU); 925 926 /* fail if file is a directory and no paged read */ 927 if (vfatFCBIsDirectory(Fcb) && !PagingIo) 928 { 929 Status = STATUS_INVALID_PARAMETER; 930 goto ByeBye; 931 } 932 933 ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset; 934 if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE && 935 ByteOffset.u.HighPart == -1) 936 { 937 ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart; 938 } 939 Length = IrpContext->Stack->Parameters.Write.Length; 940 BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; 941 942 if (ByteOffset.u.HighPart && !IsVolume) 943 { 944 Status = STATUS_INVALID_PARAMETER; 945 goto ByeBye; 946 } 947 948 if (IsFAT || IsVolume || 949 vfatDirEntryGetFirstCluster(IrpContext->DeviceExt, &Fcb->entry) == 1) 950 { 951 if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart) 952 { 953 // we can't extend the FAT, the volume or the root on FAT12/FAT16 954 Status = STATUS_END_OF_FILE; 955 goto ByeBye; 956 } 957 } 958 959 if (PagingIo || NoCache || IsVolume) 960 { 961 if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) 962 { 963 // non cached write must be sector aligned 964 Status = STATUS_INVALID_PARAMETER; 965 goto ByeBye; 966 } 967 } 968 969 OldFileSize = Fcb->RFCB.FileSize; 970 971 if (Length == 0) 972 { 973 /* Update last write time */ 974 IrpContext->Irp->IoStatus.Information = 0; 975 Status = STATUS_SUCCESS; 976 goto Metadata; 977 } 978 979 if (PagingIo) 980 { 981 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) 982 { 983 Status = STATUS_INVALID_PARAMETER; 984 goto ByeBye; 985 } 986 987 if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector)) 988 { 989 Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart; 990 } 991 } 992 993 if (!NoCache && !CcCanIWrite(IrpContext->FileObject, Length, CanWait, 994 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_DEFERRED_WRITE))) 995 { 996 BOOLEAN Retrying; 997 998 Retrying = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_DEFERRED_WRITE); 999 SetFlag(IrpContext->Flags, IRPCONTEXT_DEFERRED_WRITE); 1000 1001 IoMarkIrpPending(IrpContext->Irp); 1002 Status = STATUS_PENDING; 1003 1004 DPRINT1("Deferring write for Irp %p, context %p!\n", IrpContext->Irp, IrpContext); 1005 CcDeferWrite(IrpContext->FileObject, VfatHandleDeferredWrite, 1006 IrpContext, NULL, Length, Retrying); 1007 *pIrpContext = NULL; 1008 1009 return Status; 1010 } 1011 1012 if (IsVolume) 1013 { 1014 Resource = &IrpContext->DeviceExt->DirResource; 1015 } 1016 else if (PagingIo) 1017 { 1018 Resource = &Fcb->PagingIoResource; 1019 } 1020 else 1021 { 1022 Resource = &Fcb->MainResource; 1023 } 1024 1025 if (PagingIo) 1026 { 1027 if (!ExAcquireResourceSharedLite(Resource, CanWait)) 1028 { 1029 Resource = NULL; 1030 Status = STATUS_PENDING; 1031 goto ByeBye; 1032 } 1033 } 1034 else 1035 { 1036 if (!ExAcquireResourceExclusiveLite(Resource, CanWait)) 1037 { 1038 Resource = NULL; 1039 Status = STATUS_PENDING; 1040 goto ByeBye; 1041 } 1042 } 1043 1044 if (!PagingIo && 1045 FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) 1046 { 1047 if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp)) 1048 { 1049 Status = STATUS_FILE_LOCK_CONFLICT; 1050 goto ByeBye; 1051 } 1052 } 1053 1054 if (!CanWait && !IsVolume) 1055 { 1056 if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) 1057 { 1058 Status = STATUS_PENDING; 1059 goto ByeBye; 1060 } 1061 } 1062 1063 Buffer = VfatGetUserBuffer(IrpContext->Irp, PagingIo); 1064 1065 if (!IsFAT && !IsVolume && !PagingIo && 1066 ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) 1067 { 1068 LARGE_INTEGER AllocationSize; 1069 1070 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, CanWait)) 1071 { 1072 Status = STATUS_PENDING; 1073 goto ByeBye; 1074 } 1075 1076 AllocationSize.QuadPart = ByteOffset.u.LowPart + Length; 1077 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb, 1078 IrpContext->DeviceExt, &AllocationSize); 1079 1080 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 1081 1082 if (!NT_SUCCESS (Status)) 1083 { 1084 goto ByeBye; 1085 } 1086 } 1087 1088 if (!NoCache && !PagingIo && !IsVolume) 1089 { 1090 // cached write 1091 1092 vfatAddToStat(IrpContext->DeviceExt, Base.UserFileWrites, 1); 1093 vfatAddToStat(IrpContext->DeviceExt, Base.UserFileWriteBytes, Length); 1094 1095 _SEH2_TRY 1096 { 1097 if (IrpContext->FileObject->PrivateCacheMap == NULL) 1098 { 1099 CcInitializeCacheMap(IrpContext->FileObject, 1100 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), 1101 FALSE, 1102 &VfatGlobalData->CacheMgrCallbacks, 1103 Fcb); 1104 } 1105 1106 if (ByteOffset.QuadPart > OldFileSize.QuadPart) 1107 { 1108 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); 1109 } 1110 1111 if (CcCopyWrite(IrpContext->FileObject, 1112 &ByteOffset, 1113 Length, 1114 TRUE /*CanWait*/, 1115 Buffer)) 1116 { 1117 IrpContext->Irp->IoStatus.Information = Length; 1118 Status = STATUS_SUCCESS; 1119 } 1120 else 1121 { 1122 ASSERT(FALSE /*!CanWait*/); 1123 Status = STATUS_UNSUCCESSFUL; 1124 } 1125 } 1126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1127 { 1128 Status = _SEH2_GetExceptionCode(); 1129 } 1130 _SEH2_END; 1131 } 1132 else 1133 { 1134 // non cached write 1135 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); 1136 if (!NT_SUCCESS(Status)) 1137 { 1138 Status = STATUS_INVALID_USER_BUFFER; 1139 goto ByeBye; 1140 } 1141 1142 if (ByteOffset.QuadPart > OldFileSize.QuadPart) 1143 { 1144 CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); 1145 } 1146 1147 if (!IsVolume) 1148 { 1149 vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedWrites, 1); 1150 vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedWriteBytes, Length); 1151 } 1152 else 1153 { 1154 vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataWrites, 1); 1155 vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataWriteBytes, Length); 1156 } 1157 1158 Status = VfatWriteFileData(IrpContext, Length, ByteOffset); 1159 if (NT_SUCCESS(Status)) 1160 { 1161 IrpContext->Irp->IoStatus.Information = Length; 1162 } 1163 } 1164 1165 Metadata: 1166 if (!PagingIo && !IsFAT && !IsVolume) 1167 { 1168 if(!vfatFCBIsDirectory(Fcb)) 1169 { 1170 LARGE_INTEGER SystemTime; 1171 ULONG Filter; 1172 1173 // set dates and times 1174 KeQuerySystemTime (&SystemTime); 1175 if (vfatVolumeIsFatX(IrpContext->DeviceExt)) 1176 { 1177 FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, 1178 &SystemTime, &Fcb->entry.FatX.UpdateDate, 1179 &Fcb->entry.FatX.UpdateTime); 1180 Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate; 1181 Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime; 1182 } 1183 else 1184 { 1185 FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, 1186 &SystemTime, &Fcb->entry.Fat.UpdateDate, 1187 &Fcb->entry.Fat.UpdateTime); 1188 Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate; 1189 } 1190 /* set date and times to dirty */ 1191 Fcb->Flags |= FCB_IS_DIRTY; 1192 1193 /* Time to notify the OS */ 1194 Filter = FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES; 1195 if (ByteOffset.QuadPart != OldFileSize.QuadPart) Filter |= FILE_NOTIFY_CHANGE_SIZE; 1196 1197 vfatReportChange(IrpContext->DeviceExt, Fcb, Filter, FILE_ACTION_MODIFIED); 1198 } 1199 } 1200 1201 ByeBye: 1202 if (Resource) 1203 { 1204 ExReleaseResourceLite(Resource); 1205 } 1206 1207 if (Status == STATUS_PENDING) 1208 { 1209 Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); 1210 if (NT_SUCCESS(Status)) 1211 { 1212 Status = VfatMarkIrpContextForQueue(IrpContext); 1213 } 1214 } 1215 else 1216 { 1217 IrpContext->Irp->IoStatus.Status = Status; 1218 if (BooleanFlagOn(IrpContext->FileObject->Flags, FO_SYNCHRONOUS_IO) && 1219 !PagingIo && NT_SUCCESS(Status)) 1220 { 1221 IrpContext->FileObject->CurrentByteOffset.QuadPart = 1222 ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; 1223 } 1224 1225 if (NT_SUCCESS(Status)) 1226 IrpContext->PriorityBoost = IO_DISK_INCREMENT; 1227 } 1228 DPRINT("%x\n", Status); 1229 return Status; 1230 } 1231