ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

iofunc.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/io/iofunc.c
00005  * PURPOSE:         Generic I/O Functions that build IRPs for various operations
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  *                  Gunnar Dalsnes
00008  *                  Filip Navara (navaraf@reactos.org)
00009  */
00010 
00011 /* INCLUDES *****************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #include <ioevent.h>
00015 #define NDEBUG
00016 #include <debug.h>
00017 #include "internal/io_i.h"
00018 
00019 /* PRIVATE FUNCTIONS *********************************************************/
00020 
00021 VOID
00022 NTAPI
00023 IopCleanupAfterException(IN PFILE_OBJECT FileObject,
00024                          IN PIRP Irp,
00025                          IN PKEVENT Event OPTIONAL,
00026                          IN PKEVENT LocalEvent OPTIONAL)
00027 {
00028     PAGED_CODE();
00029     IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
00030 
00031     /* Check if we had a buffer */
00032     if (Irp->AssociatedIrp.SystemBuffer)
00033     {
00034         /* Free it */
00035         ExFreePool(Irp->AssociatedIrp.SystemBuffer);
00036     }
00037 
00038     /* Free the mdl */
00039     if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
00040 
00041     /* Free the IRP */
00042     IoFreeIrp(Irp);
00043 
00044     /* Check if we had a file lock */
00045     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
00046     {
00047         /* Release it */
00048         IopUnlockFileObject(FileObject);
00049     }
00050 
00051     /* Check if we had an event */
00052     if (Event) ObDereferenceObject(Event);
00053 
00054     /* Check if we had a local event */
00055     if (LocalEvent) ExFreePool(LocalEvent);
00056 
00057     /* Derefenrce the FO */
00058     ObDereferenceObject(FileObject);
00059 }
00060 
00061 NTSTATUS
00062 NTAPI
00063 IopFinalizeAsynchronousIo(IN NTSTATUS SynchStatus,
00064                           IN PKEVENT Event,
00065                           IN PIRP Irp,
00066                           IN KPROCESSOR_MODE PreviousMode,
00067                           IN PIO_STATUS_BLOCK KernelIosb,
00068                           OUT PIO_STATUS_BLOCK IoStatusBlock)
00069 {
00070     NTSTATUS FinalStatus = SynchStatus;
00071     PAGED_CODE();
00072     IOTRACE(IO_API_DEBUG, "IRP: %p. Status: %lx \n", Irp, SynchStatus);
00073 
00074     /* Make sure the IRP was completed, but returned pending */
00075     if (FinalStatus == STATUS_PENDING)
00076     {
00077         /* Wait for the IRP */
00078         FinalStatus = KeWaitForSingleObject(Event,
00079                                             Executive,
00080                                             PreviousMode,
00081                                             FALSE,
00082                                             NULL);
00083         if (FinalStatus == STATUS_USER_APC)
00084         {
00085             /* Abort the request */
00086             IopAbortInterruptedIrp(Event, Irp);
00087         }
00088 
00089         /* Set the final status */
00090         FinalStatus = KernelIosb->Status;
00091     }
00092 
00093     /* Wrap potential user-mode write in SEH */
00094     _SEH2_TRY
00095     {
00096         *IoStatusBlock = *KernelIosb;
00097     }
00098     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00099     {
00100         /* Get the exception code */
00101         FinalStatus = _SEH2_GetExceptionCode();
00102     }
00103     _SEH2_END;
00104 
00105     /* Free the event and return status */
00106     ExFreePool(Event);
00107     return FinalStatus;
00108 }
00109 
00110 NTSTATUS
00111 NTAPI
00112 IopPerformSynchronousRequest(IN PDEVICE_OBJECT DeviceObject,
00113                              IN PIRP Irp,
00114                              IN PFILE_OBJECT FileObject,
00115                              IN BOOLEAN Deferred,
00116                              IN KPROCESSOR_MODE PreviousMode,
00117                              IN BOOLEAN SynchIo,
00118                              IN IOP_TRANSFER_TYPE TransferType)
00119 {
00120     NTSTATUS Status;
00121     PKNORMAL_ROUTINE NormalRoutine;
00122     PVOID NormalContext;
00123     KIRQL OldIrql;
00124     PAGED_CODE();
00125     IOTRACE(IO_API_DEBUG, "IRP: %p. DO: %p. FO: %p \n",
00126             Irp, DeviceObject, FileObject);
00127 
00128     /* Queue the IRP */
00129     IopQueueIrpToThread(Irp);
00130 
00131     /* Update operation counts */
00132     IopUpdateOperationCount(TransferType);
00133 
00134     /* Call the driver */
00135     Status = IoCallDriver(DeviceObject, Irp);
00136 
00137     /* Check if we're optimizing this case */
00138     if (Deferred)
00139     {
00140         /* We are! Check if the IRP wasn't completed */
00141         if (Status != STATUS_PENDING)
00142         {
00143             /* Complete it ourselves */
00144             ASSERT(!Irp->PendingReturned);
00145             KeRaiseIrql(APC_LEVEL, &OldIrql);
00146             IopCompleteRequest(&Irp->Tail.Apc,
00147                                &NormalRoutine,
00148                                &NormalContext,
00149                                (PVOID*)&FileObject,
00150                                &NormalContext);
00151             KeLowerIrql(OldIrql);
00152         }
00153     }
00154 
00155     /* Check if this was synch I/O */
00156     if (SynchIo)
00157     {
00158         /* Make sure the IRP was completed, but returned pending */
00159         if (Status == STATUS_PENDING)
00160         {
00161             /* Wait for the IRP */
00162             Status = KeWaitForSingleObject(&FileObject->Event,
00163                                            Executive,
00164                                            PreviousMode,
00165                                            (FileObject->Flags &
00166                                             FO_ALERTABLE_IO),
00167                                            NULL);
00168             if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
00169             {
00170                 /* Abort the request */
00171                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
00172             }
00173 
00174             /* Set the final status */
00175             Status = FileObject->FinalStatus;
00176         }
00177 
00178         /* Release the file lock */
00179         IopUnlockFileObject(FileObject);
00180     }
00181 
00182     /* Return status */
00183     return Status;
00184 }
00185 
00186 NTSTATUS
00187 NTAPI
00188 IopDeviceFsIoControl(IN HANDLE DeviceHandle,
00189                      IN HANDLE Event OPTIONAL,
00190                      IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
00191                      IN PVOID UserApcContext OPTIONAL,
00192                      OUT PIO_STATUS_BLOCK IoStatusBlock,
00193                      IN ULONG IoControlCode,
00194                      IN PVOID InputBuffer,
00195                      IN ULONG InputBufferLength OPTIONAL,
00196                      OUT PVOID OutputBuffer,
00197                      IN ULONG OutputBufferLength OPTIONAL,
00198                      IN BOOLEAN IsDevIoCtl)
00199 {
00200     NTSTATUS Status;
00201     PFILE_OBJECT FileObject;
00202     PDEVICE_OBJECT DeviceObject;
00203     PIRP Irp;
00204     PIO_STACK_LOCATION StackPtr;
00205     PKEVENT EventObject = NULL;
00206     BOOLEAN LockedForSynch = FALSE;
00207     ULONG AccessType;
00208     OBJECT_HANDLE_INFORMATION HandleInformation;
00209     ACCESS_MASK DesiredAccess;
00210     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00211     ULONG BufferLength;
00212     IOTRACE(IO_CTL_DEBUG, "Handle: %lx. CTL: %lx. Type: %lx \n",
00213             DeviceHandle, IoControlCode, IsDevIoCtl);
00214 
00215     /* Get the access type */
00216     AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
00217 
00218     /* Check if we came from user mode */
00219     if (PreviousMode != KernelMode)
00220     {
00221         _SEH2_TRY
00222         {
00223             /* Probe the status block */
00224             ProbeForWriteIoStatusBlock(IoStatusBlock);
00225 
00226             /* Check if this is buffered I/O */
00227             if (AccessType == METHOD_BUFFERED)
00228             {
00229                 /* Check if we have an output buffer */
00230                 if (OutputBuffer)
00231                 {
00232                     /* Probe the output buffer */
00233                     ProbeForWrite(OutputBuffer,
00234                                   OutputBufferLength,
00235                                   sizeof(CHAR));
00236                 }
00237                 else
00238                 {
00239                     /* Make sure the caller can't fake this as we depend on this */
00240                     OutputBufferLength = 0;
00241                 }
00242             }
00243 
00244             /* Check if we we have an input buffer I/O */
00245             if (AccessType != METHOD_NEITHER)
00246             {
00247                 /* Check if we have an input buffer */
00248                 if (InputBuffer)
00249                 {
00250                     /* Probe the input buffer */
00251                     ProbeForRead(InputBuffer, InputBufferLength, sizeof(CHAR));
00252                 }
00253                 else
00254                 {
00255                     /* Make sure the caller can't fake this as we depend on this */
00256                     InputBufferLength = 0;
00257                 }
00258             }
00259         }
00260         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00261         {
00262             /* Return the exception code */
00263             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00264         }
00265         _SEH2_END;
00266     }
00267 
00268     /* Don't check for access rights right now, KernelMode can do anything */
00269     Status = ObReferenceObjectByHandle(DeviceHandle,
00270                                        0,
00271                                        IoFileObjectType,
00272                                        PreviousMode,
00273                                        (PVOID*)&FileObject,
00274                                        &HandleInformation);
00275     if (!NT_SUCCESS(Status)) return Status;
00276 
00277     /* Can't use an I/O completion port and an APC in the same time */
00278     if ((FileObject->CompletionContext) && (UserApcRoutine))
00279     {
00280         /* Fail */
00281         ObDereferenceObject(FileObject);
00282         return STATUS_INVALID_PARAMETER;
00283     }
00284 
00285     /* Check if we from user mode */
00286     if (PreviousMode != KernelMode)
00287     {
00288         /* Get the access mask */
00289         DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
00290 
00291         /* Check if we can open it */
00292         if ((DesiredAccess != FILE_ANY_ACCESS) &&
00293             (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
00294         {
00295             /* Dereference the file object and fail */
00296             ObDereferenceObject(FileObject);
00297             return STATUS_ACCESS_DENIED;
00298         }
00299     }
00300 
00301     /* Check for an event */
00302     if (Event)
00303     {
00304         /* Reference it */
00305         Status = ObReferenceObjectByHandle(Event,
00306                                            EVENT_MODIFY_STATE,
00307                                            ExEventObjectType,
00308                                            PreviousMode,
00309                                            (PVOID*)&EventObject,
00310                                            NULL);
00311         if (!NT_SUCCESS(Status))
00312         {
00313             /* Dereference the file object and fail */
00314             ObDereferenceObject(FileObject);
00315             return Status;
00316         }
00317 
00318         /* Clear it */
00319         KeClearEvent(EventObject);
00320     }
00321 
00322     /* Check if this is a file that was opened for Synch I/O */
00323     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
00324     {
00325         /* Lock it */
00326         IopLockFileObject(FileObject);
00327 
00328         /* Remember to unlock later */
00329         LockedForSynch = TRUE;
00330     }
00331 
00332     /* Check if this is a direct open or not */
00333     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
00334     {
00335         /* It's a direct open, get the attached device */
00336         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
00337     }
00338     else
00339     {
00340         /* Otherwise get the related device */
00341         DeviceObject = IoGetRelatedDeviceObject(FileObject);
00342     }
00343 
00344     /* Clear the event */
00345     KeClearEvent(&FileObject->Event);
00346 
00347     /* Allocate IRP */
00348     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00349     if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
00350 
00351     /* Setup the IRP */
00352     Irp->UserIosb = IoStatusBlock;
00353     Irp->UserEvent = EventObject;
00354     Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
00355     Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
00356     Irp->Cancel = FALSE;
00357     Irp->CancelRoutine = NULL;
00358     Irp->PendingReturned = FALSE;
00359     Irp->RequestorMode = PreviousMode;
00360     Irp->MdlAddress = NULL;
00361     Irp->AssociatedIrp.SystemBuffer = NULL;
00362     Irp->Flags = 0;
00363     Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
00364     Irp->Tail.Overlay.OriginalFileObject = FileObject;
00365     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00366 
00367     /* Set stack location settings */
00368     StackPtr = IoGetNextIrpStackLocation(Irp);
00369     StackPtr->FileObject = FileObject;
00370     StackPtr->MajorFunction = IsDevIoCtl ?
00371                               IRP_MJ_DEVICE_CONTROL :
00372                               IRP_MJ_FILE_SYSTEM_CONTROL;
00373     StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
00374     StackPtr->Control = 0;
00375     StackPtr->Flags = 0;
00376     StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
00377 
00378     /* Set the IOCTL Data */
00379     StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
00380     StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
00381     StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
00382         OutputBufferLength;
00383 
00384     /* Handle the Methods */
00385     switch (AccessType)
00386     {
00387         /* Buffered I/O */
00388         case METHOD_BUFFERED:
00389 
00390             /* Enter SEH for allocations */
00391             _SEH2_TRY
00392             {
00393                 /* Select the right Buffer Length */
00394                 BufferLength = (InputBufferLength > OutputBufferLength) ?
00395                                 InputBufferLength : OutputBufferLength;
00396 
00397                 /* Make sure there is one */
00398                 if (BufferLength)
00399                 {
00400                     /* Allocate the System Buffer */
00401                     Irp->AssociatedIrp.SystemBuffer =
00402                         ExAllocatePoolWithTag(NonPagedPool,
00403                                               BufferLength,
00404                                               TAG_SYS_BUF);
00405 
00406                     /* Check if we got a buffer */
00407                     if (InputBuffer)
00408                     {
00409                         /* Copy into the System Buffer */
00410                         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
00411                                       InputBuffer,
00412                                       InputBufferLength);
00413                     }
00414 
00415                     /* Write the flags */
00416                     Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
00417                     if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
00418 
00419                     /* Save the Buffer */
00420                     Irp->UserBuffer = OutputBuffer;
00421                 }
00422                 else
00423                 {
00424                     /* Clear the Flags and Buffer */
00425                     Irp->UserBuffer = NULL;
00426                 }
00427             }
00428             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00429             {
00430                 /* Cleanup after exception and return */
00431                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
00432                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
00433             }
00434             _SEH2_END;
00435             break;
00436 
00437         /* Direct I/O */
00438         case METHOD_IN_DIRECT:
00439         case METHOD_OUT_DIRECT:
00440 
00441             /* Enter SEH */
00442             _SEH2_TRY
00443             {
00444                 /* Check if we got an input buffer */
00445                 if ((InputBufferLength) && (InputBuffer))
00446                 {
00447                     /* Allocate the System Buffer */
00448                     Irp->AssociatedIrp.SystemBuffer =
00449                         ExAllocatePoolWithTag(NonPagedPool,
00450                                               InputBufferLength,
00451                                               TAG_SYS_BUF);
00452 
00453                     /* Copy into the System Buffer */
00454                     RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
00455                                   InputBuffer,
00456                                   InputBufferLength);
00457 
00458                     /* Write the flags */
00459                     Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
00460                 }
00461 
00462                 /* Check if we got an output buffer */
00463                 if (OutputBuffer)
00464                 {
00465                     /* Allocate the System Buffer */
00466                     Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
00467                                                     OutputBufferLength,
00468                                                     FALSE,
00469                                                     FALSE,
00470                                                     Irp);
00471                     if (!Irp->MdlAddress)
00472                     {
00473                         /* Raise exception we'll catch */
00474                         ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
00475                     }
00476 
00477                     /* Do the probe */
00478                     MmProbeAndLockPages(Irp->MdlAddress,
00479                                         PreviousMode,
00480                                         (AccessType == METHOD_IN_DIRECT) ?
00481                                         IoReadAccess : IoWriteAccess);
00482                 }
00483             }
00484             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00485             {
00486                 /* Cleanup after exception and return */
00487                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
00488                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
00489             }
00490             _SEH2_END;
00491             break;
00492 
00493         case METHOD_NEITHER:
00494 
00495             /* Just save the Buffer */
00496             Irp->UserBuffer = OutputBuffer;
00497             StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
00498     }
00499 
00500     /* Use deferred completion for FS I/O */
00501     Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
00502 
00503     /* Perform the call */
00504     return IopPerformSynchronousRequest(DeviceObject,
00505                                         Irp,
00506                                         FileObject,
00507                                         !IsDevIoCtl,
00508                                         PreviousMode,
00509                                         LockedForSynch,
00510                                         IopOtherTransfer);
00511 }
00512 
00513 NTSTATUS
00514 NTAPI
00515 IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
00516                           IN ULONG InformationClass,
00517                           IN ULONG Length,
00518                           OUT PVOID Information,
00519                           OUT PULONG ReturnedLength,
00520                           IN BOOLEAN File)
00521 {
00522     IO_STATUS_BLOCK IoStatusBlock;
00523     PIRP Irp;
00524     PDEVICE_OBJECT DeviceObject;
00525     PIO_STACK_LOCATION StackPtr;
00526     BOOLEAN LocalEvent = FALSE;
00527     KEVENT Event;
00528     NTSTATUS Status;
00529     PAGED_CODE();
00530     IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
00531             FileObject, InformationClass, File);
00532 
00533     /* Reference the object */
00534     ObReferenceObject(FileObject);
00535 
00536     /* Check if this is a file that was opened for Synch I/O */
00537     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
00538     {
00539         /* Lock it */
00540         IopLockFileObject(FileObject);
00541 
00542         /* Use File Object event */
00543         KeClearEvent(&FileObject->Event);
00544     }
00545     else
00546     {
00547         /* Use local event */
00548         KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
00549         LocalEvent = TRUE;
00550     }
00551 
00552     /* Get the Device Object */
00553     DeviceObject = IoGetRelatedDeviceObject(FileObject);
00554 
00555     /* Allocate the IRP */
00556     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00557     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
00558 
00559     /* Set the IRP */
00560     Irp->Tail.Overlay.OriginalFileObject = FileObject;
00561     Irp->RequestorMode = KernelMode;
00562     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
00563     Irp->UserIosb = &IoStatusBlock;
00564     Irp->UserEvent = (LocalEvent) ? &Event : NULL;
00565     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
00566     Irp->Flags |= IRP_BUFFERED_IO;
00567     Irp->AssociatedIrp.SystemBuffer = Information;
00568     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00569 
00570     /* Set the Stack Data */
00571     StackPtr = IoGetNextIrpStackLocation(Irp);
00572     StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION:
00573                                      IRP_MJ_QUERY_VOLUME_INFORMATION;
00574     StackPtr->FileObject = FileObject;
00575 
00576     /* Check which type this is */
00577     if (File)
00578     {
00579         /* Set Parameters */
00580         StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
00581         StackPtr->Parameters.QueryFile.Length = Length;
00582     }
00583     else
00584     {
00585         /* Set Parameters */
00586         StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
00587         StackPtr->Parameters.QueryVolume.Length = Length;
00588     }
00589 
00590     /* Queue the IRP */
00591     IopQueueIrpToThread(Irp);
00592 
00593     /* Call the Driver */
00594     Status = IoCallDriver(DeviceObject, Irp);
00595 
00596     /* Check if this was synch I/O */
00597     if (!LocalEvent)
00598     {
00599         /* Check if the requet is pending */
00600         if (Status == STATUS_PENDING)
00601         {
00602             /* Wait on the file object */
00603             Status = KeWaitForSingleObject(&FileObject->Event,
00604                                            Executive,
00605                                            KernelMode,
00606                                            FileObject->Flags & FO_ALERTABLE_IO,
00607                                            NULL);
00608             if (Status == STATUS_ALERTED)
00609             {
00610                 /* Abort the operation */
00611                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
00612             }
00613 
00614             /* Get the final status */
00615             Status = FileObject->FinalStatus;
00616         }
00617 
00618         /* Release the file lock */
00619         IopUnlockFileObject(FileObject);
00620     }
00621     else if (Status == STATUS_PENDING)
00622     {
00623         /* Wait on the local event and get the final status */
00624         KeWaitForSingleObject(&Event,
00625                               Executive,
00626                               KernelMode,
00627                               FALSE,
00628                               NULL);
00629         Status = IoStatusBlock.Status;
00630     }
00631 
00632     /* Return the Length and Status. ReturnedLength is NOT optional */
00633     *ReturnedLength = (ULONG)IoStatusBlock.Information;
00634     return Status;
00635 }
00636 
00637 /* PUBLIC FUNCTIONS **********************************************************/
00638 
00639 /*
00640  * @implemented
00641  */
00642 NTSTATUS
00643 NTAPI
00644 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject,
00645                        IN PMDL Mdl,
00646                        IN PLARGE_INTEGER Offset,
00647                        IN PKEVENT Event,
00648                        IN PIO_STATUS_BLOCK StatusBlock)
00649 {
00650     PIRP Irp;
00651     PIO_STACK_LOCATION StackPtr;
00652     PDEVICE_OBJECT DeviceObject;
00653     IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
00654             FileObject, Mdl, Offset);
00655 
00656     /* Get the Device Object */
00657     DeviceObject = IoGetRelatedDeviceObject(FileObject);
00658 
00659     /* Allocate IRP */
00660     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00661     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
00662 
00663     /* Get the Stack */
00664     StackPtr = IoGetNextIrpStackLocation(Irp);
00665 
00666     /* Create the IRP Settings */
00667     Irp->MdlAddress = Mdl;
00668     Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
00669     Irp->UserIosb = StatusBlock;
00670     Irp->UserEvent = Event;
00671     Irp->RequestorMode = KernelMode;
00672     Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
00673     Irp->Tail.Overlay.OriginalFileObject = FileObject;
00674     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00675 
00676     /* Set the Stack Settings */
00677     StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
00678     StackPtr->Parameters.Write.ByteOffset = *Offset;
00679     StackPtr->MajorFunction = IRP_MJ_WRITE;
00680     StackPtr->FileObject = FileObject;
00681 
00682     /* Call the Driver */
00683     return IoCallDriver(DeviceObject, Irp);
00684 }
00685 
00686 /*
00687  * @implemented
00688  */
00689 NTSTATUS
00690 NTAPI
00691 IoPageRead(IN PFILE_OBJECT FileObject,
00692            IN PMDL Mdl,
00693            IN PLARGE_INTEGER Offset,
00694            IN PKEVENT Event,
00695            IN PIO_STATUS_BLOCK StatusBlock)
00696 {
00697     PIRP Irp;
00698     PIO_STACK_LOCATION StackPtr;
00699     PDEVICE_OBJECT DeviceObject;
00700     IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
00701             FileObject, Mdl, Offset);
00702 
00703     /* Get the Device Object */
00704     DeviceObject = IoGetRelatedDeviceObject(FileObject);
00705 
00706     /* Allocate IRP */
00707     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00708     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
00709 
00710     /* Get the Stack */
00711     StackPtr = IoGetNextIrpStackLocation(Irp);
00712 
00713     /* Create the IRP Settings */
00714     Irp->MdlAddress = Mdl;
00715     Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
00716     Irp->UserIosb = StatusBlock;
00717     Irp->UserEvent = Event;
00718     Irp->RequestorMode = KernelMode;
00719     Irp->Flags = IRP_PAGING_IO |
00720                  IRP_NOCACHE |
00721                  IRP_SYNCHRONOUS_PAGING_IO |
00722                  IRP_INPUT_OPERATION;
00723     Irp->Tail.Overlay.OriginalFileObject = FileObject;
00724     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00725 
00726     /* Set the Stack Settings */
00727     StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
00728     StackPtr->Parameters.Read.ByteOffset = *Offset;
00729     StackPtr->MajorFunction = IRP_MJ_READ;
00730     StackPtr->FileObject = FileObject;
00731 
00732     /* Call the Driver */
00733     return IoCallDriver(DeviceObject, Irp);
00734 }
00735 
00736 /*
00737  * @implemented
00738  */
00739 NTSTATUS
00740 NTAPI
00741 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
00742                        IN FILE_INFORMATION_CLASS FileInformationClass,
00743                        IN ULONG Length,
00744                        OUT PVOID FileInformation,
00745                        OUT PULONG ReturnedLength)
00746 {
00747     /* Call the shared routine */
00748     return IopQueryDeviceInformation(FileObject,
00749                                      FileInformationClass,
00750                                      Length,
00751                                      FileInformation,
00752                                      ReturnedLength,
00753                                      TRUE);
00754 }
00755 
00756 /*
00757  * @implemented
00758  */
00759 NTSTATUS
00760 NTAPI
00761 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
00762                          IN FS_INFORMATION_CLASS FsInformationClass,
00763                          IN ULONG Length,
00764                          OUT PVOID FsInformation,
00765                          OUT PULONG ReturnedLength)
00766 {
00767     /* Call the shared routine */
00768     return IopQueryDeviceInformation(FileObject,
00769                                      FsInformationClass,
00770                                      Length,
00771                                      FsInformation,
00772                                      ReturnedLength,
00773                                      FALSE);
00774 }
00775 
00776 /*
00777  * @implemented
00778  */
00779 NTSTATUS
00780 NTAPI
00781 IoSetInformation(IN PFILE_OBJECT FileObject,
00782                  IN FILE_INFORMATION_CLASS FileInformationClass,
00783                  IN ULONG Length,
00784                  IN PVOID FileInformation)
00785 {
00786     IO_STATUS_BLOCK IoStatusBlock;
00787     PIRP Irp;
00788     PDEVICE_OBJECT DeviceObject;
00789     PIO_STACK_LOCATION StackPtr;
00790     BOOLEAN LocalEvent = FALSE;
00791     KEVENT Event;
00792     NTSTATUS Status;
00793     PAGED_CODE();
00794     IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n",
00795             FileObject, FileInformationClass, Length);
00796 
00797     /* Reference the object */
00798     ObReferenceObject(FileObject);
00799 
00800     /* Check if this is a file that was opened for Synch I/O */
00801     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
00802     {
00803         /* Lock it */
00804         IopLockFileObject(FileObject);
00805 
00806         /* Use File Object event */
00807         KeClearEvent(&FileObject->Event);
00808     }
00809     else
00810     {
00811         /* Use local event */
00812         KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
00813         LocalEvent = TRUE;
00814     }
00815 
00816     /* Get the Device Object */
00817     DeviceObject = IoGetRelatedDeviceObject(FileObject);
00818 
00819     /* Allocate the IRP */
00820     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00821     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
00822 
00823     /* Set the IRP */
00824     Irp->Tail.Overlay.OriginalFileObject = FileObject;
00825     Irp->RequestorMode = KernelMode;
00826     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
00827     Irp->UserIosb = &IoStatusBlock;
00828     Irp->UserEvent = (LocalEvent) ? &Event : NULL;
00829     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
00830     Irp->Flags |= IRP_BUFFERED_IO;
00831     Irp->AssociatedIrp.SystemBuffer = FileInformation;
00832     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00833 
00834     /* Set the Stack Data */
00835     StackPtr = IoGetNextIrpStackLocation(Irp);
00836     StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
00837     StackPtr->FileObject = FileObject;
00838 
00839     /* Set Parameters */
00840     StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
00841     StackPtr->Parameters.SetFile.Length = Length;
00842 
00843     /* Queue the IRP */
00844     IopQueueIrpToThread(Irp);
00845 
00846     /* Call the Driver */
00847     Status = IoCallDriver(DeviceObject, Irp);
00848 
00849     /* Check if this was synch I/O */
00850     if (!LocalEvent)
00851     {
00852         /* Check if the requet is pending */
00853         if (Status == STATUS_PENDING)
00854         {
00855             /* Wait on the file object */
00856             Status = KeWaitForSingleObject(&FileObject->Event,
00857                                            Executive,
00858                                            KernelMode,
00859                                            FileObject->Flags & FO_ALERTABLE_IO,
00860                                            NULL);
00861             if (Status == STATUS_ALERTED)
00862             {
00863                 /* Abort the operation */
00864                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
00865             }
00866 
00867             /* Get the final status */
00868             Status = FileObject->FinalStatus;
00869         }
00870 
00871         /* Release the file lock */
00872         IopUnlockFileObject(FileObject);
00873     }
00874     else if (Status == STATUS_PENDING)
00875     {
00876         /* Wait on the local event and get the final status */
00877         KeWaitForSingleObject(&Event,
00878                               Executive,
00879                               KernelMode,
00880                               FALSE,
00881                               NULL);
00882         Status = IoStatusBlock.Status;
00883     }
00884 
00885     /* Return the status */
00886     return Status;
00887 }
00888 
00889 /* NATIVE SERVICES ***********************************************************/
00890 
00891 /*
00892  * @implemented
00893  */
00894 NTSTATUS
00895 NTAPI
00896 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
00897                       IN HANDLE Event OPTIONAL,
00898                       IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
00899                       IN PVOID UserApcContext OPTIONAL,
00900                       OUT PIO_STATUS_BLOCK IoStatusBlock,
00901                       IN ULONG IoControlCode,
00902                       IN PVOID InputBuffer,
00903                       IN ULONG InputBufferLength OPTIONAL,
00904                       OUT PVOID OutputBuffer,
00905                       IN ULONG OutputBufferLength OPTIONAL)
00906 {
00907     /* Call the Generic Function */
00908     return IopDeviceFsIoControl(DeviceHandle,
00909                                 Event,
00910                                 UserApcRoutine,
00911                                 UserApcContext,
00912                                 IoStatusBlock,
00913                                 IoControlCode,
00914                                 InputBuffer,
00915                                 InputBufferLength,
00916                                 OutputBuffer,
00917                                 OutputBufferLength,
00918                                 TRUE);
00919 }
00920 
00921 /*
00922  * @implemented
00923  */
00924 NTSTATUS
00925 NTAPI
00926 NtFsControlFile(IN HANDLE DeviceHandle,
00927                 IN HANDLE Event OPTIONAL,
00928                 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
00929                 IN PVOID UserApcContext OPTIONAL,
00930                 OUT PIO_STATUS_BLOCK IoStatusBlock,
00931                 IN ULONG IoControlCode,
00932                 IN PVOID InputBuffer,
00933                 IN ULONG InputBufferLength OPTIONAL,
00934                 OUT PVOID OutputBuffer,
00935                 IN ULONG OutputBufferLength OPTIONAL)
00936 {
00937     /* Call the Generic Function */
00938     return IopDeviceFsIoControl(DeviceHandle,
00939                                 Event,
00940                                 UserApcRoutine,
00941                                 UserApcContext,
00942                                 IoStatusBlock,
00943                                 IoControlCode,
00944                                 InputBuffer,
00945                                 InputBufferLength,
00946                                 OutputBuffer,
00947                                 OutputBufferLength,
00948                                 FALSE);
00949 }
00950 
00951 NTSTATUS
00952 NTAPI
00953 NtFlushBuffersFile(IN HANDLE FileHandle,
00954                    OUT PIO_STATUS_BLOCK IoStatusBlock)
00955 {
00956     PFILE_OBJECT FileObject;
00957     PIRP Irp;
00958     PIO_STACK_LOCATION StackPtr;
00959     NTSTATUS Status;
00960     PDEVICE_OBJECT DeviceObject;
00961     PKEVENT Event = NULL;
00962     BOOLEAN LocalEvent = FALSE;
00963     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
00964     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
00965     IO_STATUS_BLOCK KernelIosb;
00966     PAGED_CODE();
00967     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
00968 
00969     if (PreviousMode != KernelMode)
00970     {
00971         /* Protect probes */
00972         _SEH2_TRY
00973         {
00974             /* Probe the I/O Status block */
00975             ProbeForWriteIoStatusBlock(IoStatusBlock);
00976         }
00977         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00978         {
00979             /* Return the exception code */
00980             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00981         }
00982         _SEH2_END;
00983     }
00984 
00985     /* Get the File Object */
00986     Status = ObReferenceObjectByHandle(FileHandle,
00987                                        0,
00988                                        IoFileObjectType,
00989                                        PreviousMode,
00990                                        (PVOID*)&FileObject,
00991                                        &ObjectHandleInfo);
00992     if (!NT_SUCCESS(Status)) return Status;
00993 
00994     /*
00995      * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
00996      * granted. However, if this is a named pipe, make sure we don't ask for
00997      * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
00998      * access right!
00999      */
01000     if (!(ObjectHandleInfo.GrantedAccess &
01001          ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
01002          FILE_WRITE_DATA)))
01003     {
01004         /* We failed */
01005         ObDereferenceObject(FileObject);
01006         return STATUS_ACCESS_DENIED;
01007     }
01008 
01009     /* Check if we should use Sync IO or not */
01010     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
01011     {
01012         /* Lock it */
01013         IopLockFileObject(FileObject);
01014     }
01015     else
01016     {
01017         /* Use local event */
01018         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
01019         if (!Event)
01020         {
01021             /* We failed */
01022             ObDereferenceObject(FileObject);
01023             return STATUS_INSUFFICIENT_RESOURCES;
01024         }
01025         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
01026         LocalEvent = TRUE;
01027     }
01028 
01029     /* Get the Device Object */
01030     DeviceObject = IoGetRelatedDeviceObject(FileObject);
01031 
01032     /* Clear the event */
01033     KeClearEvent(&FileObject->Event);
01034 
01035     /* Allocate the IRP */
01036     Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
01037     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
01038 
01039     /* Set up the IRP */
01040     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
01041     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
01042     Irp->UserEvent = (LocalEvent) ? Event : NULL;
01043     Irp->RequestorMode = PreviousMode;
01044     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
01045     Irp->Tail.Overlay.OriginalFileObject = FileObject;
01046     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
01047 
01048     /* Set up Stack Data */
01049     StackPtr = IoGetNextIrpStackLocation(Irp);
01050     StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
01051     StackPtr->FileObject = FileObject;
01052 
01053     /* Call the Driver */
01054     Status = IopPerformSynchronousRequest(DeviceObject,
01055                                           Irp,
01056                                           FileObject,
01057                                           FALSE,
01058                                           PreviousMode,
01059                                           !LocalEvent,
01060                                           IopOtherTransfer);
01061 
01062     /* Check if this was async I/O */
01063     if (LocalEvent)
01064     {
01065         /* It was, finalize this request */
01066         Status = IopFinalizeAsynchronousIo(Status,
01067                                            Event,
01068                                            Irp,
01069                                            PreviousMode,
01070                                            &KernelIosb,
01071                                            IoStatusBlock);
01072     }
01073 
01074     /* Return the Status */
01075     return Status;
01076 }
01077 
01078 /*
01079  * @implemented
01080  */
01081 NTSTATUS
01082 NTAPI
01083 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
01084                             IN HANDLE EventHandle OPTIONAL,
01085                             IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
01086                             IN PVOID ApcContext OPTIONAL,
01087                             OUT PIO_STATUS_BLOCK IoStatusBlock,
01088                             OUT PVOID Buffer,
01089                             IN ULONG BufferSize,
01090                             IN ULONG CompletionFilter,
01091                             IN BOOLEAN WatchTree)
01092 {
01093     PIRP Irp;
01094     PKEVENT Event = NULL;
01095     PDEVICE_OBJECT DeviceObject;
01096     PFILE_OBJECT FileObject;
01097     PIO_STACK_LOCATION IoStack;
01098     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
01099     NTSTATUS Status;
01100     BOOLEAN LockedForSync = FALSE;
01101     PAGED_CODE();
01102     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
01103 
01104     /* Check if we're called from user mode */
01105     if (PreviousMode != KernelMode)
01106     {
01107         /* Enter SEH for probing */
01108         _SEH2_TRY
01109         {
01110             /* Probe the I/O STatus block */
01111             ProbeForWriteIoStatusBlock(IoStatusBlock);
01112 
01113             /* Probe the buffer */
01114             if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
01115         }
01116         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01117         {
01118             /* Return the exception code */
01119             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01120         }
01121         _SEH2_END;
01122 
01123         /* Check if CompletionFilter is valid */
01124         if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
01125         {
01126             return STATUS_INVALID_PARAMETER;
01127         }
01128     }
01129 
01130     /* Get File Object */
01131     Status = ObReferenceObjectByHandle(FileHandle,
01132                                        FILE_LIST_DIRECTORY,
01133                                        IoFileObjectType,
01134                                        PreviousMode,
01135                                        (PVOID*)&FileObject,
01136                                        NULL);
01137     if (!NT_SUCCESS(Status)) return Status;
01138 
01139     /* Check if we have an event handle */
01140     if (EventHandle)
01141     {
01142         /* Reference it */
01143         Status = ObReferenceObjectByHandle(EventHandle,
01144                                            EVENT_MODIFY_STATE,
01145                                            ExEventObjectType,
01146                                            PreviousMode,
01147                                            (PVOID *)&Event,
01148                                            NULL);
01149         if (Status != STATUS_SUCCESS)
01150         {
01151             ObDereferenceObject(FileObject);
01152             return Status;
01153         }
01154         KeClearEvent(Event);
01155     }
01156 
01157     /* Check if we should use Sync IO or not */
01158     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
01159     {
01160         /* Lock it */
01161         IopLockFileObject(FileObject);
01162         LockedForSync = TRUE;
01163     }
01164 
01165     /* Clear File Object event */
01166     KeClearEvent(&FileObject->Event);
01167 
01168     /* Get the device object */
01169     DeviceObject = IoGetRelatedDeviceObject(FileObject);
01170 
01171     /* Allocate the IRP */
01172     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
01173     if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
01174 
01175     /* Set up the IRP */
01176     Irp->RequestorMode = PreviousMode;
01177     Irp->UserIosb = IoStatusBlock;
01178     Irp->UserEvent = Event;
01179     Irp->UserBuffer = Buffer;
01180     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
01181     Irp->Tail.Overlay.OriginalFileObject = FileObject;
01182     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
01183     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
01184 
01185     /* Set up Stack Data */
01186     IoStack = IoGetNextIrpStackLocation(Irp);
01187     IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
01188     IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
01189     IoStack->FileObject = FileObject;
01190 
01191     /* Set parameters */
01192     IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
01193     IoStack->Parameters.NotifyDirectory.Length = BufferSize;
01194     if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
01195 
01196     /* Perform the call */
01197     return IopPerformSynchronousRequest(DeviceObject,
01198                                         Irp,
01199                                         FileObject,
01200                                         FALSE,
01201                                         PreviousMode,
01202                                         LockedForSync,
01203                                         IopOtherTransfer);
01204 }
01205 
01206 /*
01207  * @implemented
01208  */
01209 NTSTATUS
01210 NTAPI
01211 NtLockFile(IN HANDLE FileHandle,
01212            IN HANDLE EventHandle OPTIONAL,
01213            IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
01214            IN PVOID ApcContext OPTIONAL,
01215            OUT PIO_STATUS_BLOCK IoStatusBlock,
01216            IN PLARGE_INTEGER ByteOffset,
01217            IN PLARGE_INTEGER Length,
01218            IN ULONG  Key,
01219            IN BOOLEAN FailImmediately,
01220            IN BOOLEAN ExclusiveLock)
01221 {
01222     PFILE_OBJECT FileObject;
01223     PLARGE_INTEGER LocalLength = NULL;
01224     PIRP Irp;
01225     PIO_STACK_LOCATION StackPtr;
01226     PDEVICE_OBJECT DeviceObject;
01227     PKEVENT Event = NULL;
01228     BOOLEAN LockedForSync = FALSE;
01229     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
01230     LARGE_INTEGER CapturedByteOffset, CapturedLength;
01231     NTSTATUS Status;
01232     OBJECT_HANDLE_INFORMATION HandleInformation;
01233     PAGED_CODE();
01234     CapturedByteOffset.QuadPart = 0;
01235     CapturedLength.QuadPart = 0;
01236     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
01237 
01238     /* Get File Object */
01239     Status = ObReferenceObjectByHandle(FileHandle,
01240                                        0,
01241                                        IoFileObjectType,
01242                                        PreviousMode,
01243                                        (PVOID*)&FileObject,
01244                                        &HandleInformation);
01245     if (!NT_SUCCESS(Status)) return Status;
01246 
01247     /* Check if we're called from user mode */
01248     if (PreviousMode != KernelMode)
01249     {
01250         /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
01251         if (!(HandleInformation.GrantedAccess &
01252             (FILE_WRITE_DATA | FILE_READ_DATA)))
01253         {
01254             ObDereferenceObject(FileObject);
01255             return STATUS_ACCESS_DENIED;
01256         }
01257 
01258         /* Enter SEH for probing */
01259         _SEH2_TRY
01260         {
01261             /* Probe the I/O STatus block */
01262             ProbeForWriteIoStatusBlock(IoStatusBlock);
01263 
01264             /* Probe and capture the large integers */
01265             CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
01266             CapturedLength = ProbeForReadLargeInteger(Length);
01267         }
01268         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01269         {
01270             /* Dereference the object and return exception code */
01271             ObDereferenceObject(FileObject);
01272             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01273         }
01274         _SEH2_END;
01275     }
01276     else
01277     {
01278         /* Otherwise, capture them directly */
01279         CapturedByteOffset = *ByteOffset;
01280         CapturedLength = *Length;
01281     }
01282 
01283     /* Check if we have an event handle */
01284     if (EventHandle)
01285     {
01286         /* Reference it */
01287         Status = ObReferenceObjectByHandle(EventHandle,
01288                                            EVENT_MODIFY_STATE,
01289                                            ExEventObjectType,
01290                                            PreviousMode,
01291                                            (PVOID *)&Event,
01292                                            NULL);
01293         if (Status != STATUS_SUCCESS) return Status;
01294         KeClearEvent(Event);
01295     }
01296 
01297     /* Get the device object */
01298     DeviceObject = IoGetRelatedDeviceObject(FileObject);
01299 
01300     /* Check if we should use Sync IO or not */
01301     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
01302     {
01303         /* Lock it */
01304         IopLockFileObject(FileObject);
01305         LockedForSync = TRUE;
01306     }
01307 
01308     /* Clear File Object event */
01309     KeClearEvent(&FileObject->Event);
01310     FileObject->LockOperation = TRUE;
01311 
01312     /* Allocate the IRP */
01313     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
01314     if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
01315 
01316     /* Set up the IRP */
01317     Irp->RequestorMode = PreviousMode;
01318     Irp->UserIosb = IoStatusBlock;
01319     Irp->UserEvent = Event;
01320     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
01321     Irp->Tail.Overlay.OriginalFileObject = FileObject;
01322     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
01323     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
01324 
01325     /* Set up Stack Data */
01326     StackPtr = IoGetNextIrpStackLocation(Irp);
01327     StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
01328     StackPtr->MinorFunction = IRP_MN_LOCK;
01329     StackPtr->FileObject = FileObject;
01330 
01331     /* Enter SEH */
01332     _SEH2_TRY
01333     {
01334         /* Allocate local buffer */
01335         LocalLength = ExAllocatePoolWithTag(NonPagedPool,
01336                                             sizeof(LARGE_INTEGER),
01337                                             TAG_LOCK);
01338 
01339         /* Set the length */
01340         *LocalLength = CapturedLength;
01341         Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
01342         StackPtr->Parameters.LockControl.Length = LocalLength;
01343     }
01344     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01345     {
01346         /* Allocating failed, clean up and return the exception code */
01347         IopCleanupAfterException(FileObject, Irp, Event, NULL);
01348         if (LocalLength) ExFreePool(LocalLength);
01349 
01350         /* Return the exception code */
01351         _SEH2_YIELD(return _SEH2_GetExceptionCode());
01352     }
01353     _SEH2_END;
01354 
01355     /* Set Parameters */
01356     StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
01357     StackPtr->Parameters.LockControl.Key = Key;
01358 
01359     /* Set Flags */
01360     if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
01361     if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
01362 
01363     /* Perform the call */
01364     return IopPerformSynchronousRequest(DeviceObject,
01365                                         Irp,
01366                                         FileObject,
01367                                         FALSE,
01368                                         PreviousMode,
01369                                         LockedForSync,
01370                                         IopOtherTransfer);
01371 }
01372 
01373 /*
01374  * @implemented
01375  */
01376 NTSTATUS
01377 NTAPI
01378 NtQueryDirectoryFile(IN HANDLE FileHandle,
01379                      IN HANDLE EventHandle OPTIONAL,
01380                      IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
01381                      IN PVOID ApcContext OPTIONAL,
01382                      OUT PIO_STATUS_BLOCK IoStatusBlock,
01383                      OUT PVOID FileInformation,
01384                      IN ULONG Length,
01385                      IN FILE_INFORMATION_CLASS FileInformationClass,
01386                      IN BOOLEAN ReturnSingleEntry,
01387                      IN PUNICODE_STRING FileName OPTIONAL,
01388                      IN BOOLEAN RestartScan)
01389 {
01390     PIRP Irp;
01391     PDEVICE_OBJECT DeviceObject;
01392     PFILE_OBJECT FileObject;
01393     PIO_STACK_LOCATION StackPtr;
01394     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
01395     NTSTATUS Status;
01396     BOOLEAN LockedForSynch = FALSE;
01397     PKEVENT Event = NULL;
01398     PVOID AuxBuffer = NULL;
01399     PMDL Mdl;
01400     UNICODE_STRING CapturedFileName;
01401     PUNICODE_STRING SearchPattern;
01402     PAGED_CODE();
01403     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
01404 
01405     /* Check if we came from user mode */
01406     if (PreviousMode != KernelMode)
01407     {
01408         /* Enter SEH for probing */
01409         _SEH2_TRY
01410         {
01411             /* Probe the I/O Status Block */
01412             ProbeForWriteIoStatusBlock(IoStatusBlock);
01413 
01414             /* Probe the file information */
01415             ProbeForWrite(FileInformation, Length, sizeof(ULONG));
01416 
01417             /* Check if we have a file name */
01418             if (FileName)
01419             {
01420                 /* Capture it */
01421                 CapturedFileName = ProbeForReadUnicodeString(FileName);
01422                 if (CapturedFileName.Length)
01423                 {
01424                     /* Probe its buffer */
01425                     ProbeForRead(CapturedFileName.Buffer,
01426                                  CapturedFileName.Length,
01427                                  1);
01428                 }
01429 
01430                 /* Allocate the auxiliary buffer */
01431                 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
01432                                                   CapturedFileName.Length +
01433                                                   sizeof(UNICODE_STRING),
01434                                                   TAG_SYSB);
01435                 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
01436                                       sizeof(UNICODE_STRING)),
01437                               CapturedFileName.Buffer,
01438                               CapturedFileName.Length);
01439 
01440                 /* Setup the search pattern */
01441                 SearchPattern = (PUNICODE_STRING)AuxBuffer;
01442                 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
01443                                                  sizeof(UNICODE_STRING));
01444                 SearchPattern->Length = CapturedFileName.Length;
01445                 SearchPattern->MaximumLength = CapturedFileName.Length;
01446             }
01447         }
01448         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01449         {
01450             /* Free buffer and return the exception code */
01451             if (AuxBuffer) ExFreePool(AuxBuffer);
01452             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01453         }
01454         _SEH2_END;
01455     }
01456 
01457     /* Get File Object */
01458     Status = ObReferenceObjectByHandle(FileHandle,
01459                                        FILE_LIST_DIRECTORY,
01460                                        IoFileObjectType,
01461                                        PreviousMode,
01462                                        (PVOID *)&FileObject,
01463                                        NULL);
01464     if (!NT_SUCCESS(Status))
01465     {
01466         /* Fail */
01467         if (AuxBuffer) ExFreePool(AuxBuffer);
01468         return Status;
01469     }
01470 
01471     /* Check if we have an even handle */
01472     if (EventHandle)
01473     {
01474         /* Get its pointer */
01475         Status = ObReferenceObjectByHandle(EventHandle,
01476                                            EVENT_MODIFY_STATE,
01477                                            ExEventObjectType,
01478                                            PreviousMode,
01479                                            (PVOID *)&Event,
01480                                            NULL);
01481         if (!NT_SUCCESS(Status))
01482         {
01483             /* Fail */
01484             ObDereferenceObject(FileObject);
01485             return Status;
01486         }
01487 
01488         /* Clear it */
01489         KeClearEvent(Event);
01490     }
01491 
01492     /* Check if this is a file that was opened for Synch I/O */
01493     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
01494     {
01495         /* Lock it */
01496         IopLockFileObject(FileObject);
01497 
01498         /* Remember to unlock later */
01499         LockedForSynch = TRUE;
01500     }
01501 
01502     /* Get the device object */
01503     DeviceObject = IoGetRelatedDeviceObject(FileObject);
01504 
01505     /* Clear the File Object's event */
01506     KeClearEvent(&FileObject->Event);
01507 
01508     /* Allocate the IRP */
01509     Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
01510     if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
01511 
01512     /* Set up the IRP */
01513     Irp->RequestorMode = PreviousMode;
01514     Irp->UserIosb = IoStatusBlock;
01515     Irp->UserEvent = Event;
01516     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
01517     Irp->Tail.Overlay.OriginalFileObject = FileObject;
01518     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
01519     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
01520     Irp->MdlAddress = NULL;
01521     Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
01522     Irp->AssociatedIrp.SystemBuffer = NULL;
01523 
01524     /* Check if this is buffered I/O */
01525     if (DeviceObject->Flags & DO_BUFFERED_IO)
01526     {
01527         /* Enter SEH */
01528         _SEH2_TRY
01529         {
01530             /* Allocate a buffer */
01531             Irp->AssociatedIrp.SystemBuffer =
01532                 ExAllocatePoolWithTag(NonPagedPool,
01533                                       Length,
01534                                       TAG_SYSB);
01535         }
01536         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01537         {
01538             /* Allocating failed, clean up and return the exception code */
01539             IopCleanupAfterException(FileObject, Irp, Event, NULL);
01540             if (AuxBuffer) ExFreePool(AuxBuffer);
01541 
01542             /* Return the exception code */
01543             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01544         }
01545         _SEH2_END;
01546 
01547         /* Set the buffer and flags */
01548         Irp->UserBuffer = FileInformation;
01549         Irp->Flags = (IRP_BUFFERED_IO |
01550                       IRP_DEALLOCATE_BUFFER |
01551                       IRP_INPUT_OPERATION);
01552     }
01553     else if (DeviceObject->Flags & DO_DIRECT_IO)
01554     {
01555         _SEH2_TRY
01556         {
01557             /* Allocate an MDL */
01558             Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
01559             if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
01560             MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
01561         }
01562         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01563         {
01564             /* Allocating failed, clean up and return the exception code */
01565             IopCleanupAfterException(FileObject, Irp, Event, NULL);
01566             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01567         }
01568         _SEH2_END;
01569     }
01570     else
01571     {
01572         /* No allocation flags, and use the buffer directly */
01573         Irp->UserBuffer = FileInformation;
01574     }
01575 
01576     /* Set up Stack Data */
01577     StackPtr = IoGetNextIrpStackLocation(Irp);
01578     StackPtr->FileObject = FileObject;
01579     StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
01580     StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
01581 
01582     /* Set Parameters */
01583     StackPtr->Parameters.QueryDirectory.FileInformationClass =
01584         FileInformationClass;
01585     StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
01586     StackPtr->Parameters.QueryDirectory.FileIndex = 0;
01587     StackPtr->Parameters.QueryDirectory.Length = Length;
01588     StackPtr->Flags = 0;
01589     if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
01590     if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
01591 
01592     /* Set deferred I/O */
01593     Irp->Flags |= IRP_DEFER_IO_COMPLETION;
01594 
01595     /* Perform the call */
01596     return IopPerformSynchronousRequest(DeviceObject,
01597                                         Irp,
01598                                         FileObject,
01599                                         TRUE,
01600                                         PreviousMode,
01601                                         LockedForSynch,
01602                                         IopOtherTransfer);
01603 }
01604 
01605 /*
01606  * @unimplemented
01607  */
01608 NTSTATUS
01609 NTAPI
01610 NtQueryEaFile(IN HANDLE FileHandle,
01611               OUT PIO_STATUS_BLOCK IoStatusBlock,
01612               OUT PVOID Buffer,
01613               IN ULONG Length,
01614               IN BOOLEAN ReturnSingleEntry,
01615               IN PVOID EaList OPTIONAL,
01616               IN ULONG EaListLength,
01617               IN PULONG EaIndex OPTIONAL,
01618               IN BOOLEAN RestartScan)
01619 {
01620     UNIMPLEMENTED;
01621     return STATUS_NOT_IMPLEMENTED;
01622 }
01623 
01624 /*
01625  * @implemented
01626  */
01627 NTSTATUS
01628 NTAPI
01629 NtQueryInformationFile(IN HANDLE FileHandle,
01630                        OUT PIO_STATUS_BLOCK IoStatusBlock,
01631                        IN PVOID FileInformation,
01632                        IN ULONG Length,
01633                        IN FILE_INFORMATION_CLASS FileInformationClass)
01634 {
01635     OBJECT_HANDLE_INFORMATION HandleInformation;
01636     PFILE_OBJECT FileObject;
01637     NTSTATUS Status;
01638     PIRP Irp;
01639     PDEVICE_OBJECT DeviceObject;
01640     PIO_STACK_LOCATION StackPtr;
01641     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
01642     PKEVENT Event = NULL;
01643     BOOLEAN LocalEvent = FALSE;
01644     PKNORMAL_ROUTINE NormalRoutine;
01645     PVOID NormalContext;
01646     KIRQL OldIrql;
01647     IO_STATUS_BLOCK KernelIosb;
01648     PAGED_CODE();
01649     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
01650 
01651     /* Check if we're called from user mode */
01652     if (PreviousMode != KernelMode)
01653     {
01654         /* Validate the information class */
01655         if ((FileInformationClass >= FileMaximumInformation) ||
01656             !(IopQueryOperationLength[FileInformationClass]))
01657         {
01658             /* Invalid class */
01659             return STATUS_INVALID_INFO_CLASS;
01660         }
01661 
01662         /* Validate the length */
01663         if (Length < IopQueryOperationLength[FileInformationClass])
01664         {
01665             /* Invalid length */
01666             return STATUS_INFO_LENGTH_MISMATCH;
01667         }
01668 
01669         /* Enter SEH for probing */
01670         _SEH2_TRY
01671         {
01672             /* Probe the I/O Status block */
01673             ProbeForWriteIoStatusBlock(IoStatusBlock);
01674 
01675             /* Probe the information */
01676             ProbeForWrite(FileInformation, Length, sizeof(ULONG));
01677         }
01678         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01679         {
01680             /* Return the exception code */
01681             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01682         }
01683         _SEH2_END;
01684     }
01685     else
01686     {
01687         /* Validate the information class */
01688         if ((FileInformationClass >= FileMaximumInformation) ||
01689             !(IopQueryOperationLength[FileInformationClass]))
01690         {
01691             /* Invalid class */
01692             return STATUS_INVALID_INFO_CLASS;
01693         }
01694 
01695         /* Validate the length */
01696         if (Length < IopQueryOperationLength[FileInformationClass])
01697         {
01698             /* Invalid length */
01699             return STATUS_INFO_LENGTH_MISMATCH;
01700         }
01701     }
01702 
01703     /* Reference the Handle */
01704     Status = ObReferenceObjectByHandle(FileHandle,
01705                                        IopQueryOperationAccess
01706                                        [FileInformationClass],
01707                                        IoFileObjectType,
01708                                        PreviousMode,
01709                                        (PVOID *)&FileObject,
01710                                        &HandleInformation);
01711     if (!NT_SUCCESS(Status)) return Status;
01712 
01713     /* Check if this is a direct open or not */
01714     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
01715     {
01716         /* Get the device object */
01717         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
01718     }
01719     else
01720     {
01721         /* Get the device object */
01722         DeviceObject = IoGetRelatedDeviceObject(FileObject);
01723     }
01724 
01725     /* Check if this is a file that was opened for Synch I/O */
01726     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
01727     {
01728         /* Lock it */
01729         IopLockFileObject(FileObject);
01730 
01731         /* Check if the caller just wants the position */
01732         if (FileInformationClass == FilePositionInformation)
01733         {
01734             /* Protect write in SEH */
01735             _SEH2_TRY
01736             {
01737                 /* Write the offset */
01738                 ((PFILE_POSITION_INFORMATION)FileInformation)->
01739                     CurrentByteOffset = FileObject->CurrentByteOffset;
01740 
01741                 /* Fill out the I/O Status Block */
01742                 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
01743                 Status = IoStatusBlock->Status = STATUS_SUCCESS;
01744             }
01745             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01746             {
01747                 /* Get the exception code */
01748                 Status = _SEH2_GetExceptionCode();
01749             }
01750             _SEH2_END;
01751 
01752             /* Release the file lock, dereference the file and return */
01753             IopUnlockFileObject(FileObject);
01754             ObDereferenceObject(FileObject);
01755             return Status;
01756         }
01757     }
01758     else
01759     {
01760         /* Use local event */
01761         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
01762         if (!Event)
01763         {
01764             ObDereferenceObject(FileObject);
01765             return STATUS_INSUFFICIENT_RESOURCES;
01766         }
01767         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
01768         LocalEvent = TRUE;
01769     }
01770 
01771     /* Clear the File Object event */
01772     KeClearEvent(&FileObject->Event);
01773 
01774     /* Allocate the IRP */
01775     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
01776     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
01777 
01778     /* Set the IRP */
01779     Irp->Tail.Overlay.OriginalFileObject = FileObject;
01780     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
01781     Irp->RequestorMode = PreviousMode;
01782     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
01783     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
01784     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
01785     Irp->UserEvent = (LocalEvent) ? Event : NULL;
01786     Irp->AssociatedIrp.SystemBuffer = NULL;
01787     Irp->MdlAddress = NULL;
01788     Irp->UserBuffer = FileInformation;
01789 
01790     /* Set the Stack Data */
01791     StackPtr = IoGetNextIrpStackLocation(Irp);
01792     StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
01793     StackPtr->FileObject = FileObject;
01794 
01795     /* Enter SEH */
01796     _SEH2_TRY
01797     {
01798         /* Allocate a buffer */
01799         Irp->AssociatedIrp.SystemBuffer =
01800             ExAllocatePoolWithTag(NonPagedPool,
01801                                   Length,
01802                                   TAG_SYSB);
01803     }
01804     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01805     {
01806         /* Allocating failed, clean up and return the exception code */
01807         IopCleanupAfterException(FileObject, Irp, NULL, Event);
01808         _SEH2_YIELD(return _SEH2_GetExceptionCode());
01809     }
01810     _SEH2_END;
01811 
01812     /* Set the flags */
01813     Irp->Flags |= (IRP_BUFFERED_IO |
01814                    IRP_DEALLOCATE_BUFFER |
01815                    IRP_INPUT_OPERATION |
01816                    IRP_DEFER_IO_COMPLETION);
01817 
01818     /* Set the Parameters */
01819     StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
01820     StackPtr->Parameters.QueryFile.Length = Length;
01821 
01822     /* Queue the IRP */
01823     IopQueueIrpToThread(Irp);
01824 
01825     /* Update operation counts */
01826     IopUpdateOperationCount(IopOtherTransfer);
01827 
01828     /* Call the Driver */
01829     Status = IoCallDriver(DeviceObject, Irp);
01830     if (Status == STATUS_PENDING)
01831     {
01832         /* Check if this was async I/O */
01833         if (LocalEvent)
01834         {
01835             /* Then to a non-alertable wait */
01836             Status = KeWaitForSingleObject(Event,
01837                                            Executive,
01838                                            PreviousMode,
01839                                            FALSE,
01840                                            NULL);
01841             if (Status == STATUS_USER_APC)
01842             {
01843                 /* Abort the request */
01844                 IopAbortInterruptedIrp(Event, Irp);
01845             }
01846 
01847             /* Set the final status */
01848             Status = KernelIosb.Status;
01849 
01850             /* Enter SEH to write the IOSB back */
01851             _SEH2_TRY
01852             {
01853                 /* Write it back to the caller */
01854                 *IoStatusBlock = KernelIosb;
01855             }
01856             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01857             {
01858                 /* Get the exception code */
01859                 Status = _SEH2_GetExceptionCode();
01860             }
01861             _SEH2_END;
01862 
01863             /* Free the event */
01864             ExFreePool(Event);
01865         }
01866         else
01867         {
01868             /* Wait for the IRP */
01869             Status = KeWaitForSingleObject(&FileObject->Event,
01870                                            Executive,
01871                                            PreviousMode,
01872                                            FileObject->Flags & FO_ALERTABLE_IO,
01873                                            NULL);
01874             if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
01875             {
01876                 /* Abort the request */
01877                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
01878             }
01879 
01880             /* Set the final status */
01881             Status = FileObject->FinalStatus;
01882 
01883             /* Release the file lock */
01884             IopUnlockFileObject(FileObject);
01885         }
01886     }
01887     else
01888     {
01889         /* Free the event if we had one */
01890         if (LocalEvent)
01891         {
01892             /* Clear it in the IRP for completion */
01893             Irp->UserEvent = NULL;
01894             ExFreePoolWithTag(Event, TAG_IO);
01895         }
01896 
01897         /* Set the caller IOSB */
01898         Irp->UserIosb = IoStatusBlock;
01899 
01900         /* The IRP wasn't completed, complete it ourselves */
01901         KeRaiseIrql(APC_LEVEL, &OldIrql);
01902         IopCompleteRequest(&Irp->Tail.Apc,
01903                            &NormalRoutine,
01904                            &NormalContext,
01905                            (PVOID*)&FileObject,
01906                            &NormalContext);
01907         KeLowerIrql(OldIrql);
01908 
01909         /* Release the file object if we had locked it*/
01910         if (!LocalEvent) IopUnlockFileObject(FileObject);
01911     }
01912 
01913     /* Return the Status */
01914     return Status;
01915 }
01916 
01917 /*
01918  * @unimplemented
01919  */
01920 NTSTATUS
01921 NTAPI
01922 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
01923                             OUT PIO_STATUS_BLOCK IoStatusBlock,
01924                             OUT PVOID Buffer,
01925                             IN ULONG Length,
01926                             IN BOOLEAN ReturnSingleEntry,
01927                             IN PVOID SidList OPTIONAL,
01928                             IN ULONG SidListLength,
01929                             IN PSID StartSid OPTIONAL,
01930                             IN BOOLEAN RestartScan)
01931 {
01932     UNIMPLEMENTED;
01933     return STATUS_NOT_IMPLEMENTED;
01934 }
01935 
01936 /*
01937  * @implemented
01938  */
01939 NTSTATUS
01940 NTAPI
01941 NtReadFile(IN HANDLE FileHandle,
01942            IN HANDLE Event OPTIONAL,
01943            IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
01944            IN PVOID ApcContext OPTIONAL,
01945            OUT PIO_STATUS_BLOCK IoStatusBlock,
01946            OUT PVOID Buffer,
01947            IN ULONG Length,
01948            IN PLARGE_INTEGER ByteOffset OPTIONAL,
01949            IN PULONG Key OPTIONAL)
01950 {
01951     NTSTATUS Status;
01952     PFILE_OBJECT FileObject;
01953     PIRP Irp;
01954     PDEVICE_OBJECT DeviceObject;
01955     PIO_STACK_LOCATION StackPtr;
01956     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
01957     PKEVENT EventObject = NULL;
01958     LARGE_INTEGER CapturedByteOffset;
01959     ULONG CapturedKey = 0;
01960     BOOLEAN Synchronous = FALSE;
01961     PMDL Mdl;
01962     PAGED_CODE();
01963     CapturedByteOffset.QuadPart = 0;
01964     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
01965 
01966     /* Validate User-Mode Buffers */
01967     if (PreviousMode != KernelMode)
01968     {
01969         _SEH2_TRY
01970         {
01971             /* Probe the status block */
01972             ProbeForWriteIoStatusBlock(IoStatusBlock);
01973 
01974             /* Probe the read buffer */
01975             ProbeForWrite(Buffer, Length, 1);
01976 
01977             /* Check if we got a byte offset */
01978             if (ByteOffset)
01979             {
01980                 /* Capture and probe it */
01981                 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
01982             }
01983 
01984             /* Capture and probe the key */
01985             if (Key) CapturedKey = ProbeForReadUlong(Key);
01986         }
01987         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01988         {
01989             /* Return the exception code */
01990             _SEH2_YIELD(return _SEH2_GetExceptionCode());
01991         }
01992         _SEH2_END;
01993     }
01994     else
01995     {
01996         /* Kernel mode: capture directly */
01997         if (ByteOffset) CapturedByteOffset = *ByteOffset;
01998         if (Key) CapturedKey = *Key;
01999     }
02000 
02001     /* Get File Object */
02002     Status = ObReferenceObjectByHandle(FileHandle,
02003                                        FILE_READ_DATA,
02004                                        IoFileObjectType,
02005                                        PreviousMode,
02006                                        (PVOID*)&FileObject,
02007                                        NULL);
02008     if (!NT_SUCCESS(Status)) return Status;
02009 
02010     /* Check for event */
02011     if (Event)
02012     {
02013         /* Reference it */
02014         Status = ObReferenceObjectByHandle(Event,
02015                                            EVENT_MODIFY_STATE,
02016                                            ExEventObjectType,
02017                                            PreviousMode,
02018                                            (PVOID*)&EventObject,
02019                                            NULL);
02020         if (!NT_SUCCESS(Status))
02021         {
02022             /* Fail */
02023             ObDereferenceObject(FileObject);
02024             return Status;
02025         }
02026 
02027         /* Otherwise reset the event */
02028         KeClearEvent(EventObject);
02029     }
02030 
02031     /* Check if we should use Sync IO or not */
02032     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
02033     {
02034         /* Lock the file object */
02035         IopLockFileObject(FileObject);
02036 
02037         /* Check if we don't have a byte offset avilable */
02038         if (!(ByteOffset) ||
02039             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
02040              (CapturedByteOffset.u.HighPart == -1)))
02041         {
02042             /* Use the Current Byte Offset instead */
02043             CapturedByteOffset = FileObject->CurrentByteOffset;
02044         }
02045 
02046         /* Remember we are sync */
02047         Synchronous = TRUE;
02048     }
02049     else if (!(ByteOffset) &&
02050              !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
02051     {
02052         /* Otherwise, this was async I/O without a byte offset, so fail */
02053         if (EventObject) ObDereferenceObject(EventObject);
02054         ObDereferenceObject(FileObject);
02055         return STATUS_INVALID_PARAMETER;
02056     }
02057 
02058     /* Get the device object */
02059     DeviceObject = IoGetRelatedDeviceObject(FileObject);
02060 
02061     /* Clear the File Object's event */
02062     KeClearEvent(&FileObject->Event);
02063 
02064     /* Allocate the IRP */
02065     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
02066     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
02067 
02068     /* Set the IRP */
02069     Irp->Tail.Overlay.OriginalFileObject = FileObject;
02070     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
02071     Irp->RequestorMode = PreviousMode;
02072     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
02073     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
02074     Irp->UserIosb = IoStatusBlock;
02075     Irp->UserEvent = EventObject;
02076     Irp->PendingReturned = FALSE;
02077     Irp->Cancel = FALSE;
02078     Irp->CancelRoutine = NULL;
02079     Irp->AssociatedIrp.SystemBuffer = NULL;
02080     Irp->MdlAddress = NULL;
02081 
02082     /* Set the Stack Data */
02083     StackPtr = IoGetNextIrpStackLocation(Irp);
02084     StackPtr->MajorFunction = IRP_MJ_READ;
02085     StackPtr->FileObject = FileObject;
02086     StackPtr->Parameters.Read.Key = CapturedKey;
02087     StackPtr->Parameters.Read.Length = Length;
02088     StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
02089 
02090     /* Check if this is buffered I/O */
02091     if (DeviceObject->Flags & DO_BUFFERED_IO)
02092     {
02093         /* Check if we have a buffer length */
02094         if (Length)
02095         {
02096             /* Enter SEH */
02097             _SEH2_TRY
02098             {
02099                 /* Allocate a buffer */
02100                 Irp->AssociatedIrp.SystemBuffer =
02101                     ExAllocatePoolWithTag(NonPagedPool,
02102                                           Length,
02103                                           TAG_SYSB);
02104             }
02105             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02106             {
02107                 /* Allocating failed, clean up and return the exception code */
02108                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
02109                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
02110             }
02111             _SEH2_END;
02112 
02113             /* Set the buffer and flags */
02114             Irp->UserBuffer = Buffer;
02115             Irp->Flags = (IRP_BUFFERED_IO |
02116                           IRP_DEALLOCATE_BUFFER |
02117                           IRP_INPUT_OPERATION);
02118         }
02119         else
02120         {
02121             /* Not reading anything */
02122             Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
02123         }
02124     }
02125     else if (DeviceObject->Flags & DO_DIRECT_IO)
02126     {
02127         /* Check if we have a buffer length */
02128         if (Length)
02129         {
02130             _SEH2_TRY
02131             {
02132                 /* Allocate an MDL */
02133                 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
02134                 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
02135             }
02136             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02137             {
02138                 /* Allocating failed, clean up and return the exception code */
02139                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
02140                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
02141             }
02142             _SEH2_END;
02143 
02144         }
02145 
02146         /* No allocation flags */
02147         Irp->Flags = 0;
02148     }
02149     else
02150     {
02151         /* No allocation flags, and use the buffer directly */
02152         Irp->Flags = 0;
02153         Irp->UserBuffer = Buffer;
02154     }
02155 
02156     /* Now set the deferred read flags */
02157     Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
02158 #if 0
02159     /* FIXME: VFAT SUCKS */
02160     if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
02161 #endif
02162 
02163     /* Perform the call */
02164     return IopPerformSynchronousRequest(DeviceObject,
02165                                         Irp,
02166                                         FileObject,
02167                                         TRUE,
02168                                         PreviousMode,
02169                                         Synchronous,
02170                                         IopReadTransfer);
02171 }
02172 
02173 /*
02174  * @unimplemented
02175  */
02176 NTSTATUS
02177 NTAPI
02178 NtReadFileScatter(IN HANDLE FileHandle,
02179                   IN HANDLE Event OPTIONAL,
02180                   IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
02181                   IN PVOID UserApcContext OPTIONAL,
02182                   OUT PIO_STATUS_BLOCK UserIoStatusBlock,
02183                   IN FILE_SEGMENT_ELEMENT BufferDescription [],
02184                   IN ULONG BufferLength,
02185                   IN PLARGE_INTEGER  ByteOffset,
02186                   IN PULONG Key OPTIONAL)
02187 {
02188     UNIMPLEMENTED;
02189     return STATUS_NOT_IMPLEMENTED;
02190 }
02191 
02192 /*
02193  * @unimplemented
02194  */
02195 NTSTATUS
02196 NTAPI
02197 NtSetEaFile(IN HANDLE FileHandle,
02198             IN PIO_STATUS_BLOCK IoStatusBlock,
02199             IN PVOID EaBuffer,
02200             IN ULONG EaBufferSize)
02201 {
02202     UNIMPLEMENTED;
02203     return STATUS_NOT_IMPLEMENTED;
02204 }
02205 
02206 /*
02207  * @implemented
02208  */
02209 NTSTATUS
02210 NTAPI
02211 NtSetInformationFile(IN HANDLE FileHandle,
02212                      OUT PIO_STATUS_BLOCK IoStatusBlock,
02213                      IN PVOID FileInformation,
02214                      IN ULONG Length,
02215                      IN FILE_INFORMATION_CLASS FileInformationClass)
02216 {
02217     PFILE_OBJECT FileObject;
02218     NTSTATUS Status;
02219     PIRP Irp;
02220     PDEVICE_OBJECT DeviceObject;
02221     PIO_STACK_LOCATION StackPtr;
02222     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
02223     PKEVENT Event = NULL;
02224     BOOLEAN LocalEvent = FALSE;
02225     PKNORMAL_ROUTINE NormalRoutine;
02226     PVOID NormalContext;
02227     KIRQL OldIrql;
02228     IO_STATUS_BLOCK KernelIosb;
02229     PVOID Queue;
02230     PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
02231     PIO_COMPLETION_CONTEXT Context;
02232     PAGED_CODE();
02233     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
02234 
02235     /* Check if we're called from user mode */
02236     if (PreviousMode != KernelMode)
02237     {
02238         /* Validate the information class */
02239         if ((FileInformationClass >= FileMaximumInformation) ||
02240             !(IopSetOperationLength[FileInformationClass]))
02241         {
02242             /* Invalid class */
02243             return STATUS_INVALID_INFO_CLASS;
02244         }
02245 
02246         /* Validate the length */
02247         if (Length < IopSetOperationLength[FileInformationClass])
02248         {
02249             /* Invalid length */
02250             return STATUS_INFO_LENGTH_MISMATCH;
02251         }
02252 
02253         /* Enter SEH for probing */
02254         _SEH2_TRY
02255         {
02256             /* Probe the I/O Status block */
02257             ProbeForWriteIoStatusBlock(IoStatusBlock);
02258 
02259             /* Probe the information */
02260             ProbeForRead(FileInformation,
02261                          Length,
02262                          (Length == sizeof(BOOLEAN)) ?
02263                          sizeof(BOOLEAN) : sizeof(ULONG));
02264         }
02265         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02266         {
02267             /* Return the exception code */
02268             _SEH2_YIELD(return _SEH2_GetExceptionCode());
02269         }
02270         _SEH2_END;
02271     }
02272     else
02273     {
02274         /* Validate the information class */
02275         if ((FileInformationClass >= FileMaximumInformation) ||
02276             !(IopSetOperationLength[FileInformationClass]))
02277         {
02278             /* Invalid class */
02279             return STATUS_INVALID_INFO_CLASS;
02280         }
02281 
02282         /* Validate the length */
02283         if (Length < IopSetOperationLength[FileInformationClass])
02284         {
02285             /* Invalid length */
02286             return STATUS_INFO_LENGTH_MISMATCH;
02287         }
02288     }
02289 
02290     /* Reference the Handle */
02291     Status = ObReferenceObjectByHandle(FileHandle,
02292                                        IopSetOperationAccess
02293                                        [FileInformationClass],
02294                                        IoFileObjectType,
02295                                        PreviousMode,
02296                                        (PVOID *)&FileObject,
02297                                        NULL);
02298     if (!NT_SUCCESS(Status)) return Status;
02299 
02300     /* Check if this is a direct open or not */
02301     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
02302     {
02303         /* Get the device object */
02304         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
02305     }
02306     else
02307     {
02308         /* Get the device object */
02309         DeviceObject = IoGetRelatedDeviceObject(FileObject);
02310     }
02311 
02312     /* Check if this is a file that was opened for Synch I/O */
02313     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
02314     {
02315         /* Lock it */
02316         IopLockFileObject(FileObject);
02317 
02318         /* Check if the caller just wants the position */
02319         if (FileInformationClass == FilePositionInformation)
02320         {
02321             /* Protect write in SEH */
02322             _SEH2_TRY
02323             {
02324                 /* Write the offset */
02325                 FileObject->CurrentByteOffset =
02326                     ((PFILE_POSITION_INFORMATION)FileInformation)->
02327                     CurrentByteOffset;
02328 
02329                 /* Fill out the I/O Status Block */
02330                 IoStatusBlock->Information = 0;
02331                 Status = IoStatusBlock->Status = STATUS_SUCCESS;
02332             }
02333             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02334             {
02335                 /* Get the exception code */
02336                 Status = _SEH2_GetExceptionCode();
02337             }
02338             _SEH2_END;
02339 
02340             /* Update transfer count */
02341             IopUpdateTransferCount(IopOtherTransfer, Length);
02342 
02343             /* Release the file lock, dereference the file and return */
02344             IopUnlockFileObject(FileObject);
02345             ObDereferenceObject(FileObject);
02346             return Status;
02347         }
02348     }
02349     else
02350     {
02351         /* Use local event */
02352         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
02353         if (!Event)
02354         {
02355             ObDereferenceObject(FileObject);
02356             return STATUS_INSUFFICIENT_RESOURCES;
02357         }
02358 
02359         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
02360         LocalEvent = TRUE;
02361     }
02362 
02363     /* Clear the File Object event */
02364     KeClearEvent(&FileObject->Event);
02365 
02366     /* Allocate the IRP */
02367     Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
02368     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
02369 
02370     /* Set the IRP */
02371     Irp->Tail.Overlay.OriginalFileObject = FileObject;
02372     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
02373     Irp->RequestorMode = PreviousMode;
02374     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
02375     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
02376     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
02377     Irp->UserEvent = (LocalEvent) ? Event : NULL;
02378     Irp->AssociatedIrp.SystemBuffer = NULL;
02379     Irp->MdlAddress = NULL;
02380     Irp->UserBuffer = FileInformation;
02381 
02382     /* Set the Stack Data */
02383     StackPtr = IoGetNextIrpStackLocation(Irp);
02384     StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
02385     StackPtr->FileObject = FileObject;
02386 
02387     /* Enter SEH */
02388     _SEH2_TRY
02389     {
02390         /* Allocate a buffer */
02391         Irp->AssociatedIrp.SystemBuffer =
02392             ExAllocatePoolWithTag(NonPagedPool,
02393                                   Length,
02394                                   TAG_SYSB);
02395 
02396         /* Copy the data into it */
02397         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
02398                       FileInformation,
02399                       Length);
02400     }
02401     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02402     {
02403         /* Allocating failed, clean up and return the exception code */
02404         IopCleanupAfterException(FileObject, Irp, NULL, Event);
02405         _SEH2_YIELD(return _SEH2_GetExceptionCode());
02406     }
02407     _SEH2_END;
02408 
02409     /* Set the flags */
02410     Irp->Flags |= (IRP_BUFFERED_IO |
02411                    IRP_DEALLOCATE_BUFFER |
02412                    IRP_DEFER_IO_COMPLETION);
02413 
02414     /* Set the Parameters */
02415     StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
02416     StackPtr->Parameters.SetFile.Length = Length;
02417 
02418     /* Queue the IRP */
02419     IopQueueIrpToThread(Irp);
02420 
02421     /* Update operation counts */
02422     IopUpdateOperationCount(IopOtherTransfer);
02423 
02424     /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
02425     /* Handle IO Completion Port quickly */
02426     if (FileInformationClass == FileCompletionInformation)
02427     {
02428         /* Check if the file object already has a completion port */
02429         if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
02430             (FileObject->CompletionContext))
02431         {
02432             /* Fail */
02433             Status = STATUS_INVALID_PARAMETER;
02434         }
02435         else
02436         {
02437             /* Reference the Port */
02438             CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
02439             Status = ObReferenceObjectByHandle(CompletionInfo->Port,
02440                                                IO_COMPLETION_MODIFY_STATE,
02441                                                IoCompletionType,
02442                                                PreviousMode,
02443                                                (PVOID*)&Queue,
02444                                                NULL);
02445             if (NT_SUCCESS(Status))
02446             {
02447                 /* Allocate the Context */
02448                 Context = ExAllocatePoolWithTag(PagedPool,
02449                                                 sizeof(IO_COMPLETION_CONTEXT),
02450                                                 IOC_TAG);
02451                 if (Context)
02452                 {
02453                     /* Set the Data */
02454                     Context->Key = CompletionInfo->Key;
02455                     Context->Port = Queue;
02456                     if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
02457                                                           CompletionContext,
02458                                                           Context,
02459                                                           NULL))
02460                     {
02461                         /*
02462                          * Someone else set the completion port in the
02463                          * meanwhile, so dereference the port and fail.
02464                          */
02465                         ExFreePool(Context);
02466                         ObDereferenceObject(Queue);
02467                         Status = STATUS_INVALID_PARAMETER;
02468                     }
02469                 }
02470                 else
02471                 {
02472                     /* Dereference the Port now */
02473                     ObDereferenceObject(Queue);
02474                     Status = STATUS_INSUFFICIENT_RESOURCES;
02475                 }
02476             }
02477         }
02478 
02479         /* Set the IRP Status */
02480         Irp->IoStatus.Status = Status;
02481         Irp->IoStatus.Information = 0;
02482     }
02483     else
02484     {
02485         /* Call the Driver */
02486         Status = IoCallDriver(DeviceObject, Irp);
02487     }
02488 
02489     /* Check if we're waiting for the IRP to complete */
02490     if (Status == STATUS_PENDING)
02491     {
02492         /* Check if this was async I/O */
02493         if (LocalEvent)
02494         {
02495             /* Then to a non-alertable wait */
02496             Status = KeWaitForSingleObject(Event,
02497                                            Executive,
02498                                            PreviousMode,
02499                                            FALSE,
02500                                            NULL);
02501             if (Status == STATUS_USER_APC)
02502             {
02503                 /* Abort the request */
02504                 IopAbortInterruptedIrp(Event, Irp);
02505             }
02506 
02507             /* Set the final status */
02508             Status = KernelIosb.Status;
02509 
02510             /* Enter SEH to write the IOSB back */
02511             _SEH2_TRY
02512             {
02513                 /* Write it back to the caller */
02514                 *IoStatusBlock = KernelIosb;
02515             }
02516             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02517             {
02518                 /* Get the exception code */
02519                 Status = _SEH2_GetExceptionCode();
02520             }
02521             _SEH2_END;
02522 
02523             /* Free the event */
02524             ExFreePool(Event);
02525         }
02526         else
02527         {
02528             /* Wait for the IRP */
02529             Status = KeWaitForSingleObject(&FileObject->Event,
02530                                            Executive,
02531                                            PreviousMode,
02532                                            FileObject->Flags & FO_ALERTABLE_IO,
02533                                            NULL);
02534             if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
02535             {
02536                 /* Abort the request */
02537                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
02538             }
02539 
02540             /* Set the final status */
02541             Status = FileObject->FinalStatus;
02542 
02543             /* Release the file lock */
02544             IopUnlockFileObject(FileObject);
02545         }
02546     }
02547     else
02548     {
02549         /* Free the event if we had one */
02550         if (LocalEvent)
02551         {
02552             /* Clear it in the IRP for completion */
02553             Irp->UserEvent = NULL;
02554             ExFreePool(Event);
02555         }
02556 
02557         /* Set the caller IOSB */
02558         Irp->UserIosb = IoStatusBlock;
02559 
02560         /* The IRP wasn't completed, complete it ourselves */
02561         KeRaiseIrql(APC_LEVEL, &OldIrql);
02562         IopCompleteRequest(&Irp->Tail.Apc,
02563                            &NormalRoutine,
02564                            &NormalContext,
02565                            (PVOID*)&FileObject,
02566                            &NormalContext);
02567         KeLowerIrql(OldIrql);
02568 
02569         /* Release the file object if we had locked it*/
02570         if (!LocalEvent) IopUnlockFileObject(FileObject);
02571     }
02572 
02573     /* Return the Status */
02574     return Status;
02575 }
02576 
02577 /*
02578  * @unimplemented
02579  */
02580 NTSTATUS
02581 NTAPI
02582 NtSetQuotaInformationFile(IN HANDLE FileHandle,
02583                           OUT PIO_STATUS_BLOCK IoStatusBlock,
02584                           IN PVOID Buffer,
02585                           IN ULONG BufferLength)
02586 {
02587     UNIMPLEMENTED;
02588     return STATUS_NOT_IMPLEMENTED;
02589 }
02590 
02591 /*
02592  * @implemented
02593  */
02594 NTSTATUS
02595 NTAPI
02596 NtUnlockFile(IN HANDLE FileHandle,
02597              OUT PIO_STATUS_BLOCK IoStatusBlock,
02598              IN PLARGE_INTEGER ByteOffset,
02599              IN PLARGE_INTEGER Length,
02600              IN ULONG Key OPTIONAL)
02601 {
02602     PFILE_OBJECT FileObject;
02603     PLARGE_INTEGER LocalLength = NULL;
02604     PIRP Irp;
02605     PIO_STACK_LOCATION StackPtr;
02606     PDEVICE_OBJECT DeviceObject;
02607     PKEVENT Event = NULL;
02608     BOOLEAN LocalEvent = FALSE;
02609     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
02610     LARGE_INTEGER CapturedByteOffset, CapturedLength;
02611     NTSTATUS Status;
02612     OBJECT_HANDLE_INFORMATION HandleInformation;
02613     IO_STATUS_BLOCK KernelIosb;
02614     PAGED_CODE();
02615     CapturedByteOffset.QuadPart = 0;
02616     CapturedLength.QuadPart = 0;
02617     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
02618 
02619     /* Get File Object */
02620     Status = ObReferenceObjectByHandle(FileHandle,
02621                                        0,
02622                                        IoFileObjectType,
02623                                        PreviousMode,
02624                                        (PVOID*)&FileObject,
02625                                        &HandleInformation);
02626     if (!NT_SUCCESS(Status)) return Status;
02627 
02628     /* Check if we're called from user mode */
02629     if (PreviousMode != KernelMode)
02630     {
02631         /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
02632         if (!(HandleInformation.GrantedAccess &
02633             (FILE_WRITE_DATA | FILE_READ_DATA)))
02634         {
02635             ObDereferenceObject(FileObject);
02636             return STATUS_ACCESS_DENIED;
02637         }
02638 
02639         /* Enter SEH for probing */
02640         _SEH2_TRY
02641         {
02642             /* Probe the I/O Status block */
02643             ProbeForWriteIoStatusBlock(IoStatusBlock);
02644 
02645             /* Probe and capture the large integers */
02646             CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
02647             CapturedLength = ProbeForReadLargeInteger(Length);
02648         }
02649         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02650         {
02651             /* Dereference the object and return exception code */
02652             ObDereferenceObject(FileObject);
02653             _SEH2_YIELD(return _SEH2_GetExceptionCode());
02654         }
02655         _SEH2_END;
02656     }
02657     else
02658     {
02659         /* Otherwise, capture them directly */
02660         CapturedByteOffset = *ByteOffset;
02661         CapturedLength = *Length;
02662     }
02663 
02664     /* Check if this is a direct open or not */
02665     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
02666     {
02667         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
02668     }
02669     else
02670     {
02671         DeviceObject = IoGetRelatedDeviceObject(FileObject);
02672     }
02673 
02674     /* Check if we should use Sync IO or not */
02675     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
02676     {
02677         /* Lock it */
02678         IopLockFileObject(FileObject);
02679     }
02680     else
02681     {
02682         /* Use local event */
02683         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
02684         if (!Event)
02685         {
02686             ObDereferenceObject(FileObject);
02687             return STATUS_INSUFFICIENT_RESOURCES;
02688         }
02689         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
02690         LocalEvent = TRUE;
02691     }
02692 
02693     /* Clear File Object event */
02694     KeClearEvent(&FileObject->Event);
02695 
02696     /* Allocate the IRP */
02697     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
02698     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
02699 
02700     /* Set up the IRP */
02701     Irp->RequestorMode = PreviousMode;
02702     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
02703     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
02704     Irp->UserEvent = (LocalEvent) ? Event : NULL;
02705     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
02706     Irp->Tail.Overlay.OriginalFileObject = FileObject;
02707     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
02708 
02709     /* Set up Stack Data */
02710     StackPtr = IoGetNextIrpStackLocation(Irp);
02711     StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
02712     StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
02713     StackPtr->FileObject = FileObject;
02714 
02715     /* Enter SEH */
02716     _SEH2_TRY
02717     {
02718         /* Allocate a buffer */
02719         LocalLength = ExAllocatePoolWithTag(NonPagedPool,
02720                                             sizeof(LARGE_INTEGER),
02721                                         TAG_LOCK);
02722 
02723         /* Set the length */
02724         *LocalLength = CapturedLength;
02725         Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
02726         StackPtr->Parameters.LockControl.Length = LocalLength;
02727     }
02728     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02729     {
02730         /* Allocating failed, clean up and return the exception code */
02731         IopCleanupAfterException(FileObject, Irp, NULL, Event);
02732         if (LocalLength) ExFreePool(LocalLength);
02733 
02734         /* Return the exception code */
02735         _SEH2_YIELD(return _SEH2_GetExceptionCode());
02736     }
02737     _SEH2_END;
02738 
02739     /* Set Parameters */
02740     StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
02741     StackPtr->Parameters.LockControl.Key = Key;
02742 
02743     /* Call the Driver */
02744     Status = IopPerformSynchronousRequest(DeviceObject,
02745                                           Irp,
02746                                           FileObject,
02747                                           FALSE,
02748                                           PreviousMode,
02749                                           !LocalEvent,
02750                                           IopOtherTransfer);
02751 
02752     /* Check if this was async I/O */
02753     if (LocalEvent)
02754     {
02755         /* It was, finalize this request */
02756         Status = IopFinalizeAsynchronousIo(Status,
02757                                            Event,
02758                                            Irp,
02759                                            PreviousMode,
02760                                            &KernelIosb,
02761                                            IoStatusBlock);
02762     }
02763 
02764     /* Return status */
02765     return Status;
02766 }
02767 
02768 /*
02769  * @implemented
02770  */
02771 NTSTATUS
02772 NTAPI
02773 NtWriteFile(IN HANDLE FileHandle,
02774             IN HANDLE Event OPTIONAL,
02775             IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
02776             IN PVOID ApcContext OPTIONAL,
02777             OUT PIO_STATUS_BLOCK IoStatusBlock,
02778             IN PVOID Buffer,
02779             IN ULONG Length,
02780             IN PLARGE_INTEGER ByteOffset OPTIONAL,
02781             IN PULONG Key OPTIONAL)
02782 {
02783     NTSTATUS Status;
02784     PFILE_OBJECT FileObject;
02785     PIRP Irp;
02786     PDEVICE_OBJECT DeviceObject;
02787     PIO_STACK_LOCATION StackPtr;
02788     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
02789     PKEVENT EventObject = NULL;
02790     LARGE_INTEGER CapturedByteOffset;
02791     ULONG CapturedKey = 0;
02792     BOOLEAN Synchronous = FALSE;
02793     PMDL Mdl;
02794     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
02795     PAGED_CODE();
02796     CapturedByteOffset.QuadPart = 0;
02797     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
02798 
02799     /* Get File Object */
02800     Status = ObReferenceObjectByHandle(FileHandle,
02801                                        0,
02802                                        IoFileObjectType,
02803                                        PreviousMode,
02804                                        (PVOID*)&FileObject,
02805                                        &ObjectHandleInfo);
02806     if (!NT_SUCCESS(Status)) return Status;
02807 
02808     /* Validate User-Mode Buffers */
02809     if (PreviousMode != KernelMode)
02810     {
02811         _SEH2_TRY
02812         {
02813             /*
02814              * Check if the handle has either FILE_WRITE_DATA or
02815              * FILE_APPEND_DATA granted. However, if this is a named pipe,
02816              * make sure we don't ask for FILE_APPEND_DATA as it interferes
02817              * with the FILE_CREATE_PIPE_INSTANCE access right!
02818              */
02819             if (!(ObjectHandleInfo.GrantedAccess &
02820                  ((!(FileObject->Flags & FO_NAMED_PIPE) ?
02821                    FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
02822             {
02823                 /* We failed */
02824                 ObDereferenceObject(FileObject);
02825                 _SEH2_YIELD(return STATUS_ACCESS_DENIED);
02826             }
02827 
02828             /* Probe the status block */
02829             ProbeForWriteIoStatusBlock(IoStatusBlock);
02830 
02831             /* Probe the read buffer */
02832             ProbeForRead(Buffer, Length, 1);
02833 
02834             /* Check if we got a byte offset */
02835             if (ByteOffset)
02836             {
02837                 /* Capture and probe it */
02838                 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
02839             }
02840 
02841             /* Capture and probe the key */
02842             if (Key) CapturedKey = ProbeForReadUlong(Key);
02843         }
02844         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02845         {
02846             /* Return the exception code */
02847             _SEH2_YIELD(return _SEH2_GetExceptionCode());
02848         }
02849         _SEH2_END;
02850     }
02851     else
02852     {
02853         /* Kernel mode: capture directly */
02854         if (ByteOffset) CapturedByteOffset = *ByteOffset;
02855         if (Key) CapturedKey = *Key;
02856     }
02857 
02858     /* Check if this is an append operation */
02859     if ((ObjectHandleInfo.GrantedAccess &
02860         (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
02861     {
02862         /* Give the drivers something to understand */
02863         CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
02864         CapturedByteOffset.u.HighPart = -1;
02865     }
02866 
02867     /* Check for event */
02868     if (Event)
02869     {
02870         /* Reference it */
02871         Status = ObReferenceObjectByHandle(Event,
02872                                            EVENT_MODIFY_STATE,
02873                                            ExEventObjectType,
02874                                            PreviousMode,
02875                                            (PVOID*)&EventObject,
02876                                            NULL);
02877         if (!NT_SUCCESS(Status))
02878         {
02879             /* Fail */
02880             ObDereferenceObject(FileObject);
02881             return Status;
02882         }
02883 
02884         /* Otherwise reset the event */
02885         KeClearEvent(EventObject);
02886     }
02887 
02888     /* Check if we should use Sync IO or not */
02889     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
02890     {
02891         /* Lock the file object */
02892         IopLockFileObject(FileObject);
02893 
02894         /* Check if we don't have a byte offset avilable */
02895         if (!(ByteOffset) ||
02896             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
02897              (CapturedByteOffset.u.HighPart == -1)))
02898         {
02899             /* Use the Current Byte Offset instead */
02900             CapturedByteOffset = FileObject->CurrentByteOffset;
02901         }
02902 
02903         /* Remember we are sync */
02904         Synchronous = TRUE;
02905     }
02906     else if (!(ByteOffset) &&
02907              !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
02908     {
02909         /* Otherwise, this was async I/O without a byte offset, so fail */
02910         if (EventObject) ObDereferenceObject(EventObject);
02911         ObDereferenceObject(FileObject);
02912         return STATUS_INVALID_PARAMETER;
02913     }
02914 
02915     /* Get the device object */
02916     DeviceObject = IoGetRelatedDeviceObject(FileObject);
02917 
02918     /* Clear the File Object's event */
02919     KeClearEvent(&FileObject->Event);
02920 
02921     /* Allocate the IRP */
02922     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
02923     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
02924 
02925     /* Set the IRP */
02926     Irp->Tail.Overlay.OriginalFileObject = FileObject;
02927     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
02928     Irp->RequestorMode = PreviousMode;
02929     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
02930     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
02931     Irp->UserIosb = IoStatusBlock;
02932     Irp->UserEvent = EventObject;
02933     Irp->PendingReturned = FALSE;
02934     Irp->Cancel = FALSE;
02935     Irp->CancelRoutine = NULL;
02936     Irp->AssociatedIrp.SystemBuffer = NULL;
02937     Irp->MdlAddress = NULL;
02938 
02939     /* Set the Stack Data */
02940     StackPtr = IoGetNextIrpStackLocation(Irp);
02941     StackPtr->MajorFunction = IRP_MJ_WRITE;
02942     StackPtr->FileObject = FileObject;
02943     StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
02944                       SL_WRITE_THROUGH : 0;
02945     StackPtr->Parameters.Write.Key = CapturedKey;
02946     StackPtr->Parameters.Write.Length = Length;
02947     StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
02948 
02949     /* Check if this is buffered I/O */
02950     if (DeviceObject->Flags & DO_BUFFERED_IO)
02951     {
02952         /* Check if we have a buffer length */
02953         if (Length)
02954         {
02955             /* Enter SEH */
02956             _SEH2_TRY
02957             {
02958                 /* Allocate a buffer */
02959                 Irp->AssociatedIrp.SystemBuffer =
02960                     ExAllocatePoolWithTag(NonPagedPool,
02961                                           Length,
02962                                           TAG_SYSB);
02963 
02964                 /* Copy the data into it */
02965                 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
02966             }
02967             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02968             {
02969                 /* Allocating failed, clean up and return the exception code */
02970                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
02971                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
02972             }
02973             _SEH2_END;
02974 
02975             /* Set the flags */
02976             Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
02977         }
02978         else
02979         {
02980             /* Not writing anything */
02981             Irp->Flags = IRP_BUFFERED_IO;
02982         }
02983     }
02984     else if (DeviceObject->Flags & DO_DIRECT_IO)
02985     {
02986         /* Check if we have a buffer length */
02987         if (Length)
02988         {
02989             _SEH2_TRY
02990             {
02991                 /* Allocate an MDL */
02992                 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
02993                 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
02994             }
02995             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02996             {
02997                 /* Allocating failed, clean up and return the exception code */
02998                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
02999                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
03000             }
03001             _SEH2_END;
03002         }
03003 
03004         /* No allocation flags */
03005         Irp->Flags = 0;
03006     }
03007     else
03008     {
03009         /* No allocation flags, and use the buffer directly */
03010         Irp->Flags = 0;
03011         Irp->UserBuffer = Buffer;
03012     }
03013 
03014     /* Now set the deferred read flags */
03015     Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
03016 #if 0
03017     /* FIXME: VFAT SUCKS */
03018     if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
03019 #endif
03020 
03021     /* Perform the call */
03022     return IopPerformSynchronousRequest(DeviceObject,
03023                                         Irp,
03024                                         FileObject,
03025                                         TRUE,
03026                                         PreviousMode,
03027                                         Synchronous,
03028                                         IopWriteTransfer);
03029 }
03030 
03031 NTSTATUS
03032 NTAPI
03033 NtWriteFileGather(IN HANDLE FileHandle,
03034                   IN HANDLE Event OPTIONAL,
03035                   IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
03036                   IN PVOID UserApcContext OPTIONAL,
03037                   OUT PIO_STATUS_BLOCK UserIoStatusBlock,
03038                   IN FILE_SEGMENT_ELEMENT BufferDescription [],
03039                   IN ULONG BufferLength,
03040                   IN PLARGE_INTEGER ByteOffset,
03041                   IN PULONG Key OPTIONAL)
03042 {
03043     UNIMPLEMENTED;
03044     return STATUS_NOT_IMPLEMENTED;
03045 }
03046 
03047 /*
03048  * @implemented
03049  */
03050 NTSTATUS
03051 NTAPI
03052 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
03053                              OUT PIO_STATUS_BLOCK IoStatusBlock,
03054                              OUT PVOID FsInformation,
03055                              IN ULONG Length,
03056                              IN FS_INFORMATION_CLASS FsInformationClass)
03057 {
03058     PFILE_OBJECT FileObject;
03059     PIRP Irp;
03060     PIO_STACK_LOCATION StackPtr;
03061     PDEVICE_OBJECT DeviceObject;
03062     PKEVENT Event = NULL;
03063     BOOLEAN LocalEvent = FALSE;
03064     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
03065     NTSTATUS Status;
03066     IO_STATUS_BLOCK KernelIosb;
03067     PAGED_CODE();
03068     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
03069 
03070     /* Check if we're called from user mode */
03071     if (PreviousMode != KernelMode)
03072     {
03073         /* Validate the information class */
03074         if ((FsInformationClass >= FileFsMaximumInformation) ||
03075             !(IopQueryFsOperationLength[FsInformationClass]))
03076         {
03077             /* Invalid class */
03078             return STATUS_INVALID_INFO_CLASS;
03079         }
03080 
03081         /* Validate the length */
03082         if (Length < IopQueryFsOperationLength[FsInformationClass])
03083         {
03084             /* Invalid length */
03085             return STATUS_INFO_LENGTH_MISMATCH;
03086         }
03087 
03088         /* Enter SEH for probing */
03089         _SEH2_TRY
03090         {
03091             /* Probe the I/O Status block */
03092             ProbeForWriteIoStatusBlock(IoStatusBlock);
03093 
03094             /* Probe the information */
03095             ProbeForWrite(FsInformation, Length, sizeof(ULONG));
03096         }
03097         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
03098         {
03099             /* Return the exception code */
03100             _SEH2_YIELD(return _SEH2_GetExceptionCode());
03101         }
03102         _SEH2_END;
03103     }
03104 
03105     /* Get File Object */
03106     Status = ObReferenceObjectByHandle(FileHandle,
03107                                        IopQueryFsOperationAccess
03108                                        [FsInformationClass],
03109                                        IoFileObjectType,
03110                                        PreviousMode,
03111                                        (PVOID*)&FileObject,
03112                                        NULL);
03113     if (!NT_SUCCESS(Status)) return Status;
03114 
03115     /* Check if we should use Sync IO or not */
03116     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
03117     {
03118         /* Lock it */
03119         IopLockFileObject(FileObject);
03120     }
03121     else
03122     {
03123         /* Use local event */
03124         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
03125         if (!Event)
03126         {
03127             ObDereferenceObject(FileObject);
03128             return STATUS_INSUFFICIENT_RESOURCES;
03129         }
03130         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
03131         LocalEvent = TRUE;
03132     }
03133 
03134     /* Get the device object */
03135     DeviceObject = IoGetRelatedDeviceObject(FileObject);
03136 
03137     /* Clear File Object event */
03138     KeClearEvent(&FileObject->Event);
03139 
03140     /* Allocate the IRP */
03141     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
03142     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
03143 
03144     /* Set up the IRP */
03145     Irp->RequestorMode = PreviousMode;
03146     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
03147     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
03148     Irp->UserEvent = (LocalEvent) ? Event : NULL;
03149     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
03150     Irp->Tail.Overlay.OriginalFileObject = FileObject;
03151     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
03152     Irp->UserBuffer = FsInformation;
03153     Irp->AssociatedIrp.SystemBuffer = NULL;
03154     Irp->MdlAddress = NULL;
03155 
03156     /* Set up Stack Data */
03157     StackPtr = IoGetNextIrpStackLocation(Irp);
03158     StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
03159     StackPtr->FileObject = FileObject;
03160 
03161     /* Enter SEH */
03162     _SEH2_TRY
03163     {
03164         /* Allocate a buffer */
03165         Irp->AssociatedIrp.SystemBuffer =
03166             ExAllocatePoolWithTag(NonPagedPool,
03167                                   Length,
03168                                   TAG_SYSB);
03169     }
03170     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
03171     {
03172         /* Allocating failed, clean up and return the exception code */
03173         IopCleanupAfterException(FileObject, Irp, NULL, Event);
03174         _SEH2_YIELD(return _SEH2_GetExceptionCode());
03175     }
03176     _SEH2_END;
03177 
03178     /* Set the flags for this buffered + deferred I/O */
03179     Irp->Flags |= (IRP_BUFFERED_IO |
03180                    IRP_DEALLOCATE_BUFFER |
03181                    IRP_INPUT_OPERATION |
03182                    IRP_DEFER_IO_COMPLETION);
03183 
03184     /* Set Parameters */
03185     StackPtr->Parameters.QueryVolume.Length = Length;
03186     StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
03187 
03188     /* Call the Driver */
03189     Status = IopPerformSynchronousRequest(DeviceObject,
03190                                           Irp,
03191                                           FileObject,
03192                                           TRUE,
03193                                           PreviousMode,
03194                                           !LocalEvent,
03195                                           IopOtherTransfer);
03196 
03197     /* Check if this was async I/O */
03198     if (LocalEvent)
03199     {
03200         /* It was, finalize this request */
03201         Status = IopFinalizeAsynchronousIo(Status,
03202                                            Event,
03203                                            Irp,
03204                                            PreviousMode,
03205                                            &KernelIosb,
03206                                            IoStatusBlock);
03207     }
03208 
03209     /* Return status */
03210     return Status;
03211 }
03212 
03213 /*
03214  * @implemented
03215  */
03216 NTSTATUS
03217 NTAPI
03218 NtSetVolumeInformationFile(IN HANDLE FileHandle,
03219                            OUT PIO_STATUS_BLOCK IoStatusBlock,
03220                            IN PVOID FsInformation,
03221                            IN ULONG Length,
03222                            IN FS_INFORMATION_CLASS FsInformationClass)
03223 {
03224     PFILE_OBJECT FileObject;
03225     PIRP Irp;
03226     PIO_STACK_LOCATION StackPtr;
03227     PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
03228     PKEVENT Event = NULL;
03229     BOOLEAN LocalEvent = FALSE;
03230     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
03231     NTSTATUS Status;
03232     IO_STATUS_BLOCK KernelIosb;
03233     TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
03234     PAGED_CODE();
03235     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
03236 
03237     /* Check if we're called from user mode */
03238     if (PreviousMode != KernelMode)
03239     {
03240         /* Validate the information class */
03241         if ((FsInformationClass >= FileFsMaximumInformation) ||
03242             !(IopSetFsOperationLength[FsInformationClass]))
03243         {
03244             /* Invalid class */
03245             return STATUS_INVALID_INFO_CLASS;
03246         }
03247 
03248         /* Validate the length */
03249         if (Length < IopSetFsOperationLength[FsInformationClass])
03250         {
03251             /* Invalid length */
03252             return STATUS_INFO_LENGTH_MISMATCH;
03253         }
03254 
03255         /* Enter SEH for probing */
03256         _SEH2_TRY
03257         {
03258             /* Probe the I/O Status block */
03259             ProbeForWriteIoStatusBlock(IoStatusBlock);
03260 
03261             /* Probe the information */
03262             ProbeForRead(FsInformation, Length, sizeof(ULONG));
03263         }
03264         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
03265         {
03266             /* Return the exception code */
03267             _SEH2_YIELD(return _SEH2_GetExceptionCode());
03268         }
03269         _SEH2_END;
03270     }
03271 
03272     /* Get File Object */
03273     Status = ObReferenceObjectByHandle(FileHandle,
03274                                        IopSetFsOperationAccess
03275                                        [FsInformationClass],
03276                                        IoFileObjectType,
03277                                        PreviousMode,
03278                                        (PVOID*)&FileObject,
03279                                        NULL);
03280     if (!NT_SUCCESS(Status)) return Status;
03281 
03282     /* Get target device for notification */
03283     Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
03284     if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
03285 
03286     /* Check if we should use Sync IO or not */
03287     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
03288     {
03289         /* Lock it */
03290         IopLockFileObject(FileObject);
03291     }
03292     else
03293     {
03294         /* Use local event */
03295         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
03296         if (!Event)
03297         {
03298             ObDereferenceObject(FileObject);
03299             if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
03300             return STATUS_INSUFFICIENT_RESOURCES;
03301         }
03302         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
03303         LocalEvent = TRUE;
03304     }
03305 
03306     /* Get the device object */
03307     DeviceObject = IoGetRelatedDeviceObject(FileObject);
03308 
03309     /* Clear File Object event */
03310     KeClearEvent(&FileObject->Event);
03311 
03312     /* Allocate the IRP */
03313     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
03314     if (!Irp)
03315     {
03316         if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
03317         return IopCleanupFailedIrp(FileObject, NULL, Event);
03318     }
03319 
03320     /* Set up the IRP */
03321     Irp->RequestorMode = PreviousMode;
03322     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
03323     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
03324     Irp->UserEvent = (LocalEvent) ? Event : NULL;
03325     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
03326     Irp->Tail.Overlay.OriginalFileObject = FileObject;
03327     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
03328     Irp->UserBuffer = FsInformation;
03329     Irp->AssociatedIrp.SystemBuffer = NULL;
03330     Irp->MdlAddress = NULL;
03331 
03332     /* Set up Stack Data */
03333     StackPtr = IoGetNextIrpStackLocation(Irp);
03334     StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
03335     StackPtr->FileObject = FileObject;
03336 
03337     /* Enter SEH */
03338     _SEH2_TRY
03339     {
03340         /* Allocate a buffer */
03341         Irp->AssociatedIrp.SystemBuffer =
03342             ExAllocatePoolWithTag(NonPagedPool,
03343                                   Length,
03344                                   TAG_SYSB);
03345 
03346         /* Copy the data into it */
03347         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
03348     }
03349     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
03350     {
03351         /* Allocating failed, clean up and return the exception code */
03352         IopCleanupAfterException(FileObject, Irp, NULL, Event);
03353         if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
03354         _SEH2_YIELD(return _SEH2_GetExceptionCode());
03355     }
03356     _SEH2_END;
03357 
03358     /* Set the flags for this buffered + deferred I/O */
03359     Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
03360 
03361     /* Set Parameters */
03362     StackPtr->Parameters.SetVolume.Length = Length;
03363     StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
03364 
03365     /* Call the Driver */
03366     Status = IopPerformSynchronousRequest(DeviceObject,
03367                                           Irp,
03368                                           FileObject,
03369                                           FALSE,
03370                                           PreviousMode,
03371                                           !LocalEvent,
03372                                           IopOtherTransfer);
03373 
03374     /* Check if this was async I/O */
03375     if (LocalEvent)
03376     {
03377         /* It was, finalize this request */
03378         Status = IopFinalizeAsynchronousIo(Status,
03379                                            Event,
03380                                            Irp,
03381                                            PreviousMode,
03382                                            &KernelIosb,
03383                                            IoStatusBlock);
03384     }
03385 
03386     if (TargetDeviceObject && NT_SUCCESS(Status))
03387     {
03388         /* Time to report change */
03389         NotificationStructure.Version = 1;
03390         NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
03391         NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
03392         NotificationStructure.FileObject = NULL;
03393         NotificationStructure.NameBufferOffset = - 1;
03394         Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
03395     }
03396 
03397     /* Return status */
03398     return Status;
03399 }
03400 
03401 /*
03402  * @unimplemented
03403  */
03404 NTSTATUS
03405 NTAPI
03406 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
03407 {
03408     UNIMPLEMENTED;
03409     return STATUS_NOT_IMPLEMENTED;
03410 }
03411 
03412 /*
03413  * @unimplemented
03414  */
03415 NTSTATUS
03416 NTAPI
03417 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
03418 {
03419     UNIMPLEMENTED;
03420     return STATUS_NOT_IMPLEMENTED;
03421 }

Generated on Sat May 26 2012 04:36:09 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.