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 static 1030 BOOLEAN 1031 IopGetMountFlag(IN PDEVICE_OBJECT DeviceObject) 1032 { 1033 KIRQL OldIrql; 1034 PVPB Vpb; 1035 BOOLEAN Mounted; 1036 1037 /* Assume not mounted */ 1038 Mounted = FALSE; 1039 1040 /* Check whether we have the mount flag */ 1041 IoAcquireVpbSpinLock(&OldIrql); 1042 1043 Vpb = DeviceObject->Vpb; 1044 if (Vpb != NULL && 1045 BooleanFlagOn(Vpb->Flags, VPB_MOUNTED)) 1046 { 1047 Mounted = TRUE; 1048 } 1049 1050 IoReleaseVpbSpinLock(OldIrql); 1051 1052 return Mounted; 1053 } 1054 1055 static 1056 BOOLEAN 1057 IopVerifyDriverObjectOnStack(IN PDEVICE_OBJECT DeviceObject, 1058 IN PDRIVER_OBJECT DriverObject) 1059 { 1060 PDEVICE_OBJECT StackDO; 1061 1062 /* Browse our whole device stack, trying to find the appropriate driver */ 1063 StackDO = IopGetDeviceAttachmentBase(DeviceObject); 1064 while (StackDO != NULL) 1065 { 1066 /* We've found the driver, return success */ 1067 if (StackDO->DriverObject == DriverObject) 1068 { 1069 return TRUE; 1070 } 1071 1072 /* Move to the next */ 1073 StackDO = StackDO->AttachedDevice; 1074 } 1075 1076 /* We only reach there if driver was not found */ 1077 return FALSE; 1078 } 1079 1080 static 1081 NTSTATUS 1082 IopGetDriverPathInformation(IN PFILE_OBJECT FileObject, 1083 IN PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo, 1084 IN ULONG Length) 1085 { 1086 KIRQL OldIrql; 1087 NTSTATUS Status; 1088 UNICODE_STRING DriverName; 1089 PDRIVER_OBJECT DriverObject; 1090 1091 /* Make sure the structure is consistent (ie, driver name fits into the buffer) */ 1092 if (Length - FIELD_OFFSET(FILE_FS_DRIVER_PATH_INFORMATION, DriverName) < DriverPathInfo->DriverNameLength) 1093 { 1094 return STATUS_INVALID_PARAMETER; 1095 } 1096 1097 /* Setup the whole driver name */ 1098 DriverName.Length = DriverPathInfo->DriverNameLength; 1099 DriverName.MaximumLength = DriverPathInfo->DriverNameLength; 1100 DriverName.Buffer = &DriverPathInfo->DriverName[0]; 1101 1102 /* Ask Ob for such driver */ 1103 Status = ObReferenceObjectByName(&DriverName, 1104 OBJ_CASE_INSENSITIVE, 1105 NULL, 1106 0, 1107 IoDriverObjectType, 1108 KernelMode, 1109 NULL, 1110 (PVOID*)&DriverObject); 1111 /* No such driver, bail out */ 1112 if (!NT_SUCCESS(Status)) 1113 { 1114 return Status; 1115 } 1116 1117 /* Lock the devices database, we'll browse it */ 1118 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 1119 /* If we have a VPB, browse the stack from the volume */ 1120 if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) 1121 { 1122 DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->Vpb->DeviceObject, DriverObject); 1123 } 1124 /* Otherwise, do it from the normal device */ 1125 else 1126 { 1127 DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->DeviceObject, DriverObject); 1128 } 1129 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 1130 1131 /* No longer needed */ 1132 ObDereferenceObject(DriverObject); 1133 1134 return STATUS_SUCCESS; 1135 } 1136 1137 /* PUBLIC FUNCTIONS **********************************************************/ 1138 1139 /* 1140 * @implemented 1141 */ 1142 NTSTATUS 1143 NTAPI 1144 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject, 1145 IN PMDL Mdl, 1146 IN PLARGE_INTEGER Offset, 1147 IN PKEVENT Event, 1148 IN PIO_STATUS_BLOCK StatusBlock) 1149 { 1150 PIRP Irp; 1151 PIO_STACK_LOCATION StackPtr; 1152 PDEVICE_OBJECT DeviceObject; 1153 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n", 1154 FileObject, Mdl, Offset); 1155 1156 /* Is the write originating from Cc? */ 1157 if (FileObject->SectionObjectPointer != NULL && 1158 FileObject->SectionObjectPointer->SharedCacheMap != NULL) 1159 { 1160 ++CcDataFlushes; 1161 CcDataPages += BYTES_TO_PAGES(MmGetMdlByteCount(Mdl)); 1162 } 1163 1164 /* Get the Device Object */ 1165 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1166 1167 /* Allocate IRP */ 1168 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1169 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 1170 1171 /* Get the Stack */ 1172 StackPtr = IoGetNextIrpStackLocation(Irp); 1173 1174 /* Create the IRP Settings */ 1175 Irp->MdlAddress = Mdl; 1176 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl); 1177 Irp->UserIosb = StatusBlock; 1178 Irp->UserEvent = Event; 1179 Irp->RequestorMode = KernelMode; 1180 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO; 1181 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1182 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1183 1184 /* Set the Stack Settings */ 1185 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl); 1186 StackPtr->Parameters.Write.ByteOffset = *Offset; 1187 StackPtr->MajorFunction = IRP_MJ_WRITE; 1188 StackPtr->FileObject = FileObject; 1189 1190 /* Call the Driver */ 1191 return IoCallDriver(DeviceObject, Irp); 1192 } 1193 1194 /* 1195 * @implemented 1196 */ 1197 NTSTATUS 1198 NTAPI 1199 IoPageRead(IN PFILE_OBJECT FileObject, 1200 IN PMDL Mdl, 1201 IN PLARGE_INTEGER Offset, 1202 IN PKEVENT Event, 1203 IN PIO_STATUS_BLOCK StatusBlock) 1204 { 1205 PIRP Irp; 1206 PIO_STACK_LOCATION StackPtr; 1207 PDEVICE_OBJECT DeviceObject; 1208 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n", 1209 FileObject, Mdl, Offset); 1210 1211 /* Get the Device Object */ 1212 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1213 1214 /* Allocate IRP */ 1215 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1216 /* If allocation failed, try to see whether we can use 1217 * the reserve IRP 1218 */ 1219 if (Irp == NULL) 1220 { 1221 /* We will use it only for paging file */ 1222 if (MmIsFileObjectAPagingFile(FileObject)) 1223 { 1224 InterlockedExchangeAdd(&IoPageReadIrpAllocationFailure, 1); 1225 Irp = IopAllocateReserveIrp(DeviceObject->StackSize); 1226 } 1227 else 1228 { 1229 InterlockedExchangeAdd(&IoPageReadNonPagefileIrpAllocationFailure, 1); 1230 } 1231 1232 /* If allocation failed (not a paging file or too big stack size) 1233 * Fail for real 1234 */ 1235 if (Irp == NULL) 1236 { 1237 return STATUS_INSUFFICIENT_RESOURCES; 1238 } 1239 } 1240 1241 /* Get the Stack */ 1242 StackPtr = IoGetNextIrpStackLocation(Irp); 1243 1244 /* Create the IRP Settings */ 1245 Irp->MdlAddress = Mdl; 1246 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl); 1247 Irp->UserIosb = StatusBlock; 1248 Irp->UserEvent = Event; 1249 Irp->RequestorMode = KernelMode; 1250 Irp->Flags = IRP_PAGING_IO | 1251 IRP_NOCACHE | 1252 IRP_SYNCHRONOUS_PAGING_IO | 1253 IRP_INPUT_OPERATION; 1254 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1255 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1256 1257 /* Set the Stack Settings */ 1258 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl); 1259 StackPtr->Parameters.Read.ByteOffset = *Offset; 1260 StackPtr->MajorFunction = IRP_MJ_READ; 1261 StackPtr->FileObject = FileObject; 1262 1263 /* Call the Driver */ 1264 return IoCallDriver(DeviceObject, Irp); 1265 } 1266 1267 /* 1268 * @implemented 1269 */ 1270 NTSTATUS 1271 NTAPI 1272 IoQueryFileInformation(IN PFILE_OBJECT FileObject, 1273 IN FILE_INFORMATION_CLASS FileInformationClass, 1274 IN ULONG Length, 1275 OUT PVOID FileInformation, 1276 OUT PULONG ReturnedLength) 1277 { 1278 /* Call the shared routine */ 1279 return IopQueryDeviceInformation(FileObject, 1280 FileInformationClass, 1281 Length, 1282 FileInformation, 1283 ReturnedLength, 1284 TRUE); 1285 } 1286 1287 /* 1288 * @implemented 1289 */ 1290 NTSTATUS 1291 NTAPI 1292 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject, 1293 IN FS_INFORMATION_CLASS FsInformationClass, 1294 IN ULONG Length, 1295 OUT PVOID FsInformation, 1296 OUT PULONG ReturnedLength) 1297 { 1298 /* Call the shared routine */ 1299 return IopQueryDeviceInformation(FileObject, 1300 FsInformationClass, 1301 Length, 1302 FsInformation, 1303 ReturnedLength, 1304 FALSE); 1305 } 1306 1307 /* 1308 * @implemented 1309 */ 1310 NTSTATUS 1311 NTAPI 1312 IoSetInformation(IN PFILE_OBJECT FileObject, 1313 IN FILE_INFORMATION_CLASS FileInformationClass, 1314 IN ULONG Length, 1315 IN PVOID FileInformation) 1316 { 1317 IO_STATUS_BLOCK IoStatusBlock; 1318 PIRP Irp; 1319 PDEVICE_OBJECT DeviceObject; 1320 PIO_STACK_LOCATION StackPtr; 1321 BOOLEAN LocalEvent = FALSE; 1322 KEVENT Event; 1323 NTSTATUS Status; 1324 PAGED_CODE(); 1325 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n", 1326 FileObject, FileInformationClass, Length); 1327 1328 /* Reference the object */ 1329 ObReferenceObject(FileObject); 1330 1331 /* Check if this is a file that was opened for Synch I/O */ 1332 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1333 { 1334 /* Lock it */ 1335 (void)IopLockFileObject(FileObject, KernelMode); 1336 1337 /* Use File Object event */ 1338 KeClearEvent(&FileObject->Event); 1339 } 1340 else 1341 { 1342 /* Use local event */ 1343 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 1344 LocalEvent = TRUE; 1345 } 1346 1347 /* Get the Device Object */ 1348 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1349 1350 /* Allocate the IRP */ 1351 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1352 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL); 1353 1354 /* Set the IRP */ 1355 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1356 Irp->RequestorMode = KernelMode; 1357 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 1358 Irp->UserIosb = &IoStatusBlock; 1359 Irp->UserEvent = (LocalEvent) ? &Event : NULL; 1360 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 1361 Irp->Flags |= IRP_BUFFERED_IO; 1362 Irp->AssociatedIrp.SystemBuffer = FileInformation; 1363 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1364 1365 /* Set the Stack Data */ 1366 StackPtr = IoGetNextIrpStackLocation(Irp); 1367 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; 1368 StackPtr->FileObject = FileObject; 1369 1370 /* Set Parameters */ 1371 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; 1372 StackPtr->Parameters.SetFile.Length = Length; 1373 1374 /* Queue the IRP */ 1375 IopQueueIrpToThread(Irp); 1376 1377 /* Call the Driver */ 1378 Status = IoCallDriver(DeviceObject, Irp); 1379 1380 /* Check if this was synch I/O */ 1381 if (!LocalEvent) 1382 { 1383 /* Check if the request is pending */ 1384 if (Status == STATUS_PENDING) 1385 { 1386 /* Wait on the file object */ 1387 Status = KeWaitForSingleObject(&FileObject->Event, 1388 Executive, 1389 KernelMode, 1390 (FileObject->Flags & 1391 FO_ALERTABLE_IO) != 0, 1392 NULL); 1393 if (Status == STATUS_ALERTED) 1394 { 1395 /* Abort the operation */ 1396 IopAbortInterruptedIrp(&FileObject->Event, Irp); 1397 } 1398 1399 /* Get the final status */ 1400 Status = FileObject->FinalStatus; 1401 } 1402 1403 /* Release the file lock */ 1404 IopUnlockFileObject(FileObject); 1405 } 1406 else if (Status == STATUS_PENDING) 1407 { 1408 /* Wait on the local event and get the final status */ 1409 KeWaitForSingleObject(&Event, 1410 Executive, 1411 KernelMode, 1412 FALSE, 1413 NULL); 1414 Status = IoStatusBlock.Status; 1415 } 1416 1417 /* Return the status */ 1418 return Status; 1419 } 1420 1421 /* NATIVE SERVICES ***********************************************************/ 1422 1423 /* 1424 * @implemented 1425 */ 1426 NTSTATUS 1427 NTAPI 1428 NtDeviceIoControlFile(IN HANDLE DeviceHandle, 1429 IN HANDLE Event OPTIONAL, 1430 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 1431 IN PVOID UserApcContext OPTIONAL, 1432 OUT PIO_STATUS_BLOCK IoStatusBlock, 1433 IN ULONG IoControlCode, 1434 IN PVOID InputBuffer, 1435 IN ULONG InputBufferLength OPTIONAL, 1436 OUT PVOID OutputBuffer, 1437 IN ULONG OutputBufferLength OPTIONAL) 1438 { 1439 /* Call the Generic Function */ 1440 return IopDeviceFsIoControl(DeviceHandle, 1441 Event, 1442 UserApcRoutine, 1443 UserApcContext, 1444 IoStatusBlock, 1445 IoControlCode, 1446 InputBuffer, 1447 InputBufferLength, 1448 OutputBuffer, 1449 OutputBufferLength, 1450 TRUE); 1451 } 1452 1453 /* 1454 * @implemented 1455 */ 1456 NTSTATUS 1457 NTAPI 1458 NtFsControlFile(IN HANDLE DeviceHandle, 1459 IN HANDLE Event OPTIONAL, 1460 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 1461 IN PVOID UserApcContext OPTIONAL, 1462 OUT PIO_STATUS_BLOCK IoStatusBlock, 1463 IN ULONG IoControlCode, 1464 IN PVOID InputBuffer, 1465 IN ULONG InputBufferLength OPTIONAL, 1466 OUT PVOID OutputBuffer, 1467 IN ULONG OutputBufferLength OPTIONAL) 1468 { 1469 /* Call the Generic Function */ 1470 return IopDeviceFsIoControl(DeviceHandle, 1471 Event, 1472 UserApcRoutine, 1473 UserApcContext, 1474 IoStatusBlock, 1475 IoControlCode, 1476 InputBuffer, 1477 InputBufferLength, 1478 OutputBuffer, 1479 OutputBufferLength, 1480 FALSE); 1481 } 1482 1483 NTSTATUS 1484 NTAPI 1485 NtFlushBuffersFile(IN HANDLE FileHandle, 1486 OUT PIO_STATUS_BLOCK IoStatusBlock) 1487 { 1488 PFILE_OBJECT FileObject; 1489 PIRP Irp; 1490 PIO_STACK_LOCATION StackPtr; 1491 NTSTATUS Status; 1492 PDEVICE_OBJECT DeviceObject; 1493 PKEVENT Event = NULL; 1494 BOOLEAN LocalEvent = FALSE; 1495 OBJECT_HANDLE_INFORMATION ObjectHandleInfo; 1496 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 1497 IO_STATUS_BLOCK KernelIosb; 1498 PAGED_CODE(); 1499 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1500 1501 if (PreviousMode != KernelMode) 1502 { 1503 /* Protect probes */ 1504 _SEH2_TRY 1505 { 1506 /* Probe the I/O Status block */ 1507 ProbeForWriteIoStatusBlock(IoStatusBlock); 1508 } 1509 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1510 { 1511 /* Return the exception code */ 1512 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1513 } 1514 _SEH2_END; 1515 } 1516 1517 /* Get the File Object */ 1518 Status = ObReferenceObjectByHandle(FileHandle, 1519 0, 1520 IoFileObjectType, 1521 PreviousMode, 1522 (PVOID*)&FileObject, 1523 &ObjectHandleInfo); 1524 if (!NT_SUCCESS(Status)) return Status; 1525 1526 /* 1527 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was 1528 * granted. However, if this is a named pipe, make sure we don't ask for 1529 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE 1530 * access right! 1531 */ 1532 if (!(ObjectHandleInfo.GrantedAccess & 1533 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | 1534 FILE_WRITE_DATA))) 1535 { 1536 /* We failed */ 1537 ObDereferenceObject(FileObject); 1538 return STATUS_ACCESS_DENIED; 1539 } 1540 1541 /* Check if we should use Sync IO or not */ 1542 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1543 { 1544 /* Lock it */ 1545 Status = IopLockFileObject(FileObject, PreviousMode); 1546 if (Status != STATUS_SUCCESS) 1547 { 1548 ObDereferenceObject(FileObject); 1549 return Status; 1550 } 1551 } 1552 else 1553 { 1554 /* Use local event */ 1555 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 1556 if (!Event) 1557 { 1558 /* We failed */ 1559 ObDereferenceObject(FileObject); 1560 return STATUS_INSUFFICIENT_RESOURCES; 1561 } 1562 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 1563 LocalEvent = TRUE; 1564 } 1565 1566 /* Get the Device Object */ 1567 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1568 1569 /* Clear the event */ 1570 KeClearEvent(&FileObject->Event); 1571 1572 /* Allocate the IRP */ 1573 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 1574 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 1575 1576 /* Set up the IRP */ 1577 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 1578 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 1579 Irp->UserEvent = (LocalEvent) ? Event : NULL; 1580 Irp->RequestorMode = PreviousMode; 1581 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1582 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1583 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 1584 1585 /* Set up Stack Data */ 1586 StackPtr = IoGetNextIrpStackLocation(Irp); 1587 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS; 1588 StackPtr->FileObject = FileObject; 1589 1590 /* Call the Driver */ 1591 Status = IopPerformSynchronousRequest(DeviceObject, 1592 Irp, 1593 FileObject, 1594 FALSE, 1595 PreviousMode, 1596 !LocalEvent, 1597 IopOtherTransfer); 1598 1599 /* Check if this was async I/O */ 1600 if (LocalEvent) 1601 { 1602 /* It was, finalize this request */ 1603 Status = IopFinalizeAsynchronousIo(Status, 1604 Event, 1605 Irp, 1606 PreviousMode, 1607 &KernelIosb, 1608 IoStatusBlock); 1609 } 1610 1611 /* Return the Status */ 1612 return Status; 1613 } 1614 1615 /* 1616 * @implemented 1617 */ 1618 NTSTATUS 1619 NTAPI 1620 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle, 1621 IN HANDLE EventHandle OPTIONAL, 1622 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1623 IN PVOID ApcContext OPTIONAL, 1624 OUT PIO_STATUS_BLOCK IoStatusBlock, 1625 OUT PVOID Buffer, 1626 IN ULONG BufferSize, 1627 IN ULONG CompletionFilter, 1628 IN BOOLEAN WatchTree) 1629 { 1630 PIRP Irp; 1631 PKEVENT Event = NULL; 1632 PDEVICE_OBJECT DeviceObject; 1633 PFILE_OBJECT FileObject; 1634 PIO_STACK_LOCATION IoStack; 1635 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1636 NTSTATUS Status; 1637 BOOLEAN LockedForSync = FALSE; 1638 PAGED_CODE(); 1639 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1640 1641 /* Check if we're called from user mode */ 1642 if (PreviousMode != KernelMode) 1643 { 1644 /* Enter SEH for probing */ 1645 _SEH2_TRY 1646 { 1647 /* Probe the I/O STatus block */ 1648 ProbeForWriteIoStatusBlock(IoStatusBlock); 1649 1650 /* Probe the buffer */ 1651 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG)); 1652 } 1653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1654 { 1655 /* Return the exception code */ 1656 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1657 } 1658 _SEH2_END; 1659 1660 /* Check if CompletionFilter is valid */ 1661 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK)) 1662 { 1663 return STATUS_INVALID_PARAMETER; 1664 } 1665 } 1666 1667 /* Get File Object */ 1668 Status = ObReferenceObjectByHandle(FileHandle, 1669 FILE_LIST_DIRECTORY, 1670 IoFileObjectType, 1671 PreviousMode, 1672 (PVOID*)&FileObject, 1673 NULL); 1674 if (!NT_SUCCESS(Status)) return Status; 1675 1676 /* Check if we have an event handle */ 1677 if (EventHandle) 1678 { 1679 /* Reference it */ 1680 Status = ObReferenceObjectByHandle(EventHandle, 1681 EVENT_MODIFY_STATE, 1682 ExEventObjectType, 1683 PreviousMode, 1684 (PVOID *)&Event, 1685 NULL); 1686 if (Status != STATUS_SUCCESS) 1687 { 1688 ObDereferenceObject(FileObject); 1689 return Status; 1690 } 1691 KeClearEvent(Event); 1692 } 1693 1694 /* Check if we should use Sync IO or not */ 1695 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1696 { 1697 /* Lock it */ 1698 Status = IopLockFileObject(FileObject, PreviousMode); 1699 if (Status != STATUS_SUCCESS) 1700 { 1701 if (Event) ObDereferenceObject(Event); 1702 ObDereferenceObject(FileObject); 1703 return Status; 1704 } 1705 LockedForSync = TRUE; 1706 } 1707 1708 /* Clear File Object event */ 1709 KeClearEvent(&FileObject->Event); 1710 1711 /* Get the device object */ 1712 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1713 1714 /* Allocate the IRP */ 1715 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1716 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL); 1717 1718 /* Set up the IRP */ 1719 Irp->RequestorMode = PreviousMode; 1720 Irp->UserIosb = IoStatusBlock; 1721 Irp->UserEvent = Event; 1722 Irp->UserBuffer = Buffer; 1723 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1724 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1725 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 1726 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 1727 1728 /* Set up Stack Data */ 1729 IoStack = IoGetNextIrpStackLocation(Irp); 1730 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; 1731 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY; 1732 IoStack->FileObject = FileObject; 1733 1734 /* Set parameters */ 1735 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter; 1736 IoStack->Parameters.NotifyDirectory.Length = BufferSize; 1737 if (WatchTree) IoStack->Flags = SL_WATCH_TREE; 1738 1739 /* Perform the call */ 1740 return IopPerformSynchronousRequest(DeviceObject, 1741 Irp, 1742 FileObject, 1743 FALSE, 1744 PreviousMode, 1745 LockedForSync, 1746 IopOtherTransfer); 1747 } 1748 1749 /* 1750 * @implemented 1751 */ 1752 NTSTATUS 1753 NTAPI 1754 NtLockFile(IN HANDLE FileHandle, 1755 IN HANDLE EventHandle OPTIONAL, 1756 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1757 IN PVOID ApcContext OPTIONAL, 1758 OUT PIO_STATUS_BLOCK IoStatusBlock, 1759 IN PLARGE_INTEGER ByteOffset, 1760 IN PLARGE_INTEGER Length, 1761 IN ULONG Key, 1762 IN BOOLEAN FailImmediately, 1763 IN BOOLEAN ExclusiveLock) 1764 { 1765 PFILE_OBJECT FileObject; 1766 PLARGE_INTEGER LocalLength = NULL; 1767 PIRP Irp; 1768 PIO_STACK_LOCATION StackPtr; 1769 PDEVICE_OBJECT DeviceObject; 1770 PKEVENT Event = NULL; 1771 BOOLEAN LockedForSync = FALSE; 1772 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 1773 LARGE_INTEGER CapturedByteOffset, CapturedLength; 1774 NTSTATUS Status; 1775 OBJECT_HANDLE_INFORMATION HandleInformation; 1776 PFAST_IO_DISPATCH FastIoDispatch; 1777 PAGED_CODE(); 1778 CapturedByteOffset.QuadPart = 0; 1779 CapturedLength.QuadPart = 0; 1780 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 1781 1782 /* Get File Object */ 1783 Status = ObReferenceObjectByHandle(FileHandle, 1784 0, 1785 IoFileObjectType, 1786 PreviousMode, 1787 (PVOID*)&FileObject, 1788 &HandleInformation); 1789 if (!NT_SUCCESS(Status)) return Status; 1790 1791 /* Check if we're called from user mode */ 1792 if (PreviousMode != KernelMode) 1793 { 1794 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */ 1795 if (!(HandleInformation.GrantedAccess & 1796 (FILE_WRITE_DATA | FILE_READ_DATA))) 1797 { 1798 ObDereferenceObject(FileObject); 1799 return STATUS_ACCESS_DENIED; 1800 } 1801 1802 /* Enter SEH for probing */ 1803 _SEH2_TRY 1804 { 1805 /* Probe the I/O STatus block */ 1806 ProbeForWriteIoStatusBlock(IoStatusBlock); 1807 1808 /* Probe and capture the large integers */ 1809 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 1810 CapturedLength = ProbeForReadLargeInteger(Length); 1811 } 1812 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1813 { 1814 /* Dereference the object and return exception code */ 1815 ObDereferenceObject(FileObject); 1816 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1817 } 1818 _SEH2_END; 1819 } 1820 else 1821 { 1822 /* Otherwise, capture them directly */ 1823 CapturedByteOffset = *ByteOffset; 1824 CapturedLength = *Length; 1825 } 1826 1827 /* Check if we have an event handle */ 1828 if (EventHandle) 1829 { 1830 /* Reference it */ 1831 Status = ObReferenceObjectByHandle(EventHandle, 1832 EVENT_MODIFY_STATE, 1833 ExEventObjectType, 1834 PreviousMode, 1835 (PVOID *)&Event, 1836 NULL); 1837 if (Status != STATUS_SUCCESS) return Status; 1838 KeClearEvent(Event); 1839 } 1840 1841 /* Get the device object */ 1842 DeviceObject = IoGetRelatedDeviceObject(FileObject); 1843 1844 /* Try to do it the FastIO way if possible */ 1845 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 1846 if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL) 1847 { 1848 IO_STATUS_BLOCK KernelIosb; 1849 1850 if (FastIoDispatch->FastIoLock(FileObject, 1851 &CapturedByteOffset, 1852 &CapturedLength, 1853 PsGetCurrentProcess(), 1854 Key, 1855 FailImmediately, 1856 ExclusiveLock, 1857 &KernelIosb, 1858 DeviceObject)) 1859 { 1860 /* Write the IOSB back */ 1861 _SEH2_TRY 1862 { 1863 *IoStatusBlock = KernelIosb; 1864 } 1865 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1866 { 1867 KernelIosb.Status = _SEH2_GetExceptionCode(); 1868 } 1869 _SEH2_END; 1870 1871 /* If we had an event, signal it */ 1872 if (EventHandle) 1873 { 1874 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 1875 ObDereferenceObject(Event); 1876 } 1877 1878 /* Set completion if required */ 1879 if (FileObject->CompletionContext != NULL && ApcContext != NULL) 1880 { 1881 if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port, 1882 FileObject->CompletionContext->Key, 1883 ApcContext, 1884 KernelIosb.Status, 1885 KernelIosb.Information, 1886 TRUE))) 1887 { 1888 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES; 1889 } 1890 } 1891 1892 FileObject->LockOperation = TRUE; 1893 1894 /* We're done with FastIO! */ 1895 ObDereferenceObject(FileObject); 1896 return KernelIosb.Status; 1897 } 1898 } 1899 1900 /* Check if we should use Sync IO or not */ 1901 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 1902 { 1903 /* Lock it */ 1904 Status = IopLockFileObject(FileObject, PreviousMode); 1905 if (Status != STATUS_SUCCESS) 1906 { 1907 if (Event) ObDereferenceObject(Event); 1908 ObDereferenceObject(FileObject); 1909 return Status; 1910 } 1911 LockedForSync = TRUE; 1912 } 1913 1914 /* Clear File Object event */ 1915 KeClearEvent(&FileObject->Event); 1916 FileObject->LockOperation = TRUE; 1917 1918 /* Allocate the IRP */ 1919 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 1920 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL); 1921 1922 /* Set up the IRP */ 1923 Irp->RequestorMode = PreviousMode; 1924 Irp->UserIosb = IoStatusBlock; 1925 Irp->UserEvent = Event; 1926 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 1927 Irp->Tail.Overlay.OriginalFileObject = FileObject; 1928 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 1929 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 1930 1931 /* Set up Stack Data */ 1932 StackPtr = IoGetNextIrpStackLocation(Irp); 1933 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; 1934 StackPtr->MinorFunction = IRP_MN_LOCK; 1935 StackPtr->FileObject = FileObject; 1936 1937 /* Allocate local buffer */ 1938 LocalLength = ExAllocatePoolWithTag(NonPagedPool, 1939 sizeof(LARGE_INTEGER), 1940 TAG_LOCK); 1941 if (!LocalLength) 1942 { 1943 /* Allocating failed, clean up and return failure */ 1944 IopCleanupAfterException(FileObject, Irp, Event, NULL); 1945 return STATUS_INSUFFICIENT_RESOURCES; 1946 } 1947 1948 /* Set the length */ 1949 *LocalLength = CapturedLength; 1950 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength; 1951 StackPtr->Parameters.LockControl.Length = LocalLength; 1952 1953 /* Set Parameters */ 1954 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset; 1955 StackPtr->Parameters.LockControl.Key = Key; 1956 1957 /* Set Flags */ 1958 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY; 1959 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK; 1960 1961 /* Perform the call */ 1962 return IopPerformSynchronousRequest(DeviceObject, 1963 Irp, 1964 FileObject, 1965 FALSE, 1966 PreviousMode, 1967 LockedForSync, 1968 IopOtherTransfer); 1969 } 1970 1971 /* 1972 * @implemented 1973 */ 1974 NTSTATUS 1975 NTAPI 1976 NtQueryDirectoryFile(IN HANDLE FileHandle, 1977 IN HANDLE EventHandle OPTIONAL, 1978 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1979 IN PVOID ApcContext OPTIONAL, 1980 OUT PIO_STATUS_BLOCK IoStatusBlock, 1981 OUT PVOID FileInformation, 1982 IN ULONG Length, 1983 IN FILE_INFORMATION_CLASS FileInformationClass, 1984 IN BOOLEAN ReturnSingleEntry, 1985 IN PUNICODE_STRING FileName OPTIONAL, 1986 IN BOOLEAN RestartScan) 1987 { 1988 PIRP Irp; 1989 PDEVICE_OBJECT DeviceObject; 1990 PFILE_OBJECT FileObject; 1991 PIO_STACK_LOCATION StackPtr; 1992 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1993 NTSTATUS Status; 1994 BOOLEAN LockedForSynch = FALSE; 1995 PKEVENT Event = NULL; 1996 volatile PVOID AuxBuffer = NULL; 1997 PMDL Mdl; 1998 UNICODE_STRING CapturedFileName; 1999 PUNICODE_STRING SearchPattern; 2000 PAGED_CODE(); 2001 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2002 2003 /* Check if we came from user mode */ 2004 if (PreviousMode != KernelMode) 2005 { 2006 /* Enter SEH for probing */ 2007 _SEH2_TRY 2008 { 2009 /* Probe the I/O Status Block */ 2010 ProbeForWriteIoStatusBlock(IoStatusBlock); 2011 2012 /* Probe the file information */ 2013 ProbeForWrite(FileInformation, Length, sizeof(ULONG)); 2014 2015 /* Check if we have a file name */ 2016 if (FileName) 2017 { 2018 /* Capture it */ 2019 CapturedFileName = ProbeForReadUnicodeString(FileName); 2020 if (CapturedFileName.Length) 2021 { 2022 /* Probe its buffer */ 2023 ProbeForRead(CapturedFileName.Buffer, 2024 CapturedFileName.Length, 2025 1); 2026 } 2027 2028 /* Allocate the auxiliary buffer */ 2029 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool, 2030 CapturedFileName.Length + 2031 sizeof(UNICODE_STRING), 2032 TAG_SYSB); 2033 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer + 2034 sizeof(UNICODE_STRING)), 2035 CapturedFileName.Buffer, 2036 CapturedFileName.Length); 2037 2038 /* Setup the search pattern */ 2039 SearchPattern = (PUNICODE_STRING)AuxBuffer; 2040 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer + 2041 sizeof(UNICODE_STRING)); 2042 SearchPattern->Length = CapturedFileName.Length; 2043 SearchPattern->MaximumLength = CapturedFileName.Length; 2044 } 2045 } 2046 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2047 { 2048 /* Free buffer and return the exception code */ 2049 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2050 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2051 } 2052 _SEH2_END; 2053 } 2054 2055 /* Check input parameters */ 2056 2057 switch (FileInformationClass) 2058 { 2059 #define CHECK_LENGTH(class, struct) \ 2060 case class: \ 2061 if (Length < sizeof(struct)) \ 2062 return STATUS_INFO_LENGTH_MISMATCH; \ 2063 break 2064 CHECK_LENGTH(FileDirectoryInformation, FILE_DIRECTORY_INFORMATION); 2065 CHECK_LENGTH(FileFullDirectoryInformation, FILE_FULL_DIR_INFORMATION); 2066 CHECK_LENGTH(FileIdFullDirectoryInformation, FILE_ID_FULL_DIR_INFORMATION); 2067 CHECK_LENGTH(FileNamesInformation, FILE_NAMES_INFORMATION); 2068 CHECK_LENGTH(FileBothDirectoryInformation, FILE_BOTH_DIR_INFORMATION); 2069 CHECK_LENGTH(FileIdBothDirectoryInformation, FILE_ID_BOTH_DIR_INFORMATION); 2070 default: 2071 break; 2072 #undef CHECK_LENGTH 2073 } 2074 2075 /* Get File Object */ 2076 Status = ObReferenceObjectByHandle(FileHandle, 2077 FILE_LIST_DIRECTORY, 2078 IoFileObjectType, 2079 PreviousMode, 2080 (PVOID *)&FileObject, 2081 NULL); 2082 if (!NT_SUCCESS(Status)) 2083 { 2084 /* Fail */ 2085 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2086 return Status; 2087 } 2088 2089 /* Are there two associated completion routines? */ 2090 if (FileObject->CompletionContext != NULL && ApcRoutine != NULL) 2091 { 2092 ObDereferenceObject(FileObject); 2093 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2094 return STATUS_INVALID_PARAMETER; 2095 } 2096 2097 /* Check if we have an even handle */ 2098 if (EventHandle) 2099 { 2100 /* Get its pointer */ 2101 Status = ObReferenceObjectByHandle(EventHandle, 2102 EVENT_MODIFY_STATE, 2103 ExEventObjectType, 2104 PreviousMode, 2105 (PVOID *)&Event, 2106 NULL); 2107 if (!NT_SUCCESS(Status)) 2108 { 2109 /* Fail */ 2110 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2111 ObDereferenceObject(FileObject); 2112 return Status; 2113 } 2114 2115 /* Clear it */ 2116 KeClearEvent(Event); 2117 } 2118 2119 /* Check if this is a file that was opened for Synch I/O */ 2120 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2121 { 2122 /* Lock it */ 2123 Status = IopLockFileObject(FileObject, PreviousMode); 2124 if (Status != STATUS_SUCCESS) 2125 { 2126 if (Event) ObDereferenceObject(Event); 2127 ObDereferenceObject(FileObject); 2128 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2129 return Status; 2130 } 2131 2132 /* Remember to unlock later */ 2133 LockedForSynch = TRUE; 2134 } 2135 2136 /* Get the device object */ 2137 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2138 2139 /* Clear the File Object's event */ 2140 KeClearEvent(&FileObject->Event); 2141 2142 /* Allocate the IRP */ 2143 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 2144 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer); 2145 2146 /* Set up the IRP */ 2147 Irp->RequestorMode = PreviousMode; 2148 Irp->UserIosb = IoStatusBlock; 2149 Irp->UserEvent = Event; 2150 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2151 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2152 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 2153 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 2154 Irp->MdlAddress = NULL; 2155 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer; 2156 Irp->AssociatedIrp.SystemBuffer = NULL; 2157 2158 /* Check if this is buffered I/O */ 2159 if (DeviceObject->Flags & DO_BUFFERED_IO) 2160 { 2161 /* Allocate a buffer */ 2162 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, 2163 Length, 2164 TAG_SYSB); 2165 if (!Irp->AssociatedIrp.SystemBuffer) 2166 { 2167 /* Allocating failed, clean up and return the exception code */ 2168 IopCleanupAfterException(FileObject, Irp, Event, NULL); 2169 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2170 2171 /* Return the exception code */ 2172 return STATUS_INSUFFICIENT_RESOURCES; 2173 } 2174 2175 /* Set the buffer and flags */ 2176 Irp->UserBuffer = FileInformation; 2177 Irp->Flags = (IRP_BUFFERED_IO | 2178 IRP_DEALLOCATE_BUFFER | 2179 IRP_INPUT_OPERATION); 2180 } 2181 else if (DeviceObject->Flags & DO_DIRECT_IO) 2182 { 2183 _SEH2_TRY 2184 { 2185 /* Allocate an MDL */ 2186 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp); 2187 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2188 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); 2189 } 2190 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2191 { 2192 /* Allocating failed, clean up and return the exception code */ 2193 IopCleanupAfterException(FileObject, Irp, Event, NULL); 2194 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2195 } 2196 _SEH2_END; 2197 } 2198 else 2199 { 2200 /* No allocation flags, and use the buffer directly */ 2201 Irp->UserBuffer = FileInformation; 2202 } 2203 2204 /* Set up Stack Data */ 2205 StackPtr = IoGetNextIrpStackLocation(Irp); 2206 StackPtr->FileObject = FileObject; 2207 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; 2208 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY; 2209 2210 /* Set Parameters */ 2211 StackPtr->Parameters.QueryDirectory.FileInformationClass = 2212 FileInformationClass; 2213 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer; 2214 StackPtr->Parameters.QueryDirectory.FileIndex = 0; 2215 StackPtr->Parameters.QueryDirectory.Length = Length; 2216 StackPtr->Flags = 0; 2217 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN; 2218 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY; 2219 2220 /* Set deferred I/O */ 2221 Irp->Flags |= IRP_DEFER_IO_COMPLETION; 2222 2223 /* Perform the call */ 2224 return IopPerformSynchronousRequest(DeviceObject, 2225 Irp, 2226 FileObject, 2227 TRUE, 2228 PreviousMode, 2229 LockedForSynch, 2230 IopOtherTransfer); 2231 } 2232 2233 /* 2234 * @unimplemented 2235 */ 2236 NTSTATUS 2237 NTAPI 2238 NtQueryEaFile(IN HANDLE FileHandle, 2239 OUT PIO_STATUS_BLOCK IoStatusBlock, 2240 OUT PVOID Buffer, 2241 IN ULONG Length, 2242 IN BOOLEAN ReturnSingleEntry, 2243 IN PVOID EaList OPTIONAL, 2244 IN ULONG EaListLength, 2245 IN PULONG EaIndex OPTIONAL, 2246 IN BOOLEAN RestartScan) 2247 { 2248 UNIMPLEMENTED; 2249 return STATUS_NOT_IMPLEMENTED; 2250 } 2251 2252 /* 2253 * @implemented 2254 */ 2255 NTSTATUS 2256 NTAPI 2257 NtQueryInformationFile(IN HANDLE FileHandle, 2258 OUT PIO_STATUS_BLOCK IoStatusBlock, 2259 IN PVOID FileInformation, 2260 IN ULONG Length, 2261 IN FILE_INFORMATION_CLASS FileInformationClass) 2262 { 2263 OBJECT_HANDLE_INFORMATION HandleInformation; 2264 PFILE_OBJECT FileObject; 2265 NTSTATUS Status; 2266 PIRP Irp; 2267 PDEVICE_OBJECT DeviceObject; 2268 PIO_STACK_LOCATION StackPtr; 2269 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2270 PKEVENT Event = NULL; 2271 BOOLEAN LocalEvent = FALSE; 2272 PKNORMAL_ROUTINE NormalRoutine; 2273 PVOID NormalContext; 2274 KIRQL OldIrql; 2275 IO_STATUS_BLOCK KernelIosb; 2276 BOOLEAN CallDriver = TRUE; 2277 PFILE_ACCESS_INFORMATION AccessBuffer; 2278 PFILE_MODE_INFORMATION ModeBuffer; 2279 PFILE_ALIGNMENT_INFORMATION AlignmentBuffer; 2280 PFILE_ALL_INFORMATION AllBuffer; 2281 PFAST_IO_DISPATCH FastIoDispatch; 2282 PAGED_CODE(); 2283 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2284 2285 /* Check if we're called from user mode */ 2286 if (PreviousMode != KernelMode) 2287 { 2288 /* Validate the information class */ 2289 if ((FileInformationClass < 0) || 2290 (FileInformationClass >= FileMaximumInformation) || 2291 !(IopQueryOperationLength[FileInformationClass])) 2292 { 2293 /* Invalid class */ 2294 return STATUS_INVALID_INFO_CLASS; 2295 } 2296 2297 /* Validate the length */ 2298 if (Length < IopQueryOperationLength[FileInformationClass]) 2299 { 2300 /* Invalid length */ 2301 return STATUS_INFO_LENGTH_MISMATCH; 2302 } 2303 2304 /* Enter SEH for probing */ 2305 _SEH2_TRY 2306 { 2307 /* Probe the I/O Status block */ 2308 ProbeForWriteIoStatusBlock(IoStatusBlock); 2309 2310 /* Probe the information */ 2311 ProbeForWrite(FileInformation, Length, sizeof(ULONG)); 2312 } 2313 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2314 { 2315 /* Return the exception code */ 2316 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2317 } 2318 _SEH2_END; 2319 } 2320 #if DBG 2321 else 2322 { 2323 /* Validate the information class */ 2324 if ((FileInformationClass < 0) || 2325 (FileInformationClass >= FileMaximumInformation) || 2326 !(IopQueryOperationLength[FileInformationClass])) 2327 { 2328 /* Invalid class */ 2329 return STATUS_INVALID_INFO_CLASS; 2330 } 2331 2332 /* Validate the length */ 2333 if (Length < IopQueryOperationLength[FileInformationClass]) 2334 { 2335 /* Invalid length */ 2336 return STATUS_INFO_LENGTH_MISMATCH; 2337 } 2338 } 2339 #endif 2340 2341 /* Reference the Handle */ 2342 Status = ObReferenceObjectByHandle(FileHandle, 2343 IopQueryOperationAccess 2344 [FileInformationClass], 2345 IoFileObjectType, 2346 PreviousMode, 2347 (PVOID *)&FileObject, 2348 &HandleInformation); 2349 if (!NT_SUCCESS(Status)) return Status; 2350 2351 /* Check if this is a direct open or not */ 2352 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 2353 { 2354 /* Get the device object */ 2355 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 2356 } 2357 else 2358 { 2359 /* Get the device object */ 2360 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2361 } 2362 2363 /* Check if this is a file that was opened for Synch I/O */ 2364 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2365 { 2366 /* Lock it */ 2367 Status = IopLockFileObject(FileObject, PreviousMode); 2368 if (Status != STATUS_SUCCESS) 2369 { 2370 ObDereferenceObject(FileObject); 2371 return Status; 2372 } 2373 2374 /* Check if the caller just wants the position */ 2375 if (FileInformationClass == FilePositionInformation) 2376 { 2377 /* Protect write in SEH */ 2378 _SEH2_TRY 2379 { 2380 /* Write the offset */ 2381 ((PFILE_POSITION_INFORMATION)FileInformation)-> 2382 CurrentByteOffset = FileObject->CurrentByteOffset; 2383 2384 /* Fill out the I/O Status Block */ 2385 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION); 2386 Status = IoStatusBlock->Status = STATUS_SUCCESS; 2387 } 2388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2389 { 2390 /* Get the exception code */ 2391 Status = _SEH2_GetExceptionCode(); 2392 } 2393 _SEH2_END; 2394 2395 /* Release the file lock, dereference the file and return */ 2396 IopUnlockFileObject(FileObject); 2397 ObDereferenceObject(FileObject); 2398 return Status; 2399 } 2400 } 2401 else 2402 { 2403 /* Use local event */ 2404 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 2405 if (!Event) 2406 { 2407 ObDereferenceObject(FileObject); 2408 return STATUS_INSUFFICIENT_RESOURCES; 2409 } 2410 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 2411 LocalEvent = TRUE; 2412 } 2413 2414 /* Check if FastIO is possible for the two available information classes */ 2415 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 2416 if (FastIoDispatch != NULL && 2417 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) || 2418 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL))) 2419 { 2420 BOOLEAN Success = FALSE; 2421 2422 if (FileInformationClass == FileBasicInformation) 2423 { 2424 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE, 2425 FileInformation, 2426 &KernelIosb, 2427 DeviceObject); 2428 } 2429 else 2430 { 2431 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE, 2432 FileInformation, 2433 &KernelIosb, 2434 DeviceObject); 2435 } 2436 2437 /* If call succeed */ 2438 if (Success) 2439 { 2440 /* Write the IOSB back */ 2441 _SEH2_TRY 2442 { 2443 *IoStatusBlock = KernelIosb; 2444 } 2445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2446 { 2447 KernelIosb.Status = _SEH2_GetExceptionCode(); 2448 } 2449 _SEH2_END; 2450 2451 /* Free the event if we had one */ 2452 if (LocalEvent) 2453 { 2454 ExFreePoolWithTag(Event, TAG_IO); 2455 } 2456 2457 /* If FO was locked, unlock it */ 2458 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2459 { 2460 IopUnlockFileObject(FileObject); 2461 } 2462 2463 /* We're done with FastIO! */ 2464 ObDereferenceObject(FileObject); 2465 return KernelIosb.Status; 2466 } 2467 } 2468 2469 /* Clear the File Object event */ 2470 KeClearEvent(&FileObject->Event); 2471 2472 /* Allocate the IRP */ 2473 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2474 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 2475 2476 /* Set the IRP */ 2477 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2478 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2479 Irp->RequestorMode = PreviousMode; 2480 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 2481 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 2482 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 2483 Irp->UserEvent = (LocalEvent) ? Event : NULL; 2484 Irp->AssociatedIrp.SystemBuffer = NULL; 2485 Irp->MdlAddress = NULL; 2486 Irp->UserBuffer = FileInformation; 2487 2488 /* Set the Stack Data */ 2489 StackPtr = IoGetNextIrpStackLocation(Irp); 2490 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION; 2491 StackPtr->FileObject = FileObject; 2492 2493 /* Enter SEH */ 2494 _SEH2_TRY 2495 { 2496 /* Allocate a buffer */ 2497 Irp->AssociatedIrp.SystemBuffer = 2498 ExAllocatePoolWithTag(NonPagedPool, 2499 Length, 2500 TAG_SYSB); 2501 } 2502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2503 { 2504 /* Allocating failed, clean up and return the exception code */ 2505 IopCleanupAfterException(FileObject, Irp, NULL, Event); 2506 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2507 } 2508 _SEH2_END; 2509 2510 /* Set the flags */ 2511 Irp->Flags |= (IRP_BUFFERED_IO | 2512 IRP_DEALLOCATE_BUFFER | 2513 IRP_INPUT_OPERATION | 2514 IRP_DEFER_IO_COMPLETION); 2515 2516 /* Set the Parameters */ 2517 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass; 2518 StackPtr->Parameters.QueryFile.Length = Length; 2519 2520 /* Queue the IRP */ 2521 IopQueueIrpToThread(Irp); 2522 2523 /* Update operation counts */ 2524 IopUpdateOperationCount(IopOtherTransfer); 2525 2526 /* Fill in file information before calling the driver. 2527 See 'File System Internals' page 485.*/ 2528 if (FileInformationClass == FileAccessInformation) 2529 { 2530 AccessBuffer = Irp->AssociatedIrp.SystemBuffer; 2531 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess; 2532 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION); 2533 CallDriver = FALSE; 2534 } 2535 else if (FileInformationClass == FileModeInformation) 2536 { 2537 ModeBuffer = Irp->AssociatedIrp.SystemBuffer; 2538 ModeBuffer->Mode = IopGetFileMode(FileObject); 2539 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION); 2540 CallDriver = FALSE; 2541 } 2542 else if (FileInformationClass == FileAlignmentInformation) 2543 { 2544 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer; 2545 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement; 2546 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION); 2547 CallDriver = FALSE; 2548 } 2549 else if (FileInformationClass == FileAllInformation) 2550 { 2551 AllBuffer = Irp->AssociatedIrp.SystemBuffer; 2552 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess; 2553 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject); 2554 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement; 2555 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) + 2556 sizeof(FILE_MODE_INFORMATION) + 2557 sizeof(FILE_ALIGNMENT_INFORMATION); 2558 } 2559 2560 /* Call the Driver */ 2561 if (CallDriver) 2562 { 2563 Status = IoCallDriver(DeviceObject, Irp); 2564 } 2565 else 2566 { 2567 Status = STATUS_SUCCESS; 2568 Irp->IoStatus.Status = STATUS_SUCCESS; 2569 } 2570 2571 if (Status == STATUS_PENDING) 2572 { 2573 /* Check if this was async I/O */ 2574 if (LocalEvent) 2575 { 2576 /* Then to a non-alertable wait */ 2577 Status = KeWaitForSingleObject(Event, 2578 Executive, 2579 PreviousMode, 2580 FALSE, 2581 NULL); 2582 if (Status == STATUS_USER_APC) 2583 { 2584 /* Abort the request */ 2585 IopAbortInterruptedIrp(Event, Irp); 2586 } 2587 2588 /* Set the final status */ 2589 Status = KernelIosb.Status; 2590 2591 /* Enter SEH to write the IOSB back */ 2592 _SEH2_TRY 2593 { 2594 /* Write it back to the caller */ 2595 *IoStatusBlock = KernelIosb; 2596 } 2597 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2598 { 2599 /* Get the exception code */ 2600 Status = _SEH2_GetExceptionCode(); 2601 } 2602 _SEH2_END; 2603 2604 /* Free the event */ 2605 ExFreePoolWithTag(Event, TAG_IO); 2606 } 2607 else 2608 { 2609 /* Wait for the IRP */ 2610 Status = KeWaitForSingleObject(&FileObject->Event, 2611 Executive, 2612 PreviousMode, 2613 (FileObject->Flags & 2614 FO_ALERTABLE_IO) != 0, 2615 NULL); 2616 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) 2617 { 2618 /* Abort the request */ 2619 IopAbortInterruptedIrp(&FileObject->Event, Irp); 2620 } 2621 2622 /* Set the final status */ 2623 Status = FileObject->FinalStatus; 2624 2625 /* Release the file lock */ 2626 IopUnlockFileObject(FileObject); 2627 } 2628 } 2629 else 2630 { 2631 /* Free the event if we had one */ 2632 if (LocalEvent) 2633 { 2634 /* Clear it in the IRP for completion */ 2635 Irp->UserEvent = NULL; 2636 ExFreePoolWithTag(Event, TAG_IO); 2637 } 2638 2639 /* Set the caller IOSB */ 2640 Irp->UserIosb = IoStatusBlock; 2641 2642 /* The IRP wasn't completed, complete it ourselves */ 2643 KeRaiseIrql(APC_LEVEL, &OldIrql); 2644 IopCompleteRequest(&Irp->Tail.Apc, 2645 &NormalRoutine, 2646 &NormalContext, 2647 (PVOID*)&FileObject, 2648 &NormalContext); 2649 KeLowerIrql(OldIrql); 2650 2651 /* Release the file object if we had locked it*/ 2652 if (!LocalEvent) IopUnlockFileObject(FileObject); 2653 } 2654 2655 /* Return the Status */ 2656 return Status; 2657 } 2658 2659 /* 2660 * @unimplemented 2661 */ 2662 NTSTATUS 2663 NTAPI 2664 NtQueryQuotaInformationFile(IN HANDLE FileHandle, 2665 OUT PIO_STATUS_BLOCK IoStatusBlock, 2666 OUT PVOID Buffer, 2667 IN ULONG Length, 2668 IN BOOLEAN ReturnSingleEntry, 2669 IN PVOID SidList OPTIONAL, 2670 IN ULONG SidListLength, 2671 IN PSID StartSid OPTIONAL, 2672 IN BOOLEAN RestartScan) 2673 { 2674 UNIMPLEMENTED; 2675 return STATUS_NOT_IMPLEMENTED; 2676 } 2677 2678 /* 2679 * @implemented 2680 */ 2681 NTSTATUS 2682 NTAPI 2683 NtReadFile(IN HANDLE FileHandle, 2684 IN HANDLE Event OPTIONAL, 2685 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 2686 IN PVOID ApcContext OPTIONAL, 2687 OUT PIO_STATUS_BLOCK IoStatusBlock, 2688 OUT PVOID Buffer, 2689 IN ULONG Length, 2690 IN PLARGE_INTEGER ByteOffset OPTIONAL, 2691 IN PULONG Key OPTIONAL) 2692 { 2693 NTSTATUS Status; 2694 PFILE_OBJECT FileObject; 2695 PIRP Irp; 2696 PDEVICE_OBJECT DeviceObject; 2697 PIO_STACK_LOCATION StackPtr; 2698 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 2699 PKEVENT EventObject = NULL; 2700 LARGE_INTEGER CapturedByteOffset; 2701 ULONG CapturedKey = 0; 2702 BOOLEAN Synchronous = FALSE; 2703 PMDL Mdl; 2704 PFAST_IO_DISPATCH FastIoDispatch; 2705 IO_STATUS_BLOCK KernelIosb; 2706 BOOLEAN Success; 2707 2708 PAGED_CODE(); 2709 CapturedByteOffset.QuadPart = 0; 2710 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2711 2712 /* Get File Object */ 2713 Status = ObReferenceObjectByHandle(FileHandle, 2714 FILE_READ_DATA, 2715 IoFileObjectType, 2716 PreviousMode, 2717 (PVOID*)&FileObject, 2718 NULL); 2719 if (!NT_SUCCESS(Status)) return Status; 2720 2721 /* Get the device object */ 2722 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2723 2724 /* Validate User-Mode Buffers */ 2725 if (PreviousMode != KernelMode) 2726 { 2727 _SEH2_TRY 2728 { 2729 /* Probe the status block */ 2730 ProbeForWriteIoStatusBlock(IoStatusBlock); 2731 2732 /* Probe the read buffer */ 2733 ProbeForWrite(Buffer, Length, 1); 2734 2735 /* Check if we got a byte offset */ 2736 if (ByteOffset) 2737 { 2738 /* Capture and probe it */ 2739 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 2740 } 2741 2742 /* Perform additional checks for non-cached file access */ 2743 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) 2744 { 2745 /* Fail if Length is not sector size aligned 2746 * Perform a quick check for 2^ sector sizes 2747 * If it fails, try a more standard way 2748 */ 2749 if ((DeviceObject->SectorSize != 0) && 2750 ((DeviceObject->SectorSize - 1) & Length) != 0) 2751 { 2752 if (Length % DeviceObject->SectorSize != 0) 2753 { 2754 /* Release the file object and and fail */ 2755 ObDereferenceObject(FileObject); 2756 return STATUS_INVALID_PARAMETER; 2757 } 2758 } 2759 2760 /* Fail if buffer doesn't match alignment requirements */ 2761 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0) 2762 { 2763 /* Release the file object and and fail */ 2764 ObDereferenceObject(FileObject); 2765 return STATUS_INVALID_PARAMETER; 2766 } 2767 2768 if (ByteOffset) 2769 { 2770 /* Fail if ByteOffset is not sector size aligned */ 2771 if ((DeviceObject->SectorSize != 0) && 2772 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0)) 2773 { 2774 /* Release the file object and and fail */ 2775 ObDereferenceObject(FileObject); 2776 return STATUS_INVALID_PARAMETER; 2777 } 2778 } 2779 } 2780 2781 /* Capture and probe the key */ 2782 if (Key) CapturedKey = ProbeForReadUlong(Key); 2783 } 2784 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2785 { 2786 /* Release the file object and return the exception code */ 2787 ObDereferenceObject(FileObject); 2788 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2789 } 2790 _SEH2_END; 2791 } 2792 else 2793 { 2794 /* Kernel mode: capture directly */ 2795 if (ByteOffset) CapturedByteOffset = *ByteOffset; 2796 if (Key) CapturedKey = *Key; 2797 } 2798 2799 /* Check for invalid offset */ 2800 if ((CapturedByteOffset.QuadPart < 0) && (CapturedByteOffset.QuadPart != -2)) 2801 { 2802 /* -2 is FILE_USE_FILE_POINTER_POSITION */ 2803 ObDereferenceObject(FileObject); 2804 return STATUS_INVALID_PARAMETER; 2805 } 2806 2807 /* Check for event */ 2808 if (Event) 2809 { 2810 /* Reference it */ 2811 Status = ObReferenceObjectByHandle(Event, 2812 EVENT_MODIFY_STATE, 2813 ExEventObjectType, 2814 PreviousMode, 2815 (PVOID*)&EventObject, 2816 NULL); 2817 if (!NT_SUCCESS(Status)) 2818 { 2819 /* Fail */ 2820 ObDereferenceObject(FileObject); 2821 return Status; 2822 } 2823 2824 /* Otherwise reset the event */ 2825 KeClearEvent(EventObject); 2826 } 2827 2828 /* Check if we should use Sync IO or not */ 2829 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2830 { 2831 /* Lock the file object */ 2832 Status = IopLockFileObject(FileObject, PreviousMode); 2833 if (Status != STATUS_SUCCESS) 2834 { 2835 if (EventObject) ObDereferenceObject(EventObject); 2836 ObDereferenceObject(FileObject); 2837 return Status; 2838 } 2839 2840 /* Check if we don't have a byte offset available */ 2841 if (!(ByteOffset) || 2842 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && 2843 (CapturedByteOffset.u.HighPart == -1))) 2844 { 2845 /* Use the Current Byte Offset instead */ 2846 CapturedByteOffset = FileObject->CurrentByteOffset; 2847 } 2848 2849 /* If the file is cached, try fast I/O */ 2850 if (FileObject->PrivateCacheMap) 2851 { 2852 /* Perform fast read */ 2853 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 2854 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL); 2855 2856 Success = FastIoDispatch->FastIoRead(FileObject, 2857 &CapturedByteOffset, 2858 Length, 2859 TRUE, 2860 CapturedKey, 2861 Buffer, 2862 &KernelIosb, 2863 DeviceObject); 2864 2865 /* Only accept the result if we got a straightforward status */ 2866 if (Success && 2867 (KernelIosb.Status == STATUS_SUCCESS || 2868 KernelIosb.Status == STATUS_BUFFER_OVERFLOW || 2869 KernelIosb.Status == STATUS_END_OF_FILE)) 2870 { 2871 /* Fast path -- update transfer & operation counts */ 2872 IopUpdateOperationCount(IopReadTransfer); 2873 IopUpdateTransferCount(IopReadTransfer, 2874 (ULONG)KernelIosb.Information); 2875 2876 /* Enter SEH to write the IOSB back */ 2877 _SEH2_TRY 2878 { 2879 /* Write it back to the caller */ 2880 *IoStatusBlock = KernelIosb; 2881 } 2882 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2883 { 2884 /* The caller's IOSB was invalid, so fail */ 2885 if (EventObject) ObDereferenceObject(EventObject); 2886 IopUnlockFileObject(FileObject); 2887 ObDereferenceObject(FileObject); 2888 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2889 } 2890 _SEH2_END; 2891 2892 /* Signal the completion event */ 2893 if (EventObject) 2894 { 2895 KeSetEvent(EventObject, 0, FALSE); 2896 ObDereferenceObject(EventObject); 2897 } 2898 2899 /* Clean up */ 2900 IopUnlockFileObject(FileObject); 2901 ObDereferenceObject(FileObject); 2902 return KernelIosb.Status; 2903 } 2904 } 2905 2906 /* Remember we are sync */ 2907 Synchronous = TRUE; 2908 } 2909 else if (!(ByteOffset) && 2910 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) 2911 { 2912 /* Otherwise, this was async I/O without a byte offset, so fail */ 2913 if (EventObject) ObDereferenceObject(EventObject); 2914 ObDereferenceObject(FileObject); 2915 return STATUS_INVALID_PARAMETER; 2916 } 2917 2918 /* Clear the File Object's event */ 2919 KeClearEvent(&FileObject->Event); 2920 2921 /* Allocate the IRP */ 2922 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2923 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 2924 2925 /* Set the IRP */ 2926 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2927 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2928 Irp->RequestorMode = PreviousMode; 2929 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 2930 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 2931 Irp->UserIosb = IoStatusBlock; 2932 Irp->UserEvent = EventObject; 2933 Irp->PendingReturned = FALSE; 2934 Irp->Cancel = FALSE; 2935 Irp->CancelRoutine = NULL; 2936 Irp->AssociatedIrp.SystemBuffer = NULL; 2937 Irp->MdlAddress = NULL; 2938 2939 /* Set the Stack Data */ 2940 StackPtr = IoGetNextIrpStackLocation(Irp); 2941 StackPtr->MajorFunction = IRP_MJ_READ; 2942 StackPtr->FileObject = FileObject; 2943 StackPtr->Parameters.Read.Key = CapturedKey; 2944 StackPtr->Parameters.Read.Length = Length; 2945 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset; 2946 2947 /* Check if this is buffered I/O */ 2948 if (DeviceObject->Flags & DO_BUFFERED_IO) 2949 { 2950 /* Check if we have a buffer length */ 2951 if (Length) 2952 { 2953 /* Enter SEH */ 2954 _SEH2_TRY 2955 { 2956 /* Allocate a buffer */ 2957 Irp->AssociatedIrp.SystemBuffer = 2958 ExAllocatePoolWithTag(NonPagedPool, 2959 Length, 2960 TAG_SYSB); 2961 } 2962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2963 { 2964 /* Allocating failed, clean up and return the exception code */ 2965 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 2966 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2967 } 2968 _SEH2_END; 2969 2970 /* Set the buffer and flags */ 2971 Irp->UserBuffer = Buffer; 2972 Irp->Flags = (IRP_BUFFERED_IO | 2973 IRP_DEALLOCATE_BUFFER | 2974 IRP_INPUT_OPERATION); 2975 } 2976 else 2977 { 2978 /* Not reading anything */ 2979 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; 2980 } 2981 } 2982 else if (DeviceObject->Flags & DO_DIRECT_IO) 2983 { 2984 /* Check if we have a buffer length */ 2985 if (Length) 2986 { 2987 _SEH2_TRY 2988 { 2989 /* Allocate an MDL */ 2990 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); 2991 if (!Mdl) 2992 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2993 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); 2994 } 2995 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2996 { 2997 /* Allocating failed, clean up and return the exception code */ 2998 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 2999 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3000 } 3001 _SEH2_END; 3002 3003 } 3004 3005 /* No allocation flags */ 3006 Irp->Flags = 0; 3007 } 3008 else 3009 { 3010 /* No allocation flags, and use the buffer directly */ 3011 Irp->Flags = 0; 3012 Irp->UserBuffer = Buffer; 3013 } 3014 3015 /* Now set the deferred read flags */ 3016 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION); 3017 3018 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; 3019 3020 /* Perform the call */ 3021 return IopPerformSynchronousRequest(DeviceObject, 3022 Irp, 3023 FileObject, 3024 TRUE, 3025 PreviousMode, 3026 Synchronous, 3027 IopReadTransfer); 3028 } 3029 3030 /* 3031 * @unimplemented 3032 */ 3033 NTSTATUS 3034 NTAPI 3035 NtReadFileScatter(IN HANDLE FileHandle, 3036 IN HANDLE Event OPTIONAL, 3037 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 3038 IN PVOID UserApcContext OPTIONAL, 3039 OUT PIO_STATUS_BLOCK UserIoStatusBlock, 3040 IN FILE_SEGMENT_ELEMENT BufferDescription [], 3041 IN ULONG BufferLength, 3042 IN PLARGE_INTEGER ByteOffset, 3043 IN PULONG Key OPTIONAL) 3044 { 3045 UNIMPLEMENTED; 3046 return STATUS_NOT_IMPLEMENTED; 3047 } 3048 3049 /* 3050 * @unimplemented 3051 */ 3052 NTSTATUS 3053 NTAPI 3054 NtSetEaFile(IN HANDLE FileHandle, 3055 IN PIO_STATUS_BLOCK IoStatusBlock, 3056 IN PVOID EaBuffer, 3057 IN ULONG EaBufferSize) 3058 { 3059 UNIMPLEMENTED; 3060 return STATUS_NOT_IMPLEMENTED; 3061 } 3062 3063 /* 3064 * @implemented 3065 */ 3066 NTSTATUS 3067 NTAPI 3068 NtSetInformationFile(IN HANDLE FileHandle, 3069 OUT PIO_STATUS_BLOCK IoStatusBlock, 3070 IN PVOID FileInformation, 3071 IN ULONG Length, 3072 IN FILE_INFORMATION_CLASS FileInformationClass) 3073 { 3074 PFILE_OBJECT FileObject; 3075 NTSTATUS Status; 3076 PIRP Irp; 3077 PDEVICE_OBJECT DeviceObject; 3078 PIO_STACK_LOCATION StackPtr; 3079 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3080 PKEVENT Event = NULL; 3081 BOOLEAN LocalEvent = FALSE; 3082 PKNORMAL_ROUTINE NormalRoutine; 3083 PVOID NormalContext; 3084 KIRQL OldIrql; 3085 IO_STATUS_BLOCK KernelIosb; 3086 PVOID Queue; 3087 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation; 3088 PIO_COMPLETION_CONTEXT Context; 3089 PFILE_RENAME_INFORMATION RenameInfo; 3090 HANDLE TargetHandle = NULL; 3091 PAGED_CODE(); 3092 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3093 3094 /* Check if we're called from user mode */ 3095 if (PreviousMode != KernelMode) 3096 { 3097 /* Validate the information class */ 3098 if ((FileInformationClass < 0) || 3099 (FileInformationClass >= FileMaximumInformation) || 3100 !(IopSetOperationLength[FileInformationClass])) 3101 { 3102 /* Invalid class */ 3103 return STATUS_INVALID_INFO_CLASS; 3104 } 3105 3106 /* Validate the length */ 3107 if (Length < IopSetOperationLength[FileInformationClass]) 3108 { 3109 /* Invalid length */ 3110 return STATUS_INFO_LENGTH_MISMATCH; 3111 } 3112 3113 /* Enter SEH for probing */ 3114 _SEH2_TRY 3115 { 3116 /* Probe the I/O Status block */ 3117 ProbeForWriteIoStatusBlock(IoStatusBlock); 3118 3119 /* Probe the information */ 3120 ProbeForRead(FileInformation, 3121 Length, 3122 (Length == sizeof(BOOLEAN)) ? 3123 sizeof(BOOLEAN) : sizeof(ULONG)); 3124 } 3125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3126 { 3127 /* Return the exception code */ 3128 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3129 } 3130 _SEH2_END; 3131 } 3132 else 3133 { 3134 /* Validate the information class */ 3135 if ((FileInformationClass < 0) || 3136 (FileInformationClass >= FileMaximumInformation) || 3137 !(IopSetOperationLength[FileInformationClass])) 3138 { 3139 /* Invalid class */ 3140 return STATUS_INVALID_INFO_CLASS; 3141 } 3142 3143 /* Validate the length */ 3144 if (Length < IopSetOperationLength[FileInformationClass]) 3145 { 3146 /* Invalid length */ 3147 return STATUS_INFO_LENGTH_MISMATCH; 3148 } 3149 } 3150 3151 /* Reference the Handle */ 3152 Status = ObReferenceObjectByHandle(FileHandle, 3153 IopSetOperationAccess 3154 [FileInformationClass], 3155 IoFileObjectType, 3156 PreviousMode, 3157 (PVOID *)&FileObject, 3158 NULL); 3159 if (!NT_SUCCESS(Status)) return Status; 3160 3161 /* Check if this is a direct open or not */ 3162 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 3163 { 3164 /* Get the device object */ 3165 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 3166 } 3167 else 3168 { 3169 /* Get the device object */ 3170 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3171 } 3172 3173 DPRINT("Will call: %p\n", DeviceObject); 3174 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName); 3175 3176 /* Check if this is a file that was opened for Synch I/O */ 3177 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3178 { 3179 /* Lock it */ 3180 Status = IopLockFileObject(FileObject, PreviousMode); 3181 if (Status != STATUS_SUCCESS) 3182 { 3183 ObDereferenceObject(FileObject); 3184 return Status; 3185 } 3186 3187 /* Check if the caller just wants the position */ 3188 if (FileInformationClass == FilePositionInformation) 3189 { 3190 /* Protect write in SEH */ 3191 _SEH2_TRY 3192 { 3193 /* Write the offset */ 3194 FileObject->CurrentByteOffset = 3195 ((PFILE_POSITION_INFORMATION)FileInformation)-> 3196 CurrentByteOffset; 3197 3198 /* Fill out the I/O Status Block */ 3199 IoStatusBlock->Information = 0; 3200 Status = IoStatusBlock->Status = STATUS_SUCCESS; 3201 } 3202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3203 { 3204 /* Get the exception code */ 3205 Status = _SEH2_GetExceptionCode(); 3206 } 3207 _SEH2_END; 3208 3209 /* Update transfer count */ 3210 IopUpdateTransferCount(IopOtherTransfer, Length); 3211 3212 /* Release the file lock, dereference the file and return */ 3213 IopUnlockFileObject(FileObject); 3214 ObDereferenceObject(FileObject); 3215 return Status; 3216 } 3217 } 3218 else 3219 { 3220 /* Use local event */ 3221 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3222 if (!Event) 3223 { 3224 ObDereferenceObject(FileObject); 3225 return STATUS_INSUFFICIENT_RESOURCES; 3226 } 3227 3228 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3229 LocalEvent = TRUE; 3230 } 3231 3232 /* Clear the File Object event */ 3233 KeClearEvent(&FileObject->Event); 3234 3235 /* Allocate the IRP */ 3236 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 3237 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3238 3239 /* Set the IRP */ 3240 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3241 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3242 Irp->RequestorMode = PreviousMode; 3243 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3244 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3245 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3246 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3247 Irp->AssociatedIrp.SystemBuffer = NULL; 3248 Irp->MdlAddress = NULL; 3249 Irp->UserBuffer = FileInformation; 3250 3251 /* Set the Stack Data */ 3252 StackPtr = IoGetNextIrpStackLocation(Irp); 3253 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; 3254 StackPtr->FileObject = FileObject; 3255 3256 /* Enter SEH */ 3257 _SEH2_TRY 3258 { 3259 /* Allocate a buffer */ 3260 Irp->AssociatedIrp.SystemBuffer = 3261 ExAllocatePoolWithTag(NonPagedPool, 3262 Length, 3263 TAG_SYSB); 3264 3265 /* Copy the data into it */ 3266 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 3267 FileInformation, 3268 Length); 3269 } 3270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3271 { 3272 /* Allocating failed, clean up and return the exception code */ 3273 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3274 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3275 } 3276 _SEH2_END; 3277 3278 /* Set the flags */ 3279 Irp->Flags |= (IRP_BUFFERED_IO | 3280 IRP_DEALLOCATE_BUFFER | 3281 IRP_DEFER_IO_COMPLETION); 3282 3283 /* Set the Parameters */ 3284 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; 3285 StackPtr->Parameters.SetFile.Length = Length; 3286 3287 /* Queue the IRP */ 3288 IopQueueIrpToThread(Irp); 3289 3290 /* Update operation counts */ 3291 IopUpdateOperationCount(IopOtherTransfer); 3292 3293 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */ 3294 /* Handle IO Completion Port quickly */ 3295 if (FileInformationClass == FileCompletionInformation) 3296 { 3297 /* Check if the file object already has a completion port */ 3298 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || 3299 (FileObject->CompletionContext)) 3300 { 3301 /* Fail */ 3302 Status = STATUS_INVALID_PARAMETER; 3303 } 3304 else 3305 { 3306 /* Reference the Port */ 3307 CompletionInfo = Irp->AssociatedIrp.SystemBuffer; 3308 Status = ObReferenceObjectByHandle(CompletionInfo->Port, 3309 IO_COMPLETION_MODIFY_STATE, 3310 IoCompletionType, 3311 PreviousMode, 3312 (PVOID*)&Queue, 3313 NULL); 3314 if (NT_SUCCESS(Status)) 3315 { 3316 /* Allocate the Context */ 3317 Context = ExAllocatePoolWithTag(PagedPool, 3318 sizeof(IO_COMPLETION_CONTEXT), 3319 IOC_TAG); 3320 if (Context) 3321 { 3322 /* Set the Data */ 3323 Context->Key = CompletionInfo->Key; 3324 Context->Port = Queue; 3325 if (InterlockedCompareExchangePointer((PVOID*)&FileObject-> 3326 CompletionContext, 3327 Context, 3328 NULL)) 3329 { 3330 /* 3331 * Someone else set the completion port in the 3332 * meanwhile, so dereference the port and fail. 3333 */ 3334 ExFreePoolWithTag(Context, IOC_TAG); 3335 ObDereferenceObject(Queue); 3336 Status = STATUS_INVALID_PARAMETER; 3337 } 3338 } 3339 else 3340 { 3341 /* Dereference the Port now */ 3342 ObDereferenceObject(Queue); 3343 Status = STATUS_INSUFFICIENT_RESOURCES; 3344 } 3345 } 3346 } 3347 3348 /* Set the IRP Status */ 3349 Irp->IoStatus.Status = Status; 3350 Irp->IoStatus.Information = 0; 3351 } 3352 else if (FileInformationClass == FileRenameInformation || 3353 FileInformationClass == FileLinkInformation || 3354 FileInformationClass == FileMoveClusterInformation) 3355 { 3356 /* Get associated information */ 3357 RenameInfo = Irp->AssociatedIrp.SystemBuffer; 3358 3359 /* Only rename if: 3360 * -> We have a name 3361 * -> In unicode 3362 * -> sizes are valid 3363 */ 3364 if (RenameInfo->FileNameLength != 0 && 3365 !(RenameInfo->FileNameLength & 1) && 3366 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength)) 3367 { 3368 /* Properly set information received */ 3369 if (FileInformationClass == FileMoveClusterInformation) 3370 { 3371 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount; 3372 } 3373 else 3374 { 3375 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists; 3376 } 3377 3378 /* If we got fully path OR relative target, attempt a parent directory open */ 3379 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory) 3380 { 3381 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject); 3382 if (!NT_SUCCESS(Status)) 3383 { 3384 Irp->IoStatus.Status = Status; 3385 } 3386 else 3387 { 3388 /* Call the Driver */ 3389 Status = IoCallDriver(DeviceObject, Irp); 3390 } 3391 } 3392 else 3393 { 3394 /* Call the Driver */ 3395 Status = IoCallDriver(DeviceObject, Irp); 3396 } 3397 } 3398 else 3399 { 3400 Status = STATUS_INVALID_PARAMETER; 3401 Irp->IoStatus.Status = Status; 3402 } 3403 } 3404 else 3405 { 3406 /* Call the Driver */ 3407 Status = IoCallDriver(DeviceObject, Irp); 3408 } 3409 3410 /* Check if we're waiting for the IRP to complete */ 3411 if (Status == STATUS_PENDING) 3412 { 3413 /* Check if this was async I/O */ 3414 if (LocalEvent) 3415 { 3416 /* Then to a non-alertable wait */ 3417 Status = KeWaitForSingleObject(Event, 3418 Executive, 3419 PreviousMode, 3420 FALSE, 3421 NULL); 3422 if (Status == STATUS_USER_APC) 3423 { 3424 /* Abort the request */ 3425 IopAbortInterruptedIrp(Event, Irp); 3426 } 3427 3428 /* Set the final status */ 3429 Status = KernelIosb.Status; 3430 3431 /* Enter SEH to write the IOSB back */ 3432 _SEH2_TRY 3433 { 3434 /* Write it back to the caller */ 3435 *IoStatusBlock = KernelIosb; 3436 } 3437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3438 { 3439 /* Get the exception code */ 3440 Status = _SEH2_GetExceptionCode(); 3441 } 3442 _SEH2_END; 3443 3444 /* Free the event */ 3445 ExFreePoolWithTag(Event, TAG_IO); 3446 } 3447 else 3448 { 3449 /* Wait for the IRP */ 3450 Status = KeWaitForSingleObject(&FileObject->Event, 3451 Executive, 3452 PreviousMode, 3453 (FileObject->Flags & 3454 FO_ALERTABLE_IO) != 0, 3455 NULL); 3456 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) 3457 { 3458 /* Abort the request */ 3459 IopAbortInterruptedIrp(&FileObject->Event, Irp); 3460 } 3461 3462 /* Set the final status */ 3463 Status = FileObject->FinalStatus; 3464 3465 /* Release the file lock */ 3466 IopUnlockFileObject(FileObject); 3467 } 3468 } 3469 else 3470 { 3471 /* Free the event if we had one */ 3472 if (LocalEvent) 3473 { 3474 /* Clear it in the IRP for completion */ 3475 Irp->UserEvent = NULL; 3476 ExFreePoolWithTag(Event, TAG_IO); 3477 } 3478 3479 /* Set the caller IOSB */ 3480 Irp->UserIosb = IoStatusBlock; 3481 3482 /* The IRP wasn't completed, complete it ourselves */ 3483 KeRaiseIrql(APC_LEVEL, &OldIrql); 3484 IopCompleteRequest(&Irp->Tail.Apc, 3485 &NormalRoutine, 3486 &NormalContext, 3487 (PVOID*)&FileObject, 3488 &NormalContext); 3489 KeLowerIrql(OldIrql); 3490 3491 /* Release the file object if we had locked it*/ 3492 if (!LocalEvent) IopUnlockFileObject(FileObject); 3493 } 3494 3495 if (TargetHandle != NULL) 3496 { 3497 ObCloseHandle(TargetHandle, KernelMode); 3498 } 3499 3500 /* Return the Status */ 3501 return Status; 3502 } 3503 3504 /* 3505 * @unimplemented 3506 */ 3507 NTSTATUS 3508 NTAPI 3509 NtSetQuotaInformationFile(IN HANDLE FileHandle, 3510 OUT PIO_STATUS_BLOCK IoStatusBlock, 3511 IN PVOID Buffer, 3512 IN ULONG BufferLength) 3513 { 3514 UNIMPLEMENTED; 3515 return STATUS_NOT_IMPLEMENTED; 3516 } 3517 3518 /* 3519 * @implemented 3520 */ 3521 NTSTATUS 3522 NTAPI 3523 NtUnlockFile(IN HANDLE FileHandle, 3524 OUT PIO_STATUS_BLOCK IoStatusBlock, 3525 IN PLARGE_INTEGER ByteOffset, 3526 IN PLARGE_INTEGER Length, 3527 IN ULONG Key OPTIONAL) 3528 { 3529 PFILE_OBJECT FileObject; 3530 PLARGE_INTEGER LocalLength = NULL; 3531 PIRP Irp; 3532 PIO_STACK_LOCATION StackPtr; 3533 PDEVICE_OBJECT DeviceObject; 3534 PKEVENT Event = NULL; 3535 BOOLEAN LocalEvent = FALSE; 3536 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3537 LARGE_INTEGER CapturedByteOffset, CapturedLength; 3538 NTSTATUS Status; 3539 OBJECT_HANDLE_INFORMATION HandleInformation; 3540 IO_STATUS_BLOCK KernelIosb; 3541 PFAST_IO_DISPATCH FastIoDispatch; 3542 PAGED_CODE(); 3543 CapturedByteOffset.QuadPart = 0; 3544 CapturedLength.QuadPart = 0; 3545 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3546 3547 /* Get File Object */ 3548 Status = ObReferenceObjectByHandle(FileHandle, 3549 0, 3550 IoFileObjectType, 3551 PreviousMode, 3552 (PVOID*)&FileObject, 3553 &HandleInformation); 3554 if (!NT_SUCCESS(Status)) return Status; 3555 3556 /* Check if we're called from user mode */ 3557 if (PreviousMode != KernelMode) 3558 { 3559 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */ 3560 if (!(HandleInformation.GrantedAccess & 3561 (FILE_WRITE_DATA | FILE_READ_DATA))) 3562 { 3563 ObDereferenceObject(FileObject); 3564 return STATUS_ACCESS_DENIED; 3565 } 3566 3567 /* Enter SEH for probing */ 3568 _SEH2_TRY 3569 { 3570 /* Probe the I/O Status block */ 3571 ProbeForWriteIoStatusBlock(IoStatusBlock); 3572 3573 /* Probe and capture the large integers */ 3574 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 3575 CapturedLength = ProbeForReadLargeInteger(Length); 3576 } 3577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3578 { 3579 /* Dereference the object and return exception code */ 3580 ObDereferenceObject(FileObject); 3581 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3582 } 3583 _SEH2_END; 3584 } 3585 else 3586 { 3587 /* Otherwise, capture them directly */ 3588 CapturedByteOffset = *ByteOffset; 3589 CapturedLength = *Length; 3590 } 3591 3592 /* Check if this is a direct open or not */ 3593 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 3594 { 3595 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 3596 } 3597 else 3598 { 3599 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3600 } 3601 3602 /* Try to do it the FastIO way if possible */ 3603 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 3604 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL) 3605 { 3606 if (FastIoDispatch->FastIoUnlockSingle(FileObject, 3607 &CapturedByteOffset, 3608 &CapturedLength, 3609 PsGetCurrentProcess(), 3610 Key, 3611 &KernelIosb, 3612 DeviceObject)) 3613 { 3614 /* Write the IOSB back */ 3615 _SEH2_TRY 3616 { 3617 *IoStatusBlock = KernelIosb; 3618 } 3619 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3620 { 3621 KernelIosb.Status = _SEH2_GetExceptionCode(); 3622 } 3623 _SEH2_END; 3624 3625 /* We're done with FastIO! */ 3626 ObDereferenceObject(FileObject); 3627 return KernelIosb.Status; 3628 } 3629 } 3630 3631 /* Check if we should use Sync IO or not */ 3632 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3633 { 3634 /* Lock it */ 3635 Status = IopLockFileObject(FileObject, PreviousMode); 3636 if (Status != STATUS_SUCCESS) 3637 { 3638 ObDereferenceObject(FileObject); 3639 return Status; 3640 } 3641 } 3642 else 3643 { 3644 /* Use local event */ 3645 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3646 if (!Event) 3647 { 3648 ObDereferenceObject(FileObject); 3649 return STATUS_INSUFFICIENT_RESOURCES; 3650 } 3651 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3652 LocalEvent = TRUE; 3653 } 3654 3655 /* Clear File Object event */ 3656 KeClearEvent(&FileObject->Event); 3657 3658 /* Allocate the IRP */ 3659 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3660 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3661 3662 /* Set up the IRP */ 3663 Irp->RequestorMode = PreviousMode; 3664 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3665 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3666 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3667 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3668 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3669 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3670 3671 /* Set up Stack Data */ 3672 StackPtr = IoGetNextIrpStackLocation(Irp); 3673 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; 3674 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE; 3675 StackPtr->FileObject = FileObject; 3676 3677 /* Enter SEH */ 3678 _SEH2_TRY 3679 { 3680 /* Allocate a buffer */ 3681 LocalLength = ExAllocatePoolWithTag(NonPagedPool, 3682 sizeof(LARGE_INTEGER), 3683 TAG_LOCK); 3684 3685 /* Set the length */ 3686 *LocalLength = CapturedLength; 3687 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength; 3688 StackPtr->Parameters.LockControl.Length = LocalLength; 3689 } 3690 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3691 { 3692 /* Allocating failed, clean up and return the exception code */ 3693 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3694 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK); 3695 3696 /* Return the exception code */ 3697 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3698 } 3699 _SEH2_END; 3700 3701 /* Set Parameters */ 3702 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset; 3703 StackPtr->Parameters.LockControl.Key = Key; 3704 3705 /* Call the Driver */ 3706 Status = IopPerformSynchronousRequest(DeviceObject, 3707 Irp, 3708 FileObject, 3709 FALSE, 3710 PreviousMode, 3711 !LocalEvent, 3712 IopOtherTransfer); 3713 3714 /* Check if this was async I/O */ 3715 if (LocalEvent) 3716 { 3717 /* It was, finalize this request */ 3718 Status = IopFinalizeAsynchronousIo(Status, 3719 Event, 3720 Irp, 3721 PreviousMode, 3722 &KernelIosb, 3723 IoStatusBlock); 3724 } 3725 3726 /* Return status */ 3727 return Status; 3728 } 3729 3730 /* 3731 * @implemented 3732 */ 3733 NTSTATUS 3734 NTAPI 3735 NtWriteFile(IN HANDLE FileHandle, 3736 IN HANDLE Event OPTIONAL, 3737 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 3738 IN PVOID ApcContext OPTIONAL, 3739 OUT PIO_STATUS_BLOCK IoStatusBlock, 3740 IN PVOID Buffer, 3741 IN ULONG Length, 3742 IN PLARGE_INTEGER ByteOffset OPTIONAL, 3743 IN PULONG Key OPTIONAL) 3744 { 3745 NTSTATUS Status; 3746 PFILE_OBJECT FileObject; 3747 PIRP Irp; 3748 PDEVICE_OBJECT DeviceObject; 3749 PIO_STACK_LOCATION StackPtr; 3750 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3751 PKEVENT EventObject = NULL; 3752 LARGE_INTEGER CapturedByteOffset; 3753 ULONG CapturedKey = 0; 3754 BOOLEAN Synchronous = FALSE; 3755 PMDL Mdl; 3756 OBJECT_HANDLE_INFORMATION ObjectHandleInfo; 3757 PFAST_IO_DISPATCH FastIoDispatch; 3758 IO_STATUS_BLOCK KernelIosb; 3759 BOOLEAN Success; 3760 3761 PAGED_CODE(); 3762 CapturedByteOffset.QuadPart = 0; 3763 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3764 3765 /* Get File Object for write */ 3766 Status = ObReferenceFileObjectForWrite(FileHandle, 3767 PreviousMode, 3768 &FileObject, 3769 &ObjectHandleInfo); 3770 if (!NT_SUCCESS(Status)) return Status; 3771 3772 /* Get the device object */ 3773 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3774 3775 /* Validate User-Mode Buffers */ 3776 if (PreviousMode != KernelMode) 3777 { 3778 _SEH2_TRY 3779 { 3780 /* Probe the status block */ 3781 ProbeForWriteIoStatusBlock(IoStatusBlock); 3782 3783 /* Probe the read buffer */ 3784 ProbeForRead(Buffer, Length, 1); 3785 3786 /* Check if we got a byte offset */ 3787 if (ByteOffset) 3788 { 3789 /* Capture and probe it */ 3790 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 3791 } 3792 3793 /* Perform additional checks for non-cached file access */ 3794 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) 3795 { 3796 /* Fail if Length is not sector size aligned 3797 * Perform a quick check for 2^ sector sizes 3798 * If it fails, try a more standard way 3799 */ 3800 if ((DeviceObject->SectorSize != 0) && 3801 ((DeviceObject->SectorSize - 1) & Length) != 0) 3802 { 3803 if (Length % DeviceObject->SectorSize != 0) 3804 { 3805 /* Release the file object and and fail */ 3806 ObDereferenceObject(FileObject); 3807 return STATUS_INVALID_PARAMETER; 3808 } 3809 } 3810 3811 /* Fail if buffer doesn't match alignment requirements */ 3812 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0) 3813 { 3814 /* Release the file object and and fail */ 3815 ObDereferenceObject(FileObject); 3816 return STATUS_INVALID_PARAMETER; 3817 } 3818 3819 if (ByteOffset) 3820 { 3821 /* Fail if ByteOffset is not sector size aligned */ 3822 if ((DeviceObject->SectorSize != 0) && 3823 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0)) 3824 { 3825 /* Only if that's not specific values for synchronous IO */ 3826 if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) && 3827 (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION || 3828 !BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))) 3829 { 3830 /* Release the file object and and fail */ 3831 ObDereferenceObject(FileObject); 3832 return STATUS_INVALID_PARAMETER; 3833 } 3834 } 3835 } 3836 } 3837 3838 /* Capture and probe the key */ 3839 if (Key) CapturedKey = ProbeForReadUlong(Key); 3840 } 3841 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3842 { 3843 /* Release the file object and return the exception code */ 3844 ObDereferenceObject(FileObject); 3845 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3846 } 3847 _SEH2_END; 3848 } 3849 else 3850 { 3851 /* Kernel mode: capture directly */ 3852 if (ByteOffset) CapturedByteOffset = *ByteOffset; 3853 if (Key) CapturedKey = *Key; 3854 } 3855 3856 /* Check for invalid offset */ 3857 if (CapturedByteOffset.QuadPart < -2) 3858 { 3859 /* -1 is FILE_WRITE_TO_END_OF_FILE */ 3860 /* -2 is FILE_USE_FILE_POINTER_POSITION */ 3861 ObDereferenceObject(FileObject); 3862 return STATUS_INVALID_PARAMETER; 3863 } 3864 3865 /* Check if this is an append operation */ 3866 if ((ObjectHandleInfo.GrantedAccess & 3867 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA) 3868 { 3869 /* Give the drivers something to understand */ 3870 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE; 3871 CapturedByteOffset.u.HighPart = -1; 3872 } 3873 3874 /* Check for event */ 3875 if (Event) 3876 { 3877 /* Reference it */ 3878 Status = ObReferenceObjectByHandle(Event, 3879 EVENT_MODIFY_STATE, 3880 ExEventObjectType, 3881 PreviousMode, 3882 (PVOID*)&EventObject, 3883 NULL); 3884 if (!NT_SUCCESS(Status)) 3885 { 3886 /* Fail */ 3887 ObDereferenceObject(FileObject); 3888 return Status; 3889 } 3890 3891 /* Otherwise reset the event */ 3892 KeClearEvent(EventObject); 3893 } 3894 3895 /* Check if we should use Sync IO or not */ 3896 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3897 { 3898 /* Lock the file object */ 3899 Status = IopLockFileObject(FileObject, PreviousMode); 3900 if (Status != STATUS_SUCCESS) 3901 { 3902 if (EventObject) ObDereferenceObject(EventObject); 3903 ObDereferenceObject(FileObject); 3904 return Status; 3905 } 3906 3907 /* Check if we don't have a byte offset available */ 3908 if (!(ByteOffset) || 3909 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && 3910 (CapturedByteOffset.u.HighPart == -1))) 3911 { 3912 /* Use the Current Byte Offset instead */ 3913 CapturedByteOffset = FileObject->CurrentByteOffset; 3914 } 3915 3916 /* If the file is cached, try fast I/O */ 3917 if (FileObject->PrivateCacheMap) 3918 { 3919 /* Perform fast write */ 3920 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 3921 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL); 3922 3923 Success = FastIoDispatch->FastIoWrite(FileObject, 3924 &CapturedByteOffset, 3925 Length, 3926 TRUE, 3927 CapturedKey, 3928 Buffer, 3929 &KernelIosb, 3930 DeviceObject); 3931 3932 /* Only accept the result if it was successful */ 3933 if (Success && 3934 KernelIosb.Status == STATUS_SUCCESS) 3935 { 3936 /* Fast path -- update transfer & operation counts */ 3937 IopUpdateOperationCount(IopWriteTransfer); 3938 IopUpdateTransferCount(IopWriteTransfer, 3939 (ULONG)KernelIosb.Information); 3940 3941 /* Enter SEH to write the IOSB back */ 3942 _SEH2_TRY 3943 { 3944 /* Write it back to the caller */ 3945 *IoStatusBlock = KernelIosb; 3946 } 3947 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3948 { 3949 /* The caller's IOSB was invalid, so fail */ 3950 if (EventObject) ObDereferenceObject(EventObject); 3951 IopUnlockFileObject(FileObject); 3952 ObDereferenceObject(FileObject); 3953 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3954 } 3955 _SEH2_END; 3956 3957 /* Signal the completion event */ 3958 if (EventObject) 3959 { 3960 KeSetEvent(EventObject, 0, FALSE); 3961 ObDereferenceObject(EventObject); 3962 } 3963 3964 /* Clean up */ 3965 IopUnlockFileObject(FileObject); 3966 ObDereferenceObject(FileObject); 3967 return KernelIosb.Status; 3968 } 3969 } 3970 3971 /* Remember we are sync */ 3972 Synchronous = TRUE; 3973 } 3974 else if (!(ByteOffset) && 3975 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) 3976 { 3977 /* Otherwise, this was async I/O without a byte offset, so fail */ 3978 if (EventObject) ObDereferenceObject(EventObject); 3979 ObDereferenceObject(FileObject); 3980 return STATUS_INVALID_PARAMETER; 3981 } 3982 3983 /* Clear the File Object's event */ 3984 KeClearEvent(&FileObject->Event); 3985 3986 /* Allocate the IRP */ 3987 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3988 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 3989 3990 /* Set the IRP */ 3991 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3992 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3993 Irp->RequestorMode = PreviousMode; 3994 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 3995 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 3996 Irp->UserIosb = IoStatusBlock; 3997 Irp->UserEvent = EventObject; 3998 Irp->PendingReturned = FALSE; 3999 Irp->Cancel = FALSE; 4000 Irp->CancelRoutine = NULL; 4001 Irp->AssociatedIrp.SystemBuffer = NULL; 4002 Irp->MdlAddress = NULL; 4003 4004 /* Set the Stack Data */ 4005 StackPtr = IoGetNextIrpStackLocation(Irp); 4006 StackPtr->MajorFunction = IRP_MJ_WRITE; 4007 StackPtr->FileObject = FileObject; 4008 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ? 4009 SL_WRITE_THROUGH : 0; 4010 StackPtr->Parameters.Write.Key = CapturedKey; 4011 StackPtr->Parameters.Write.Length = Length; 4012 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset; 4013 4014 /* Check if this is buffered I/O */ 4015 if (DeviceObject->Flags & DO_BUFFERED_IO) 4016 { 4017 /* Check if we have a buffer length */ 4018 if (Length) 4019 { 4020 /* Enter SEH */ 4021 _SEH2_TRY 4022 { 4023 /* Allocate a buffer */ 4024 Irp->AssociatedIrp.SystemBuffer = 4025 ExAllocatePoolWithTag(NonPagedPool, 4026 Length, 4027 TAG_SYSB); 4028 4029 /* Copy the data into it */ 4030 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length); 4031 } 4032 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4033 { 4034 /* Allocating failed, clean up and return the exception code */ 4035 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 4036 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4037 } 4038 _SEH2_END; 4039 4040 /* Set the flags */ 4041 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); 4042 } 4043 else 4044 { 4045 /* Not writing anything */ 4046 Irp->Flags = IRP_BUFFERED_IO; 4047 } 4048 } 4049 else if (DeviceObject->Flags & DO_DIRECT_IO) 4050 { 4051 /* Check if we have a buffer length */ 4052 if (Length) 4053 { 4054 _SEH2_TRY 4055 { 4056 /* Allocate an MDL */ 4057 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); 4058 if (!Mdl) 4059 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 4060 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess); 4061 } 4062 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4063 { 4064 /* Allocating failed, clean up and return the exception code */ 4065 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 4066 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4067 } 4068 _SEH2_END; 4069 } 4070 4071 /* No allocation flags */ 4072 Irp->Flags = 0; 4073 } 4074 else 4075 { 4076 /* No allocation flags, and use the buffer directly */ 4077 Irp->Flags = 0; 4078 Irp->UserBuffer = Buffer; 4079 } 4080 4081 /* Now set the deferred read flags */ 4082 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION); 4083 4084 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; 4085 4086 /* Perform the call */ 4087 return IopPerformSynchronousRequest(DeviceObject, 4088 Irp, 4089 FileObject, 4090 TRUE, 4091 PreviousMode, 4092 Synchronous, 4093 IopWriteTransfer); 4094 } 4095 4096 NTSTATUS 4097 NTAPI 4098 NtWriteFileGather(IN HANDLE FileHandle, 4099 IN HANDLE Event OPTIONAL, 4100 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 4101 IN PVOID UserApcContext OPTIONAL, 4102 OUT PIO_STATUS_BLOCK UserIoStatusBlock, 4103 IN FILE_SEGMENT_ELEMENT BufferDescription [], 4104 IN ULONG BufferLength, 4105 IN PLARGE_INTEGER ByteOffset, 4106 IN PULONG Key OPTIONAL) 4107 { 4108 UNIMPLEMENTED; 4109 return STATUS_NOT_IMPLEMENTED; 4110 } 4111 4112 /* 4113 * @implemented 4114 */ 4115 NTSTATUS 4116 NTAPI 4117 NtQueryVolumeInformationFile(IN HANDLE FileHandle, 4118 OUT PIO_STATUS_BLOCK IoStatusBlock, 4119 OUT PVOID FsInformation, 4120 IN ULONG Length, 4121 IN FS_INFORMATION_CLASS FsInformationClass) 4122 { 4123 PFILE_OBJECT FileObject; 4124 PIRP Irp; 4125 PIO_STACK_LOCATION StackPtr; 4126 PDEVICE_OBJECT DeviceObject; 4127 PKEVENT Event = NULL; 4128 BOOLEAN LocalEvent = FALSE; 4129 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 4130 NTSTATUS Status; 4131 IO_STATUS_BLOCK KernelIosb; 4132 PAGED_CODE(); 4133 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 4134 4135 /* Check if we're called from user mode */ 4136 if (PreviousMode != KernelMode) 4137 { 4138 /* Validate the information class */ 4139 if ((FsInformationClass < 0) || 4140 (FsInformationClass >= FileFsMaximumInformation) || 4141 !(IopQueryFsOperationLength[FsInformationClass])) 4142 { 4143 /* Invalid class */ 4144 return STATUS_INVALID_INFO_CLASS; 4145 } 4146 4147 /* Validate the length */ 4148 if (Length < IopQueryFsOperationLength[FsInformationClass]) 4149 { 4150 /* Invalid length */ 4151 return STATUS_INFO_LENGTH_MISMATCH; 4152 } 4153 4154 /* Enter SEH for probing */ 4155 _SEH2_TRY 4156 { 4157 /* Probe the I/O Status block */ 4158 ProbeForWriteIoStatusBlock(IoStatusBlock); 4159 4160 /* Probe the information */ 4161 ProbeForWrite(FsInformation, Length, sizeof(ULONG)); 4162 } 4163 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4164 { 4165 /* Return the exception code */ 4166 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4167 } 4168 _SEH2_END; 4169 } 4170 4171 /* Get File Object */ 4172 Status = ObReferenceObjectByHandle(FileHandle, 4173 IopQueryFsOperationAccess 4174 [FsInformationClass], 4175 IoFileObjectType, 4176 PreviousMode, 4177 (PVOID*)&FileObject, 4178 NULL); 4179 if (!NT_SUCCESS(Status)) return Status; 4180 4181 /* Only allow direct device open for FileFsDeviceInformation */ 4182 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) && 4183 FsInformationClass != FileFsDeviceInformation) 4184 { 4185 ObDereferenceObject(FileObject); 4186 return STATUS_INVALID_DEVICE_REQUEST; 4187 } 4188 4189 /* Check if we should use Sync IO or not */ 4190 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 4191 { 4192 /* Lock it */ 4193 Status = IopLockFileObject(FileObject, PreviousMode); 4194 if (Status != STATUS_SUCCESS) 4195 { 4196 ObDereferenceObject(FileObject); 4197 return Status; 4198 } 4199 } 4200 4201 /* 4202 * Quick path for FileFsDeviceInformation - the kernel has enough 4203 * info to reply instead of the driver, excepted for network file systems 4204 */ 4205 if (FsInformationClass == FileFsDeviceInformation && 4206 (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) || FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)) 4207 { 4208 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo = FsInformation; 4209 DeviceObject = FileObject->DeviceObject; 4210 4211 _SEH2_TRY 4212 { 4213 FsDeviceInfo->DeviceType = DeviceObject->DeviceType; 4214 4215 /* Complete characteristcs with mount status if relevant */ 4216 FsDeviceInfo->Characteristics = DeviceObject->Characteristics; 4217 if (IopGetMountFlag(DeviceObject)) 4218 { 4219 SetFlag(FsDeviceInfo->Characteristics, FILE_DEVICE_IS_MOUNTED); 4220 } 4221 4222 IoStatusBlock->Information = sizeof(FILE_FS_DEVICE_INFORMATION); 4223 IoStatusBlock->Status = STATUS_SUCCESS; 4224 } 4225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4226 { 4227 /* Check if we had a file lock */ 4228 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4229 { 4230 /* Release it */ 4231 IopUnlockFileObject(FileObject); 4232 } 4233 4234 /* Dereference the FO */ 4235 ObDereferenceObject(FileObject); 4236 4237 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4238 } 4239 _SEH2_END; 4240 4241 /* Check if we had a file lock */ 4242 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4243 { 4244 /* Release it */ 4245 IopUnlockFileObject(FileObject); 4246 } 4247 4248 /* Dereference the FO */ 4249 ObDereferenceObject(FileObject); 4250 4251 return STATUS_SUCCESS; 4252 } 4253 /* This is to be handled by the kernel, not by FSD */ 4254 else if (FsInformationClass == FileFsDriverPathInformation) 4255 { 4256 PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo; 4257 4258 _SEH2_TRY 4259 { 4260 /* Allocate our local structure */ 4261 DriverPathInfo = ExAllocatePoolWithQuotaTag(NonPagedPool, Length, TAG_IO); 4262 4263 /* And copy back caller data */ 4264 RtlCopyMemory(DriverPathInfo, FsInformation, Length); 4265 4266 /* Is the driver in the IO path? */ 4267 Status = IopGetDriverPathInformation(FileObject, DriverPathInfo, Length); 4268 /* We failed, don't continue execution */ 4269 if (!NT_SUCCESS(Status)) 4270 { 4271 RtlRaiseStatus(Status); 4272 } 4273 4274 /* We succeed, copy back info */ 4275 ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath; 4276 4277 /* We're done */ 4278 IoStatusBlock->Information = sizeof(FILE_FS_DRIVER_PATH_INFORMATION); 4279 IoStatusBlock->Status = STATUS_SUCCESS; 4280 } 4281 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4282 { 4283 Status = _SEH2_GetExceptionCode(); 4284 } 4285 _SEH2_END; 4286 4287 /* Don't leak */ 4288 if (DriverPathInfo != NULL) 4289 { 4290 ExFreePoolWithTag(DriverPathInfo, TAG_IO); 4291 } 4292 4293 /* Check if we had a file lock */ 4294 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4295 { 4296 /* Release it */ 4297 IopUnlockFileObject(FileObject); 4298 } 4299 4300 /* Dereference the FO */ 4301 ObDereferenceObject(FileObject); 4302 4303 return Status; 4304 } 4305 4306 if (!BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4307 { 4308 /* Use local event */ 4309 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 4310 if (!Event) 4311 { 4312 ObDereferenceObject(FileObject); 4313 return STATUS_INSUFFICIENT_RESOURCES; 4314 } 4315 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 4316 LocalEvent = TRUE; 4317 } 4318 4319 /* Get the device object */ 4320 DeviceObject = IoGetRelatedDeviceObject(FileObject); 4321 4322 /* Clear File Object event */ 4323 KeClearEvent(&FileObject->Event); 4324 4325 /* Allocate the IRP */ 4326 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4327 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 4328 4329 /* Set up the IRP */ 4330 Irp->RequestorMode = PreviousMode; 4331 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 4332 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 4333 Irp->UserEvent = (LocalEvent) ? Event : NULL; 4334 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 4335 Irp->Tail.Overlay.OriginalFileObject = FileObject; 4336 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 4337 Irp->UserBuffer = FsInformation; 4338 Irp->AssociatedIrp.SystemBuffer = NULL; 4339 Irp->MdlAddress = NULL; 4340 4341 /* Set up Stack Data */ 4342 StackPtr = IoGetNextIrpStackLocation(Irp); 4343 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION; 4344 StackPtr->FileObject = FileObject; 4345 4346 /* Enter SEH */ 4347 _SEH2_TRY 4348 { 4349 /* Allocate a buffer */ 4350 Irp->AssociatedIrp.SystemBuffer = 4351 ExAllocatePoolWithTag(NonPagedPool, 4352 Length, 4353 TAG_SYSB); 4354 } 4355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4356 { 4357 /* Allocating failed, clean up and return the exception code */ 4358 IopCleanupAfterException(FileObject, Irp, NULL, Event); 4359 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4360 } 4361 _SEH2_END; 4362 4363 /* Set the flags for this buffered + deferred I/O */ 4364 Irp->Flags |= (IRP_BUFFERED_IO | 4365 IRP_DEALLOCATE_BUFFER | 4366 IRP_INPUT_OPERATION | 4367 IRP_DEFER_IO_COMPLETION); 4368 4369 /* Set Parameters */ 4370 StackPtr->Parameters.QueryVolume.Length = Length; 4371 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass; 4372 4373 /* Call the Driver */ 4374 Status = IopPerformSynchronousRequest(DeviceObject, 4375 Irp, 4376 FileObject, 4377 TRUE, 4378 PreviousMode, 4379 !LocalEvent, 4380 IopOtherTransfer); 4381 4382 /* Check if this was async I/O */ 4383 if (LocalEvent) 4384 { 4385 /* It was, finalize this request */ 4386 Status = IopFinalizeAsynchronousIo(Status, 4387 Event, 4388 Irp, 4389 PreviousMode, 4390 &KernelIosb, 4391 IoStatusBlock); 4392 } 4393 4394 /* Return status */ 4395 return Status; 4396 } 4397 4398 /* 4399 * @implemented 4400 */ 4401 NTSTATUS 4402 NTAPI 4403 NtSetVolumeInformationFile(IN HANDLE FileHandle, 4404 OUT PIO_STATUS_BLOCK IoStatusBlock, 4405 IN PVOID FsInformation, 4406 IN ULONG Length, 4407 IN FS_INFORMATION_CLASS FsInformationClass) 4408 { 4409 PFILE_OBJECT FileObject; 4410 PIRP Irp; 4411 PIO_STACK_LOCATION StackPtr; 4412 PDEVICE_OBJECT DeviceObject, TargetDeviceObject; 4413 PKEVENT Event = NULL; 4414 BOOLEAN LocalEvent = FALSE; 4415 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 4416 NTSTATUS Status; 4417 IO_STATUS_BLOCK KernelIosb; 4418 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure; 4419 PAGED_CODE(); 4420 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 4421 4422 /* Check if we're called from user mode */ 4423 if (PreviousMode != KernelMode) 4424 { 4425 /* Validate the information class */ 4426 if ((FsInformationClass < 0) || 4427 (FsInformationClass >= FileFsMaximumInformation) || 4428 !(IopSetFsOperationLength[FsInformationClass])) 4429 { 4430 /* Invalid class */ 4431 return STATUS_INVALID_INFO_CLASS; 4432 } 4433 4434 /* Validate the length */ 4435 if (Length < IopSetFsOperationLength[FsInformationClass]) 4436 { 4437 /* Invalid length */ 4438 return STATUS_INFO_LENGTH_MISMATCH; 4439 } 4440 4441 /* Enter SEH for probing */ 4442 _SEH2_TRY 4443 { 4444 /* Probe the I/O Status block */ 4445 ProbeForWriteIoStatusBlock(IoStatusBlock); 4446 4447 /* Probe the information */ 4448 ProbeForRead(FsInformation, Length, sizeof(ULONG)); 4449 } 4450 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4451 { 4452 /* Return the exception code */ 4453 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4454 } 4455 _SEH2_END; 4456 } 4457 4458 /* Get File Object */ 4459 Status = ObReferenceObjectByHandle(FileHandle, 4460 IopSetFsOperationAccess 4461 [FsInformationClass], 4462 IoFileObjectType, 4463 PreviousMode, 4464 (PVOID*)&FileObject, 4465 NULL); 4466 if (!NT_SUCCESS(Status)) return Status; 4467 4468 /* Get target device for notification */ 4469 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject); 4470 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL; 4471 4472 /* Check if we should use Sync IO or not */ 4473 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 4474 { 4475 /* Lock it */ 4476 Status = IopLockFileObject(FileObject, PreviousMode); 4477 if (Status != STATUS_SUCCESS) 4478 { 4479 ObDereferenceObject(FileObject); 4480 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4481 return Status; 4482 } 4483 } 4484 else 4485 { 4486 /* Use local event */ 4487 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 4488 if (!Event) 4489 { 4490 ObDereferenceObject(FileObject); 4491 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4492 return STATUS_INSUFFICIENT_RESOURCES; 4493 } 4494 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 4495 LocalEvent = TRUE; 4496 } 4497 4498 /* Get the device object */ 4499 DeviceObject = IoGetRelatedDeviceObject(FileObject); 4500 4501 /* Clear File Object event */ 4502 KeClearEvent(&FileObject->Event); 4503 4504 /* Allocate the IRP */ 4505 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4506 if (!Irp) 4507 { 4508 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4509 return IopCleanupFailedIrp(FileObject, NULL, Event); 4510 } 4511 4512 /* Set up the IRP */ 4513 Irp->RequestorMode = PreviousMode; 4514 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 4515 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 4516 Irp->UserEvent = (LocalEvent) ? Event : NULL; 4517 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 4518 Irp->Tail.Overlay.OriginalFileObject = FileObject; 4519 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 4520 Irp->UserBuffer = FsInformation; 4521 Irp->AssociatedIrp.SystemBuffer = NULL; 4522 Irp->MdlAddress = NULL; 4523 4524 /* Set up Stack Data */ 4525 StackPtr = IoGetNextIrpStackLocation(Irp); 4526 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION; 4527 StackPtr->FileObject = FileObject; 4528 4529 /* Enter SEH */ 4530 _SEH2_TRY 4531 { 4532 /* Allocate a buffer */ 4533 Irp->AssociatedIrp.SystemBuffer = 4534 ExAllocatePoolWithTag(NonPagedPool, 4535 Length, 4536 TAG_SYSB); 4537 4538 /* Copy the data into it */ 4539 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length); 4540 } 4541 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4542 { 4543 /* Allocating failed, clean up and return the exception code */ 4544 IopCleanupAfterException(FileObject, Irp, NULL, Event); 4545 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4546 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4547 } 4548 _SEH2_END; 4549 4550 /* Set the flags for this buffered + deferred I/O */ 4551 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); 4552 4553 /* Set Parameters */ 4554 StackPtr->Parameters.SetVolume.Length = Length; 4555 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass; 4556 4557 /* Call the Driver */ 4558 Status = IopPerformSynchronousRequest(DeviceObject, 4559 Irp, 4560 FileObject, 4561 FALSE, 4562 PreviousMode, 4563 !LocalEvent, 4564 IopOtherTransfer); 4565 4566 /* Check if this was async I/O */ 4567 if (LocalEvent) 4568 { 4569 /* It was, finalize this request */ 4570 Status = IopFinalizeAsynchronousIo(Status, 4571 Event, 4572 Irp, 4573 PreviousMode, 4574 &KernelIosb, 4575 IoStatusBlock); 4576 } 4577 4578 if (TargetDeviceObject && NT_SUCCESS(Status)) 4579 { 4580 /* Time to report change */ 4581 NotificationStructure.Version = 1; 4582 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION); 4583 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE; 4584 NotificationStructure.FileObject = NULL; 4585 NotificationStructure.NameBufferOffset = - 1; 4586 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure); 4587 } 4588 4589 /* Return status */ 4590 return Status; 4591 } 4592 4593 /* 4594 * @unimplemented 4595 */ 4596 NTSTATUS 4597 NTAPI 4598 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle) 4599 { 4600 UNIMPLEMENTED; 4601 return STATUS_NOT_IMPLEMENTED; 4602 } 4603 4604 /* 4605 * @unimplemented 4606 */ 4607 NTSTATUS 4608 NTAPI 4609 NtRequestDeviceWakeup(IN HANDLE DeviceHandle) 4610 { 4611 UNIMPLEMENTED; 4612 return STATUS_NOT_IMPLEMENTED; 4613 } 4614