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