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