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 /* Get File Object */ 2056 Status = ObReferenceObjectByHandle(FileHandle, 2057 FILE_LIST_DIRECTORY, 2058 IoFileObjectType, 2059 PreviousMode, 2060 (PVOID *)&FileObject, 2061 NULL); 2062 if (!NT_SUCCESS(Status)) 2063 { 2064 /* Fail */ 2065 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2066 return Status; 2067 } 2068 2069 /* Are there two associated completion routines? */ 2070 if (FileObject->CompletionContext != NULL && ApcRoutine != NULL) 2071 { 2072 ObDereferenceObject(FileObject); 2073 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2074 return STATUS_INVALID_PARAMETER; 2075 } 2076 2077 /* Check if we have an even handle */ 2078 if (EventHandle) 2079 { 2080 /* Get its pointer */ 2081 Status = ObReferenceObjectByHandle(EventHandle, 2082 EVENT_MODIFY_STATE, 2083 ExEventObjectType, 2084 PreviousMode, 2085 (PVOID *)&Event, 2086 NULL); 2087 if (!NT_SUCCESS(Status)) 2088 { 2089 /* Fail */ 2090 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2091 ObDereferenceObject(FileObject); 2092 return Status; 2093 } 2094 2095 /* Clear it */ 2096 KeClearEvent(Event); 2097 } 2098 2099 /* Check if this is a file that was opened for Synch I/O */ 2100 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2101 { 2102 /* Lock it */ 2103 Status = IopLockFileObject(FileObject, PreviousMode); 2104 if (Status != STATUS_SUCCESS) 2105 { 2106 if (Event) ObDereferenceObject(Event); 2107 ObDereferenceObject(FileObject); 2108 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2109 return Status; 2110 } 2111 2112 /* Remember to unlock later */ 2113 LockedForSynch = TRUE; 2114 } 2115 2116 /* Get the device object */ 2117 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2118 2119 /* Clear the File Object's event */ 2120 KeClearEvent(&FileObject->Event); 2121 2122 /* Allocate the IRP */ 2123 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 2124 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer); 2125 2126 /* Set up the IRP */ 2127 Irp->RequestorMode = PreviousMode; 2128 Irp->UserIosb = IoStatusBlock; 2129 Irp->UserEvent = Event; 2130 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2131 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2132 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 2133 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 2134 Irp->MdlAddress = NULL; 2135 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer; 2136 Irp->AssociatedIrp.SystemBuffer = NULL; 2137 2138 /* Check if this is buffered I/O */ 2139 if (DeviceObject->Flags & DO_BUFFERED_IO) 2140 { 2141 /* Allocate a buffer */ 2142 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, 2143 Length, 2144 TAG_SYSB); 2145 if (!Irp->AssociatedIrp.SystemBuffer) 2146 { 2147 /* Allocating failed, clean up and return the exception code */ 2148 IopCleanupAfterException(FileObject, Irp, Event, NULL); 2149 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB); 2150 2151 /* Return the exception code */ 2152 return STATUS_INSUFFICIENT_RESOURCES; 2153 } 2154 2155 /* Set the buffer and flags */ 2156 Irp->UserBuffer = FileInformation; 2157 Irp->Flags = (IRP_BUFFERED_IO | 2158 IRP_DEALLOCATE_BUFFER | 2159 IRP_INPUT_OPERATION); 2160 } 2161 else if (DeviceObject->Flags & DO_DIRECT_IO) 2162 { 2163 _SEH2_TRY 2164 { 2165 /* Allocate an MDL */ 2166 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp); 2167 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2168 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); 2169 } 2170 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2171 { 2172 /* Allocating failed, clean up and return the exception code */ 2173 IopCleanupAfterException(FileObject, Irp, Event, NULL); 2174 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2175 } 2176 _SEH2_END; 2177 } 2178 else 2179 { 2180 /* No allocation flags, and use the buffer directly */ 2181 Irp->UserBuffer = FileInformation; 2182 } 2183 2184 /* Set up Stack Data */ 2185 StackPtr = IoGetNextIrpStackLocation(Irp); 2186 StackPtr->FileObject = FileObject; 2187 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; 2188 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY; 2189 2190 /* Set Parameters */ 2191 StackPtr->Parameters.QueryDirectory.FileInformationClass = 2192 FileInformationClass; 2193 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer; 2194 StackPtr->Parameters.QueryDirectory.FileIndex = 0; 2195 StackPtr->Parameters.QueryDirectory.Length = Length; 2196 StackPtr->Flags = 0; 2197 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN; 2198 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY; 2199 2200 /* Set deferred I/O */ 2201 Irp->Flags |= IRP_DEFER_IO_COMPLETION; 2202 2203 /* Perform the call */ 2204 return IopPerformSynchronousRequest(DeviceObject, 2205 Irp, 2206 FileObject, 2207 TRUE, 2208 PreviousMode, 2209 LockedForSynch, 2210 IopOtherTransfer); 2211 } 2212 2213 /* 2214 * @unimplemented 2215 */ 2216 NTSTATUS 2217 NTAPI 2218 NtQueryEaFile(IN HANDLE FileHandle, 2219 OUT PIO_STATUS_BLOCK IoStatusBlock, 2220 OUT PVOID Buffer, 2221 IN ULONG Length, 2222 IN BOOLEAN ReturnSingleEntry, 2223 IN PVOID EaList OPTIONAL, 2224 IN ULONG EaListLength, 2225 IN PULONG EaIndex OPTIONAL, 2226 IN BOOLEAN RestartScan) 2227 { 2228 UNIMPLEMENTED; 2229 return STATUS_NOT_IMPLEMENTED; 2230 } 2231 2232 /* 2233 * @implemented 2234 */ 2235 NTSTATUS 2236 NTAPI 2237 NtQueryInformationFile(IN HANDLE FileHandle, 2238 OUT PIO_STATUS_BLOCK IoStatusBlock, 2239 IN PVOID FileInformation, 2240 IN ULONG Length, 2241 IN FILE_INFORMATION_CLASS FileInformationClass) 2242 { 2243 OBJECT_HANDLE_INFORMATION HandleInformation; 2244 PFILE_OBJECT FileObject; 2245 NTSTATUS Status; 2246 PIRP Irp; 2247 PDEVICE_OBJECT DeviceObject; 2248 PIO_STACK_LOCATION StackPtr; 2249 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2250 PKEVENT Event = NULL; 2251 BOOLEAN LocalEvent = FALSE; 2252 PKNORMAL_ROUTINE NormalRoutine; 2253 PVOID NormalContext; 2254 KIRQL OldIrql; 2255 IO_STATUS_BLOCK KernelIosb; 2256 BOOLEAN CallDriver = TRUE; 2257 PFILE_ACCESS_INFORMATION AccessBuffer; 2258 PFILE_MODE_INFORMATION ModeBuffer; 2259 PFILE_ALIGNMENT_INFORMATION AlignmentBuffer; 2260 PFILE_ALL_INFORMATION AllBuffer; 2261 PFAST_IO_DISPATCH FastIoDispatch; 2262 PAGED_CODE(); 2263 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2264 2265 /* Check if we're called from user mode */ 2266 if (PreviousMode != KernelMode) 2267 { 2268 /* Validate the information class */ 2269 if ((FileInformationClass < 0) || 2270 (FileInformationClass >= FileMaximumInformation) || 2271 !(IopQueryOperationLength[FileInformationClass])) 2272 { 2273 /* Invalid class */ 2274 return STATUS_INVALID_INFO_CLASS; 2275 } 2276 2277 /* Validate the length */ 2278 if (Length < IopQueryOperationLength[FileInformationClass]) 2279 { 2280 /* Invalid length */ 2281 return STATUS_INFO_LENGTH_MISMATCH; 2282 } 2283 2284 /* Enter SEH for probing */ 2285 _SEH2_TRY 2286 { 2287 /* Probe the I/O Status block */ 2288 ProbeForWriteIoStatusBlock(IoStatusBlock); 2289 2290 /* Probe the information */ 2291 ProbeForWrite(FileInformation, Length, sizeof(ULONG)); 2292 } 2293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2294 { 2295 /* Return the exception code */ 2296 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2297 } 2298 _SEH2_END; 2299 } 2300 #if DBG 2301 else 2302 { 2303 /* Validate the information class */ 2304 if ((FileInformationClass < 0) || 2305 (FileInformationClass >= FileMaximumInformation) || 2306 !(IopQueryOperationLength[FileInformationClass])) 2307 { 2308 /* Invalid class */ 2309 return STATUS_INVALID_INFO_CLASS; 2310 } 2311 2312 /* Validate the length */ 2313 if (Length < IopQueryOperationLength[FileInformationClass]) 2314 { 2315 /* Invalid length */ 2316 return STATUS_INFO_LENGTH_MISMATCH; 2317 } 2318 } 2319 #endif 2320 2321 /* Reference the Handle */ 2322 Status = ObReferenceObjectByHandle(FileHandle, 2323 IopQueryOperationAccess 2324 [FileInformationClass], 2325 IoFileObjectType, 2326 PreviousMode, 2327 (PVOID *)&FileObject, 2328 &HandleInformation); 2329 if (!NT_SUCCESS(Status)) return Status; 2330 2331 /* Check if this is a direct open or not */ 2332 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 2333 { 2334 /* Get the device object */ 2335 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 2336 } 2337 else 2338 { 2339 /* Get the device object */ 2340 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2341 } 2342 2343 /* Check if this is a file that was opened for Synch I/O */ 2344 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2345 { 2346 /* Lock it */ 2347 Status = IopLockFileObject(FileObject, PreviousMode); 2348 if (Status != STATUS_SUCCESS) 2349 { 2350 ObDereferenceObject(FileObject); 2351 return Status; 2352 } 2353 2354 /* Check if the caller just wants the position */ 2355 if (FileInformationClass == FilePositionInformation) 2356 { 2357 /* Protect write in SEH */ 2358 _SEH2_TRY 2359 { 2360 /* Write the offset */ 2361 ((PFILE_POSITION_INFORMATION)FileInformation)-> 2362 CurrentByteOffset = FileObject->CurrentByteOffset; 2363 2364 /* Fill out the I/O Status Block */ 2365 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION); 2366 Status = IoStatusBlock->Status = STATUS_SUCCESS; 2367 } 2368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2369 { 2370 /* Get the exception code */ 2371 Status = _SEH2_GetExceptionCode(); 2372 } 2373 _SEH2_END; 2374 2375 /* Release the file lock, dereference the file and return */ 2376 IopUnlockFileObject(FileObject); 2377 ObDereferenceObject(FileObject); 2378 return Status; 2379 } 2380 } 2381 else 2382 { 2383 /* Use local event */ 2384 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 2385 if (!Event) 2386 { 2387 ObDereferenceObject(FileObject); 2388 return STATUS_INSUFFICIENT_RESOURCES; 2389 } 2390 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 2391 LocalEvent = TRUE; 2392 } 2393 2394 /* Check if FastIO is possible for the two available information classes */ 2395 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 2396 if (FastIoDispatch != NULL && 2397 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) || 2398 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL))) 2399 { 2400 BOOLEAN Success = FALSE; 2401 2402 if (FileInformationClass == FileBasicInformation) 2403 { 2404 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE, 2405 FileInformation, 2406 &KernelIosb, 2407 DeviceObject); 2408 } 2409 else 2410 { 2411 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE, 2412 FileInformation, 2413 &KernelIosb, 2414 DeviceObject); 2415 } 2416 2417 /* If call succeed */ 2418 if (Success) 2419 { 2420 /* Write the IOSB back */ 2421 _SEH2_TRY 2422 { 2423 *IoStatusBlock = KernelIosb; 2424 } 2425 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2426 { 2427 KernelIosb.Status = _SEH2_GetExceptionCode(); 2428 } 2429 _SEH2_END; 2430 2431 /* Free the event if we had one */ 2432 if (LocalEvent) 2433 { 2434 ExFreePoolWithTag(Event, TAG_IO); 2435 } 2436 2437 /* If FO was locked, unlock it */ 2438 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2439 { 2440 IopUnlockFileObject(FileObject); 2441 } 2442 2443 /* We're done with FastIO! */ 2444 ObDereferenceObject(FileObject); 2445 return KernelIosb.Status; 2446 } 2447 } 2448 2449 /* Clear the File Object event */ 2450 KeClearEvent(&FileObject->Event); 2451 2452 /* Allocate the IRP */ 2453 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2454 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 2455 2456 /* Set the IRP */ 2457 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2458 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2459 Irp->RequestorMode = PreviousMode; 2460 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 2461 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 2462 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 2463 Irp->UserEvent = (LocalEvent) ? Event : NULL; 2464 Irp->AssociatedIrp.SystemBuffer = NULL; 2465 Irp->MdlAddress = NULL; 2466 Irp->UserBuffer = FileInformation; 2467 2468 /* Set the Stack Data */ 2469 StackPtr = IoGetNextIrpStackLocation(Irp); 2470 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION; 2471 StackPtr->FileObject = FileObject; 2472 2473 /* Enter SEH */ 2474 _SEH2_TRY 2475 { 2476 /* Allocate a buffer */ 2477 Irp->AssociatedIrp.SystemBuffer = 2478 ExAllocatePoolWithTag(NonPagedPool, 2479 Length, 2480 TAG_SYSB); 2481 } 2482 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2483 { 2484 /* Allocating failed, clean up and return the exception code */ 2485 IopCleanupAfterException(FileObject, Irp, NULL, Event); 2486 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2487 } 2488 _SEH2_END; 2489 2490 /* Set the flags */ 2491 Irp->Flags |= (IRP_BUFFERED_IO | 2492 IRP_DEALLOCATE_BUFFER | 2493 IRP_INPUT_OPERATION | 2494 IRP_DEFER_IO_COMPLETION); 2495 2496 /* Set the Parameters */ 2497 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass; 2498 StackPtr->Parameters.QueryFile.Length = Length; 2499 2500 /* Queue the IRP */ 2501 IopQueueIrpToThread(Irp); 2502 2503 /* Update operation counts */ 2504 IopUpdateOperationCount(IopOtherTransfer); 2505 2506 /* Fill in file information before calling the driver. 2507 See 'File System Internals' page 485.*/ 2508 if (FileInformationClass == FileAccessInformation) 2509 { 2510 AccessBuffer = Irp->AssociatedIrp.SystemBuffer; 2511 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess; 2512 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION); 2513 CallDriver = FALSE; 2514 } 2515 else if (FileInformationClass == FileModeInformation) 2516 { 2517 ModeBuffer = Irp->AssociatedIrp.SystemBuffer; 2518 ModeBuffer->Mode = IopGetFileMode(FileObject); 2519 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION); 2520 CallDriver = FALSE; 2521 } 2522 else if (FileInformationClass == FileAlignmentInformation) 2523 { 2524 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer; 2525 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement; 2526 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION); 2527 CallDriver = FALSE; 2528 } 2529 else if (FileInformationClass == FileAllInformation) 2530 { 2531 AllBuffer = Irp->AssociatedIrp.SystemBuffer; 2532 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess; 2533 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject); 2534 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement; 2535 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) + 2536 sizeof(FILE_MODE_INFORMATION) + 2537 sizeof(FILE_ALIGNMENT_INFORMATION); 2538 } 2539 2540 /* Call the Driver */ 2541 if (CallDriver) 2542 { 2543 Status = IoCallDriver(DeviceObject, Irp); 2544 } 2545 else 2546 { 2547 Status = STATUS_SUCCESS; 2548 Irp->IoStatus.Status = STATUS_SUCCESS; 2549 } 2550 2551 if (Status == STATUS_PENDING) 2552 { 2553 /* Check if this was async I/O */ 2554 if (LocalEvent) 2555 { 2556 /* Then to a non-alertable wait */ 2557 Status = KeWaitForSingleObject(Event, 2558 Executive, 2559 PreviousMode, 2560 FALSE, 2561 NULL); 2562 if (Status == STATUS_USER_APC) 2563 { 2564 /* Abort the request */ 2565 IopAbortInterruptedIrp(Event, Irp); 2566 } 2567 2568 /* Set the final status */ 2569 Status = KernelIosb.Status; 2570 2571 /* Enter SEH to write the IOSB back */ 2572 _SEH2_TRY 2573 { 2574 /* Write it back to the caller */ 2575 *IoStatusBlock = KernelIosb; 2576 } 2577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2578 { 2579 /* Get the exception code */ 2580 Status = _SEH2_GetExceptionCode(); 2581 } 2582 _SEH2_END; 2583 2584 /* Free the event */ 2585 ExFreePoolWithTag(Event, TAG_IO); 2586 } 2587 else 2588 { 2589 /* Wait for the IRP */ 2590 Status = KeWaitForSingleObject(&FileObject->Event, 2591 Executive, 2592 PreviousMode, 2593 (FileObject->Flags & 2594 FO_ALERTABLE_IO) != 0, 2595 NULL); 2596 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) 2597 { 2598 /* Abort the request */ 2599 IopAbortInterruptedIrp(&FileObject->Event, Irp); 2600 } 2601 2602 /* Set the final status */ 2603 Status = FileObject->FinalStatus; 2604 2605 /* Release the file lock */ 2606 IopUnlockFileObject(FileObject); 2607 } 2608 } 2609 else 2610 { 2611 /* Free the event if we had one */ 2612 if (LocalEvent) 2613 { 2614 /* Clear it in the IRP for completion */ 2615 Irp->UserEvent = NULL; 2616 ExFreePoolWithTag(Event, TAG_IO); 2617 } 2618 2619 /* Set the caller IOSB */ 2620 Irp->UserIosb = IoStatusBlock; 2621 2622 /* The IRP wasn't completed, complete it ourselves */ 2623 KeRaiseIrql(APC_LEVEL, &OldIrql); 2624 IopCompleteRequest(&Irp->Tail.Apc, 2625 &NormalRoutine, 2626 &NormalContext, 2627 (PVOID*)&FileObject, 2628 &NormalContext); 2629 KeLowerIrql(OldIrql); 2630 2631 /* Release the file object if we had locked it*/ 2632 if (!LocalEvent) IopUnlockFileObject(FileObject); 2633 } 2634 2635 /* Return the Status */ 2636 return Status; 2637 } 2638 2639 /* 2640 * @unimplemented 2641 */ 2642 NTSTATUS 2643 NTAPI 2644 NtQueryQuotaInformationFile(IN HANDLE FileHandle, 2645 OUT PIO_STATUS_BLOCK IoStatusBlock, 2646 OUT PVOID Buffer, 2647 IN ULONG Length, 2648 IN BOOLEAN ReturnSingleEntry, 2649 IN PVOID SidList OPTIONAL, 2650 IN ULONG SidListLength, 2651 IN PSID StartSid OPTIONAL, 2652 IN BOOLEAN RestartScan) 2653 { 2654 UNIMPLEMENTED; 2655 return STATUS_NOT_IMPLEMENTED; 2656 } 2657 2658 /* 2659 * @implemented 2660 */ 2661 NTSTATUS 2662 NTAPI 2663 NtReadFile(IN HANDLE FileHandle, 2664 IN HANDLE Event OPTIONAL, 2665 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 2666 IN PVOID ApcContext OPTIONAL, 2667 OUT PIO_STATUS_BLOCK IoStatusBlock, 2668 OUT PVOID Buffer, 2669 IN ULONG Length, 2670 IN PLARGE_INTEGER ByteOffset OPTIONAL, 2671 IN PULONG Key OPTIONAL) 2672 { 2673 NTSTATUS Status; 2674 PFILE_OBJECT FileObject; 2675 PIRP Irp; 2676 PDEVICE_OBJECT DeviceObject; 2677 PIO_STACK_LOCATION StackPtr; 2678 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 2679 PKEVENT EventObject = NULL; 2680 LARGE_INTEGER CapturedByteOffset; 2681 ULONG CapturedKey = 0; 2682 BOOLEAN Synchronous = FALSE; 2683 PMDL Mdl; 2684 PFAST_IO_DISPATCH FastIoDispatch; 2685 IO_STATUS_BLOCK KernelIosb; 2686 BOOLEAN Success; 2687 2688 PAGED_CODE(); 2689 CapturedByteOffset.QuadPart = 0; 2690 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 2691 2692 /* Get File Object */ 2693 Status = ObReferenceObjectByHandle(FileHandle, 2694 FILE_READ_DATA, 2695 IoFileObjectType, 2696 PreviousMode, 2697 (PVOID*)&FileObject, 2698 NULL); 2699 if (!NT_SUCCESS(Status)) return Status; 2700 2701 /* Get the device object */ 2702 DeviceObject = IoGetRelatedDeviceObject(FileObject); 2703 2704 /* Validate User-Mode Buffers */ 2705 if (PreviousMode != KernelMode) 2706 { 2707 _SEH2_TRY 2708 { 2709 /* Probe the status block */ 2710 ProbeForWriteIoStatusBlock(IoStatusBlock); 2711 2712 /* Probe the read buffer */ 2713 ProbeForWrite(Buffer, Length, 1); 2714 2715 /* Check if we got a byte offset */ 2716 if (ByteOffset) 2717 { 2718 /* Capture and probe it */ 2719 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 2720 } 2721 2722 /* Perform additional checks for non-cached file access */ 2723 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) 2724 { 2725 /* Fail if Length is not sector size aligned 2726 * Perform a quick check for 2^ sector sizes 2727 * If it fails, try a more standard way 2728 */ 2729 if ((DeviceObject->SectorSize != 0) && 2730 ((DeviceObject->SectorSize - 1) & Length) != 0) 2731 { 2732 if (Length % DeviceObject->SectorSize != 0) 2733 { 2734 /* Release the file object and and fail */ 2735 ObDereferenceObject(FileObject); 2736 return STATUS_INVALID_PARAMETER; 2737 } 2738 } 2739 2740 /* Fail if buffer doesn't match alignment requirements */ 2741 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0) 2742 { 2743 /* Release the file object and and fail */ 2744 ObDereferenceObject(FileObject); 2745 return STATUS_INVALID_PARAMETER; 2746 } 2747 2748 if (ByteOffset) 2749 { 2750 /* Fail if ByteOffset is not sector size aligned */ 2751 if ((DeviceObject->SectorSize != 0) && 2752 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0)) 2753 { 2754 /* Release the file object and and fail */ 2755 ObDereferenceObject(FileObject); 2756 return STATUS_INVALID_PARAMETER; 2757 } 2758 } 2759 } 2760 2761 /* Capture and probe the key */ 2762 if (Key) CapturedKey = ProbeForReadUlong(Key); 2763 } 2764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2765 { 2766 /* Release the file object and return the exception code */ 2767 ObDereferenceObject(FileObject); 2768 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2769 } 2770 _SEH2_END; 2771 } 2772 else 2773 { 2774 /* Kernel mode: capture directly */ 2775 if (ByteOffset) CapturedByteOffset = *ByteOffset; 2776 if (Key) CapturedKey = *Key; 2777 } 2778 2779 /* Check for event */ 2780 if (Event) 2781 { 2782 /* Reference it */ 2783 Status = ObReferenceObjectByHandle(Event, 2784 EVENT_MODIFY_STATE, 2785 ExEventObjectType, 2786 PreviousMode, 2787 (PVOID*)&EventObject, 2788 NULL); 2789 if (!NT_SUCCESS(Status)) 2790 { 2791 /* Fail */ 2792 ObDereferenceObject(FileObject); 2793 return Status; 2794 } 2795 2796 /* Otherwise reset the event */ 2797 KeClearEvent(EventObject); 2798 } 2799 2800 /* Check if we should use Sync IO or not */ 2801 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 2802 { 2803 /* Lock the file object */ 2804 Status = IopLockFileObject(FileObject, PreviousMode); 2805 if (Status != STATUS_SUCCESS) 2806 { 2807 if (EventObject) ObDereferenceObject(EventObject); 2808 ObDereferenceObject(FileObject); 2809 return Status; 2810 } 2811 2812 /* Check if we don't have a byte offset available */ 2813 if (!(ByteOffset) || 2814 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && 2815 (CapturedByteOffset.u.HighPart == -1))) 2816 { 2817 /* Use the Current Byte Offset instead */ 2818 CapturedByteOffset = FileObject->CurrentByteOffset; 2819 } 2820 2821 /* If the file is cached, try fast I/O */ 2822 if (FileObject->PrivateCacheMap) 2823 { 2824 /* Perform fast read */ 2825 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 2826 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL); 2827 2828 Success = FastIoDispatch->FastIoRead(FileObject, 2829 &CapturedByteOffset, 2830 Length, 2831 TRUE, 2832 CapturedKey, 2833 Buffer, 2834 &KernelIosb, 2835 DeviceObject); 2836 2837 /* Only accept the result if we got a straightforward status */ 2838 if (Success && 2839 (KernelIosb.Status == STATUS_SUCCESS || 2840 KernelIosb.Status == STATUS_BUFFER_OVERFLOW || 2841 KernelIosb.Status == STATUS_END_OF_FILE)) 2842 { 2843 /* Fast path -- update transfer & operation counts */ 2844 IopUpdateOperationCount(IopReadTransfer); 2845 IopUpdateTransferCount(IopReadTransfer, 2846 (ULONG)KernelIosb.Information); 2847 2848 /* Enter SEH to write the IOSB back */ 2849 _SEH2_TRY 2850 { 2851 /* Write it back to the caller */ 2852 *IoStatusBlock = KernelIosb; 2853 } 2854 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2855 { 2856 /* The caller's IOSB was invalid, so fail */ 2857 if (EventObject) ObDereferenceObject(EventObject); 2858 IopUnlockFileObject(FileObject); 2859 ObDereferenceObject(FileObject); 2860 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2861 } 2862 _SEH2_END; 2863 2864 /* Signal the completion event */ 2865 if (EventObject) 2866 { 2867 KeSetEvent(EventObject, 0, FALSE); 2868 ObDereferenceObject(EventObject); 2869 } 2870 2871 /* Clean up */ 2872 IopUnlockFileObject(FileObject); 2873 ObDereferenceObject(FileObject); 2874 return KernelIosb.Status; 2875 } 2876 } 2877 2878 /* Remember we are sync */ 2879 Synchronous = TRUE; 2880 } 2881 else if (!(ByteOffset) && 2882 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) 2883 { 2884 /* Otherwise, this was async I/O without a byte offset, so fail */ 2885 if (EventObject) ObDereferenceObject(EventObject); 2886 ObDereferenceObject(FileObject); 2887 return STATUS_INVALID_PARAMETER; 2888 } 2889 2890 /* Clear the File Object's event */ 2891 KeClearEvent(&FileObject->Event); 2892 2893 /* Allocate the IRP */ 2894 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2895 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 2896 2897 /* Set the IRP */ 2898 Irp->Tail.Overlay.OriginalFileObject = FileObject; 2899 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 2900 Irp->RequestorMode = PreviousMode; 2901 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 2902 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 2903 Irp->UserIosb = IoStatusBlock; 2904 Irp->UserEvent = EventObject; 2905 Irp->PendingReturned = FALSE; 2906 Irp->Cancel = FALSE; 2907 Irp->CancelRoutine = NULL; 2908 Irp->AssociatedIrp.SystemBuffer = NULL; 2909 Irp->MdlAddress = NULL; 2910 2911 /* Set the Stack Data */ 2912 StackPtr = IoGetNextIrpStackLocation(Irp); 2913 StackPtr->MajorFunction = IRP_MJ_READ; 2914 StackPtr->FileObject = FileObject; 2915 StackPtr->Parameters.Read.Key = CapturedKey; 2916 StackPtr->Parameters.Read.Length = Length; 2917 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset; 2918 2919 /* Check if this is buffered I/O */ 2920 if (DeviceObject->Flags & DO_BUFFERED_IO) 2921 { 2922 /* Check if we have a buffer length */ 2923 if (Length) 2924 { 2925 /* Enter SEH */ 2926 _SEH2_TRY 2927 { 2928 /* Allocate a buffer */ 2929 Irp->AssociatedIrp.SystemBuffer = 2930 ExAllocatePoolWithTag(NonPagedPool, 2931 Length, 2932 TAG_SYSB); 2933 } 2934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2935 { 2936 /* Allocating failed, clean up and return the exception code */ 2937 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 2938 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2939 } 2940 _SEH2_END; 2941 2942 /* Set the buffer and flags */ 2943 Irp->UserBuffer = Buffer; 2944 Irp->Flags = (IRP_BUFFERED_IO | 2945 IRP_DEALLOCATE_BUFFER | 2946 IRP_INPUT_OPERATION); 2947 } 2948 else 2949 { 2950 /* Not reading anything */ 2951 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; 2952 } 2953 } 2954 else if (DeviceObject->Flags & DO_DIRECT_IO) 2955 { 2956 /* Check if we have a buffer length */ 2957 if (Length) 2958 { 2959 _SEH2_TRY 2960 { 2961 /* Allocate an MDL */ 2962 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); 2963 if (!Mdl) 2964 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 2965 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); 2966 } 2967 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2968 { 2969 /* Allocating failed, clean up and return the exception code */ 2970 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 2971 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2972 } 2973 _SEH2_END; 2974 2975 } 2976 2977 /* No allocation flags */ 2978 Irp->Flags = 0; 2979 } 2980 else 2981 { 2982 /* No allocation flags, and use the buffer directly */ 2983 Irp->Flags = 0; 2984 Irp->UserBuffer = Buffer; 2985 } 2986 2987 /* Now set the deferred read flags */ 2988 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION); 2989 #if 0 2990 /* FIXME: VFAT SUCKS */ 2991 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; 2992 #endif 2993 2994 /* Perform the call */ 2995 return IopPerformSynchronousRequest(DeviceObject, 2996 Irp, 2997 FileObject, 2998 TRUE, 2999 PreviousMode, 3000 Synchronous, 3001 IopReadTransfer); 3002 } 3003 3004 /* 3005 * @unimplemented 3006 */ 3007 NTSTATUS 3008 NTAPI 3009 NtReadFileScatter(IN HANDLE FileHandle, 3010 IN HANDLE Event OPTIONAL, 3011 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 3012 IN PVOID UserApcContext OPTIONAL, 3013 OUT PIO_STATUS_BLOCK UserIoStatusBlock, 3014 IN FILE_SEGMENT_ELEMENT BufferDescription [], 3015 IN ULONG BufferLength, 3016 IN PLARGE_INTEGER ByteOffset, 3017 IN PULONG Key OPTIONAL) 3018 { 3019 UNIMPLEMENTED; 3020 return STATUS_NOT_IMPLEMENTED; 3021 } 3022 3023 /* 3024 * @unimplemented 3025 */ 3026 NTSTATUS 3027 NTAPI 3028 NtSetEaFile(IN HANDLE FileHandle, 3029 IN PIO_STATUS_BLOCK IoStatusBlock, 3030 IN PVOID EaBuffer, 3031 IN ULONG EaBufferSize) 3032 { 3033 UNIMPLEMENTED; 3034 return STATUS_NOT_IMPLEMENTED; 3035 } 3036 3037 /* 3038 * @implemented 3039 */ 3040 NTSTATUS 3041 NTAPI 3042 NtSetInformationFile(IN HANDLE FileHandle, 3043 OUT PIO_STATUS_BLOCK IoStatusBlock, 3044 IN PVOID FileInformation, 3045 IN ULONG Length, 3046 IN FILE_INFORMATION_CLASS FileInformationClass) 3047 { 3048 PFILE_OBJECT FileObject; 3049 NTSTATUS Status; 3050 PIRP Irp; 3051 PDEVICE_OBJECT DeviceObject; 3052 PIO_STACK_LOCATION StackPtr; 3053 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 3054 PKEVENT Event = NULL; 3055 BOOLEAN LocalEvent = FALSE; 3056 PKNORMAL_ROUTINE NormalRoutine; 3057 PVOID NormalContext; 3058 KIRQL OldIrql; 3059 IO_STATUS_BLOCK KernelIosb; 3060 PVOID Queue; 3061 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation; 3062 PIO_COMPLETION_CONTEXT Context; 3063 PFILE_RENAME_INFORMATION RenameInfo; 3064 HANDLE TargetHandle = NULL; 3065 PAGED_CODE(); 3066 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3067 3068 /* Check if we're called from user mode */ 3069 if (PreviousMode != KernelMode) 3070 { 3071 /* Validate the information class */ 3072 if ((FileInformationClass < 0) || 3073 (FileInformationClass >= FileMaximumInformation) || 3074 !(IopSetOperationLength[FileInformationClass])) 3075 { 3076 /* Invalid class */ 3077 return STATUS_INVALID_INFO_CLASS; 3078 } 3079 3080 /* Validate the length */ 3081 if (Length < IopSetOperationLength[FileInformationClass]) 3082 { 3083 /* Invalid length */ 3084 return STATUS_INFO_LENGTH_MISMATCH; 3085 } 3086 3087 /* Enter SEH for probing */ 3088 _SEH2_TRY 3089 { 3090 /* Probe the I/O Status block */ 3091 ProbeForWriteIoStatusBlock(IoStatusBlock); 3092 3093 /* Probe the information */ 3094 ProbeForRead(FileInformation, 3095 Length, 3096 (Length == sizeof(BOOLEAN)) ? 3097 sizeof(BOOLEAN) : sizeof(ULONG)); 3098 } 3099 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3100 { 3101 /* Return the exception code */ 3102 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3103 } 3104 _SEH2_END; 3105 } 3106 else 3107 { 3108 /* Validate the information class */ 3109 if ((FileInformationClass < 0) || 3110 (FileInformationClass >= FileMaximumInformation) || 3111 !(IopSetOperationLength[FileInformationClass])) 3112 { 3113 /* Invalid class */ 3114 return STATUS_INVALID_INFO_CLASS; 3115 } 3116 3117 /* Validate the length */ 3118 if (Length < IopSetOperationLength[FileInformationClass]) 3119 { 3120 /* Invalid length */ 3121 return STATUS_INFO_LENGTH_MISMATCH; 3122 } 3123 } 3124 3125 /* Reference the Handle */ 3126 Status = ObReferenceObjectByHandle(FileHandle, 3127 IopSetOperationAccess 3128 [FileInformationClass], 3129 IoFileObjectType, 3130 PreviousMode, 3131 (PVOID *)&FileObject, 3132 NULL); 3133 if (!NT_SUCCESS(Status)) return Status; 3134 3135 /* Check if this is a direct open or not */ 3136 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 3137 { 3138 /* Get the device object */ 3139 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 3140 } 3141 else 3142 { 3143 /* Get the device object */ 3144 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3145 } 3146 3147 DPRINT("Will call: %p\n", DeviceObject); 3148 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName); 3149 3150 /* Check if this is a file that was opened for Synch I/O */ 3151 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3152 { 3153 /* Lock it */ 3154 Status = IopLockFileObject(FileObject, PreviousMode); 3155 if (Status != STATUS_SUCCESS) 3156 { 3157 ObDereferenceObject(FileObject); 3158 return Status; 3159 } 3160 3161 /* Check if the caller just wants the position */ 3162 if (FileInformationClass == FilePositionInformation) 3163 { 3164 /* Protect write in SEH */ 3165 _SEH2_TRY 3166 { 3167 /* Write the offset */ 3168 FileObject->CurrentByteOffset = 3169 ((PFILE_POSITION_INFORMATION)FileInformation)-> 3170 CurrentByteOffset; 3171 3172 /* Fill out the I/O Status Block */ 3173 IoStatusBlock->Information = 0; 3174 Status = IoStatusBlock->Status = STATUS_SUCCESS; 3175 } 3176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3177 { 3178 /* Get the exception code */ 3179 Status = _SEH2_GetExceptionCode(); 3180 } 3181 _SEH2_END; 3182 3183 /* Update transfer count */ 3184 IopUpdateTransferCount(IopOtherTransfer, Length); 3185 3186 /* Release the file lock, dereference the file and return */ 3187 IopUnlockFileObject(FileObject); 3188 ObDereferenceObject(FileObject); 3189 return Status; 3190 } 3191 } 3192 else 3193 { 3194 /* Use local event */ 3195 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3196 if (!Event) 3197 { 3198 ObDereferenceObject(FileObject); 3199 return STATUS_INSUFFICIENT_RESOURCES; 3200 } 3201 3202 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3203 LocalEvent = TRUE; 3204 } 3205 3206 /* Clear the File Object event */ 3207 KeClearEvent(&FileObject->Event); 3208 3209 /* Allocate the IRP */ 3210 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 3211 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3212 3213 /* Set the IRP */ 3214 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3215 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3216 Irp->RequestorMode = PreviousMode; 3217 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3218 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3219 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3220 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3221 Irp->AssociatedIrp.SystemBuffer = NULL; 3222 Irp->MdlAddress = NULL; 3223 Irp->UserBuffer = FileInformation; 3224 3225 /* Set the Stack Data */ 3226 StackPtr = IoGetNextIrpStackLocation(Irp); 3227 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; 3228 StackPtr->FileObject = FileObject; 3229 3230 /* Enter SEH */ 3231 _SEH2_TRY 3232 { 3233 /* Allocate a buffer */ 3234 Irp->AssociatedIrp.SystemBuffer = 3235 ExAllocatePoolWithTag(NonPagedPool, 3236 Length, 3237 TAG_SYSB); 3238 3239 /* Copy the data into it */ 3240 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 3241 FileInformation, 3242 Length); 3243 } 3244 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3245 { 3246 /* Allocating failed, clean up and return the exception code */ 3247 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3248 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3249 } 3250 _SEH2_END; 3251 3252 /* Set the flags */ 3253 Irp->Flags |= (IRP_BUFFERED_IO | 3254 IRP_DEALLOCATE_BUFFER | 3255 IRP_DEFER_IO_COMPLETION); 3256 3257 /* Set the Parameters */ 3258 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; 3259 StackPtr->Parameters.SetFile.Length = Length; 3260 3261 /* Queue the IRP */ 3262 IopQueueIrpToThread(Irp); 3263 3264 /* Update operation counts */ 3265 IopUpdateOperationCount(IopOtherTransfer); 3266 3267 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */ 3268 /* Handle IO Completion Port quickly */ 3269 if (FileInformationClass == FileCompletionInformation) 3270 { 3271 /* Check if the file object already has a completion port */ 3272 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || 3273 (FileObject->CompletionContext)) 3274 { 3275 /* Fail */ 3276 Status = STATUS_INVALID_PARAMETER; 3277 } 3278 else 3279 { 3280 /* Reference the Port */ 3281 CompletionInfo = Irp->AssociatedIrp.SystemBuffer; 3282 Status = ObReferenceObjectByHandle(CompletionInfo->Port, 3283 IO_COMPLETION_MODIFY_STATE, 3284 IoCompletionType, 3285 PreviousMode, 3286 (PVOID*)&Queue, 3287 NULL); 3288 if (NT_SUCCESS(Status)) 3289 { 3290 /* Allocate the Context */ 3291 Context = ExAllocatePoolWithTag(PagedPool, 3292 sizeof(IO_COMPLETION_CONTEXT), 3293 IOC_TAG); 3294 if (Context) 3295 { 3296 /* Set the Data */ 3297 Context->Key = CompletionInfo->Key; 3298 Context->Port = Queue; 3299 if (InterlockedCompareExchangePointer((PVOID*)&FileObject-> 3300 CompletionContext, 3301 Context, 3302 NULL)) 3303 { 3304 /* 3305 * Someone else set the completion port in the 3306 * meanwhile, so dereference the port and fail. 3307 */ 3308 ExFreePoolWithTag(Context, IOC_TAG); 3309 ObDereferenceObject(Queue); 3310 Status = STATUS_INVALID_PARAMETER; 3311 } 3312 } 3313 else 3314 { 3315 /* Dereference the Port now */ 3316 ObDereferenceObject(Queue); 3317 Status = STATUS_INSUFFICIENT_RESOURCES; 3318 } 3319 } 3320 } 3321 3322 /* Set the IRP Status */ 3323 Irp->IoStatus.Status = Status; 3324 Irp->IoStatus.Information = 0; 3325 } 3326 else if (FileInformationClass == FileRenameInformation || 3327 FileInformationClass == FileLinkInformation || 3328 FileInformationClass == FileMoveClusterInformation) 3329 { 3330 /* Get associated information */ 3331 RenameInfo = Irp->AssociatedIrp.SystemBuffer; 3332 3333 /* Only rename if: 3334 * -> We have a name 3335 * -> In unicode 3336 * -> sizes are valid 3337 */ 3338 if (RenameInfo->FileNameLength != 0 && 3339 !(RenameInfo->FileNameLength & 1) && 3340 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength)) 3341 { 3342 /* Properly set information received */ 3343 if (FileInformationClass == FileMoveClusterInformation) 3344 { 3345 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount; 3346 } 3347 else 3348 { 3349 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists; 3350 } 3351 3352 /* If we got fully path OR relative target, attempt a parent directory open */ 3353 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory) 3354 { 3355 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject); 3356 if (!NT_SUCCESS(Status)) 3357 { 3358 Irp->IoStatus.Status = Status; 3359 } 3360 else 3361 { 3362 /* Call the Driver */ 3363 Status = IoCallDriver(DeviceObject, Irp); 3364 } 3365 } 3366 else 3367 { 3368 /* Call the Driver */ 3369 Status = IoCallDriver(DeviceObject, Irp); 3370 } 3371 } 3372 else 3373 { 3374 Status = STATUS_INVALID_PARAMETER; 3375 Irp->IoStatus.Status = Status; 3376 } 3377 } 3378 else 3379 { 3380 /* Call the Driver */ 3381 Status = IoCallDriver(DeviceObject, Irp); 3382 } 3383 3384 /* Check if we're waiting for the IRP to complete */ 3385 if (Status == STATUS_PENDING) 3386 { 3387 /* Check if this was async I/O */ 3388 if (LocalEvent) 3389 { 3390 /* Then to a non-alertable wait */ 3391 Status = KeWaitForSingleObject(Event, 3392 Executive, 3393 PreviousMode, 3394 FALSE, 3395 NULL); 3396 if (Status == STATUS_USER_APC) 3397 { 3398 /* Abort the request */ 3399 IopAbortInterruptedIrp(Event, Irp); 3400 } 3401 3402 /* Set the final status */ 3403 Status = KernelIosb.Status; 3404 3405 /* Enter SEH to write the IOSB back */ 3406 _SEH2_TRY 3407 { 3408 /* Write it back to the caller */ 3409 *IoStatusBlock = KernelIosb; 3410 } 3411 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3412 { 3413 /* Get the exception code */ 3414 Status = _SEH2_GetExceptionCode(); 3415 } 3416 _SEH2_END; 3417 3418 /* Free the event */ 3419 ExFreePoolWithTag(Event, TAG_IO); 3420 } 3421 else 3422 { 3423 /* Wait for the IRP */ 3424 Status = KeWaitForSingleObject(&FileObject->Event, 3425 Executive, 3426 PreviousMode, 3427 (FileObject->Flags & 3428 FO_ALERTABLE_IO) != 0, 3429 NULL); 3430 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) 3431 { 3432 /* Abort the request */ 3433 IopAbortInterruptedIrp(&FileObject->Event, Irp); 3434 } 3435 3436 /* Set the final status */ 3437 Status = FileObject->FinalStatus; 3438 3439 /* Release the file lock */ 3440 IopUnlockFileObject(FileObject); 3441 } 3442 } 3443 else 3444 { 3445 /* Free the event if we had one */ 3446 if (LocalEvent) 3447 { 3448 /* Clear it in the IRP for completion */ 3449 Irp->UserEvent = NULL; 3450 ExFreePoolWithTag(Event, TAG_IO); 3451 } 3452 3453 /* Set the caller IOSB */ 3454 Irp->UserIosb = IoStatusBlock; 3455 3456 /* The IRP wasn't completed, complete it ourselves */ 3457 KeRaiseIrql(APC_LEVEL, &OldIrql); 3458 IopCompleteRequest(&Irp->Tail.Apc, 3459 &NormalRoutine, 3460 &NormalContext, 3461 (PVOID*)&FileObject, 3462 &NormalContext); 3463 KeLowerIrql(OldIrql); 3464 3465 /* Release the file object if we had locked it*/ 3466 if (!LocalEvent) IopUnlockFileObject(FileObject); 3467 } 3468 3469 if (TargetHandle != NULL) 3470 { 3471 ObCloseHandle(TargetHandle, KernelMode); 3472 } 3473 3474 /* Return the Status */ 3475 return Status; 3476 } 3477 3478 /* 3479 * @unimplemented 3480 */ 3481 NTSTATUS 3482 NTAPI 3483 NtSetQuotaInformationFile(IN HANDLE FileHandle, 3484 OUT PIO_STATUS_BLOCK IoStatusBlock, 3485 IN PVOID Buffer, 3486 IN ULONG BufferLength) 3487 { 3488 UNIMPLEMENTED; 3489 return STATUS_NOT_IMPLEMENTED; 3490 } 3491 3492 /* 3493 * @implemented 3494 */ 3495 NTSTATUS 3496 NTAPI 3497 NtUnlockFile(IN HANDLE FileHandle, 3498 OUT PIO_STATUS_BLOCK IoStatusBlock, 3499 IN PLARGE_INTEGER ByteOffset, 3500 IN PLARGE_INTEGER Length, 3501 IN ULONG Key OPTIONAL) 3502 { 3503 PFILE_OBJECT FileObject; 3504 PLARGE_INTEGER LocalLength = NULL; 3505 PIRP Irp; 3506 PIO_STACK_LOCATION StackPtr; 3507 PDEVICE_OBJECT DeviceObject; 3508 PKEVENT Event = NULL; 3509 BOOLEAN LocalEvent = FALSE; 3510 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3511 LARGE_INTEGER CapturedByteOffset, CapturedLength; 3512 NTSTATUS Status; 3513 OBJECT_HANDLE_INFORMATION HandleInformation; 3514 IO_STATUS_BLOCK KernelIosb; 3515 PFAST_IO_DISPATCH FastIoDispatch; 3516 PAGED_CODE(); 3517 CapturedByteOffset.QuadPart = 0; 3518 CapturedLength.QuadPart = 0; 3519 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3520 3521 /* Get File Object */ 3522 Status = ObReferenceObjectByHandle(FileHandle, 3523 0, 3524 IoFileObjectType, 3525 PreviousMode, 3526 (PVOID*)&FileObject, 3527 &HandleInformation); 3528 if (!NT_SUCCESS(Status)) return Status; 3529 3530 /* Check if we're called from user mode */ 3531 if (PreviousMode != KernelMode) 3532 { 3533 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */ 3534 if (!(HandleInformation.GrantedAccess & 3535 (FILE_WRITE_DATA | FILE_READ_DATA))) 3536 { 3537 ObDereferenceObject(FileObject); 3538 return STATUS_ACCESS_DENIED; 3539 } 3540 3541 /* Enter SEH for probing */ 3542 _SEH2_TRY 3543 { 3544 /* Probe the I/O Status block */ 3545 ProbeForWriteIoStatusBlock(IoStatusBlock); 3546 3547 /* Probe and capture the large integers */ 3548 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 3549 CapturedLength = ProbeForReadLargeInteger(Length); 3550 } 3551 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3552 { 3553 /* Dereference the object and return exception code */ 3554 ObDereferenceObject(FileObject); 3555 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3556 } 3557 _SEH2_END; 3558 } 3559 else 3560 { 3561 /* Otherwise, capture them directly */ 3562 CapturedByteOffset = *ByteOffset; 3563 CapturedLength = *Length; 3564 } 3565 3566 /* Check if this is a direct open or not */ 3567 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) 3568 { 3569 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); 3570 } 3571 else 3572 { 3573 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3574 } 3575 3576 /* Try to do it the FastIO way if possible */ 3577 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 3578 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL) 3579 { 3580 if (FastIoDispatch->FastIoUnlockSingle(FileObject, 3581 &CapturedByteOffset, 3582 &CapturedLength, 3583 PsGetCurrentProcess(), 3584 Key, 3585 &KernelIosb, 3586 DeviceObject)) 3587 { 3588 /* Write the IOSB back */ 3589 _SEH2_TRY 3590 { 3591 *IoStatusBlock = KernelIosb; 3592 } 3593 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3594 { 3595 KernelIosb.Status = _SEH2_GetExceptionCode(); 3596 } 3597 _SEH2_END; 3598 3599 /* We're done with FastIO! */ 3600 ObDereferenceObject(FileObject); 3601 return KernelIosb.Status; 3602 } 3603 } 3604 3605 /* Check if we should use Sync IO or not */ 3606 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3607 { 3608 /* Lock it */ 3609 Status = IopLockFileObject(FileObject, PreviousMode); 3610 if (Status != STATUS_SUCCESS) 3611 { 3612 ObDereferenceObject(FileObject); 3613 return Status; 3614 } 3615 } 3616 else 3617 { 3618 /* Use local event */ 3619 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 3620 if (!Event) 3621 { 3622 ObDereferenceObject(FileObject); 3623 return STATUS_INSUFFICIENT_RESOURCES; 3624 } 3625 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 3626 LocalEvent = TRUE; 3627 } 3628 3629 /* Clear File Object event */ 3630 KeClearEvent(&FileObject->Event); 3631 3632 /* Allocate the IRP */ 3633 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3634 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 3635 3636 /* Set up the IRP */ 3637 Irp->RequestorMode = PreviousMode; 3638 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 3639 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 3640 Irp->UserEvent = (LocalEvent) ? Event : NULL; 3641 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3642 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3643 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 3644 3645 /* Set up Stack Data */ 3646 StackPtr = IoGetNextIrpStackLocation(Irp); 3647 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL; 3648 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE; 3649 StackPtr->FileObject = FileObject; 3650 3651 /* Enter SEH */ 3652 _SEH2_TRY 3653 { 3654 /* Allocate a buffer */ 3655 LocalLength = ExAllocatePoolWithTag(NonPagedPool, 3656 sizeof(LARGE_INTEGER), 3657 TAG_LOCK); 3658 3659 /* Set the length */ 3660 *LocalLength = CapturedLength; 3661 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength; 3662 StackPtr->Parameters.LockControl.Length = LocalLength; 3663 } 3664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3665 { 3666 /* Allocating failed, clean up and return the exception code */ 3667 IopCleanupAfterException(FileObject, Irp, NULL, Event); 3668 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK); 3669 3670 /* Return the exception code */ 3671 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3672 } 3673 _SEH2_END; 3674 3675 /* Set Parameters */ 3676 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset; 3677 StackPtr->Parameters.LockControl.Key = Key; 3678 3679 /* Call the Driver */ 3680 Status = IopPerformSynchronousRequest(DeviceObject, 3681 Irp, 3682 FileObject, 3683 FALSE, 3684 PreviousMode, 3685 !LocalEvent, 3686 IopOtherTransfer); 3687 3688 /* Check if this was async I/O */ 3689 if (LocalEvent) 3690 { 3691 /* It was, finalize this request */ 3692 Status = IopFinalizeAsynchronousIo(Status, 3693 Event, 3694 Irp, 3695 PreviousMode, 3696 &KernelIosb, 3697 IoStatusBlock); 3698 } 3699 3700 /* Return status */ 3701 return Status; 3702 } 3703 3704 /* 3705 * @implemented 3706 */ 3707 NTSTATUS 3708 NTAPI 3709 NtWriteFile(IN HANDLE FileHandle, 3710 IN HANDLE Event OPTIONAL, 3711 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 3712 IN PVOID ApcContext OPTIONAL, 3713 OUT PIO_STATUS_BLOCK IoStatusBlock, 3714 IN PVOID Buffer, 3715 IN ULONG Length, 3716 IN PLARGE_INTEGER ByteOffset OPTIONAL, 3717 IN PULONG Key OPTIONAL) 3718 { 3719 NTSTATUS Status; 3720 PFILE_OBJECT FileObject; 3721 PIRP Irp; 3722 PDEVICE_OBJECT DeviceObject; 3723 PIO_STACK_LOCATION StackPtr; 3724 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 3725 PKEVENT EventObject = NULL; 3726 LARGE_INTEGER CapturedByteOffset; 3727 ULONG CapturedKey = 0; 3728 BOOLEAN Synchronous = FALSE; 3729 PMDL Mdl; 3730 OBJECT_HANDLE_INFORMATION ObjectHandleInfo; 3731 PFAST_IO_DISPATCH FastIoDispatch; 3732 IO_STATUS_BLOCK KernelIosb; 3733 BOOLEAN Success; 3734 3735 PAGED_CODE(); 3736 CapturedByteOffset.QuadPart = 0; 3737 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 3738 3739 /* Get File Object for write */ 3740 Status = ObReferenceFileObjectForWrite(FileHandle, 3741 PreviousMode, 3742 &FileObject, 3743 &ObjectHandleInfo); 3744 if (!NT_SUCCESS(Status)) return Status; 3745 3746 /* Get the device object */ 3747 DeviceObject = IoGetRelatedDeviceObject(FileObject); 3748 3749 /* Validate User-Mode Buffers */ 3750 if (PreviousMode != KernelMode) 3751 { 3752 _SEH2_TRY 3753 { 3754 /* Probe the status block */ 3755 ProbeForWriteIoStatusBlock(IoStatusBlock); 3756 3757 /* Probe the read buffer */ 3758 ProbeForRead(Buffer, Length, 1); 3759 3760 /* Check if we got a byte offset */ 3761 if (ByteOffset) 3762 { 3763 /* Capture and probe it */ 3764 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); 3765 } 3766 3767 /* Perform additional checks for non-cached file access */ 3768 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) 3769 { 3770 /* Fail if Length is not sector size aligned 3771 * Perform a quick check for 2^ sector sizes 3772 * If it fails, try a more standard way 3773 */ 3774 if ((DeviceObject->SectorSize != 0) && 3775 ((DeviceObject->SectorSize - 1) & Length) != 0) 3776 { 3777 if (Length % DeviceObject->SectorSize != 0) 3778 { 3779 /* Release the file object and and fail */ 3780 ObDereferenceObject(FileObject); 3781 return STATUS_INVALID_PARAMETER; 3782 } 3783 } 3784 3785 /* Fail if buffer doesn't match alignment requirements */ 3786 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0) 3787 { 3788 /* Release the file object and and fail */ 3789 ObDereferenceObject(FileObject); 3790 return STATUS_INVALID_PARAMETER; 3791 } 3792 3793 if (ByteOffset) 3794 { 3795 /* Fail if ByteOffset is not sector size aligned */ 3796 if ((DeviceObject->SectorSize != 0) && 3797 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0)) 3798 { 3799 /* Only if that's not specific values for synchronous IO */ 3800 if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) && 3801 (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION || 3802 !BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))) 3803 { 3804 /* Release the file object and and fail */ 3805 ObDereferenceObject(FileObject); 3806 return STATUS_INVALID_PARAMETER; 3807 } 3808 } 3809 } 3810 } 3811 3812 /* Capture and probe the key */ 3813 if (Key) CapturedKey = ProbeForReadUlong(Key); 3814 } 3815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3816 { 3817 /* Release the file object and return the exception code */ 3818 ObDereferenceObject(FileObject); 3819 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3820 } 3821 _SEH2_END; 3822 } 3823 else 3824 { 3825 /* Kernel mode: capture directly */ 3826 if (ByteOffset) CapturedByteOffset = *ByteOffset; 3827 if (Key) CapturedKey = *Key; 3828 } 3829 3830 /* Check if this is an append operation */ 3831 if ((ObjectHandleInfo.GrantedAccess & 3832 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA) 3833 { 3834 /* Give the drivers something to understand */ 3835 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE; 3836 CapturedByteOffset.u.HighPart = -1; 3837 } 3838 3839 /* Check for event */ 3840 if (Event) 3841 { 3842 /* Reference it */ 3843 Status = ObReferenceObjectByHandle(Event, 3844 EVENT_MODIFY_STATE, 3845 ExEventObjectType, 3846 PreviousMode, 3847 (PVOID*)&EventObject, 3848 NULL); 3849 if (!NT_SUCCESS(Status)) 3850 { 3851 /* Fail */ 3852 ObDereferenceObject(FileObject); 3853 return Status; 3854 } 3855 3856 /* Otherwise reset the event */ 3857 KeClearEvent(EventObject); 3858 } 3859 3860 /* Check if we should use Sync IO or not */ 3861 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 3862 { 3863 /* Lock the file object */ 3864 Status = IopLockFileObject(FileObject, PreviousMode); 3865 if (Status != STATUS_SUCCESS) 3866 { 3867 if (EventObject) ObDereferenceObject(EventObject); 3868 ObDereferenceObject(FileObject); 3869 return Status; 3870 } 3871 3872 /* Check if we don't have a byte offset available */ 3873 if (!(ByteOffset) || 3874 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && 3875 (CapturedByteOffset.u.HighPart == -1))) 3876 { 3877 /* Use the Current Byte Offset instead */ 3878 CapturedByteOffset = FileObject->CurrentByteOffset; 3879 } 3880 3881 /* If the file is cached, try fast I/O */ 3882 if (FileObject->PrivateCacheMap) 3883 { 3884 /* Perform fast write */ 3885 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch; 3886 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL); 3887 3888 Success = FastIoDispatch->FastIoWrite(FileObject, 3889 &CapturedByteOffset, 3890 Length, 3891 TRUE, 3892 CapturedKey, 3893 Buffer, 3894 &KernelIosb, 3895 DeviceObject); 3896 3897 /* Only accept the result if it was successful */ 3898 if (Success && 3899 KernelIosb.Status == STATUS_SUCCESS) 3900 { 3901 /* Fast path -- update transfer & operation counts */ 3902 IopUpdateOperationCount(IopWriteTransfer); 3903 IopUpdateTransferCount(IopWriteTransfer, 3904 (ULONG)KernelIosb.Information); 3905 3906 /* Enter SEH to write the IOSB back */ 3907 _SEH2_TRY 3908 { 3909 /* Write it back to the caller */ 3910 *IoStatusBlock = KernelIosb; 3911 } 3912 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3913 { 3914 /* The caller's IOSB was invalid, so fail */ 3915 if (EventObject) ObDereferenceObject(EventObject); 3916 IopUnlockFileObject(FileObject); 3917 ObDereferenceObject(FileObject); 3918 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 3919 } 3920 _SEH2_END; 3921 3922 /* Signal the completion event */ 3923 if (EventObject) 3924 { 3925 KeSetEvent(EventObject, 0, FALSE); 3926 ObDereferenceObject(EventObject); 3927 } 3928 3929 /* Clean up */ 3930 IopUnlockFileObject(FileObject); 3931 ObDereferenceObject(FileObject); 3932 return KernelIosb.Status; 3933 } 3934 } 3935 3936 /* Remember we are sync */ 3937 Synchronous = TRUE; 3938 } 3939 else if (!(ByteOffset) && 3940 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) 3941 { 3942 /* Otherwise, this was async I/O without a byte offset, so fail */ 3943 if (EventObject) ObDereferenceObject(EventObject); 3944 ObDereferenceObject(FileObject); 3945 return STATUS_INVALID_PARAMETER; 3946 } 3947 3948 /* Clear the File Object's event */ 3949 KeClearEvent(&FileObject->Event); 3950 3951 /* Allocate the IRP */ 3952 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 3953 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL); 3954 3955 /* Set the IRP */ 3956 Irp->Tail.Overlay.OriginalFileObject = FileObject; 3957 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 3958 Irp->RequestorMode = PreviousMode; 3959 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; 3960 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; 3961 Irp->UserIosb = IoStatusBlock; 3962 Irp->UserEvent = EventObject; 3963 Irp->PendingReturned = FALSE; 3964 Irp->Cancel = FALSE; 3965 Irp->CancelRoutine = NULL; 3966 Irp->AssociatedIrp.SystemBuffer = NULL; 3967 Irp->MdlAddress = NULL; 3968 3969 /* Set the Stack Data */ 3970 StackPtr = IoGetNextIrpStackLocation(Irp); 3971 StackPtr->MajorFunction = IRP_MJ_WRITE; 3972 StackPtr->FileObject = FileObject; 3973 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ? 3974 SL_WRITE_THROUGH : 0; 3975 StackPtr->Parameters.Write.Key = CapturedKey; 3976 StackPtr->Parameters.Write.Length = Length; 3977 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset; 3978 3979 /* Check if this is buffered I/O */ 3980 if (DeviceObject->Flags & DO_BUFFERED_IO) 3981 { 3982 /* Check if we have a buffer length */ 3983 if (Length) 3984 { 3985 /* Enter SEH */ 3986 _SEH2_TRY 3987 { 3988 /* Allocate a buffer */ 3989 Irp->AssociatedIrp.SystemBuffer = 3990 ExAllocatePoolWithTag(NonPagedPool, 3991 Length, 3992 TAG_SYSB); 3993 3994 /* Copy the data into it */ 3995 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length); 3996 } 3997 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3998 { 3999 /* Allocating failed, clean up and return the exception code */ 4000 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 4001 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4002 } 4003 _SEH2_END; 4004 4005 /* Set the flags */ 4006 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); 4007 } 4008 else 4009 { 4010 /* Not writing anything */ 4011 Irp->Flags = IRP_BUFFERED_IO; 4012 } 4013 } 4014 else if (DeviceObject->Flags & DO_DIRECT_IO) 4015 { 4016 /* Check if we have a buffer length */ 4017 if (Length) 4018 { 4019 _SEH2_TRY 4020 { 4021 /* Allocate an MDL */ 4022 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); 4023 if (!Mdl) 4024 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 4025 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess); 4026 } 4027 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4028 { 4029 /* Allocating failed, clean up and return the exception code */ 4030 IopCleanupAfterException(FileObject, Irp, EventObject, NULL); 4031 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4032 } 4033 _SEH2_END; 4034 } 4035 4036 /* No allocation flags */ 4037 Irp->Flags = 0; 4038 } 4039 else 4040 { 4041 /* No allocation flags, and use the buffer directly */ 4042 Irp->Flags = 0; 4043 Irp->UserBuffer = Buffer; 4044 } 4045 4046 /* Now set the deferred read flags */ 4047 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION); 4048 #if 0 4049 /* FIXME: VFAT SUCKS */ 4050 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; 4051 #endif 4052 4053 /* Perform the call */ 4054 return IopPerformSynchronousRequest(DeviceObject, 4055 Irp, 4056 FileObject, 4057 TRUE, 4058 PreviousMode, 4059 Synchronous, 4060 IopWriteTransfer); 4061 } 4062 4063 NTSTATUS 4064 NTAPI 4065 NtWriteFileGather(IN HANDLE FileHandle, 4066 IN HANDLE Event OPTIONAL, 4067 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, 4068 IN PVOID UserApcContext OPTIONAL, 4069 OUT PIO_STATUS_BLOCK UserIoStatusBlock, 4070 IN FILE_SEGMENT_ELEMENT BufferDescription [], 4071 IN ULONG BufferLength, 4072 IN PLARGE_INTEGER ByteOffset, 4073 IN PULONG Key OPTIONAL) 4074 { 4075 UNIMPLEMENTED; 4076 return STATUS_NOT_IMPLEMENTED; 4077 } 4078 4079 /* 4080 * @implemented 4081 */ 4082 NTSTATUS 4083 NTAPI 4084 NtQueryVolumeInformationFile(IN HANDLE FileHandle, 4085 OUT PIO_STATUS_BLOCK IoStatusBlock, 4086 OUT PVOID FsInformation, 4087 IN ULONG Length, 4088 IN FS_INFORMATION_CLASS FsInformationClass) 4089 { 4090 PFILE_OBJECT FileObject; 4091 PIRP Irp; 4092 PIO_STACK_LOCATION StackPtr; 4093 PDEVICE_OBJECT DeviceObject; 4094 PKEVENT Event = NULL; 4095 BOOLEAN LocalEvent = FALSE; 4096 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 4097 NTSTATUS Status; 4098 IO_STATUS_BLOCK KernelIosb; 4099 PAGED_CODE(); 4100 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 4101 4102 /* Check if we're called from user mode */ 4103 if (PreviousMode != KernelMode) 4104 { 4105 /* Validate the information class */ 4106 if ((FsInformationClass < 0) || 4107 (FsInformationClass >= FileFsMaximumInformation) || 4108 !(IopQueryFsOperationLength[FsInformationClass])) 4109 { 4110 /* Invalid class */ 4111 return STATUS_INVALID_INFO_CLASS; 4112 } 4113 4114 /* Validate the length */ 4115 if (Length < IopQueryFsOperationLength[FsInformationClass]) 4116 { 4117 /* Invalid length */ 4118 return STATUS_INFO_LENGTH_MISMATCH; 4119 } 4120 4121 /* Enter SEH for probing */ 4122 _SEH2_TRY 4123 { 4124 /* Probe the I/O Status block */ 4125 ProbeForWriteIoStatusBlock(IoStatusBlock); 4126 4127 /* Probe the information */ 4128 ProbeForWrite(FsInformation, Length, sizeof(ULONG)); 4129 } 4130 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4131 { 4132 /* Return the exception code */ 4133 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4134 } 4135 _SEH2_END; 4136 } 4137 4138 /* Get File Object */ 4139 Status = ObReferenceObjectByHandle(FileHandle, 4140 IopQueryFsOperationAccess 4141 [FsInformationClass], 4142 IoFileObjectType, 4143 PreviousMode, 4144 (PVOID*)&FileObject, 4145 NULL); 4146 if (!NT_SUCCESS(Status)) return Status; 4147 4148 /* Only allow direct device open for FileFsDeviceInformation */ 4149 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) && 4150 FsInformationClass != FileFsDeviceInformation) 4151 { 4152 ObDereferenceObject(FileObject); 4153 return STATUS_INVALID_DEVICE_REQUEST; 4154 } 4155 4156 /* Check if we should use Sync IO or not */ 4157 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 4158 { 4159 /* Lock it */ 4160 Status = IopLockFileObject(FileObject, PreviousMode); 4161 if (Status != STATUS_SUCCESS) 4162 { 4163 ObDereferenceObject(FileObject); 4164 return Status; 4165 } 4166 } 4167 4168 /* 4169 * Quick path for FileFsDeviceInformation - the kernel has enough 4170 * info to reply instead of the driver, excepted for network file systems 4171 */ 4172 if (FsInformationClass == FileFsDeviceInformation && 4173 (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) || FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)) 4174 { 4175 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo = FsInformation; 4176 DeviceObject = FileObject->DeviceObject; 4177 4178 _SEH2_TRY 4179 { 4180 FsDeviceInfo->DeviceType = DeviceObject->DeviceType; 4181 4182 /* Complete characteristcs with mount status if relevant */ 4183 FsDeviceInfo->Characteristics = DeviceObject->Characteristics; 4184 if (IopGetMountFlag(DeviceObject)) 4185 { 4186 SetFlag(FsDeviceInfo->Characteristics, FILE_DEVICE_IS_MOUNTED); 4187 } 4188 4189 IoStatusBlock->Information = sizeof(FILE_FS_DEVICE_INFORMATION); 4190 IoStatusBlock->Status = STATUS_SUCCESS; 4191 } 4192 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4193 { 4194 /* Check if we had a file lock */ 4195 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4196 { 4197 /* Release it */ 4198 IopUnlockFileObject(FileObject); 4199 } 4200 4201 /* Dereference the FO */ 4202 ObDereferenceObject(FileObject); 4203 4204 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4205 } 4206 _SEH2_END; 4207 4208 /* Check if we had a file lock */ 4209 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4210 { 4211 /* Release it */ 4212 IopUnlockFileObject(FileObject); 4213 } 4214 4215 /* Dereference the FO */ 4216 ObDereferenceObject(FileObject); 4217 4218 return STATUS_SUCCESS; 4219 } 4220 /* This is to be handled by the kernel, not by FSD */ 4221 else if (FsInformationClass == FileFsDriverPathInformation) 4222 { 4223 PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo; 4224 4225 _SEH2_TRY 4226 { 4227 /* Allocate our local structure */ 4228 DriverPathInfo = ExAllocatePoolWithQuotaTag(NonPagedPool, Length, TAG_IO); 4229 4230 /* And copy back caller data */ 4231 RtlCopyMemory(DriverPathInfo, FsInformation, Length); 4232 4233 /* Is the driver in the IO path? */ 4234 Status = IopGetDriverPathInformation(FileObject, DriverPathInfo, Length); 4235 /* We failed, don't continue execution */ 4236 if (!NT_SUCCESS(Status)) 4237 { 4238 RtlRaiseStatus(Status); 4239 } 4240 4241 /* We succeed, copy back info */ 4242 ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath; 4243 4244 /* We're done */ 4245 IoStatusBlock->Information = sizeof(FILE_FS_DRIVER_PATH_INFORMATION); 4246 IoStatusBlock->Status = STATUS_SUCCESS; 4247 } 4248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4249 { 4250 Status = _SEH2_GetExceptionCode(); 4251 } 4252 _SEH2_END; 4253 4254 /* Don't leak */ 4255 if (DriverPathInfo != NULL) 4256 { 4257 ExFreePoolWithTag(DriverPathInfo, TAG_IO); 4258 } 4259 4260 /* Check if we had a file lock */ 4261 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4262 { 4263 /* Release it */ 4264 IopUnlockFileObject(FileObject); 4265 } 4266 4267 /* Dereference the FO */ 4268 ObDereferenceObject(FileObject); 4269 4270 return Status; 4271 } 4272 4273 if (!BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)) 4274 { 4275 /* Use local event */ 4276 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 4277 if (!Event) 4278 { 4279 ObDereferenceObject(FileObject); 4280 return STATUS_INSUFFICIENT_RESOURCES; 4281 } 4282 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 4283 LocalEvent = TRUE; 4284 } 4285 4286 /* Get the device object */ 4287 DeviceObject = IoGetRelatedDeviceObject(FileObject); 4288 4289 /* Clear File Object event */ 4290 KeClearEvent(&FileObject->Event); 4291 4292 /* Allocate the IRP */ 4293 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4294 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event); 4295 4296 /* Set up the IRP */ 4297 Irp->RequestorMode = PreviousMode; 4298 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 4299 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 4300 Irp->UserEvent = (LocalEvent) ? Event : NULL; 4301 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 4302 Irp->Tail.Overlay.OriginalFileObject = FileObject; 4303 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 4304 Irp->UserBuffer = FsInformation; 4305 Irp->AssociatedIrp.SystemBuffer = NULL; 4306 Irp->MdlAddress = NULL; 4307 4308 /* Set up Stack Data */ 4309 StackPtr = IoGetNextIrpStackLocation(Irp); 4310 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION; 4311 StackPtr->FileObject = FileObject; 4312 4313 /* Enter SEH */ 4314 _SEH2_TRY 4315 { 4316 /* Allocate a buffer */ 4317 Irp->AssociatedIrp.SystemBuffer = 4318 ExAllocatePoolWithTag(NonPagedPool, 4319 Length, 4320 TAG_SYSB); 4321 } 4322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4323 { 4324 /* Allocating failed, clean up and return the exception code */ 4325 IopCleanupAfterException(FileObject, Irp, NULL, Event); 4326 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4327 } 4328 _SEH2_END; 4329 4330 /* Set the flags for this buffered + deferred I/O */ 4331 Irp->Flags |= (IRP_BUFFERED_IO | 4332 IRP_DEALLOCATE_BUFFER | 4333 IRP_INPUT_OPERATION | 4334 IRP_DEFER_IO_COMPLETION); 4335 4336 /* Set Parameters */ 4337 StackPtr->Parameters.QueryVolume.Length = Length; 4338 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass; 4339 4340 /* Call the Driver */ 4341 Status = IopPerformSynchronousRequest(DeviceObject, 4342 Irp, 4343 FileObject, 4344 TRUE, 4345 PreviousMode, 4346 !LocalEvent, 4347 IopOtherTransfer); 4348 4349 /* Check if this was async I/O */ 4350 if (LocalEvent) 4351 { 4352 /* It was, finalize this request */ 4353 Status = IopFinalizeAsynchronousIo(Status, 4354 Event, 4355 Irp, 4356 PreviousMode, 4357 &KernelIosb, 4358 IoStatusBlock); 4359 } 4360 4361 /* Return status */ 4362 return Status; 4363 } 4364 4365 /* 4366 * @implemented 4367 */ 4368 NTSTATUS 4369 NTAPI 4370 NtSetVolumeInformationFile(IN HANDLE FileHandle, 4371 OUT PIO_STATUS_BLOCK IoStatusBlock, 4372 IN PVOID FsInformation, 4373 IN ULONG Length, 4374 IN FS_INFORMATION_CLASS FsInformationClass) 4375 { 4376 PFILE_OBJECT FileObject; 4377 PIRP Irp; 4378 PIO_STACK_LOCATION StackPtr; 4379 PDEVICE_OBJECT DeviceObject, TargetDeviceObject; 4380 PKEVENT Event = NULL; 4381 BOOLEAN LocalEvent = FALSE; 4382 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 4383 NTSTATUS Status; 4384 IO_STATUS_BLOCK KernelIosb; 4385 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure; 4386 PAGED_CODE(); 4387 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); 4388 4389 /* Check if we're called from user mode */ 4390 if (PreviousMode != KernelMode) 4391 { 4392 /* Validate the information class */ 4393 if ((FsInformationClass < 0) || 4394 (FsInformationClass >= FileFsMaximumInformation) || 4395 !(IopSetFsOperationLength[FsInformationClass])) 4396 { 4397 /* Invalid class */ 4398 return STATUS_INVALID_INFO_CLASS; 4399 } 4400 4401 /* Validate the length */ 4402 if (Length < IopSetFsOperationLength[FsInformationClass]) 4403 { 4404 /* Invalid length */ 4405 return STATUS_INFO_LENGTH_MISMATCH; 4406 } 4407 4408 /* Enter SEH for probing */ 4409 _SEH2_TRY 4410 { 4411 /* Probe the I/O Status block */ 4412 ProbeForWriteIoStatusBlock(IoStatusBlock); 4413 4414 /* Probe the information */ 4415 ProbeForRead(FsInformation, Length, sizeof(ULONG)); 4416 } 4417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4418 { 4419 /* Return the exception code */ 4420 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4421 } 4422 _SEH2_END; 4423 } 4424 4425 /* Get File Object */ 4426 Status = ObReferenceObjectByHandle(FileHandle, 4427 IopSetFsOperationAccess 4428 [FsInformationClass], 4429 IoFileObjectType, 4430 PreviousMode, 4431 (PVOID*)&FileObject, 4432 NULL); 4433 if (!NT_SUCCESS(Status)) return Status; 4434 4435 /* Get target device for notification */ 4436 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject); 4437 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL; 4438 4439 /* Check if we should use Sync IO or not */ 4440 if (FileObject->Flags & FO_SYNCHRONOUS_IO) 4441 { 4442 /* Lock it */ 4443 Status = IopLockFileObject(FileObject, PreviousMode); 4444 if (Status != STATUS_SUCCESS) 4445 { 4446 ObDereferenceObject(FileObject); 4447 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4448 return Status; 4449 } 4450 } 4451 else 4452 { 4453 /* Use local event */ 4454 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); 4455 if (!Event) 4456 { 4457 ObDereferenceObject(FileObject); 4458 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4459 return STATUS_INSUFFICIENT_RESOURCES; 4460 } 4461 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 4462 LocalEvent = TRUE; 4463 } 4464 4465 /* Get the device object */ 4466 DeviceObject = IoGetRelatedDeviceObject(FileObject); 4467 4468 /* Clear File Object event */ 4469 KeClearEvent(&FileObject->Event); 4470 4471 /* Allocate the IRP */ 4472 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 4473 if (!Irp) 4474 { 4475 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4476 return IopCleanupFailedIrp(FileObject, NULL, Event); 4477 } 4478 4479 /* Set up the IRP */ 4480 Irp->RequestorMode = PreviousMode; 4481 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; 4482 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; 4483 Irp->UserEvent = (LocalEvent) ? Event : NULL; 4484 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 4485 Irp->Tail.Overlay.OriginalFileObject = FileObject; 4486 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; 4487 Irp->UserBuffer = FsInformation; 4488 Irp->AssociatedIrp.SystemBuffer = NULL; 4489 Irp->MdlAddress = NULL; 4490 4491 /* Set up Stack Data */ 4492 StackPtr = IoGetNextIrpStackLocation(Irp); 4493 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION; 4494 StackPtr->FileObject = FileObject; 4495 4496 /* Enter SEH */ 4497 _SEH2_TRY 4498 { 4499 /* Allocate a buffer */ 4500 Irp->AssociatedIrp.SystemBuffer = 4501 ExAllocatePoolWithTag(NonPagedPool, 4502 Length, 4503 TAG_SYSB); 4504 4505 /* Copy the data into it */ 4506 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length); 4507 } 4508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4509 { 4510 /* Allocating failed, clean up and return the exception code */ 4511 IopCleanupAfterException(FileObject, Irp, NULL, Event); 4512 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject); 4513 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4514 } 4515 _SEH2_END; 4516 4517 /* Set the flags for this buffered + deferred I/O */ 4518 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); 4519 4520 /* Set Parameters */ 4521 StackPtr->Parameters.SetVolume.Length = Length; 4522 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass; 4523 4524 /* Call the Driver */ 4525 Status = IopPerformSynchronousRequest(DeviceObject, 4526 Irp, 4527 FileObject, 4528 FALSE, 4529 PreviousMode, 4530 !LocalEvent, 4531 IopOtherTransfer); 4532 4533 /* Check if this was async I/O */ 4534 if (LocalEvent) 4535 { 4536 /* It was, finalize this request */ 4537 Status = IopFinalizeAsynchronousIo(Status, 4538 Event, 4539 Irp, 4540 PreviousMode, 4541 &KernelIosb, 4542 IoStatusBlock); 4543 } 4544 4545 if (TargetDeviceObject && NT_SUCCESS(Status)) 4546 { 4547 /* Time to report change */ 4548 NotificationStructure.Version = 1; 4549 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION); 4550 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE; 4551 NotificationStructure.FileObject = NULL; 4552 NotificationStructure.NameBufferOffset = - 1; 4553 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure); 4554 } 4555 4556 /* Return status */ 4557 return Status; 4558 } 4559 4560 /* 4561 * @unimplemented 4562 */ 4563 NTSTATUS 4564 NTAPI 4565 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle) 4566 { 4567 UNIMPLEMENTED; 4568 return STATUS_NOT_IMPLEMENTED; 4569 } 4570 4571 /* 4572 * @unimplemented 4573 */ 4574 NTSTATUS 4575 NTAPI 4576 NtRequestDeviceWakeup(IN HANDLE DeviceHandle) 4577 { 4578 UNIMPLEMENTED; 4579 return STATUS_NOT_IMPLEMENTED; 4580 } 4581