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