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