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