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