1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/iomgr/iofunc.c 5 * PURPOSE: Generic I/O Functions that build IRPs for various operations 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Gunnar Dalsnes 8 * Filip Navara (navaraf@reactos.org) 9 * Pierre Schweitzer (pierre@reactos.org) 10 */ 11 12 /* INCLUDES *****************************************************************/ 13 14 #include <ntoskrnl.h> 15 #include <ioevent.h> 16 #define NDEBUG 17 #include <debug.h> 18 #include "internal/io_i.h" 19 20 volatile LONG IoPageReadIrpAllocationFailure = 0; 21 volatile LONG IoPageReadNonPagefileIrpAllocationFailure = 0; 22 23 /* PRIVATE FUNCTIONS *********************************************************/ 24 25 VOID 26 NTAPI 27 IopCleanupAfterException(IN PFILE_OBJECT FileObject, 28 IN PIRP Irp OPTIONAL, 29 IN PKEVENT Event OPTIONAL, 30 IN PKEVENT LocalEvent OPTIONAL) 31 { 32 PAGED_CODE(); 33 IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject); 34 35 if (Irp) 36 { 37 /* Check if we had a buffer */ 38 if (Irp->AssociatedIrp.SystemBuffer) 39 { 40 /* Free it */ 41 ExFreePool(Irp->AssociatedIrp.SystemBuffer); 42 } 43 44 /* Free the mdl */ 45 if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress); 46 47 /* Free the IRP */ 48 IoFreeIrp(Irp); 49 } 50 51 /* Check if we had a file lock */ 52 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 53 { 54 /* Release it */ 55 IopUnlockFileObject(FileObject); 56 } 57 58 /* Check if we had an event */ 59 if (Event) ObDereferenceObject(Event); 60 61 /* Check if we had a local event */ 62 if (LocalEvent) ExFreePool(LocalEvent); 63 64 /* Derefenrce the FO */ 65 ObDereferenceObject(FileObject); 66 } 67 68 NTSTATUS 69 NTAPI 70 IopFinalizeAsynchronousIo(IN NTSTATUS SynchStatus, 71 IN PKEVENT Event, 72 IN PIRP Irp, 73 IN KPROCESSOR_MODE PreviousMode, 74 IN PIO_STATUS_BLOCK KernelIosb, 75 OUT PIO_STATUS_BLOCK IoStatusBlock) 76 { 77 NTSTATUS FinalStatus = SynchStatus; 78 PAGED_CODE(); 79 IOTRACE(IO_API_DEBUG, "IRP: %p. Status: %lx \n", Irp, SynchStatus); 80 81 /* Make sure the IRP was completed, but returned pending */ 82 if (FinalStatus == STATUS_PENDING) 83 { 84 /* Wait for the IRP */ 85 FinalStatus = KeWaitForSingleObject(Event, 86 Executive, 87 PreviousMode, 88 FALSE, 89 NULL); 90 if (FinalStatus == STATUS_USER_APC) 91 { 92 /* Abort the request */ 93 IopAbortInterruptedIrp(Event, Irp); 94 } 95 96 /* Set the final status */ 97 FinalStatus = KernelIosb->Status; 98 } 99 100 /* Wrap potential user-mode write in SEH */ 101 _SEH2_TRY 102 { 103 *IoStatusBlock = *KernelIosb; 104 } 105 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 106 { 107 /* Get the exception code */ 108 FinalStatus = _SEH2_GetExceptionCode(); 109 } 110 _SEH2_END; 111 112 /* Free the event and return status */ 113 ExFreePool(Event); 114 return FinalStatus; 115 } 116 117 NTSTATUS 118 NTAPI 119 IopPerformSynchronousRequest(IN PDEVICE_OBJECT DeviceObject, 120 IN PIRP Irp, 121 IN PFILE_OBJECT FileObject, 122 IN BOOLEAN Deferred, 123 IN KPROCESSOR_MODE PreviousMode, 124 IN BOOLEAN SynchIo, 125 IN IOP_TRANSFER_TYPE TransferType) 126 { 127 NTSTATUS Status; 128 PKNORMAL_ROUTINE NormalRoutine; 129 PVOID NormalContext = NULL; 130 KIRQL OldIrql; 131 PAGED_CODE(); 132 IOTRACE(IO_API_DEBUG, "IRP: %p. DO: %p. FO: %p \n", 133 Irp, DeviceObject, FileObject); 134 135 /* Queue the IRP */ 136 IopQueueIrpToThread(Irp); 137 138 /* Update operation counts */ 139 IopUpdateOperationCount(TransferType); 140 141 /* Call the driver */ 142 Status = IoCallDriver(DeviceObject, Irp); 143 144 /* Check if we're optimizing this case */ 145 if (Deferred) 146 { 147 /* We are! Check if the IRP wasn't completed */ 148 if (Status != STATUS_PENDING) 149 { 150 /* Complete it ourselves */ 151 ASSERT(!Irp->PendingReturned); 152 KeRaiseIrql(APC_LEVEL, &OldIrql); 153 IopCompleteRequest(&Irp->Tail.Apc, 154 &NormalRoutine, 155 &NormalContext, 156 (PVOID*)&FileObject, 157 &NormalContext); 158 KeLowerIrql(OldIrql); 159 } 160 } 161 162 /* Check if this was synch I/O */ 163 if (SynchIo) 164 { 165 /* Make sure the IRP was completed, but returned pending */ 166 if (Status == STATUS_PENDING) 167 { 168 /* Wait for the IRP */ 169 Status = KeWaitForSingleObject(&FileObject->Event, 170 Executive, 171 PreviousMode, 172 (FileObject->Flags & 173 FO_ALERTABLE_IO) != 0, 174 NULL); 175 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC)) 176 { 177 /* Abort the request */ 178 IopAbortInterruptedIrp(&FileObject->Event, Irp); 179 } 180 181 /* Set the final status */ 182 Status = FileObject->FinalStatus; 183 } 184 185 /* Release the file lock */ 186 IopUnlockFileObject(FileObject); 187 } 188 189 /* Return status */ 190 return Status; 191 } 192 193 NTSTATUS 194 NTAPI 195 IopDeviceFsIoControl(IN HANDLE DeviceHandle, 196 IN HANDLE Event OPTIONAL, 197 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 198 IN PVOID UserApcContext OPTIONAL, 199 OUT PIO_STATUS_BLOCK IoStatusBlock, 200 IN ULONG IoControlCode, 201 IN PVOID InputBuffer, 202 IN ULONG InputBufferLength OPTIONAL, 203 OUT PVOID OutputBuffer, 204 IN ULONG OutputBufferLength OPTIONAL, 205 IN BOOLEAN IsDevIoCtl) 206 { 207 NTSTATUS Status; 208 PFILE_OBJECT FileObject; 209 PDEVICE_OBJECT DeviceObject; 210 PIRP Irp; 211 PIO_STACK_LOCATION StackPtr; 212 PKEVENT EventObject = NULL; 213 BOOLEAN LockedForSynch = FALSE; 214 ULONG AccessType; 215 OBJECT_HANDLE_INFORMATION HandleInformation; 216 ACCESS_MASK DesiredAccess; 217 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 218 ULONG BufferLength; 219 POOL_TYPE PoolType; 220 221 PAGED_CODE(); 222 223 IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n", 224 DeviceHandle, IoControlCode, IsDevIoCtl); 225 226 /* Get the access type */ 227 AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode); 228 229 /* Check if we came from user mode */ 230 if (PreviousMode != KernelMode) 231 { 232 _SEH2_TRY 233 { 234 /* Probe the status block */ 235 ProbeForWriteIoStatusBlock(IoStatusBlock); 236 237 /* Check if this is buffered I/O */ 238 if (AccessType == METHOD_BUFFERED) 239 { 240 /* Check if we have an output buffer */ 241 if (OutputBuffer) 242 { 243 /* Probe the output buffer */ 244 ProbeForWrite(OutputBuffer, 245 OutputBufferLength, 246 sizeof(CHAR)); 247 } 248 else 249 { 250 /* Make sure the caller can't fake this as we depend on this */ 251 OutputBufferLength = 0; 252 } 253 } 254 255 /* Check if we we have an input buffer I/O */ 256 if (AccessType != METHOD_NEITHER) 257 { 258 /* Check if we have an input buffer */ 259 if (InputBuffer) 260 { 261 /* Probe the input buffer */ 262 ProbeForRead(InputBuffer, InputBufferLength, sizeof(CHAR)); 263 } 264 else 265 { 266 /* Make sure the caller can't fake this as we depend on this */ 267 InputBufferLength = 0; 268 } 269 } 270 } 271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 272 { 273 /* Return the exception code */ 274 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 275 } 276 _SEH2_END; 277 } 278 279 /* Don't check for access rights right now, KernelMode can do anything */ 280 Status = ObReferenceObjectByHandle(DeviceHandle, 281 0, 282 IoFileObjectType, 283 PreviousMode, 284 (PVOID*)&FileObject, 285 &HandleInformation); 286 if (!NT_SUCCESS(Status)) return Status; 287 288 /* Can't use an I/O completion port and an APC in the same time */ 289 if ((FileObject->CompletionContext) && (UserApcRoutine)) 290 { 291 /* Fail */ 292 ObDereferenceObject(FileObject); 293 return STATUS_INVALID_PARAMETER; 294 } 295 296 /* Check if we from user mode */ 297 if (PreviousMode != KernelMode) 298 { 299 /* Get the access mask */ 300 DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3); 301 302 /* Check if we can open it */ 303 if ((DesiredAccess != FILE_ANY_ACCESS) && 304 (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess) 305 { 306 /* Dereference the file object and fail */ 307 ObDereferenceObject(FileObject); 308 return STATUS_ACCESS_DENIED; 309 } 310 } 311 312 /* Check for an event */ 313 if (Event) 314 { 315 /* Reference it */ 316 Status = ObReferenceObjectByHandle(Event, 317 EVENT_MODIFY_STATE, 318 ExEventObjectType, 319 PreviousMode, 320 (PVOID*)&EventObject, 321 NULL); 322 if (!NT_SUCCESS(Status)) 323 { 324 /* Dereference the file object and fail */ 325 ObDereferenceObject(FileObject); 326 return Status; 327 } 328 329 /* Clear it */ 330 KeClearEvent(EventObject); 331 } 332 333 /* Check if this is a file that was opened for Synch I/O */ 334 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 335 { 336 /* Lock it */ 337 IopLockFileObject(FileObject); 338 339 /* Remember to unlock later */ 340 LockedForSynch = TRUE; 341 } 342 343 /* Check if this is a direct open or not */ 344 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 345 { 346 /* It's a direct open, get the attached device */ 347 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 348 } 349 else 350 { 351 /* Otherwise get the related device */ 352 DeviceObject = IoGetRelatedDeviceObject(FileObject); 353 } 354 355 /* If this is a device I/O, try to do it with FastIO path */ 356 if (IsDevIoCtl) 357 { 358 PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 359 360 /* Check whether FSD is FastIO aware and provide an appropriate routine */ 361 if (FastIoDispatch != NULL && FastIoDispatch->FastIoDeviceControl != NULL) 362 { 363 IO_STATUS_BLOCK KernelIosb; 364 365 /* If we have an output buffer coming from usermode */ 366 if (PreviousMode != KernelMode && OutputBuffer != NULL) 367 { 368 /* Probe it according to its usage */ 369 _SEH2_TRY 370 { 371 if (AccessType == METHOD_IN_DIRECT) 372 { 373 ProbeForRead(OutputBuffer, OutputBufferLength, sizeof(CHAR)); 374 } 375 else if (AccessType == METHOD_OUT_DIRECT) 376 { 377 ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(CHAR)); 378 } 379 } 380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 381 { 382 /* Cleanup after exception and return */ 383 IopCleanupAfterException(FileObject, NULL, EventObject, NULL); 384 385 /* Return the exception code */ 386 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 387 } 388 _SEH2_END; 389 } 390 391 /* If we are dismounting a volume, increase the dismount count */ 392 if (IoControlCode == FSCTL_DISMOUNT_VOLUME) 393 { 394 InterlockedIncrement((PLONG)&SharedUserData->DismountCount); 395 } 396 397 /* Call the FSD */ 398 if (FastIoDispatch->FastIoDeviceControl(FileObject, 399 TRUE, 400 InputBuffer, 401 InputBufferLength, 402 OutputBuffer, 403 OutputBufferLength, 404 IoControlCode, 405 &KernelIosb, 406 DeviceObject)) 407 { 408 IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL }; 409 410 /* Write the IOSB back */ 411 _SEH2_TRY 412 { 413 *IoStatusBlock = KernelIosb; 414 415 } 416 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 417 { 418 KernelIosb.Status = _SEH2_GetExceptionCode(); 419 } 420 _SEH2_END; 421 422 /* Backup our complete context in case it exists */ 423 if (FileObject->CompletionContext) 424 { 425 CompletionInfo = *(FileObject->CompletionContext); 426 } 427 428 /* If we had an event, signal it */ 429 if (Event) 430 { 431 KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE); 432 ObDereferenceObject(EventObject); 433 } 434 435 /* If FO was locked, unlock it */ 436 if (LockedForSynch) 437 { 438 IopUnlockFileObject(FileObject); 439 } 440 441 /* Set completion if required */ 442 if (CompletionInfo.Port != NULL && UserApcContext != NULL) 443 { 444 if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port, 445 CompletionInfo.Key, 446 UserApcContext, 447 KernelIosb.Status, 448 KernelIosb.Information, 449 TRUE))) 450 { 451 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES; 452 } 453 } 454 455 /* We're done with FastIO! */ 456 ObDereferenceObject(FileObject); 457 return KernelIosb.Status; 458 } 459 } 460 } 461 462 /* Clear the event */ 463 KeClearEvent(&FileObject->Event); 464 465 /* Allocate IRP */ 466 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 467 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 468 469 /* Setup the IRP */ 470 Irp->UserIosb = IoStatusBlock; 471 Irp->UserEvent = EventObject; 472 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine; 473 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext; 474 Irp->Cancel = FALSE; 475 Irp->CancelRoutine = NULL; 476 Irp->PendingReturned = FALSE; 477 Irp->RequestorMode = PreviousMode; 478 Irp->MdlAddress = NULL; 479 Irp->AssociatedIrp.SystemBuffer = NULL; 480 Irp->Flags = 0; 481 Irp->Tail.Overlay.AuxiliaryBuffer = NULL; 482 Irp->Tail.Overlay.OriginalFileObject = FileObject; 483 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 484 485 /* Set stack location settings */ 486 StackPtr = IoGetNextIrpStackLocation(Irp); 487 StackPtr->FileObject = FileObject; 488 StackPtr->MajorFunction = IsDevIoCtl ? 489 IRP_MJ_DEVICE_CONTROL : 490 IRP_MJ_FILE_SYSTEM_CONTROL; 491 StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */ 492 StackPtr->Control = 0; 493 StackPtr->Flags = 0; 494 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL; 495 496 /* Set the IOCTL Data */ 497 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode; 498 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; 499 StackPtr->Parameters.DeviceIoControl.OutputBufferLength = 500 OutputBufferLength; 501 502 PoolType = IsDevIoCtl ? NonPagedPoolCacheAligned : NonPagedPool; 503 504 /* Handle the Methods */ 505 switch (AccessType) 506 { 507 /* Buffered I/O */ 508 case METHOD_BUFFERED: 509 510 /* Enter SEH for allocations */ 511 _SEH2_TRY 512 { 513 /* Select the right Buffer Length */ 514 BufferLength = (InputBufferLength > OutputBufferLength) ? 515 InputBufferLength : OutputBufferLength; 516 517 /* Make sure there is one */ 518 if (BufferLength) 519 { 520 /* Allocate the System Buffer */ 521 Irp->AssociatedIrp.SystemBuffer = 522 ExAllocatePoolWithQuotaTag(PoolType, 523 BufferLength, 524 TAG_SYS_BUF); 525 526 /* Check if we got a buffer */ 527 if (InputBuffer) 528 { 529 /* Copy into the System Buffer */ 530 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 531 InputBuffer, 532 InputBufferLength); 533 } 534 535 /* Write the flags */ 536 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; 537 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION; 538 539 /* Save the Buffer */ 540 Irp->UserBuffer = OutputBuffer; 541 } 542 else 543 { 544 /* Clear the Flags and Buffer */ 545 Irp->UserBuffer = NULL; 546 } 547 } 548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 549 { 550 /* Cleanup after exception and return */ 551 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 552 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 553 } 554 _SEH2_END; 555 break; 556 557 /* Direct I/O */ 558 case METHOD_IN_DIRECT: 559 case METHOD_OUT_DIRECT: 560 561 /* Enter SEH */ 562 _SEH2_TRY 563 { 564 /* Check if we got an input buffer */ 565 if ((InputBufferLength) && (InputBuffer)) 566 { 567 /* Allocate the System Buffer */ 568 Irp->AssociatedIrp.SystemBuffer = 569 ExAllocatePoolWithQuotaTag(PoolType, 570 InputBufferLength, 571 TAG_SYS_BUF); 572 573 /* Copy into the System Buffer */ 574 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 575 InputBuffer, 576 InputBufferLength); 577 578 /* Write the flags */ 579 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; 580 } 581 582 /* Check if we got an output buffer */ 583 if (OutputBufferLength) 584 { 585 /* Allocate the System Buffer */ 586 Irp->MdlAddress = IoAllocateMdl(OutputBuffer, 587 OutputBufferLength, 588 FALSE, 589 FALSE, 590 Irp); 591 if (!Irp->MdlAddress) 592 { 593 /* Raise exception we'll catch */ 594 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 595 } 596 597 /* Do the probe */ 598 MmProbeAndLockPages(Irp->MdlAddress, 599 PreviousMode, 600 (AccessType == METHOD_IN_DIRECT) ? 601 IoReadAccess : IoWriteAccess); 602 } 603 } 604 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 605 { 606 /* Cleanup after exception and return */ 607 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 608 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 609 } 610 _SEH2_END; 611 break; 612 613 case METHOD_NEITHER: 614 615 /* Just save the Buffer */ 616 Irp->UserBuffer = OutputBuffer; 617 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer; 618 } 619 620 /* Use deferred completion for FS I/O */ 621 if (!IsDevIoCtl) 622 { 623 Irp->Flags |= IRP_DEFER_IO_COMPLETION; 624 } 625 626 /* If we are dismounting a volume, increaase the dismount count */ 627 if (IoControlCode == FSCTL_DISMOUNT_VOLUME) 628 { 629 InterlockedIncrement((PLONG)&SharedUserData->DismountCount); 630 } 631 632 /* Perform the call */ 633 return IopPerformSynchronousRequest(DeviceObject, 634 Irp, 635 FileObject, 636 !IsDevIoCtl, 637 PreviousMode, 638 LockedForSynch, 639 IopOtherTransfer); 640 } 641 642 NTSTATUS 643 NTAPI 644 IopQueryDeviceInformation(IN PFILE_OBJECT FileObject, 645 IN ULONG InformationClass, 646 IN ULONG Length, 647 OUT PVOID Information, 648 OUT PULONG ReturnedLength, 649 IN BOOLEAN File) 650 { 651 IO_STATUS_BLOCK IoStatusBlock; 652 PIRP Irp; 653 PDEVICE_OBJECT DeviceObject; 654 PIO_STACK_LOCATION StackPtr; 655 BOOLEAN LocalEvent = FALSE; 656 KEVENT Event; 657 NTSTATUS Status; 658 PAGED_CODE(); 659 IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n", 660 FileObject, InformationClass, File); 661 662 /* Reference the object */ 663 ObReferenceObject(FileObject); 664 665 /* Check if this is a file that was opened for Synch I/O */ 666 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 667 { 668 /* Lock it */ 669 IopLockFileObject(FileObject); 670 671 /* Use File Object event */ 672 KeClearEvent(&FileObject->Event); 673 } 674 else 675 { 676 /* Use local event */ 677 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 678 LocalEvent = TRUE; 679 } 680 681 /* Get the Device Object */ 682 DeviceObject = IoGetRelatedDeviceObject(FileObject); 683 684 /* Allocate the IRP */ 685 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 686 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL); 687 688 /* Set the IRP */ 689 Irp->Tail.Overlay.OriginalFileObject = FileObject; 690 Irp->RequestorMode = KernelMode; 691 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 692 Irp->UserIosb = &IoStatusBlock; 693 Irp->UserEvent = (LocalEvent) ? &Event : NULL; 694 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 695 Irp->Flags |= IRP_BUFFERED_IO; 696 Irp->AssociatedIrp.SystemBuffer = Information; 697 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 698 699 /* Set the Stack Data */ 700 StackPtr = IoGetNextIrpStackLocation(Irp); 701 StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION: 702 IRP_MJ_QUERY_VOLUME_INFORMATION; 703 StackPtr->FileObject = FileObject; 704 705 /* Check which type this is */ 706 if (File) 707 { 708 /* Set Parameters */ 709 StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass; 710 StackPtr->Parameters.QueryFile.Length = Length; 711 } 712 else 713 { 714 /* Set Parameters */ 715 StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass; 716 StackPtr->Parameters.QueryVolume.Length = Length; 717 } 718 719 /* Queue the IRP */ 720 IopQueueIrpToThread(Irp); 721 722 /* Call the Driver */ 723 Status = IoCallDriver(DeviceObject, Irp); 724 725 /* Check if this was synch I/O */ 726 if (!LocalEvent) 727 { 728 /* Check if the request is pending */ 729 if (Status == STATUS_PENDING) 730 { 731 /* Wait on the file object */ 732 Status = KeWaitForSingleObject(&FileObject->Event, 733 Executive, 734 KernelMode, 735 (FileObject->Flags & 736 FO_ALERTABLE_IO) != 0, 737 NULL); 738 if (Status == STATUS_ALERTED) 739 { 740 /* Abort the operation */ 741 IopAbortInterruptedIrp(&FileObject->Event, Irp); 742 } 743 744 /* Get the final status */ 745 Status = FileObject->FinalStatus; 746 } 747 748 /* Release the file lock */ 749 IopUnlockFileObject(FileObject); 750 } 751 else if (Status == STATUS_PENDING) 752 { 753 /* Wait on the local event and get the final status */ 754 KeWaitForSingleObject(&Event, 755 Executive, 756 KernelMode, 757 FALSE, 758 NULL); 759 Status = IoStatusBlock.Status; 760 } 761 762 /* Return the Length and Status. ReturnedLength is NOT optional */ 763 *ReturnedLength = (ULONG)IoStatusBlock.Information; 764 return Status; 765 } 766 767 NTSTATUS 768 NTAPI 769 IopGetFileInformation(IN PFILE_OBJECT FileObject, 770 IN ULONG Length, 771 IN FILE_INFORMATION_CLASS FileInfoClass, 772 OUT PVOID Buffer, 773 OUT PULONG ReturnedLength) 774 { 775 PIRP Irp; 776 KEVENT Event; 777 NTSTATUS Status; 778 PIO_STACK_LOCATION Stack; 779 PDEVICE_OBJECT DeviceObject; 780 IO_STATUS_BLOCK IoStatusBlock; 781 782 PAGED_CODE(); 783 784 /* Allocate an IRP */ 785 ObReferenceObject(FileObject); 786 DeviceObject = IoGetRelatedDeviceObject(FileObject); 787 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 788 if (Irp == NULL) 789 { 790 ObDereferenceObject(FileObject); 791 return STATUS_INSUFFICIENT_RESOURCES; 792 } 793 794 /* Init event */ 795 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 796 797 /* Setup the IRP */ 798 Irp->UserIosb = &IoStatusBlock; 799 Irp->UserEvent = &Event; 800 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 801 Irp->RequestorMode = KernelMode; 802 Irp->AssociatedIrp.SystemBuffer = Buffer; 803 Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME; 804 Irp->Tail.Overlay.OriginalFileObject = FileObject; 805 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 806 807 Stack = IoGetNextIrpStackLocation(Irp); 808 Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION; 809 Stack->FileObject = FileObject; 810 Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass; 811 Stack->Parameters.QueryFile.Length = Length; 812 813 814 /* Queue the IRP */ 815 IopQueueIrpToThread(Irp); 816 817 /* Call the driver */ 818 Status = IoCallDriver(DeviceObject, Irp); 819 if (Status == STATUS_PENDING) 820 { 821 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 822 Status = IoStatusBlock.Status; 823 } 824 825 *ReturnedLength = IoStatusBlock.Information; 826 return Status; 827 } 828 829 NTSTATUS 830 NTAPI 831 IopGetBasicInformationFile(IN PFILE_OBJECT FileObject, 832 OUT PFILE_BASIC_INFORMATION BasicInfo) 833 { 834 ULONG ReturnedLength; 835 PDEVICE_OBJECT DeviceObject; 836 IO_STATUS_BLOCK IoStatusBlock; 837 838 PAGED_CODE(); 839 840 /* Try to do it the fast way if possible */ 841 DeviceObject = IoGetRelatedDeviceObject(FileObject); 842 if (DeviceObject->DriverObject->FastIoDispatch != NULL && 843 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL && 844 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject, 845 ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0), 846 BasicInfo, 847 &IoStatusBlock, 848 DeviceObject)) 849 { 850 return IoStatusBlock.Status; 851 } 852 853 /* In case it failed, fall back to IRP-based method */ 854 return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength); 855 } 856 857 NTSTATUS 858 NTAPI 859 IopOpenLinkOrRenameTarget(OUT PHANDLE Handle, 860 IN PIRP Irp, 861 IN PFILE_RENAME_INFORMATION RenameInfo, 862 IN PFILE_OBJECT FileObject) 863 { 864 NTSTATUS Status; 865 HANDLE TargetHandle; 866 UNICODE_STRING FileName; 867 PIO_STACK_LOCATION Stack; 868 PFILE_OBJECT TargetFileObject; 869 IO_STATUS_BLOCK IoStatusBlock; 870 FILE_BASIC_INFORMATION BasicInfo; 871 OBJECT_ATTRIBUTES ObjectAttributes; 872 OBJECT_HANDLE_INFORMATION HandleInformation; 873 ACCESS_MASK DesiredAccess = FILE_WRITE_DATA; 874 875 PAGED_CODE(); 876 877 /* First, establish whether our target is a directory */ 878 if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)) 879 { 880 Status = IopGetBasicInformationFile(FileObject, &BasicInfo); 881 if (!NT_SUCCESS(Status)) 882 { 883 return Status; 884 } 885 886 if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 887 DesiredAccess = FILE_ADD_SUBDIRECTORY; 888 } 889 } 890 891 /* Setup the string to the target */ 892 FileName.Buffer = RenameInfo->FileName; 893 FileName.Length = RenameInfo->FileNameLength; 894 FileName.MaximumLength = RenameInfo->FileNameLength; 895 896 InitializeObjectAttributes(&ObjectAttributes, 897 &FileName, 898 (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE, 899 RenameInfo->RootDirectory, 900 NULL); 901 902 /* And open its parent directory */ 903 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) 904 { 905 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 906 #if 0 907 /* Commented out - we don't support FO extension yet 908 * FIXME: Corrected last arg when it's supported 909 */ 910 Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle, 911 DesiredAccess | SYNCHRONIZE, 912 &ObjectAttributes, 913 &IoStatusBlock, 914 NULL, 915 0, 916 FILE_SHARE_READ | FILE_SHARE_WRITE, 917 FILE_OPEN, 918 FILE_OPEN_FOR_BACKUP_INTENT, 919 NULL, 920 0, 921 CreateFileTypeNone, 922 NULL, 923 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING, 924 FileObject->DeviceObject); 925 #else 926 ASSERT(FALSE); 927 UNIMPLEMENTED; 928 return STATUS_NOT_IMPLEMENTED; 929 #endif 930 } 931 else 932 { 933 Status = IoCreateFile(&TargetHandle, 934 DesiredAccess | SYNCHRONIZE, 935 &ObjectAttributes, 936 &IoStatusBlock, 937 NULL, 938 0, 939 FILE_SHARE_READ | FILE_SHARE_WRITE, 940 FILE_OPEN, 941 FILE_OPEN_FOR_BACKUP_INTENT, 942 NULL, 943 0, 944 CreateFileTypeNone, 945 NULL, 946 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING); 947 } 948 949 if (!NT_SUCCESS(Status)) 950 { 951 return Status; 952 } 953 954 /* Once open, continue only if: 955 * Target exists and we're allowed to overwrite it 956 */ 957 Stack = IoGetNextIrpStackLocation(Irp); 958 if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation && 959 !RenameInfo->ReplaceIfExists && 960 IoStatusBlock.Information == FILE_EXISTS) 961 { 962 ObCloseHandle(TargetHandle, KernelMode); 963 return STATUS_OBJECT_NAME_COLLISION; 964 } 965 966 /* Now, we'll get the associated device of the target, to check for same device location 967 * So, get the FO first 968 */ 969 Status = ObReferenceObjectByHandle(TargetHandle, 970 FILE_WRITE_DATA, 971 IoFileObjectType, 972 KernelMode, 973 (PVOID *)&TargetFileObject, 974 &HandleInformation); 975 if (!NT_SUCCESS(Status)) 976 { 977 ObCloseHandle(TargetHandle, KernelMode); 978 return Status; 979 } 980 981 /* We can dereference, we have the handle */ 982 ObDereferenceObject(TargetFileObject); 983 /* If we're not on the same device, error out **/ 984 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject)) 985 { 986 ObCloseHandle(TargetHandle, KernelMode); 987 return STATUS_NOT_SAME_DEVICE; 988 } 989 990 /* Return parent directory file object and handle */ 991 Stack->Parameters.SetFile.FileObject = TargetFileObject; 992 *Handle = TargetHandle; 993 994 return STATUS_SUCCESS; 995 } 996 997 static 998 ULONG 999 IopGetFileMode(IN PFILE_OBJECT FileObject) 1000 { 1001 ULONG Mode = 0; 1002 1003 if (FileObject->Flags & FO_WRITE_THROUGH) 1004 Mode |= FILE_WRITE_THROUGH; 1005 1006 if (FileObject->Flags & FO_SEQUENTIAL_ONLY) 1007 Mode |= FILE_SEQUENTIAL_ONLY; 1008 1009 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) 1010 Mode |= FILE_NO_INTERMEDIATE_BUFFERING; 1011 1012 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1013 { 1014 if (FileObject->Flags & FO_ALERTABLE_IO) 1015 Mode |= FILE_SYNCHRONOUS_IO_ALERT; 1016 else 1017 Mode |= FILE_SYNCHRONOUS_IO_NONALERT; 1018 } 1019 1020 if (FileObject->Flags & FO_DELETE_ON_CLOSE) 1021 Mode |= FILE_DELETE_ON_CLOSE; 1022 1023 return Mode; 1024 } 1025 1026 /* PUBLIC FUNCTIONS **********************************************************/ 1027 1028 /* 1029 * @implemented 1030 */ 1031 NTSTATUS 1032 NTAPI 1033 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject, 1034 IN PMDL Mdl, 1035 IN PLARGE_INTEGER Offset, 1036 IN PKEVENT Event, 1037 IN PIO_STATUS_BLOCK StatusBlock) 1038 { 1039 PIRP Irp; 1040 PIO_STACK_LOCATION StackPtr; 1041 PDEVICE_OBJECT DeviceObject; 1042 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n", 1043 FileObject, Mdl, Offset); 1044 1045 /* Is the write originating from Cc? */ 1046 if (FileObject->SectionObjectPointer != NULL && 1047 FileObject->SectionObjectPointer->SharedCacheMap != NULL) 1048 { 1049 ++CcDataFlushes; 1050 CcDataPages += BYTES_TO_PAGES(MmGetMdlByteCount(Mdl)); 1051 } 1052 1053 /* Get the Device Object */ 1054 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1055 1056 /* Allocate IRP */ 1057 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1058 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 1059 1060 /* Get the Stack */ 1061 StackPtr = IoGetNextIrpStackLocation(Irp); 1062 1063 /* Create the IRP Settings */ 1064 Irp->MdlAddress = Mdl; 1065 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl); 1066 Irp->UserIosb = StatusBlock; 1067 Irp->UserEvent = Event; 1068 Irp->RequestorMode = KernelMode; 1069 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO; 1070 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1071 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1072 1073 /* Set the Stack Settings */ 1074 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl); 1075 StackPtr->Parameters.Write.ByteOffset = *Offset; 1076 StackPtr->MajorFunction = IRP_MJ_WRITE; 1077 StackPtr->FileObject = FileObject; 1078 1079 /* Call the Driver */ 1080 return IoCallDriver(DeviceObject, Irp); 1081 } 1082 1083 /* 1084 * @implemented 1085 */ 1086 NTSTATUS 1087 NTAPI 1088 IoPageRead(IN PFILE_OBJECT FileObject, 1089 IN PMDL Mdl, 1090 IN PLARGE_INTEGER Offset, 1091 IN PKEVENT Event, 1092 IN PIO_STATUS_BLOCK StatusBlock) 1093 { 1094 PIRP Irp; 1095 PIO_STACK_LOCATION StackPtr; 1096 PDEVICE_OBJECT DeviceObject; 1097 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n", 1098 FileObject, Mdl, Offset); 1099 1100 /* Get the Device Object */ 1101 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1102 1103 /* Allocate IRP */ 1104 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1105 /* If allocation failed, try to see whether we can use 1106 * the reserve IRP 1107 */ 1108 if (Irp == NULL) 1109 { 1110 /* We will use it only for paging file */ 1111 if (MmIsFileObjectAPagingFile(FileObject)) 1112 { 1113 InterlockedExchangeAdd(&IoPageReadIrpAllocationFailure, 1); 1114 Irp = IopAllocateReserveIrp(DeviceObject->StackSize); 1115 } 1116 else 1117 { 1118 InterlockedExchangeAdd(&IoPageReadNonPagefileIrpAllocationFailure, 1); 1119 } 1120 1121 /* If allocation failed (not a paging file or too big stack size) 1122 * Fail for real 1123 */ 1124 if (Irp == NULL) 1125 { 1126 return STATUS_INSUFFICIENT_RESOURCES; 1127 } 1128 } 1129 1130 /* Get the Stack */ 1131 StackPtr = IoGetNextIrpStackLocation(Irp); 1132 1133 /* Create the IRP Settings */ 1134 Irp->MdlAddress = Mdl; 1135 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl); 1136 Irp->UserIosb = StatusBlock; 1137 Irp->UserEvent = Event; 1138 Irp->RequestorMode = KernelMode; 1139 Irp->Flags = IRP_PAGING_IO | 1140 IRP_NOCACHE | 1141 IRP_SYNCHRONOUS_PAGING_IO | 1142 IRP_INPUT_OPERATION; 1143 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1144 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1145 1146 /* Set the Stack Settings */ 1147 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl); 1148 StackPtr->Parameters.Read.ByteOffset = *Offset; 1149 StackPtr->MajorFunction = IRP_MJ_READ; 1150 StackPtr->FileObject = FileObject; 1151 1152 /* Call the Driver */ 1153 return IoCallDriver(DeviceObject, Irp); 1154 } 1155 1156 /* 1157 * @implemented 1158 */ 1159 NTSTATUS 1160 NTAPI 1161 IoQueryFileInformation(IN PFILE_OBJECT FileObject, 1162 IN FILE_INFORMATION_CLASS FileInformationClass, 1163 IN ULONG Length, 1164 OUT PVOID FileInformation, 1165 OUT PULONG ReturnedLength) 1166 { 1167 /* Call the shared routine */ 1168 return IopQueryDeviceInformation(FileObject, 1169 FileInformationClass, 1170 Length, 1171 FileInformation, 1172 ReturnedLength, 1173 TRUE); 1174 } 1175 1176 /* 1177 * @implemented 1178 */ 1179 NTSTATUS 1180 NTAPI 1181 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject, 1182 IN FS_INFORMATION_CLASS FsInformationClass, 1183 IN ULONG Length, 1184 OUT PVOID FsInformation, 1185 OUT PULONG ReturnedLength) 1186 { 1187 /* Call the shared routine */ 1188 return IopQueryDeviceInformation(FileObject, 1189 FsInformationClass, 1190 Length, 1191 FsInformation, 1192 ReturnedLength, 1193 FALSE); 1194 } 1195 1196 /* 1197 * @implemented 1198 */ 1199 NTSTATUS 1200 NTAPI 1201 IoSetInformation(IN PFILE_OBJECT FileObject, 1202 IN FILE_INFORMATION_CLASS FileInformationClass, 1203 IN ULONG Length, 1204 IN PVOID FileInformation) 1205 { 1206 IO_STATUS_BLOCK IoStatusBlock; 1207 PIRP Irp; 1208 PDEVICE_OBJECT DeviceObject; 1209 PIO_STACK_LOCATION StackPtr; 1210 BOOLEAN LocalEvent = FALSE; 1211 KEVENT Event; 1212 NTSTATUS Status; 1213 PAGED_CODE(); 1214 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n", 1215 FileObject, FileInformationClass, Length); 1216 1217 /* Reference the object */ 1218 ObReferenceObject(FileObject); 1219 1220 /* Check if this is a file that was opened for Synch I/O */ 1221 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1222 { 1223 /* Lock it */ 1224 IopLockFileObject(FileObject); 1225 1226 /* Use File Object event */ 1227 KeClearEvent(&FileObject->Event); 1228 } 1229 else 1230 { 1231 /* Use local event */ 1232 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 1233 LocalEvent = TRUE; 1234 } 1235 1236 /* Get the Device Object */ 1237 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1238 1239 /* Allocate the IRP */ 1240 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1241 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL); 1242 1243 /* Set the IRP */ 1244 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1245 Irp->RequestorMode = KernelMode; 1246 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 1247 Irp->UserIosb = &IoStatusBlock; 1248 Irp->UserEvent = (LocalEvent) ? &Event : NULL; 1249 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 1250 Irp->Flags |= IRP_BUFFERED_IO; 1251 Irp->AssociatedIrp.SystemBuffer = FileInformation; 1252 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1253 1254 /* Set the Stack Data */ 1255 StackPtr = IoGetNextIrpStackLocation(Irp); 1256 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; 1257 StackPtr->FileObject = FileObject; 1258 1259 /* Set Parameters */ 1260 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; 1261 StackPtr->Parameters.SetFile.Length = Length; 1262 1263 /* Queue the IRP */ 1264 IopQueueIrpToThread(Irp); 1265 1266 /* Call the Driver */ 1267 Status = IoCallDriver(DeviceObject, Irp); 1268 1269 /* Check if this was synch I/O */ 1270 if (!LocalEvent) 1271 { 1272 /* Check if the request is pending */ 1273 if (Status == STATUS_PENDING) 1274 { 1275 /* Wait on the file object */ 1276 Status = KeWaitForSingleObject(&FileObject->Event, 1277 Executive, 1278 KernelMode, 1279 (FileObject->Flags & 1280 FO_ALERTABLE_IO) != 0, 1281 NULL); 1282 if (Status == STATUS_ALERTED) 1283 { 1284 /* Abort the operation */ 1285 IopAbortInterruptedIrp(&FileObject->Event, Irp); 1286 } 1287 1288 /* Get the final status */ 1289 Status = FileObject->FinalStatus; 1290 } 1291 1292 /* Release the file lock */ 1293 IopUnlockFileObject(FileObject); 1294 } 1295 else if (Status == STATUS_PENDING) 1296 { 1297 /* Wait on the local event and get the final status */ 1298 KeWaitForSingleObject(&Event, 1299 Executive, 1300 KernelMode, 1301 FALSE, 1302 NULL); 1303 Status = IoStatusBlock.Status; 1304 } 1305 1306 /* Return the status */ 1307 return Status; 1308 } 1309 1310 /* NATIVE SERVICES ***********************************************************/ 1311 1312 /* 1313 * @implemented 1314 */ 1315 NTSTATUS 1316 NTAPI 1317 NtDeviceIoControlFile(IN HANDLE DeviceHandle, 1318 IN HANDLE Event OPTIONAL, 1319 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 1320 IN PVOID UserApcContext OPTIONAL, 1321 OUT PIO_STATUS_BLOCK IoStatusBlock, 1322 IN ULONG IoControlCode, 1323 IN PVOID InputBuffer, 1324 IN ULONG InputBufferLength OPTIONAL, 1325 OUT PVOID OutputBuffer, 1326 IN ULONG OutputBufferLength OPTIONAL) 1327 { 1328 /* Call the Generic Function */ 1329 return IopDeviceFsIoControl(DeviceHandle, 1330 Event, 1331 UserApcRoutine, 1332 UserApcContext, 1333 IoStatusBlock, 1334 IoControlCode, 1335 InputBuffer, 1336 InputBufferLength, 1337 OutputBuffer, 1338 OutputBufferLength, 1339 TRUE); 1340 } 1341 1342 /* 1343 * @implemented 1344 */ 1345 NTSTATUS 1346 NTAPI 1347 NtFsControlFile(IN HANDLE DeviceHandle, 1348 IN HANDLE Event OPTIONAL, 1349 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 1350 IN PVOID UserApcContext OPTIONAL, 1351 OUT PIO_STATUS_BLOCK IoStatusBlock, 1352 IN ULONG IoControlCode, 1353 IN PVOID InputBuffer, 1354 IN ULONG InputBufferLength OPTIONAL, 1355 OUT PVOID OutputBuffer, 1356 IN ULONG OutputBufferLength OPTIONAL) 1357 { 1358 /* Call the Generic Function */ 1359 return IopDeviceFsIoControl(DeviceHandle, 1360 Event, 1361 UserApcRoutine, 1362 UserApcContext, 1363 IoStatusBlock, 1364 IoControlCode, 1365 InputBuffer, 1366 InputBufferLength, 1367 OutputBuffer, 1368 OutputBufferLength, 1369 FALSE); 1370 } 1371 1372 NTSTATUS 1373 NTAPI 1374 NtFlushBuffersFile(IN HANDLE FileHandle, 1375 OUT PIO_STATUS_BLOCK IoStatusBlock) 1376 { 1377 PFILE_OBJECT FileObject; 1378 PIRP Irp; 1379 PIO_STACK_LOCATION StackPtr; 1380 NTSTATUS Status; 1381 PDEVICE_OBJECT DeviceObject; 1382 PKEVENT Event = NULL; 1383 BOOLEAN LocalEvent = FALSE; 1384 OBJECT_HANDLE_INFORMATION ObjectHandleInfo; 1385 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 1386 IO_STATUS_BLOCK KernelIosb; 1387 PAGED_CODE(); 1388 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1389 1390 if (PreviousMode != KernelMode) 1391 { 1392 /* Protect probes */ 1393 _SEH2_TRY 1394 { 1395 /* Probe the I/O Status block */ 1396 ProbeForWriteIoStatusBlock(IoStatusBlock); 1397 } 1398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1399 { 1400 /* Return the exception code */ 1401 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1402 } 1403 _SEH2_END; 1404 } 1405 1406 /* Get the File Object */ 1407 Status = ObReferenceObjectByHandle(FileHandle, 1408 0, 1409 IoFileObjectType, 1410 PreviousMode, 1411 (PVOID*)&FileObject, 1412 &ObjectHandleInfo); 1413 if (!NT_SUCCESS(Status)) return Status; 1414 1415 /* 1416 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was 1417 * granted. However, if this is a named pipe, make sure we don't ask for 1418 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE 1419 * access right! 1420 */ 1421 if (!(ObjectHandleInfo.GrantedAccess & 1422 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | 1423 FILE_WRITE_DATA))) 1424 { 1425 /* We failed */ 1426 ObDereferenceObject(FileObject); 1427 return STATUS_ACCESS_DENIED; 1428 } 1429 1430 /* Check if we should use Sync IO or not */ 1431 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1432 { 1433 /* Lock it */ 1434 IopLockFileObject(FileObject); 1435 } 1436 else 1437 { 1438 /* Use local event */ 1439 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 1440 if (!Event) 1441 { 1442 /* We failed */ 1443 ObDereferenceObject(FileObject); 1444 return STATUS_INSUFFICIENT_RESOURCES; 1445 } 1446 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 1447 LocalEvent = TRUE; 1448 } 1449 1450 /* Get the Device Object */ 1451 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1452 1453 /* Clear the event */ 1454 KeClearEvent(&FileObject->Event); 1455 1456 /* Allocate the IRP */ 1457 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 1458 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 1459 1460 /* Set up the IRP */ 1461 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 1462 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 1463 Irp->UserEvent = (LocalEvent) ? Event : NULL; 1464 Irp->RequestorMode = PreviousMode; 1465 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1466 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1467 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 1468 1469 /* Set up Stack Data */ 1470 StackPtr = IoGetNextIrpStackLocation(Irp); 1471 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS; 1472 StackPtr->FileObject = FileObject; 1473 1474 /* Call the Driver */ 1475 Status = IopPerformSynchronousRequest(DeviceObject, 1476 Irp, 1477 FileObject, 1478 FALSE, 1479 PreviousMode, 1480 !LocalEvent, 1481 IopOtherTransfer); 1482 1483 /* Check if this was async I/O */ 1484 if (LocalEvent) 1485 { 1486 /* It was, finalize this request */ 1487 Status = IopFinalizeAsynchronousIo(Status, 1488 Event, 1489 Irp, 1490 PreviousMode, 1491 &KernelIosb, 1492 IoStatusBlock); 1493 } 1494 1495 /* Return the Status */ 1496 return Status; 1497 } 1498 1499 /* 1500 * @implemented 1501 */ 1502 NTSTATUS 1503 NTAPI 1504 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle, 1505 IN HANDLE EventHandle OPTIONAL, 1506 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1507 IN PVOID ApcContext OPTIONAL, 1508 OUT PIO_STATUS_BLOCK IoStatusBlock, 1509 OUT PVOID Buffer, 1510 IN ULONG BufferSize, 1511 IN ULONG CompletionFilter, 1512 IN BOOLEAN WatchTree) 1513 { 1514 PIRP Irp; 1515 PKEVENT Event = NULL; 1516 PDEVICE_OBJECT DeviceObject; 1517 PFILE_OBJECT FileObject; 1518 PIO_STACK_LOCATION IoStack; 1519 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1520 NTSTATUS Status; 1521 BOOLEAN LockedForSync = FALSE; 1522 PAGED_CODE(); 1523 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1524 1525 /* Check if we're called from user mode */ 1526 if (PreviousMode != KernelMode) 1527 { 1528 /* Enter SEH for probing */ 1529 _SEH2_TRY 1530 { 1531 /* Probe the I/O STatus block */ 1532 ProbeForWriteIoStatusBlock(IoStatusBlock); 1533 1534 /* Probe the buffer */ 1535 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG)); 1536 } 1537 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1538 { 1539 /* Return the exception code */ 1540 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1541 } 1542 _SEH2_END; 1543 1544 /* Check if CompletionFilter is valid */ 1545 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK)) 1546 { 1547 return STATUS_INVALID_PARAMETER; 1548 } 1549 } 1550 1551 /* Get File Object */ 1552 Status = ObReferenceObjectByHandle(FileHandle, 1553 FILE_LIST_DIRECTORY, 1554 IoFileObjectType, 1555 PreviousMode, 1556 (PVOID*)&FileObject, 1557 NULL); 1558 if (!NT_SUCCESS(Status)) return Status; 1559 1560 /* Check if we have an event handle */ 1561 if (EventHandle) 1562 { 1563 /* Reference it */ 1564 Status = ObReferenceObjectByHandle(EventHandle, 1565 EVENT_MODIFY_STATE, 1566 ExEventObjectType, 1567 PreviousMode, 1568 (PVOID *)&Event, 1569 NULL); 1570 if (Status != STATUS_SUCCESS) 1571 { 1572 ObDereferenceObject(FileObject); 1573 return Status; 1574 } 1575 KeClearEvent(Event); 1576 } 1577 1578 /* Check if we should use Sync IO or not */ 1579 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1580 { 1581 /* Lock it */ 1582 IopLockFileObject(FileObject); 1583 LockedForSync = TRUE; 1584 } 1585 1586 /* Clear File Object event */ 1587 KeClearEvent(&FileObject->Event); 1588 1589 /* Get the device object */ 1590 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1591 1592 /* Allocate the IRP */ 1593 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1594 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL); 1595 1596 /* Set up the IRP */ 1597 Irp->RequestorMode = PreviousMode; 1598 Irp->UserIosb = IoStatusBlock; 1599 Irp->UserEvent = Event; 1600 Irp->UserBuffer = Buffer; 1601 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1602 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1603 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 1604 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 1605 1606 /* Set up Stack Data */ 1607 IoStack = IoGetNextIrpStackLocation(Irp); 1608 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; 1609 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY; 1610 IoStack->FileObject = FileObject; 1611 1612 /* Set parameters */ 1613 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter; 1614 IoStack->Parameters.NotifyDirectory.Length = BufferSize; 1615 if (WatchTree) IoStack->Flags = SL_WATCH_TREE; 1616 1617 /* Perform the call */ 1618 return IopPerformSynchronousRequest(DeviceObject, 1619 Irp, 1620 FileObject, 1621 FALSE, 1622 PreviousMode, 1623 LockedForSync, 1624 IopOtherTransfer); 1625 } 1626 1627 /* 1628 * @implemented 1629 */ 1630 NTSTATUS 1631 NTAPI 1632 NtLockFile(IN HANDLE FileHandle, 1633 IN HANDLE EventHandle OPTIONAL, 1634 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1635 IN PVOID ApcContext OPTIONAL, 1636 OUT PIO_STATUS_BLOCK IoStatusBlock, 1637 IN PLARGE_INTEGER ByteOffset, 1638 IN PLARGE_INTEGER Length, 1639 IN ULONG Key, 1640 IN BOOLEAN FailImmediately, 1641 IN BOOLEAN ExclusiveLock) 1642 { 1643 PFILE_OBJECT FileObject; 1644 PLARGE_INTEGER LocalLength = NULL; 1645 PIRP Irp; 1646 PIO_STACK_LOCATION StackPtr; 1647 PDEVICE_OBJECT DeviceObject; 1648 PKEVENT Event = NULL; 1649 BOOLEAN LockedForSync = FALSE; 1650 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 1651 LARGE_INTEGER CapturedByteOffset, CapturedLength; 1652 NTSTATUS Status; 1653 OBJECT_HANDLE_INFORMATION HandleInformation; 1654 PFAST_IO_DISPATCH FastIoDispatch; 1655 PAGED_CODE(); 1656 CapturedByteOffset.QuadPart = 0; 1657 CapturedLength.QuadPart = 0; 1658 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1659 1660 /* Get File Object */ 1661 Status = ObReferenceObjectByHandle(FileHandle, 1662 0, 1663 IoFileObjectType, 1664 PreviousMode, 1665 (PVOID*)&FileObject, 1666 &HandleInformation); 1667 if (!NT_SUCCESS(Status)) return Status; 1668 1669 /* Check if we're called from user mode */ 1670 if (PreviousMode != KernelMode) 1671 { 1672 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */ 1673 if (!(HandleInformation.GrantedAccess & 1674 (FILE_WRITE_DATA | FILE_READ_DATA))) 1675 { 1676 ObDereferenceObject(FileObject); 1677 return STATUS_ACCESS_DENIED; 1678 } 1679 1680 /* Enter SEH for probing */ 1681 _SEH2_TRY 1682 { 1683 /* Probe the I/O STatus block */ 1684 ProbeForWriteIoStatusBlock(IoStatusBlock); 1685 1686 /* Probe and capture the large integers */ 1687 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 1688 CapturedLength = ProbeForReadLargeInteger(Length); 1689 } 1690 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1691 { 1692 /* Dereference the object and return exception code */ 1693 ObDereferenceObject(FileObject); 1694 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1695 } 1696 _SEH2_END; 1697 } 1698 else 1699 { 1700 /* Otherwise, capture them directly */ 1701 CapturedByteOffset = *ByteOffset; 1702 CapturedLength = *Length; 1703 } 1704 1705 /* Check if we have an event handle */ 1706 if (EventHandle) 1707 { 1708 /* Reference it */ 1709 Status = ObReferenceObjectByHandle(EventHandle, 1710 EVENT_MODIFY_STATE, 1711 ExEventObjectType, 1712 PreviousMode, 1713 (PVOID *)&Event, 1714 NULL); 1715 if (Status != STATUS_SUCCESS) return Status; 1716 KeClearEvent(Event); 1717 } 1718 1719 /* Get the device object */ 1720 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1721 1722 /* Try to do it the FastIO way if possible */ 1723 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 1724 if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL) 1725 { 1726 IO_STATUS_BLOCK KernelIosb; 1727 1728 if (FastIoDispatch->FastIoLock(FileObject, 1729 &CapturedByteOffset, 1730 &CapturedLength, 1731 PsGetCurrentProcess(), 1732 Key, 1733 FailImmediately, 1734 ExclusiveLock, 1735 &KernelIosb, 1736 DeviceObject)) 1737 { 1738 /* Write the IOSB back */ 1739 _SEH2_TRY 1740 { 1741 *IoStatusBlock = KernelIosb; 1742 } 1743 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1744 { 1745 KernelIosb.Status = _SEH2_GetExceptionCode(); 1746 } 1747 _SEH2_END; 1748 1749 /* If we had an event, signal it */ 1750 if (EventHandle) 1751 { 1752 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 1753 ObDereferenceObject(Event); 1754 } 1755 1756 /* Set completion if required */ 1757 if (FileObject->CompletionContext != NULL && ApcContext != NULL) 1758 { 1759 if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port, 1760 FileObject->CompletionContext->Key, 1761 ApcContext, 1762 KernelIosb.Status, 1763 KernelIosb.Information, 1764 TRUE))) 1765 { 1766 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES; 1767 } 1768 } 1769 1770 FileObject->LockOperation = TRUE; 1771 1772 /* We're done with FastIO! */ 1773 ObDereferenceObject(FileObject); 1774 return KernelIosb.Status; 1775 } 1776 } 1777 1778 /* Check if we should use Sync IO or not */ 1779 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1780 { 1781 /* Lock it */ 1782 IopLockFileObject(FileObject); 1783 LockedForSync = TRUE; 1784 } 1785 1786 /* Clear File Object event */ 1787 KeClearEvent(&FileObject->Event); 1788 FileObject->LockOperation = TRUE; 1789 1790 /* Allocate the IRP */ 1791 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1792 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL); 1793 1794 /* Set up the IRP */ 1795 Irp->RequestorMode = PreviousMode; 1796 Irp->UserIosb = IoStatusBlock; 1797 Irp->UserEvent = Event; 1798 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1799 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1800 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 1801 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 1802 1803 /* Set up Stack Data */ 1804 StackPtr = IoGetNextIrpStackLocation(Irp); 1805 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; 1806 StackPtr->MinorFunction = IRP_MN_LOCK; 1807 StackPtr->FileObject = FileObject; 1808 1809 /* Allocate local buffer */ 1810 LocalLength = ExAllocatePoolWithTag(NonPagedPool, 1811 sizeof(LARGE_INTEGER), 1812 TAG_LOCK); 1813 if (!LocalLength) 1814 { 1815 /* Allocating failed, clean up and return failure */ 1816 IopCleanupAfterException(FileObject, Irp, Event, NULL); 1817 return STATUS_INSUFFICIENT_RESOURCES; 1818 } 1819 1820 /* Set the length */ 1821 *LocalLength = CapturedLength; 1822 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength; 1823 StackPtr->Parameters.LockControl.Length = LocalLength; 1824 1825 /* Set Parameters */ 1826 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset; 1827 StackPtr->Parameters.LockControl.Key = Key; 1828 1829 /* Set Flags */ 1830 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY; 1831 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK; 1832 1833 /* Perform the call */ 1834 return IopPerformSynchronousRequest(DeviceObject, 1835 Irp, 1836 FileObject, 1837 FALSE, 1838 PreviousMode, 1839 LockedForSync, 1840 IopOtherTransfer); 1841 } 1842 1843 /* 1844 * @implemented 1845 */ 1846 NTSTATUS 1847 NTAPI 1848 NtQueryDirectoryFile(IN HANDLE FileHandle, 1849 IN HANDLE EventHandle OPTIONAL, 1850 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1851 IN PVOID ApcContext OPTIONAL, 1852 OUT PIO_STATUS_BLOCK IoStatusBlock, 1853 OUT PVOID FileInformation, 1854 IN ULONG Length, 1855 IN FILE_INFORMATION_CLASS FileInformationClass, 1856 IN BOOLEAN ReturnSingleEntry, 1857 IN PUNICODE_STRING FileName OPTIONAL, 1858 IN BOOLEAN RestartScan) 1859 { 1860 PIRP Irp; 1861 PDEVICE_OBJECT DeviceObject; 1862 PFILE_OBJECT FileObject; 1863 PIO_STACK_LOCATION StackPtr; 1864 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1865 NTSTATUS Status; 1866 BOOLEAN LockedForSynch = FALSE; 1867 PKEVENT Event = NULL; 1868 volatile PVOID AuxBuffer = NULL; 1869 PMDL Mdl; 1870 UNICODE_STRING CapturedFileName; 1871 PUNICODE_STRING SearchPattern; 1872 PAGED_CODE(); 1873 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1874 1875 /* Check if we came from user mode */ 1876 if (PreviousMode != KernelMode) 1877 { 1878 /* Enter SEH for probing */ 1879 _SEH2_TRY 1880 { 1881 /* Probe the I/O Status Block */ 1882 ProbeForWriteIoStatusBlock(IoStatusBlock); 1883 1884 /* Probe the file information */ 1885 ProbeForWrite(FileInformation, Length, sizeof(ULONG)); 1886 1887 /* Check if we have a file name */ 1888 if (FileName) 1889 { 1890 /* Capture it */ 1891 CapturedFileName = ProbeForReadUnicodeString(FileName); 1892 if (CapturedFileName.Length) 1893 { 1894 /* Probe its buffer */ 1895 ProbeForRead(CapturedFileName.Buffer, 1896 CapturedFileName.Length, 1897 1); 1898 } 1899 1900 /* Allocate the auxiliary buffer */ 1901 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool, 1902 CapturedFileName.Length + 1903 sizeof(UNICODE_STRING), 1904 TAG_SYSB); 1905 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer + 1906 sizeof(UNICODE_STRING)), 1907 CapturedFileName.Buffer, 1908 CapturedFileName.Length); 1909 1910 /* Setup the search pattern */ 1911 SearchPattern = (PUNICODE_STRING)AuxBuffer; 1912 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer + 1913 sizeof(UNICODE_STRING)); 1914 SearchPattern->Length = CapturedFileName.Length; 1915 SearchPattern->MaximumLength = CapturedFileName.Length; 1916 } 1917 } 1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1919 { 1920 /* Free buffer and return the exception code */ 1921 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 1922 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1923 } 1924 _SEH2_END; 1925 } 1926 1927 /* Get File Object */ 1928 Status = ObReferenceObjectByHandle(FileHandle, 1929 FILE_LIST_DIRECTORY, 1930 IoFileObjectType, 1931 PreviousMode, 1932 (PVOID *)&FileObject, 1933 NULL); 1934 if (!NT_SUCCESS(Status)) 1935 { 1936 /* Fail */ 1937 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 1938 return Status; 1939 } 1940 1941 /* Are there two associated completion routines? */ 1942 if (FileObject->CompletionContext != NULL && ApcRoutine != NULL) 1943 { 1944 ObDereferenceObject(FileObject); 1945 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 1946 return STATUS_INVALID_PARAMETER; 1947 } 1948 1949 /* Check if we have an even handle */ 1950 if (EventHandle) 1951 { 1952 /* Get its pointer */ 1953 Status = ObReferenceObjectByHandle(EventHandle, 1954 EVENT_MODIFY_STATE, 1955 ExEventObjectType, 1956 PreviousMode, 1957 (PVOID *)&Event, 1958 NULL); 1959 if (!NT_SUCCESS(Status)) 1960 { 1961 /* Fail */ 1962 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 1963 ObDereferenceObject(FileObject); 1964 return Status; 1965 } 1966 1967 /* Clear it */ 1968 KeClearEvent(Event); 1969 } 1970 1971 /* Check if this is a file that was opened for Synch I/O */ 1972 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1973 { 1974 /* Lock it */ 1975 IopLockFileObject(FileObject); 1976 1977 /* Remember to unlock later */ 1978 LockedForSynch = TRUE; 1979 } 1980 1981 /* Get the device object */ 1982 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1983 1984 /* Clear the File Object's event */ 1985 KeClearEvent(&FileObject->Event); 1986 1987 /* Allocate the IRP */ 1988 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 1989 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer); 1990 1991 /* Set up the IRP */ 1992 Irp->RequestorMode = PreviousMode; 1993 Irp->UserIosb = IoStatusBlock; 1994 Irp->UserEvent = Event; 1995 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1996 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1997 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 1998 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 1999 Irp->MdlAddress = NULL; 2000 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer; 2001 Irp->AssociatedIrp.SystemBuffer = NULL; 2002 2003 /* Check if this is buffered I/O */ 2004 if (DeviceObject->Flags & DO_BUFFERED_IO) 2005 { 2006 /* Allocate a buffer */ 2007 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, 2008 Length, 2009 TAG_SYSB); 2010 if (!Irp->AssociatedIrp.SystemBuffer) 2011 { 2012 /* Allocating failed, clean up and return the exception code */ 2013 IopCleanupAfterException(FileObject, Irp, Event, NULL); 2014 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2015 2016 /* Return the exception code */ 2017 return STATUS_INSUFFICIENT_RESOURCES; 2018 } 2019 2020 /* Set the buffer and flags */ 2021 Irp->UserBuffer = FileInformation; 2022 Irp->Flags = (IRP_BUFFERED_IO | 2023 IRP_DEALLOCATE_BUFFER | 2024 IRP_INPUT_OPERATION); 2025 } 2026 else if (DeviceObject->Flags & DO_DIRECT_IO) 2027 { 2028 _SEH2_TRY 2029 { 2030 /* Allocate an MDL */ 2031 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp); 2032 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2033 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); 2034 } 2035 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2036 { 2037 /* Allocating failed, clean up and return the exception code */ 2038 IopCleanupAfterException(FileObject, Irp, Event, NULL); 2039 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2040 } 2041 _SEH2_END; 2042 } 2043 else 2044 { 2045 /* No allocation flags, and use the buffer directly */ 2046 Irp->UserBuffer = FileInformation; 2047 } 2048 2049 /* Set up Stack Data */ 2050 StackPtr = IoGetNextIrpStackLocation(Irp); 2051 StackPtr->FileObject = FileObject; 2052 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; 2053 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY; 2054 2055 /* Set Parameters */ 2056 StackPtr->Parameters.QueryDirectory.FileInformationClass = 2057 FileInformationClass; 2058 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer; 2059 StackPtr->Parameters.QueryDirectory.FileIndex = 0; 2060 StackPtr->Parameters.QueryDirectory.Length = Length; 2061 StackPtr->Flags = 0; 2062 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN; 2063 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY; 2064 2065 /* Set deferred I/O */ 2066 Irp->Flags |= IRP_DEFER_IO_COMPLETION; 2067 2068 /* Perform the call */ 2069 return IopPerformSynchronousRequest(DeviceObject, 2070 Irp, 2071 FileObject, 2072 TRUE, 2073 PreviousMode, 2074 LockedForSynch, 2075 IopOtherTransfer); 2076 } 2077 2078 /* 2079 * @unimplemented 2080 */ 2081 NTSTATUS 2082 NTAPI 2083 NtQueryEaFile(IN HANDLE FileHandle, 2084 OUT PIO_STATUS_BLOCK IoStatusBlock, 2085 OUT PVOID Buffer, 2086 IN ULONG Length, 2087 IN BOOLEAN ReturnSingleEntry, 2088 IN PVOID EaList OPTIONAL, 2089 IN ULONG EaListLength, 2090 IN PULONG EaIndex OPTIONAL, 2091 IN BOOLEAN RestartScan) 2092 { 2093 UNIMPLEMENTED; 2094 return STATUS_NOT_IMPLEMENTED; 2095 } 2096 2097 /* 2098 * @implemented 2099 */ 2100 NTSTATUS 2101 NTAPI 2102 NtQueryInformationFile(IN HANDLE FileHandle, 2103 OUT PIO_STATUS_BLOCK IoStatusBlock, 2104 IN PVOID FileInformation, 2105 IN ULONG Length, 2106 IN FILE_INFORMATION_CLASS FileInformationClass) 2107 { 2108 OBJECT_HANDLE_INFORMATION HandleInformation; 2109 PFILE_OBJECT FileObject; 2110 NTSTATUS Status; 2111 PIRP Irp; 2112 PDEVICE_OBJECT DeviceObject; 2113 PIO_STACK_LOCATION StackPtr; 2114 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2115 PKEVENT Event = NULL; 2116 BOOLEAN LocalEvent = FALSE; 2117 PKNORMAL_ROUTINE NormalRoutine; 2118 PVOID NormalContext; 2119 KIRQL OldIrql; 2120 IO_STATUS_BLOCK KernelIosb; 2121 BOOLEAN CallDriver = TRUE; 2122 PFILE_ACCESS_INFORMATION AccessBuffer; 2123 PFILE_MODE_INFORMATION ModeBuffer; 2124 PFILE_ALIGNMENT_INFORMATION AlignmentBuffer; 2125 PFILE_ALL_INFORMATION AllBuffer; 2126 PFAST_IO_DISPATCH FastIoDispatch; 2127 PAGED_CODE(); 2128 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2129 2130 /* Check if we're called from user mode */ 2131 if (PreviousMode != KernelMode) 2132 { 2133 /* Validate the information class */ 2134 if ((FileInformationClass >= FileMaximumInformation) || 2135 !(IopQueryOperationLength[FileInformationClass])) 2136 { 2137 /* Invalid class */ 2138 return STATUS_INVALID_INFO_CLASS; 2139 } 2140 2141 /* Validate the length */ 2142 if (Length < IopQueryOperationLength[FileInformationClass]) 2143 { 2144 /* Invalid length */ 2145 return STATUS_INFO_LENGTH_MISMATCH; 2146 } 2147 2148 /* Enter SEH for probing */ 2149 _SEH2_TRY 2150 { 2151 /* Probe the I/O Status block */ 2152 ProbeForWriteIoStatusBlock(IoStatusBlock); 2153 2154 /* Probe the information */ 2155 ProbeForWrite(FileInformation, Length, sizeof(ULONG)); 2156 } 2157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2158 { 2159 /* Return the exception code */ 2160 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2161 } 2162 _SEH2_END; 2163 } 2164 #if DBG 2165 else 2166 { 2167 /* Validate the information class */ 2168 if ((FileInformationClass >= FileMaximumInformation) || 2169 !(IopQueryOperationLength[FileInformationClass])) 2170 { 2171 /* Invalid class */ 2172 return STATUS_INVALID_INFO_CLASS; 2173 } 2174 2175 /* Validate the length */ 2176 if (Length < IopQueryOperationLength[FileInformationClass]) 2177 { 2178 /* Invalid length */ 2179 return STATUS_INFO_LENGTH_MISMATCH; 2180 } 2181 } 2182 #endif 2183 2184 /* Reference the Handle */ 2185 Status = ObReferenceObjectByHandle(FileHandle, 2186 IopQueryOperationAccess 2187 [FileInformationClass], 2188 IoFileObjectType, 2189 PreviousMode, 2190 (PVOID *)&FileObject, 2191 &HandleInformation); 2192 if (!NT_SUCCESS(Status)) return Status; 2193 2194 /* Check if this is a direct open or not */ 2195 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 2196 { 2197 /* Get the device object */ 2198 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 2199 } 2200 else 2201 { 2202 /* Get the device object */ 2203 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2204 } 2205 2206 /* Check if this is a file that was opened for Synch I/O */ 2207 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2208 { 2209 /* Lock it */ 2210 IopLockFileObject(FileObject); 2211 2212 /* Check if the caller just wants the position */ 2213 if (FileInformationClass == FilePositionInformation) 2214 { 2215 /* Protect write in SEH */ 2216 _SEH2_TRY 2217 { 2218 /* Write the offset */ 2219 ((PFILE_POSITION_INFORMATION)FileInformation)-> 2220 CurrentByteOffset = FileObject->CurrentByteOffset; 2221 2222 /* Fill out the I/O Status Block */ 2223 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION); 2224 Status = IoStatusBlock->Status = STATUS_SUCCESS; 2225 } 2226 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2227 { 2228 /* Get the exception code */ 2229 Status = _SEH2_GetExceptionCode(); 2230 } 2231 _SEH2_END; 2232 2233 /* Release the file lock, dereference the file and return */ 2234 IopUnlockFileObject(FileObject); 2235 ObDereferenceObject(FileObject); 2236 return Status; 2237 } 2238 } 2239 else 2240 { 2241 /* Use local event */ 2242 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 2243 if (!Event) 2244 { 2245 ObDereferenceObject(FileObject); 2246 return STATUS_INSUFFICIENT_RESOURCES; 2247 } 2248 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 2249 LocalEvent = TRUE; 2250 } 2251 2252 /* Check if FastIO is possible for the two available information classes */ 2253 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 2254 if (FastIoDispatch != NULL && 2255 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) || 2256 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL))) 2257 { 2258 BOOLEAN Success = FALSE; 2259 2260 if (FileInformationClass == FileBasicInformation) 2261 { 2262 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE, 2263 FileInformation, 2264 &KernelIosb, 2265 DeviceObject); 2266 } 2267 else 2268 { 2269 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE, 2270 FileInformation, 2271 &KernelIosb, 2272 DeviceObject); 2273 } 2274 2275 /* If call succeed */ 2276 if (Success) 2277 { 2278 /* Write the IOSB back */ 2279 _SEH2_TRY 2280 { 2281 *IoStatusBlock = KernelIosb; 2282 } 2283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2284 { 2285 KernelIosb.Status = _SEH2_GetExceptionCode(); 2286 } 2287 _SEH2_END; 2288 2289 /* Free the event if we had one */ 2290 if (LocalEvent) 2291 { 2292 ExFreePoolWithTag(Event, TAG_IO); 2293 } 2294 2295 /* If FO was locked, unlock it */ 2296 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2297 { 2298 IopUnlockFileObject(FileObject); 2299 } 2300 2301 /* We're done with FastIO! */ 2302 ObDereferenceObject(FileObject); 2303 return KernelIosb.Status; 2304 } 2305 } 2306 2307 /* Clear the File Object event */ 2308 KeClearEvent(&FileObject->Event); 2309 2310 /* Allocate the IRP */ 2311 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2312 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 2313 2314 /* Set the IRP */ 2315 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2316 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2317 Irp->RequestorMode = PreviousMode; 2318 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 2319 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 2320 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 2321 Irp->UserEvent = (LocalEvent) ? Event : NULL; 2322 Irp->AssociatedIrp.SystemBuffer = NULL; 2323 Irp->MdlAddress = NULL; 2324 Irp->UserBuffer = FileInformation; 2325 2326 /* Set the Stack Data */ 2327 StackPtr = IoGetNextIrpStackLocation(Irp); 2328 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION; 2329 StackPtr->FileObject = FileObject; 2330 2331 /* Enter SEH */ 2332 _SEH2_TRY 2333 { 2334 /* Allocate a buffer */ 2335 Irp->AssociatedIrp.SystemBuffer = 2336 ExAllocatePoolWithTag(NonPagedPool, 2337 Length, 2338 TAG_SYSB); 2339 } 2340 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2341 { 2342 /* Allocating failed, clean up and return the exception code */ 2343 IopCleanupAfterException(FileObject, Irp, NULL, Event); 2344 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2345 } 2346 _SEH2_END; 2347 2348 /* Set the flags */ 2349 Irp->Flags |= (IRP_BUFFERED_IO | 2350 IRP_DEALLOCATE_BUFFER | 2351 IRP_INPUT_OPERATION | 2352 IRP_DEFER_IO_COMPLETION); 2353 2354 /* Set the Parameters */ 2355 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass; 2356 StackPtr->Parameters.QueryFile.Length = Length; 2357 2358 /* Queue the IRP */ 2359 IopQueueIrpToThread(Irp); 2360 2361 /* Update operation counts */ 2362 IopUpdateOperationCount(IopOtherTransfer); 2363 2364 /* Fill in file information before calling the driver. 2365 See 'File System Internals' page 485.*/ 2366 if (FileInformationClass == FileAccessInformation) 2367 { 2368 AccessBuffer = Irp->AssociatedIrp.SystemBuffer; 2369 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess; 2370 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION); 2371 CallDriver = FALSE; 2372 } 2373 else if (FileInformationClass == FileModeInformation) 2374 { 2375 ModeBuffer = Irp->AssociatedIrp.SystemBuffer; 2376 ModeBuffer->Mode = IopGetFileMode(FileObject); 2377 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION); 2378 CallDriver = FALSE; 2379 } 2380 else if (FileInformationClass == FileAlignmentInformation) 2381 { 2382 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer; 2383 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement; 2384 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION); 2385 CallDriver = FALSE; 2386 } 2387 else if (FileInformationClass == FileAllInformation) 2388 { 2389 AllBuffer = Irp->AssociatedIrp.SystemBuffer; 2390 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess; 2391 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject); 2392 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement; 2393 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) + 2394 sizeof(FILE_MODE_INFORMATION) + 2395 sizeof(FILE_ALIGNMENT_INFORMATION); 2396 } 2397 2398 /* Call the Driver */ 2399 if (CallDriver) 2400 { 2401 Status = IoCallDriver(DeviceObject, Irp); 2402 } 2403 else 2404 { 2405 Status = STATUS_SUCCESS; 2406 Irp->IoStatus.Status = STATUS_SUCCESS; 2407 } 2408 2409 if (Status == STATUS_PENDING) 2410 { 2411 /* Check if this was async I/O */ 2412 if (LocalEvent) 2413 { 2414 /* Then to a non-alertable wait */ 2415 Status = KeWaitForSingleObject(Event, 2416 Executive, 2417 PreviousMode, 2418 FALSE, 2419 NULL); 2420 if (Status == STATUS_USER_APC) 2421 { 2422 /* Abort the request */ 2423 IopAbortInterruptedIrp(Event, Irp); 2424 } 2425 2426 /* Set the final status */ 2427 Status = KernelIosb.Status; 2428 2429 /* Enter SEH to write the IOSB back */ 2430 _SEH2_TRY 2431 { 2432 /* Write it back to the caller */ 2433 *IoStatusBlock = KernelIosb; 2434 } 2435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2436 { 2437 /* Get the exception code */ 2438 Status = _SEH2_GetExceptionCode(); 2439 } 2440 _SEH2_END; 2441 2442 /* Free the event */ 2443 ExFreePoolWithTag(Event, TAG_IO); 2444 } 2445 else 2446 { 2447 /* Wait for the IRP */ 2448 Status = KeWaitForSingleObject(&FileObject->Event, 2449 Executive, 2450 PreviousMode, 2451 (FileObject->Flags & 2452 FO_ALERTABLE_IO) != 0, 2453 NULL); 2454 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) 2455 { 2456 /* Abort the request */ 2457 IopAbortInterruptedIrp(&FileObject->Event, Irp); 2458 } 2459 2460 /* Set the final status */ 2461 Status = FileObject->FinalStatus; 2462 2463 /* Release the file lock */ 2464 IopUnlockFileObject(FileObject); 2465 } 2466 } 2467 else 2468 { 2469 /* Free the event if we had one */ 2470 if (LocalEvent) 2471 { 2472 /* Clear it in the IRP for completion */ 2473 Irp->UserEvent = NULL; 2474 ExFreePoolWithTag(Event, TAG_IO); 2475 } 2476 2477 /* Set the caller IOSB */ 2478 Irp->UserIosb = IoStatusBlock; 2479 2480 /* The IRP wasn't completed, complete it ourselves */ 2481 KeRaiseIrql(APC_LEVEL, &OldIrql); 2482 IopCompleteRequest(&Irp->Tail.Apc, 2483 &NormalRoutine, 2484 &NormalContext, 2485 (PVOID*)&FileObject, 2486 &NormalContext); 2487 KeLowerIrql(OldIrql); 2488 2489 /* Release the file object if we had locked it*/ 2490 if (!LocalEvent) IopUnlockFileObject(FileObject); 2491 } 2492 2493 /* Return the Status */ 2494 return Status; 2495 } 2496 2497 /* 2498 * @unimplemented 2499 */ 2500 NTSTATUS 2501 NTAPI 2502 NtQueryQuotaInformationFile(IN HANDLE FileHandle, 2503 OUT PIO_STATUS_BLOCK IoStatusBlock, 2504 OUT PVOID Buffer, 2505 IN ULONG Length, 2506 IN BOOLEAN ReturnSingleEntry, 2507 IN PVOID SidList OPTIONAL, 2508 IN ULONG SidListLength, 2509 IN PSID StartSid OPTIONAL, 2510 IN BOOLEAN RestartScan) 2511 { 2512 UNIMPLEMENTED; 2513 return STATUS_NOT_IMPLEMENTED; 2514 } 2515 2516 /* 2517 * @implemented 2518 */ 2519 NTSTATUS 2520 NTAPI 2521 NtReadFile(IN HANDLE FileHandle, 2522 IN HANDLE Event OPTIONAL, 2523 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 2524 IN PVOID ApcContext OPTIONAL, 2525 OUT PIO_STATUS_BLOCK IoStatusBlock, 2526 OUT PVOID Buffer, 2527 IN ULONG Length, 2528 IN PLARGE_INTEGER ByteOffset OPTIONAL, 2529 IN PULONG Key OPTIONAL) 2530 { 2531 NTSTATUS Status; 2532 PFILE_OBJECT FileObject; 2533 PIRP Irp; 2534 PDEVICE_OBJECT DeviceObject; 2535 PIO_STACK_LOCATION StackPtr; 2536 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 2537 PKEVENT EventObject = NULL; 2538 LARGE_INTEGER CapturedByteOffset; 2539 ULONG CapturedKey = 0; 2540 BOOLEAN Synchronous = FALSE; 2541 PMDL Mdl; 2542 PFAST_IO_DISPATCH FastIoDispatch; 2543 IO_STATUS_BLOCK KernelIosb; 2544 BOOLEAN Success; 2545 2546 PAGED_CODE(); 2547 CapturedByteOffset.QuadPart = 0; 2548 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2549 2550 /* Validate User-Mode Buffers */ 2551 if (PreviousMode != KernelMode) 2552 { 2553 _SEH2_TRY 2554 { 2555 /* Probe the status block */ 2556 ProbeForWriteIoStatusBlock(IoStatusBlock); 2557 2558 /* Probe the read buffer */ 2559 ProbeForWrite(Buffer, Length, 1); 2560 2561 /* Check if we got a byte offset */ 2562 if (ByteOffset) 2563 { 2564 /* Capture and probe it */ 2565 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 2566 } 2567 2568 /* Capture and probe the key */ 2569 if (Key) CapturedKey = ProbeForReadUlong(Key); 2570 } 2571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2572 { 2573 /* Return the exception code */ 2574 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2575 } 2576 _SEH2_END; 2577 } 2578 else 2579 { 2580 /* Kernel mode: capture directly */ 2581 if (ByteOffset) CapturedByteOffset = *ByteOffset; 2582 if (Key) CapturedKey = *Key; 2583 } 2584 2585 /* Get File Object */ 2586 Status = ObReferenceObjectByHandle(FileHandle, 2587 FILE_READ_DATA, 2588 IoFileObjectType, 2589 PreviousMode, 2590 (PVOID*)&FileObject, 2591 NULL); 2592 if (!NT_SUCCESS(Status)) return Status; 2593 2594 /* Check for event */ 2595 if (Event) 2596 { 2597 /* Reference it */ 2598 Status = ObReferenceObjectByHandle(Event, 2599 EVENT_MODIFY_STATE, 2600 ExEventObjectType, 2601 PreviousMode, 2602 (PVOID*)&EventObject, 2603 NULL); 2604 if (!NT_SUCCESS(Status)) 2605 { 2606 /* Fail */ 2607 ObDereferenceObject(FileObject); 2608 return Status; 2609 } 2610 2611 /* Otherwise reset the event */ 2612 KeClearEvent(EventObject); 2613 } 2614 2615 /* Get the device object */ 2616 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2617 2618 /* Check if we should use Sync IO or not */ 2619 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2620 { 2621 /* Lock the file object */ 2622 IopLockFileObject(FileObject); 2623 2624 /* Check if we don't have a byte offset available */ 2625 if (!(ByteOffset) || 2626 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && 2627 (CapturedByteOffset.u.HighPart == -1))) 2628 { 2629 /* Use the Current Byte Offset instead */ 2630 CapturedByteOffset = FileObject->CurrentByteOffset; 2631 } 2632 2633 /* If the file is cached, try fast I/O */ 2634 if (FileObject->PrivateCacheMap) 2635 { 2636 /* Perform fast read */ 2637 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 2638 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL); 2639 2640 Success = FastIoDispatch->FastIoRead(FileObject, 2641 &CapturedByteOffset, 2642 Length, 2643 TRUE, 2644 CapturedKey, 2645 Buffer, 2646 &KernelIosb, 2647 DeviceObject); 2648 2649 /* Only accept the result if we got a straightforward status */ 2650 if (Success && 2651 (KernelIosb.Status == STATUS_SUCCESS || 2652 KernelIosb.Status == STATUS_BUFFER_OVERFLOW || 2653 KernelIosb.Status == STATUS_END_OF_FILE)) 2654 { 2655 /* Fast path -- update transfer & operation counts */ 2656 IopUpdateOperationCount(IopReadTransfer); 2657 IopUpdateTransferCount(IopReadTransfer, 2658 (ULONG)KernelIosb.Information); 2659 2660 /* Enter SEH to write the IOSB back */ 2661 _SEH2_TRY 2662 { 2663 /* Write it back to the caller */ 2664 *IoStatusBlock = KernelIosb; 2665 } 2666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2667 { 2668 /* The caller's IOSB was invalid, so fail */ 2669 if (EventObject) ObDereferenceObject(EventObject); 2670 IopUnlockFileObject(FileObject); 2671 ObDereferenceObject(FileObject); 2672 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2673 } 2674 _SEH2_END; 2675 2676 /* Signal the completion event */ 2677 if (EventObject) 2678 { 2679 KeSetEvent(EventObject, 0, FALSE); 2680 ObDereferenceObject(EventObject); 2681 } 2682 2683 /* Clean up */ 2684 IopUnlockFileObject(FileObject); 2685 ObDereferenceObject(FileObject); 2686 return KernelIosb.Status; 2687 } 2688 } 2689 2690 /* Remember we are sync */ 2691 Synchronous = TRUE; 2692 } 2693 else if (!(ByteOffset) && 2694 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) 2695 { 2696 /* Otherwise, this was async I/O without a byte offset, so fail */ 2697 if (EventObject) ObDereferenceObject(EventObject); 2698 ObDereferenceObject(FileObject); 2699 return STATUS_INVALID_PARAMETER; 2700 } 2701 2702 /* Clear the File Object's event */ 2703 KeClearEvent(&FileObject->Event); 2704 2705 /* Allocate the IRP */ 2706 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2707 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 2708 2709 /* Set the IRP */ 2710 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2711 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2712 Irp->RequestorMode = PreviousMode; 2713 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 2714 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 2715 Irp->UserIosb = IoStatusBlock; 2716 Irp->UserEvent = EventObject; 2717 Irp->PendingReturned = FALSE; 2718 Irp->Cancel = FALSE; 2719 Irp->CancelRoutine = NULL; 2720 Irp->AssociatedIrp.SystemBuffer = NULL; 2721 Irp->MdlAddress = NULL; 2722 2723 /* Set the Stack Data */ 2724 StackPtr = IoGetNextIrpStackLocation(Irp); 2725 StackPtr->MajorFunction = IRP_MJ_READ; 2726 StackPtr->FileObject = FileObject; 2727 StackPtr->Parameters.Read.Key = CapturedKey; 2728 StackPtr->Parameters.Read.Length = Length; 2729 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset; 2730 2731 /* Check if this is buffered I/O */ 2732 if (DeviceObject->Flags & DO_BUFFERED_IO) 2733 { 2734 /* Check if we have a buffer length */ 2735 if (Length) 2736 { 2737 /* Enter SEH */ 2738 _SEH2_TRY 2739 { 2740 /* Allocate a buffer */ 2741 Irp->AssociatedIrp.SystemBuffer = 2742 ExAllocatePoolWithTag(NonPagedPool, 2743 Length, 2744 TAG_SYSB); 2745 } 2746 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2747 { 2748 /* Allocating failed, clean up and return the exception code */ 2749 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 2750 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2751 } 2752 _SEH2_END; 2753 2754 /* Set the buffer and flags */ 2755 Irp->UserBuffer = Buffer; 2756 Irp->Flags = (IRP_BUFFERED_IO | 2757 IRP_DEALLOCATE_BUFFER | 2758 IRP_INPUT_OPERATION); 2759 } 2760 else 2761 { 2762 /* Not reading anything */ 2763 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; 2764 } 2765 } 2766 else if (DeviceObject->Flags & DO_DIRECT_IO) 2767 { 2768 /* Check if we have a buffer length */ 2769 if (Length) 2770 { 2771 _SEH2_TRY 2772 { 2773 /* Allocate an MDL */ 2774 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); 2775 if (!Mdl) 2776 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2777 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); 2778 } 2779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2780 { 2781 /* Allocating failed, clean up and return the exception code */ 2782 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 2783 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2784 } 2785 _SEH2_END; 2786 2787 } 2788 2789 /* No allocation flags */ 2790 Irp->Flags = 0; 2791 } 2792 else 2793 { 2794 /* No allocation flags, and use the buffer directly */ 2795 Irp->Flags = 0; 2796 Irp->UserBuffer = Buffer; 2797 } 2798 2799 /* Now set the deferred read flags */ 2800 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION); 2801 #if 0 2802 /* FIXME: VFAT SUCKS */ 2803 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; 2804 #endif 2805 2806 /* Perform the call */ 2807 return IopPerformSynchronousRequest(DeviceObject, 2808 Irp, 2809 FileObject, 2810 TRUE, 2811 PreviousMode, 2812 Synchronous, 2813 IopReadTransfer); 2814 } 2815 2816 /* 2817 * @unimplemented 2818 */ 2819 NTSTATUS 2820 NTAPI 2821 NtReadFileScatter(IN HANDLE FileHandle, 2822 IN HANDLE Event OPTIONAL, 2823 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 2824 IN PVOID UserApcContext OPTIONAL, 2825 OUT PIO_STATUS_BLOCK UserIoStatusBlock, 2826 IN FILE_SEGMENT_ELEMENT BufferDescription [], 2827 IN ULONG BufferLength, 2828 IN PLARGE_INTEGER ByteOffset, 2829 IN PULONG Key OPTIONAL) 2830 { 2831 UNIMPLEMENTED; 2832 return STATUS_NOT_IMPLEMENTED; 2833 } 2834 2835 /* 2836 * @unimplemented 2837 */ 2838 NTSTATUS 2839 NTAPI 2840 NtSetEaFile(IN HANDLE FileHandle, 2841 IN PIO_STATUS_BLOCK IoStatusBlock, 2842 IN PVOID EaBuffer, 2843 IN ULONG EaBufferSize) 2844 { 2845 UNIMPLEMENTED; 2846 return STATUS_NOT_IMPLEMENTED; 2847 } 2848 2849 /* 2850 * @implemented 2851 */ 2852 NTSTATUS 2853 NTAPI 2854 NtSetInformationFile(IN HANDLE FileHandle, 2855 OUT PIO_STATUS_BLOCK IoStatusBlock, 2856 IN PVOID FileInformation, 2857 IN ULONG Length, 2858 IN FILE_INFORMATION_CLASS FileInformationClass) 2859 { 2860 PFILE_OBJECT FileObject; 2861 NTSTATUS Status; 2862 PIRP Irp; 2863 PDEVICE_OBJECT DeviceObject; 2864 PIO_STACK_LOCATION StackPtr; 2865 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2866 PKEVENT Event = NULL; 2867 BOOLEAN LocalEvent = FALSE; 2868 PKNORMAL_ROUTINE NormalRoutine; 2869 PVOID NormalContext; 2870 KIRQL OldIrql; 2871 IO_STATUS_BLOCK KernelIosb; 2872 PVOID Queue; 2873 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation; 2874 PIO_COMPLETION_CONTEXT Context; 2875 PFILE_RENAME_INFORMATION RenameInfo; 2876 HANDLE TargetHandle = NULL; 2877 PAGED_CODE(); 2878 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2879 2880 /* Check if we're called from user mode */ 2881 if (PreviousMode != KernelMode) 2882 { 2883 /* Validate the information class */ 2884 if ((FileInformationClass >= FileMaximumInformation) || 2885 !(IopSetOperationLength[FileInformationClass])) 2886 { 2887 /* Invalid class */ 2888 return STATUS_INVALID_INFO_CLASS; 2889 } 2890 2891 /* Validate the length */ 2892 if (Length < IopSetOperationLength[FileInformationClass]) 2893 { 2894 /* Invalid length */ 2895 return STATUS_INFO_LENGTH_MISMATCH; 2896 } 2897 2898 /* Enter SEH for probing */ 2899 _SEH2_TRY 2900 { 2901 /* Probe the I/O Status block */ 2902 ProbeForWriteIoStatusBlock(IoStatusBlock); 2903 2904 /* Probe the information */ 2905 ProbeForRead(FileInformation, 2906 Length, 2907 (Length == sizeof(BOOLEAN)) ? 2908 sizeof(BOOLEAN) : sizeof(ULONG)); 2909 } 2910 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2911 { 2912 /* Return the exception code */ 2913 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2914 } 2915 _SEH2_END; 2916 } 2917 else 2918 { 2919 /* Validate the information class */ 2920 if ((FileInformationClass >= FileMaximumInformation) || 2921 !(IopSetOperationLength[FileInformationClass])) 2922 { 2923 /* Invalid class */ 2924 return STATUS_INVALID_INFO_CLASS; 2925 } 2926 2927 /* Validate the length */ 2928 if (Length < IopSetOperationLength[FileInformationClass]) 2929 { 2930 /* Invalid length */ 2931 return STATUS_INFO_LENGTH_MISMATCH; 2932 } 2933 } 2934 2935 /* Reference the Handle */ 2936 Status = ObReferenceObjectByHandle(FileHandle, 2937 IopSetOperationAccess 2938 [FileInformationClass], 2939 IoFileObjectType, 2940 PreviousMode, 2941 (PVOID *)&FileObject, 2942 NULL); 2943 if (!NT_SUCCESS(Status)) return Status; 2944 2945 /* Check if this is a direct open or not */ 2946 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 2947 { 2948 /* Get the device object */ 2949 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 2950 } 2951 else 2952 { 2953 /* Get the device object */ 2954 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2955 } 2956 2957 DPRINT("Will call: %p\n", DeviceObject); 2958 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName); 2959 2960 /* Check if this is a file that was opened for Synch I/O */ 2961 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2962 { 2963 /* Lock it */ 2964 IopLockFileObject(FileObject); 2965 2966 /* Check if the caller just wants the position */ 2967 if (FileInformationClass == FilePositionInformation) 2968 { 2969 /* Protect write in SEH */ 2970 _SEH2_TRY 2971 { 2972 /* Write the offset */ 2973 FileObject->CurrentByteOffset = 2974 ((PFILE_POSITION_INFORMATION)FileInformation)-> 2975 CurrentByteOffset; 2976 2977 /* Fill out the I/O Status Block */ 2978 IoStatusBlock->Information = 0; 2979 Status = IoStatusBlock->Status = STATUS_SUCCESS; 2980 } 2981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2982 { 2983 /* Get the exception code */ 2984 Status = _SEH2_GetExceptionCode(); 2985 } 2986 _SEH2_END; 2987 2988 /* Update transfer count */ 2989 IopUpdateTransferCount(IopOtherTransfer, Length); 2990 2991 /* Release the file lock, dereference the file and return */ 2992 IopUnlockFileObject(FileObject); 2993 ObDereferenceObject(FileObject); 2994 return Status; 2995 } 2996 } 2997 else 2998 { 2999 /* Use local event */ 3000 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3001 if (!Event) 3002 { 3003 ObDereferenceObject(FileObject); 3004 return STATUS_INSUFFICIENT_RESOURCES; 3005 } 3006 3007 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3008 LocalEvent = TRUE; 3009 } 3010 3011 /* Clear the File Object event */ 3012 KeClearEvent(&FileObject->Event); 3013 3014 /* Allocate the IRP */ 3015 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 3016 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3017 3018 /* Set the IRP */ 3019 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3020 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3021 Irp->RequestorMode = PreviousMode; 3022 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3023 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3024 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3025 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3026 Irp->AssociatedIrp.SystemBuffer = NULL; 3027 Irp->MdlAddress = NULL; 3028 Irp->UserBuffer = FileInformation; 3029 3030 /* Set the Stack Data */ 3031 StackPtr = IoGetNextIrpStackLocation(Irp); 3032 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; 3033 StackPtr->FileObject = FileObject; 3034 3035 /* Enter SEH */ 3036 _SEH2_TRY 3037 { 3038 /* Allocate a buffer */ 3039 Irp->AssociatedIrp.SystemBuffer = 3040 ExAllocatePoolWithTag(NonPagedPool, 3041 Length, 3042 TAG_SYSB); 3043 3044 /* Copy the data into it */ 3045 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 3046 FileInformation, 3047 Length); 3048 } 3049 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3050 { 3051 /* Allocating failed, clean up and return the exception code */ 3052 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3053 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3054 } 3055 _SEH2_END; 3056 3057 /* Set the flags */ 3058 Irp->Flags |= (IRP_BUFFERED_IO | 3059 IRP_DEALLOCATE_BUFFER | 3060 IRP_DEFER_IO_COMPLETION); 3061 3062 /* Set the Parameters */ 3063 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; 3064 StackPtr->Parameters.SetFile.Length = Length; 3065 3066 /* Queue the IRP */ 3067 IopQueueIrpToThread(Irp); 3068 3069 /* Update operation counts */ 3070 IopUpdateOperationCount(IopOtherTransfer); 3071 3072 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */ 3073 /* Handle IO Completion Port quickly */ 3074 if (FileInformationClass == FileCompletionInformation) 3075 { 3076 /* Check if the file object already has a completion port */ 3077 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || 3078 (FileObject->CompletionContext)) 3079 { 3080 /* Fail */ 3081 Status = STATUS_INVALID_PARAMETER; 3082 } 3083 else 3084 { 3085 /* Reference the Port */ 3086 CompletionInfo = Irp->AssociatedIrp.SystemBuffer; 3087 Status = ObReferenceObjectByHandle(CompletionInfo->Port, 3088 IO_COMPLETION_MODIFY_STATE, 3089 IoCompletionType, 3090 PreviousMode, 3091 (PVOID*)&Queue, 3092 NULL); 3093 if (NT_SUCCESS(Status)) 3094 { 3095 /* Allocate the Context */ 3096 Context = ExAllocatePoolWithTag(PagedPool, 3097 sizeof(IO_COMPLETION_CONTEXT), 3098 IOC_TAG); 3099 if (Context) 3100 { 3101 /* Set the Data */ 3102 Context->Key = CompletionInfo->Key; 3103 Context->Port = Queue; 3104 if (InterlockedCompareExchangePointer((PVOID*)&FileObject-> 3105 CompletionContext, 3106 Context, 3107 NULL)) 3108 { 3109 /* 3110 * Someone else set the completion port in the 3111 * meanwhile, so dereference the port and fail. 3112 */ 3113 ExFreePoolWithTag(Context, IOC_TAG); 3114 ObDereferenceObject(Queue); 3115 Status = STATUS_INVALID_PARAMETER; 3116 } 3117 } 3118 else 3119 { 3120 /* Dereference the Port now */ 3121 ObDereferenceObject(Queue); 3122 Status = STATUS_INSUFFICIENT_RESOURCES; 3123 } 3124 } 3125 } 3126 3127 /* Set the IRP Status */ 3128 Irp->IoStatus.Status = Status; 3129 Irp->IoStatus.Information = 0; 3130 } 3131 else if (FileInformationClass == FileRenameInformation || 3132 FileInformationClass == FileLinkInformation || 3133 FileInformationClass == FileMoveClusterInformation) 3134 { 3135 /* Get associated information */ 3136 RenameInfo = Irp->AssociatedIrp.SystemBuffer; 3137 3138 /* Only rename if: 3139 * -> We have a name 3140 * -> In unicode 3141 * -> sizes are valid 3142 */ 3143 if (RenameInfo->FileNameLength != 0 && 3144 !(RenameInfo->FileNameLength & 1) && 3145 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength)) 3146 { 3147 /* Properly set information received */ 3148 if (FileInformationClass == FileMoveClusterInformation) 3149 { 3150 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount; 3151 } 3152 else 3153 { 3154 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists; 3155 } 3156 3157 /* If we got fully path OR relative target, attempt a parent directory open */ 3158 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory) 3159 { 3160 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject); 3161 if (!NT_SUCCESS(Status)) 3162 { 3163 Irp->IoStatus.Status = Status; 3164 } 3165 else 3166 { 3167 /* Call the Driver */ 3168 Status = IoCallDriver(DeviceObject, Irp); 3169 } 3170 } 3171 else 3172 { 3173 /* Call the Driver */ 3174 Status = IoCallDriver(DeviceObject, Irp); 3175 } 3176 } 3177 else 3178 { 3179 Status = STATUS_INVALID_PARAMETER; 3180 Irp->IoStatus.Status = Status; 3181 } 3182 } 3183 else 3184 { 3185 /* Call the Driver */ 3186 Status = IoCallDriver(DeviceObject, Irp); 3187 } 3188 3189 /* Check if we're waiting for the IRP to complete */ 3190 if (Status == STATUS_PENDING) 3191 { 3192 /* Check if this was async I/O */ 3193 if (LocalEvent) 3194 { 3195 /* Then to a non-alertable wait */ 3196 Status = KeWaitForSingleObject(Event, 3197 Executive, 3198 PreviousMode, 3199 FALSE, 3200 NULL); 3201 if (Status == STATUS_USER_APC) 3202 { 3203 /* Abort the request */ 3204 IopAbortInterruptedIrp(Event, Irp); 3205 } 3206 3207 /* Set the final status */ 3208 Status = KernelIosb.Status; 3209 3210 /* Enter SEH to write the IOSB back */ 3211 _SEH2_TRY 3212 { 3213 /* Write it back to the caller */ 3214 *IoStatusBlock = KernelIosb; 3215 } 3216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3217 { 3218 /* Get the exception code */ 3219 Status = _SEH2_GetExceptionCode(); 3220 } 3221 _SEH2_END; 3222 3223 /* Free the event */ 3224 ExFreePoolWithTag(Event, TAG_IO); 3225 } 3226 else 3227 { 3228 /* Wait for the IRP */ 3229 Status = KeWaitForSingleObject(&FileObject->Event, 3230 Executive, 3231 PreviousMode, 3232 (FileObject->Flags & 3233 FO_ALERTABLE_IO) != 0, 3234 NULL); 3235 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) 3236 { 3237 /* Abort the request */ 3238 IopAbortInterruptedIrp(&FileObject->Event, Irp); 3239 } 3240 3241 /* Set the final status */ 3242 Status = FileObject->FinalStatus; 3243 3244 /* Release the file lock */ 3245 IopUnlockFileObject(FileObject); 3246 } 3247 } 3248 else 3249 { 3250 /* Free the event if we had one */ 3251 if (LocalEvent) 3252 { 3253 /* Clear it in the IRP for completion */ 3254 Irp->UserEvent = NULL; 3255 ExFreePoolWithTag(Event, TAG_IO); 3256 } 3257 3258 /* Set the caller IOSB */ 3259 Irp->UserIosb = IoStatusBlock; 3260 3261 /* The IRP wasn't completed, complete it ourselves */ 3262 KeRaiseIrql(APC_LEVEL, &OldIrql); 3263 IopCompleteRequest(&Irp->Tail.Apc, 3264 &NormalRoutine, 3265 &NormalContext, 3266 (PVOID*)&FileObject, 3267 &NormalContext); 3268 KeLowerIrql(OldIrql); 3269 3270 /* Release the file object if we had locked it*/ 3271 if (!LocalEvent) IopUnlockFileObject(FileObject); 3272 } 3273 3274 if (TargetHandle != NULL) 3275 { 3276 ObCloseHandle(TargetHandle, KernelMode); 3277 } 3278 3279 /* Return the Status */ 3280 return Status; 3281 } 3282 3283 /* 3284 * @unimplemented 3285 */ 3286 NTSTATUS 3287 NTAPI 3288 NtSetQuotaInformationFile(IN HANDLE FileHandle, 3289 OUT PIO_STATUS_BLOCK IoStatusBlock, 3290 IN PVOID Buffer, 3291 IN ULONG BufferLength) 3292 { 3293 UNIMPLEMENTED; 3294 return STATUS_NOT_IMPLEMENTED; 3295 } 3296 3297 /* 3298 * @implemented 3299 */ 3300 NTSTATUS 3301 NTAPI 3302 NtUnlockFile(IN HANDLE FileHandle, 3303 OUT PIO_STATUS_BLOCK IoStatusBlock, 3304 IN PLARGE_INTEGER ByteOffset, 3305 IN PLARGE_INTEGER Length, 3306 IN ULONG Key OPTIONAL) 3307 { 3308 PFILE_OBJECT FileObject; 3309 PLARGE_INTEGER LocalLength = NULL; 3310 PIRP Irp; 3311 PIO_STACK_LOCATION StackPtr; 3312 PDEVICE_OBJECT DeviceObject; 3313 PKEVENT Event = NULL; 3314 BOOLEAN LocalEvent = FALSE; 3315 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3316 LARGE_INTEGER CapturedByteOffset, CapturedLength; 3317 NTSTATUS Status; 3318 OBJECT_HANDLE_INFORMATION HandleInformation; 3319 IO_STATUS_BLOCK KernelIosb; 3320 PFAST_IO_DISPATCH FastIoDispatch; 3321 PAGED_CODE(); 3322 CapturedByteOffset.QuadPart = 0; 3323 CapturedLength.QuadPart = 0; 3324 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3325 3326 /* Get File Object */ 3327 Status = ObReferenceObjectByHandle(FileHandle, 3328 0, 3329 IoFileObjectType, 3330 PreviousMode, 3331 (PVOID*)&FileObject, 3332 &HandleInformation); 3333 if (!NT_SUCCESS(Status)) return Status; 3334 3335 /* Check if we're called from user mode */ 3336 if (PreviousMode != KernelMode) 3337 { 3338 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */ 3339 if (!(HandleInformation.GrantedAccess & 3340 (FILE_WRITE_DATA | FILE_READ_DATA))) 3341 { 3342 ObDereferenceObject(FileObject); 3343 return STATUS_ACCESS_DENIED; 3344 } 3345 3346 /* Enter SEH for probing */ 3347 _SEH2_TRY 3348 { 3349 /* Probe the I/O Status block */ 3350 ProbeForWriteIoStatusBlock(IoStatusBlock); 3351 3352 /* Probe and capture the large integers */ 3353 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 3354 CapturedLength = ProbeForReadLargeInteger(Length); 3355 } 3356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3357 { 3358 /* Dereference the object and return exception code */ 3359 ObDereferenceObject(FileObject); 3360 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3361 } 3362 _SEH2_END; 3363 } 3364 else 3365 { 3366 /* Otherwise, capture them directly */ 3367 CapturedByteOffset = *ByteOffset; 3368 CapturedLength = *Length; 3369 } 3370 3371 /* Check if this is a direct open or not */ 3372 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 3373 { 3374 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 3375 } 3376 else 3377 { 3378 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3379 } 3380 3381 /* Try to do it the FastIO way if possible */ 3382 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 3383 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL) 3384 { 3385 if (FastIoDispatch->FastIoUnlockSingle(FileObject, 3386 &CapturedByteOffset, 3387 &CapturedLength, 3388 PsGetCurrentProcess(), 3389 Key, 3390 &KernelIosb, 3391 DeviceObject)) 3392 { 3393 /* Write the IOSB back */ 3394 _SEH2_TRY 3395 { 3396 *IoStatusBlock = KernelIosb; 3397 } 3398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3399 { 3400 KernelIosb.Status = _SEH2_GetExceptionCode(); 3401 } 3402 _SEH2_END; 3403 3404 /* We're done with FastIO! */ 3405 ObDereferenceObject(FileObject); 3406 return KernelIosb.Status; 3407 } 3408 } 3409 3410 /* Check if we should use Sync IO or not */ 3411 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3412 { 3413 /* Lock it */ 3414 IopLockFileObject(FileObject); 3415 } 3416 else 3417 { 3418 /* Use local event */ 3419 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3420 if (!Event) 3421 { 3422 ObDereferenceObject(FileObject); 3423 return STATUS_INSUFFICIENT_RESOURCES; 3424 } 3425 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3426 LocalEvent = TRUE; 3427 } 3428 3429 /* Clear File Object event */ 3430 KeClearEvent(&FileObject->Event); 3431 3432 /* Allocate the IRP */ 3433 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3434 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3435 3436 /* Set up the IRP */ 3437 Irp->RequestorMode = PreviousMode; 3438 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3439 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3440 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3441 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3442 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3443 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3444 3445 /* Set up Stack Data */ 3446 StackPtr = IoGetNextIrpStackLocation(Irp); 3447 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; 3448 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE; 3449 StackPtr->FileObject = FileObject; 3450 3451 /* Enter SEH */ 3452 _SEH2_TRY 3453 { 3454 /* Allocate a buffer */ 3455 LocalLength = ExAllocatePoolWithTag(NonPagedPool, 3456 sizeof(LARGE_INTEGER), 3457 TAG_LOCK); 3458 3459 /* Set the length */ 3460 *LocalLength = CapturedLength; 3461 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength; 3462 StackPtr->Parameters.LockControl.Length = LocalLength; 3463 } 3464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3465 { 3466 /* Allocating failed, clean up and return the exception code */ 3467 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3468 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK); 3469 3470 /* Return the exception code */ 3471 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3472 } 3473 _SEH2_END; 3474 3475 /* Set Parameters */ 3476 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset; 3477 StackPtr->Parameters.LockControl.Key = Key; 3478 3479 /* Call the Driver */ 3480 Status = IopPerformSynchronousRequest(DeviceObject, 3481 Irp, 3482 FileObject, 3483 FALSE, 3484 PreviousMode, 3485 !LocalEvent, 3486 IopOtherTransfer); 3487 3488 /* Check if this was async I/O */ 3489 if (LocalEvent) 3490 { 3491 /* It was, finalize this request */ 3492 Status = IopFinalizeAsynchronousIo(Status, 3493 Event, 3494 Irp, 3495 PreviousMode, 3496 &KernelIosb, 3497 IoStatusBlock); 3498 } 3499 3500 /* Return status */ 3501 return Status; 3502 } 3503 3504 /* 3505 * @implemented 3506 */ 3507 NTSTATUS 3508 NTAPI 3509 NtWriteFile(IN HANDLE FileHandle, 3510 IN HANDLE Event OPTIONAL, 3511 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 3512 IN PVOID ApcContext OPTIONAL, 3513 OUT PIO_STATUS_BLOCK IoStatusBlock, 3514 IN PVOID Buffer, 3515 IN ULONG Length, 3516 IN PLARGE_INTEGER ByteOffset OPTIONAL, 3517 IN PULONG Key OPTIONAL) 3518 { 3519 NTSTATUS Status; 3520 PFILE_OBJECT FileObject; 3521 PIRP Irp; 3522 PDEVICE_OBJECT DeviceObject; 3523 PIO_STACK_LOCATION StackPtr; 3524 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3525 PKEVENT EventObject = NULL; 3526 LARGE_INTEGER CapturedByteOffset; 3527 ULONG CapturedKey = 0; 3528 BOOLEAN Synchronous = FALSE; 3529 PMDL Mdl; 3530 OBJECT_HANDLE_INFORMATION ObjectHandleInfo; 3531 PFAST_IO_DISPATCH FastIoDispatch; 3532 IO_STATUS_BLOCK KernelIosb; 3533 BOOLEAN Success; 3534 3535 PAGED_CODE(); 3536 CapturedByteOffset.QuadPart = 0; 3537 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3538 3539 /* Get File Object for write */ 3540 Status = ObReferenceFileObjectForWrite(FileHandle, 3541 PreviousMode, 3542 &FileObject, 3543 &ObjectHandleInfo); 3544 if (!NT_SUCCESS(Status)) return Status; 3545 3546 /* Validate User-Mode Buffers */ 3547 if (PreviousMode != KernelMode) 3548 { 3549 _SEH2_TRY 3550 { 3551 /* Probe the status block */ 3552 ProbeForWriteIoStatusBlock(IoStatusBlock); 3553 3554 /* Probe the read buffer */ 3555 ProbeForRead(Buffer, Length, 1); 3556 3557 /* Check if we got a byte offset */ 3558 if (ByteOffset) 3559 { 3560 /* Capture and probe it */ 3561 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 3562 } 3563 3564 /* Capture and probe the key */ 3565 if (Key) CapturedKey = ProbeForReadUlong(Key); 3566 } 3567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3568 { 3569 /* Release the file object and return the exception code */ 3570 ObDereferenceObject(FileObject); 3571 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3572 } 3573 _SEH2_END; 3574 } 3575 else 3576 { 3577 /* Kernel mode: capture directly */ 3578 if (ByteOffset) CapturedByteOffset = *ByteOffset; 3579 if (Key) CapturedKey = *Key; 3580 } 3581 3582 /* Check if this is an append operation */ 3583 if ((ObjectHandleInfo.GrantedAccess & 3584 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA) 3585 { 3586 /* Give the drivers something to understand */ 3587 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE; 3588 CapturedByteOffset.u.HighPart = -1; 3589 } 3590 3591 /* Check for event */ 3592 if (Event) 3593 { 3594 /* Reference it */ 3595 Status = ObReferenceObjectByHandle(Event, 3596 EVENT_MODIFY_STATE, 3597 ExEventObjectType, 3598 PreviousMode, 3599 (PVOID*)&EventObject, 3600 NULL); 3601 if (!NT_SUCCESS(Status)) 3602 { 3603 /* Fail */ 3604 ObDereferenceObject(FileObject); 3605 return Status; 3606 } 3607 3608 /* Otherwise reset the event */ 3609 KeClearEvent(EventObject); 3610 } 3611 3612 /* Get the device object */ 3613 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3614 3615 /* Check if we should use Sync IO or not */ 3616 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3617 { 3618 /* Lock the file object */ 3619 IopLockFileObject(FileObject); 3620 3621 /* Check if we don't have a byte offset available */ 3622 if (!(ByteOffset) || 3623 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && 3624 (CapturedByteOffset.u.HighPart == -1))) 3625 { 3626 /* Use the Current Byte Offset instead */ 3627 CapturedByteOffset = FileObject->CurrentByteOffset; 3628 } 3629 3630 /* If the file is cached, try fast I/O */ 3631 if (FileObject->PrivateCacheMap) 3632 { 3633 /* Perform fast write */ 3634 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 3635 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL); 3636 3637 Success = FastIoDispatch->FastIoWrite(FileObject, 3638 &CapturedByteOffset, 3639 Length, 3640 TRUE, 3641 CapturedKey, 3642 Buffer, 3643 &KernelIosb, 3644 DeviceObject); 3645 3646 /* Only accept the result if it was successful */ 3647 if (Success && 3648 KernelIosb.Status == STATUS_SUCCESS) 3649 { 3650 /* Fast path -- update transfer & operation counts */ 3651 IopUpdateOperationCount(IopWriteTransfer); 3652 IopUpdateTransferCount(IopWriteTransfer, 3653 (ULONG)KernelIosb.Information); 3654 3655 /* Enter SEH to write the IOSB back */ 3656 _SEH2_TRY 3657 { 3658 /* Write it back to the caller */ 3659 *IoStatusBlock = KernelIosb; 3660 } 3661 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3662 { 3663 /* The caller's IOSB was invalid, so fail */ 3664 if (EventObject) ObDereferenceObject(EventObject); 3665 IopUnlockFileObject(FileObject); 3666 ObDereferenceObject(FileObject); 3667 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3668 } 3669 _SEH2_END; 3670 3671 /* Signal the completion event */ 3672 if (EventObject) 3673 { 3674 KeSetEvent(EventObject, 0, FALSE); 3675 ObDereferenceObject(EventObject); 3676 } 3677 3678 /* Clean up */ 3679 IopUnlockFileObject(FileObject); 3680 ObDereferenceObject(FileObject); 3681 return KernelIosb.Status; 3682 } 3683 } 3684 3685 /* Remember we are sync */ 3686 Synchronous = TRUE; 3687 } 3688 else if (!(ByteOffset) && 3689 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) 3690 { 3691 /* Otherwise, this was async I/O without a byte offset, so fail */ 3692 if (EventObject) ObDereferenceObject(EventObject); 3693 ObDereferenceObject(FileObject); 3694 return STATUS_INVALID_PARAMETER; 3695 } 3696 3697 /* Clear the File Object's event */ 3698 KeClearEvent(&FileObject->Event); 3699 3700 /* Allocate the IRP */ 3701 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3702 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 3703 3704 /* Set the IRP */ 3705 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3706 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3707 Irp->RequestorMode = PreviousMode; 3708 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 3709 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 3710 Irp->UserIosb = IoStatusBlock; 3711 Irp->UserEvent = EventObject; 3712 Irp->PendingReturned = FALSE; 3713 Irp->Cancel = FALSE; 3714 Irp->CancelRoutine = NULL; 3715 Irp->AssociatedIrp.SystemBuffer = NULL; 3716 Irp->MdlAddress = NULL; 3717 3718 /* Set the Stack Data */ 3719 StackPtr = IoGetNextIrpStackLocation(Irp); 3720 StackPtr->MajorFunction = IRP_MJ_WRITE; 3721 StackPtr->FileObject = FileObject; 3722 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ? 3723 SL_WRITE_THROUGH : 0; 3724 StackPtr->Parameters.Write.Key = CapturedKey; 3725 StackPtr->Parameters.Write.Length = Length; 3726 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset; 3727 3728 /* Check if this is buffered I/O */ 3729 if (DeviceObject->Flags & DO_BUFFERED_IO) 3730 { 3731 /* Check if we have a buffer length */ 3732 if (Length) 3733 { 3734 /* Enter SEH */ 3735 _SEH2_TRY 3736 { 3737 /* Allocate a buffer */ 3738 Irp->AssociatedIrp.SystemBuffer = 3739 ExAllocatePoolWithTag(NonPagedPool, 3740 Length, 3741 TAG_SYSB); 3742 3743 /* Copy the data into it */ 3744 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length); 3745 } 3746 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3747 { 3748 /* Allocating failed, clean up and return the exception code */ 3749 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 3750 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3751 } 3752 _SEH2_END; 3753 3754 /* Set the flags */ 3755 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); 3756 } 3757 else 3758 { 3759 /* Not writing anything */ 3760 Irp->Flags = IRP_BUFFERED_IO; 3761 } 3762 } 3763 else if (DeviceObject->Flags & DO_DIRECT_IO) 3764 { 3765 /* Check if we have a buffer length */ 3766 if (Length) 3767 { 3768 _SEH2_TRY 3769 { 3770 /* Allocate an MDL */ 3771 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); 3772 if (!Mdl) 3773 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 3774 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess); 3775 } 3776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3777 { 3778 /* Allocating failed, clean up and return the exception code */ 3779 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 3780 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3781 } 3782 _SEH2_END; 3783 } 3784 3785 /* No allocation flags */ 3786 Irp->Flags = 0; 3787 } 3788 else 3789 { 3790 /* No allocation flags, and use the buffer directly */ 3791 Irp->Flags = 0; 3792 Irp->UserBuffer = Buffer; 3793 } 3794 3795 /* Now set the deferred read flags */ 3796 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION); 3797 #if 0 3798 /* FIXME: VFAT SUCKS */ 3799 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; 3800 #endif 3801 3802 /* Perform the call */ 3803 return IopPerformSynchronousRequest(DeviceObject, 3804 Irp, 3805 FileObject, 3806 TRUE, 3807 PreviousMode, 3808 Synchronous, 3809 IopWriteTransfer); 3810 } 3811 3812 NTSTATUS 3813 NTAPI 3814 NtWriteFileGather(IN HANDLE FileHandle, 3815 IN HANDLE Event OPTIONAL, 3816 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 3817 IN PVOID UserApcContext OPTIONAL, 3818 OUT PIO_STATUS_BLOCK UserIoStatusBlock, 3819 IN FILE_SEGMENT_ELEMENT BufferDescription [], 3820 IN ULONG BufferLength, 3821 IN PLARGE_INTEGER ByteOffset, 3822 IN PULONG Key OPTIONAL) 3823 { 3824 UNIMPLEMENTED; 3825 return STATUS_NOT_IMPLEMENTED; 3826 } 3827 3828 /* 3829 * @implemented 3830 */ 3831 NTSTATUS 3832 NTAPI 3833 NtQueryVolumeInformationFile(IN HANDLE FileHandle, 3834 OUT PIO_STATUS_BLOCK IoStatusBlock, 3835 OUT PVOID FsInformation, 3836 IN ULONG Length, 3837 IN FS_INFORMATION_CLASS FsInformationClass) 3838 { 3839 PFILE_OBJECT FileObject; 3840 PIRP Irp; 3841 PIO_STACK_LOCATION StackPtr; 3842 PDEVICE_OBJECT DeviceObject; 3843 PKEVENT Event = NULL; 3844 BOOLEAN LocalEvent = FALSE; 3845 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3846 NTSTATUS Status; 3847 IO_STATUS_BLOCK KernelIosb; 3848 PAGED_CODE(); 3849 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3850 3851 /* Check if we're called from user mode */ 3852 if (PreviousMode != KernelMode) 3853 { 3854 /* Validate the information class */ 3855 if ((FsInformationClass >= FileFsMaximumInformation) || 3856 !(IopQueryFsOperationLength[FsInformationClass])) 3857 { 3858 /* Invalid class */ 3859 return STATUS_INVALID_INFO_CLASS; 3860 } 3861 3862 /* Validate the length */ 3863 if (Length < IopQueryFsOperationLength[FsInformationClass]) 3864 { 3865 /* Invalid length */ 3866 return STATUS_INFO_LENGTH_MISMATCH; 3867 } 3868 3869 /* Enter SEH for probing */ 3870 _SEH2_TRY 3871 { 3872 /* Probe the I/O Status block */ 3873 ProbeForWriteIoStatusBlock(IoStatusBlock); 3874 3875 /* Probe the information */ 3876 ProbeForWrite(FsInformation, Length, sizeof(ULONG)); 3877 } 3878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3879 { 3880 /* Return the exception code */ 3881 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3882 } 3883 _SEH2_END; 3884 } 3885 3886 /* Get File Object */ 3887 Status = ObReferenceObjectByHandle(FileHandle, 3888 IopQueryFsOperationAccess 3889 [FsInformationClass], 3890 IoFileObjectType, 3891 PreviousMode, 3892 (PVOID*)&FileObject, 3893 NULL); 3894 if (!NT_SUCCESS(Status)) return Status; 3895 3896 /* Check if we should use Sync IO or not */ 3897 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3898 { 3899 /* Lock it */ 3900 IopLockFileObject(FileObject); 3901 } 3902 else 3903 { 3904 /* Use local event */ 3905 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3906 if (!Event) 3907 { 3908 ObDereferenceObject(FileObject); 3909 return STATUS_INSUFFICIENT_RESOURCES; 3910 } 3911 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3912 LocalEvent = TRUE; 3913 } 3914 3915 /* Get the device object */ 3916 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3917 3918 /* Clear File Object event */ 3919 KeClearEvent(&FileObject->Event); 3920 3921 /* Allocate the IRP */ 3922 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3923 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3924 3925 /* Set up the IRP */ 3926 Irp->RequestorMode = PreviousMode; 3927 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3928 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3929 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3930 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3931 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3932 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3933 Irp->UserBuffer = FsInformation; 3934 Irp->AssociatedIrp.SystemBuffer = NULL; 3935 Irp->MdlAddress = NULL; 3936 3937 /* Set up Stack Data */ 3938 StackPtr = IoGetNextIrpStackLocation(Irp); 3939 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION; 3940 StackPtr->FileObject = FileObject; 3941 3942 /* Enter SEH */ 3943 _SEH2_TRY 3944 { 3945 /* Allocate a buffer */ 3946 Irp->AssociatedIrp.SystemBuffer = 3947 ExAllocatePoolWithTag(NonPagedPool, 3948 Length, 3949 TAG_SYSB); 3950 } 3951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3952 { 3953 /* Allocating failed, clean up and return the exception code */ 3954 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3955 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3956 } 3957 _SEH2_END; 3958 3959 /* Set the flags for this buffered + deferred I/O */ 3960 Irp->Flags |= (IRP_BUFFERED_IO | 3961 IRP_DEALLOCATE_BUFFER | 3962 IRP_INPUT_OPERATION | 3963 IRP_DEFER_IO_COMPLETION); 3964 3965 /* Set Parameters */ 3966 StackPtr->Parameters.QueryVolume.Length = Length; 3967 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass; 3968 3969 /* Call the Driver */ 3970 Status = IopPerformSynchronousRequest(DeviceObject, 3971 Irp, 3972 FileObject, 3973 TRUE, 3974 PreviousMode, 3975 !LocalEvent, 3976 IopOtherTransfer); 3977 3978 /* Check if this was async I/O */ 3979 if (LocalEvent) 3980 { 3981 /* It was, finalize this request */ 3982 Status = IopFinalizeAsynchronousIo(Status, 3983 Event, 3984 Irp, 3985 PreviousMode, 3986 &KernelIosb, 3987 IoStatusBlock); 3988 } 3989 3990 /* Return status */ 3991 return Status; 3992 } 3993 3994 /* 3995 * @implemented 3996 */ 3997 NTSTATUS 3998 NTAPI 3999 NtSetVolumeInformationFile(IN HANDLE FileHandle, 4000 OUT PIO_STATUS_BLOCK IoStatusBlock, 4001 IN PVOID FsInformation, 4002 IN ULONG Length, 4003 IN FS_INFORMATION_CLASS FsInformationClass) 4004 { 4005 PFILE_OBJECT FileObject; 4006 PIRP Irp; 4007 PIO_STACK_LOCATION StackPtr; 4008 PDEVICE_OBJECT DeviceObject, TargetDeviceObject; 4009 PKEVENT Event = NULL; 4010 BOOLEAN LocalEvent = FALSE; 4011 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 4012 NTSTATUS Status; 4013 IO_STATUS_BLOCK KernelIosb; 4014 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure; 4015 PAGED_CODE(); 4016 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 4017 4018 /* Check if we're called from user mode */ 4019 if (PreviousMode != KernelMode) 4020 { 4021 /* Validate the information class */ 4022 if ((FsInformationClass >= FileFsMaximumInformation) || 4023 !(IopSetFsOperationLength[FsInformationClass])) 4024 { 4025 /* Invalid class */ 4026 return STATUS_INVALID_INFO_CLASS; 4027 } 4028 4029 /* Validate the length */ 4030 if (Length < IopSetFsOperationLength[FsInformationClass]) 4031 { 4032 /* Invalid length */ 4033 return STATUS_INFO_LENGTH_MISMATCH; 4034 } 4035 4036 /* Enter SEH for probing */ 4037 _SEH2_TRY 4038 { 4039 /* Probe the I/O Status block */ 4040 ProbeForWriteIoStatusBlock(IoStatusBlock); 4041 4042 /* Probe the information */ 4043 ProbeForRead(FsInformation, Length, sizeof(ULONG)); 4044 } 4045 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4046 { 4047 /* Return the exception code */ 4048 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4049 } 4050 _SEH2_END; 4051 } 4052 4053 /* Get File Object */ 4054 Status = ObReferenceObjectByHandle(FileHandle, 4055 IopSetFsOperationAccess 4056 [FsInformationClass], 4057 IoFileObjectType, 4058 PreviousMode, 4059 (PVOID*)&FileObject, 4060 NULL); 4061 if (!NT_SUCCESS(Status)) return Status; 4062 4063 /* Get target device for notification */ 4064 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject); 4065 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL; 4066 4067 /* Check if we should use Sync IO or not */ 4068 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 4069 { 4070 /* Lock it */ 4071 IopLockFileObject(FileObject); 4072 } 4073 else 4074 { 4075 /* Use local event */ 4076 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 4077 if (!Event) 4078 { 4079 ObDereferenceObject(FileObject); 4080 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4081 return STATUS_INSUFFICIENT_RESOURCES; 4082 } 4083 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 4084 LocalEvent = TRUE; 4085 } 4086 4087 /* Get the device object */ 4088 DeviceObject = IoGetRelatedDeviceObject(FileObject); 4089 4090 /* Clear File Object event */ 4091 KeClearEvent(&FileObject->Event); 4092 4093 /* Allocate the IRP */ 4094 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4095 if (!Irp) 4096 { 4097 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4098 return IopCleanupFailedIrp(FileObject, NULL, Event); 4099 } 4100 4101 /* Set up the IRP */ 4102 Irp->RequestorMode = PreviousMode; 4103 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 4104 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 4105 Irp->UserEvent = (LocalEvent) ? Event : NULL; 4106 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 4107 Irp->Tail.Overlay.OriginalFileObject = FileObject; 4108 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 4109 Irp->UserBuffer = FsInformation; 4110 Irp->AssociatedIrp.SystemBuffer = NULL; 4111 Irp->MdlAddress = NULL; 4112 4113 /* Set up Stack Data */ 4114 StackPtr = IoGetNextIrpStackLocation(Irp); 4115 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION; 4116 StackPtr->FileObject = FileObject; 4117 4118 /* Enter SEH */ 4119 _SEH2_TRY 4120 { 4121 /* Allocate a buffer */ 4122 Irp->AssociatedIrp.SystemBuffer = 4123 ExAllocatePoolWithTag(NonPagedPool, 4124 Length, 4125 TAG_SYSB); 4126 4127 /* Copy the data into it */ 4128 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length); 4129 } 4130 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4131 { 4132 /* Allocating failed, clean up and return the exception code */ 4133 IopCleanupAfterException(FileObject, Irp, NULL, Event); 4134 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4135 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4136 } 4137 _SEH2_END; 4138 4139 /* Set the flags for this buffered + deferred I/O */ 4140 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); 4141 4142 /* Set Parameters */ 4143 StackPtr->Parameters.SetVolume.Length = Length; 4144 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass; 4145 4146 /* Call the Driver */ 4147 Status = IopPerformSynchronousRequest(DeviceObject, 4148 Irp, 4149 FileObject, 4150 FALSE, 4151 PreviousMode, 4152 !LocalEvent, 4153 IopOtherTransfer); 4154 4155 /* Check if this was async I/O */ 4156 if (LocalEvent) 4157 { 4158 /* It was, finalize this request */ 4159 Status = IopFinalizeAsynchronousIo(Status, 4160 Event, 4161 Irp, 4162 PreviousMode, 4163 &KernelIosb, 4164 IoStatusBlock); 4165 } 4166 4167 if (TargetDeviceObject && NT_SUCCESS(Status)) 4168 { 4169 /* Time to report change */ 4170 NotificationStructure.Version = 1; 4171 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION); 4172 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE; 4173 NotificationStructure.FileObject = NULL; 4174 NotificationStructure.NameBufferOffset = - 1; 4175 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure); 4176 } 4177 4178 /* Return status */ 4179 return Status; 4180 } 4181 4182 /* 4183 * @unimplemented 4184 */ 4185 NTSTATUS 4186 NTAPI 4187 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle) 4188 { 4189 UNIMPLEMENTED; 4190 return STATUS_NOT_IMPLEMENTED; 4191 } 4192 4193 /* 4194 * @unimplemented 4195 */ 4196 NTSTATUS 4197 NTAPI 4198 NtRequestDeviceWakeup(IN HANDLE DeviceHandle) 4199 { 4200 UNIMPLEMENTED; 4201 return STATUS_NOT_IMPLEMENTED; 4202 } 4203