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