xref: /reactos/ntoskrnl/io/iomgr/iofunc.c (revision 1ac9e484)
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     /* Get File Object */
2056     Status = ObReferenceObjectByHandle(FileHandle,
2057                                        FILE_LIST_DIRECTORY,
2058                                        IoFileObjectType,
2059                                        PreviousMode,
2060                                        (PVOID *)&FileObject,
2061                                        NULL);
2062     if (!NT_SUCCESS(Status))
2063     {
2064         /* Fail */
2065         if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2066         return Status;
2067     }
2068 
2069     /* Are there two associated completion routines? */
2070     if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
2071     {
2072         ObDereferenceObject(FileObject);
2073         if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2074         return STATUS_INVALID_PARAMETER;
2075     }
2076 
2077     /* Check if we have an even handle */
2078     if (EventHandle)
2079     {
2080         /* Get its pointer */
2081         Status = ObReferenceObjectByHandle(EventHandle,
2082                                            EVENT_MODIFY_STATE,
2083                                            ExEventObjectType,
2084                                            PreviousMode,
2085                                            (PVOID *)&Event,
2086                                            NULL);
2087         if (!NT_SUCCESS(Status))
2088         {
2089             /* Fail */
2090             if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2091             ObDereferenceObject(FileObject);
2092             return Status;
2093         }
2094 
2095         /* Clear it */
2096         KeClearEvent(Event);
2097     }
2098 
2099     /* Check if this is a file that was opened for Synch I/O */
2100     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2101     {
2102         /* Lock it */
2103         Status = IopLockFileObject(FileObject, PreviousMode);
2104         if (Status != STATUS_SUCCESS)
2105         {
2106             if (Event) ObDereferenceObject(Event);
2107             ObDereferenceObject(FileObject);
2108             if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2109             return Status;
2110         }
2111 
2112         /* Remember to unlock later */
2113         LockedForSynch = TRUE;
2114     }
2115 
2116     /* Get the device object */
2117     DeviceObject = IoGetRelatedDeviceObject(FileObject);
2118 
2119     /* Clear the File Object's event */
2120     KeClearEvent(&FileObject->Event);
2121 
2122     /* Allocate the IRP */
2123     Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2124     if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
2125 
2126     /* Set up the IRP */
2127     Irp->RequestorMode = PreviousMode;
2128     Irp->UserIosb = IoStatusBlock;
2129     Irp->UserEvent = Event;
2130     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2131     Irp->Tail.Overlay.OriginalFileObject = FileObject;
2132     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2133     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2134     Irp->MdlAddress = NULL;
2135     Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
2136     Irp->AssociatedIrp.SystemBuffer = NULL;
2137 
2138     /* Check if this is buffered I/O */
2139     if (DeviceObject->Flags & DO_BUFFERED_IO)
2140     {
2141         /* Allocate a buffer */
2142         Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2143                                                                 Length,
2144                                                                 TAG_SYSB);
2145         if (!Irp->AssociatedIrp.SystemBuffer)
2146         {
2147             /* Allocating failed, clean up and return the exception code */
2148             IopCleanupAfterException(FileObject, Irp, Event, NULL);
2149             if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2150 
2151             /* Return the exception code */
2152             return STATUS_INSUFFICIENT_RESOURCES;
2153         }
2154 
2155         /* Set the buffer and flags */
2156         Irp->UserBuffer = FileInformation;
2157         Irp->Flags = (IRP_BUFFERED_IO |
2158                       IRP_DEALLOCATE_BUFFER |
2159                       IRP_INPUT_OPERATION);
2160     }
2161     else if (DeviceObject->Flags & DO_DIRECT_IO)
2162     {
2163         _SEH2_TRY
2164         {
2165             /* Allocate an MDL */
2166             Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
2167             if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2168             MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2169         }
2170         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2171         {
2172             /* Allocating failed, clean up and return the exception code */
2173             IopCleanupAfterException(FileObject, Irp, Event, NULL);
2174             _SEH2_YIELD(return _SEH2_GetExceptionCode());
2175         }
2176         _SEH2_END;
2177     }
2178     else
2179     {
2180         /* No allocation flags, and use the buffer directly */
2181         Irp->UserBuffer = FileInformation;
2182     }
2183 
2184     /* Set up Stack Data */
2185     StackPtr = IoGetNextIrpStackLocation(Irp);
2186     StackPtr->FileObject = FileObject;
2187     StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2188     StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
2189 
2190     /* Set Parameters */
2191     StackPtr->Parameters.QueryDirectory.FileInformationClass =
2192         FileInformationClass;
2193     StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
2194     StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2195     StackPtr->Parameters.QueryDirectory.Length = Length;
2196     StackPtr->Flags = 0;
2197     if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2198     if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
2199 
2200     /* Set deferred I/O */
2201     Irp->Flags |= IRP_DEFER_IO_COMPLETION;
2202 
2203     /* Perform the call */
2204     return IopPerformSynchronousRequest(DeviceObject,
2205                                         Irp,
2206                                         FileObject,
2207                                         TRUE,
2208                                         PreviousMode,
2209                                         LockedForSynch,
2210                                         IopOtherTransfer);
2211 }
2212 
2213 /*
2214  * @unimplemented
2215  */
2216 NTSTATUS
2217 NTAPI
2218 NtQueryEaFile(IN HANDLE FileHandle,
2219               OUT PIO_STATUS_BLOCK IoStatusBlock,
2220               OUT PVOID Buffer,
2221               IN ULONG Length,
2222               IN BOOLEAN ReturnSingleEntry,
2223               IN PVOID EaList OPTIONAL,
2224               IN ULONG EaListLength,
2225               IN PULONG EaIndex OPTIONAL,
2226               IN BOOLEAN RestartScan)
2227 {
2228     UNIMPLEMENTED;
2229     return STATUS_NOT_IMPLEMENTED;
2230 }
2231 
2232 /*
2233  * @implemented
2234  */
2235 NTSTATUS
2236 NTAPI
2237 NtQueryInformationFile(IN HANDLE FileHandle,
2238                        OUT PIO_STATUS_BLOCK IoStatusBlock,
2239                        IN PVOID FileInformation,
2240                        IN ULONG Length,
2241                        IN FILE_INFORMATION_CLASS FileInformationClass)
2242 {
2243     OBJECT_HANDLE_INFORMATION HandleInformation;
2244     PFILE_OBJECT FileObject;
2245     NTSTATUS Status;
2246     PIRP Irp;
2247     PDEVICE_OBJECT DeviceObject;
2248     PIO_STACK_LOCATION StackPtr;
2249     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2250     PKEVENT Event = NULL;
2251     BOOLEAN LocalEvent = FALSE;
2252     PKNORMAL_ROUTINE NormalRoutine;
2253     PVOID NormalContext;
2254     KIRQL OldIrql;
2255     IO_STATUS_BLOCK KernelIosb;
2256     BOOLEAN CallDriver = TRUE;
2257     PFILE_ACCESS_INFORMATION AccessBuffer;
2258     PFILE_MODE_INFORMATION ModeBuffer;
2259     PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
2260     PFILE_ALL_INFORMATION AllBuffer;
2261     PFAST_IO_DISPATCH FastIoDispatch;
2262     PAGED_CODE();
2263     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2264 
2265     /* Check if we're called from user mode */
2266     if (PreviousMode != KernelMode)
2267     {
2268         /* Validate the information class */
2269         if ((FileInformationClass < 0) ||
2270             (FileInformationClass >= FileMaximumInformation) ||
2271             !(IopQueryOperationLength[FileInformationClass]))
2272         {
2273             /* Invalid class */
2274             return STATUS_INVALID_INFO_CLASS;
2275         }
2276 
2277         /* Validate the length */
2278         if (Length < IopQueryOperationLength[FileInformationClass])
2279         {
2280             /* Invalid length */
2281             return STATUS_INFO_LENGTH_MISMATCH;
2282         }
2283 
2284         /* Enter SEH for probing */
2285         _SEH2_TRY
2286         {
2287             /* Probe the I/O Status block */
2288             ProbeForWriteIoStatusBlock(IoStatusBlock);
2289 
2290             /* Probe the information */
2291             ProbeForWrite(FileInformation, Length, sizeof(ULONG));
2292         }
2293         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2294         {
2295             /* Return the exception code */
2296             _SEH2_YIELD(return _SEH2_GetExceptionCode());
2297         }
2298         _SEH2_END;
2299     }
2300 #if DBG
2301     else
2302     {
2303         /* Validate the information class */
2304         if ((FileInformationClass < 0) ||
2305             (FileInformationClass >= FileMaximumInformation) ||
2306             !(IopQueryOperationLength[FileInformationClass]))
2307         {
2308             /* Invalid class */
2309             return STATUS_INVALID_INFO_CLASS;
2310         }
2311 
2312         /* Validate the length */
2313         if (Length < IopQueryOperationLength[FileInformationClass])
2314         {
2315             /* Invalid length */
2316             return STATUS_INFO_LENGTH_MISMATCH;
2317         }
2318     }
2319 #endif
2320 
2321     /* Reference the Handle */
2322     Status = ObReferenceObjectByHandle(FileHandle,
2323                                        IopQueryOperationAccess
2324                                        [FileInformationClass],
2325                                        IoFileObjectType,
2326                                        PreviousMode,
2327                                        (PVOID *)&FileObject,
2328                                        &HandleInformation);
2329     if (!NT_SUCCESS(Status)) return Status;
2330 
2331     /* Check if this is a direct open or not */
2332     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2333     {
2334         /* Get the device object */
2335         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2336     }
2337     else
2338     {
2339         /* Get the device object */
2340         DeviceObject = IoGetRelatedDeviceObject(FileObject);
2341     }
2342 
2343     /* Check if this is a file that was opened for Synch I/O */
2344     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2345     {
2346         /* Lock it */
2347         Status = IopLockFileObject(FileObject, PreviousMode);
2348         if (Status != STATUS_SUCCESS)
2349         {
2350             ObDereferenceObject(FileObject);
2351             return Status;
2352         }
2353 
2354         /* Check if the caller just wants the position */
2355         if (FileInformationClass == FilePositionInformation)
2356         {
2357             /* Protect write in SEH */
2358             _SEH2_TRY
2359             {
2360                 /* Write the offset */
2361                 ((PFILE_POSITION_INFORMATION)FileInformation)->
2362                     CurrentByteOffset = FileObject->CurrentByteOffset;
2363 
2364                 /* Fill out the I/O Status Block */
2365                 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
2366                 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2367             }
2368             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2369             {
2370                 /* Get the exception code */
2371                 Status = _SEH2_GetExceptionCode();
2372             }
2373             _SEH2_END;
2374 
2375             /* Release the file lock, dereference the file and return */
2376             IopUnlockFileObject(FileObject);
2377             ObDereferenceObject(FileObject);
2378             return Status;
2379         }
2380     }
2381     else
2382     {
2383         /* Use local event */
2384         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2385         if (!Event)
2386         {
2387             ObDereferenceObject(FileObject);
2388             return STATUS_INSUFFICIENT_RESOURCES;
2389         }
2390         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2391         LocalEvent = TRUE;
2392     }
2393 
2394     /* Check if FastIO is possible for the two available information classes */
2395     FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2396     if (FastIoDispatch != NULL &&
2397         ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
2398          (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
2399     {
2400         BOOLEAN Success = FALSE;
2401 
2402         if (FileInformationClass == FileBasicInformation)
2403         {
2404             Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
2405                                                            FileInformation,
2406                                                            &KernelIosb,
2407                                                            DeviceObject);
2408         }
2409         else
2410         {
2411             Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
2412                                                               FileInformation,
2413                                                               &KernelIosb,
2414                                                               DeviceObject);
2415         }
2416 
2417         /* If call succeed */
2418         if (Success)
2419         {
2420             /* Write the IOSB back */
2421             _SEH2_TRY
2422             {
2423                 *IoStatusBlock = KernelIosb;
2424             }
2425             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2426             {
2427                 KernelIosb.Status = _SEH2_GetExceptionCode();
2428             }
2429             _SEH2_END;
2430 
2431             /* Free the event if we had one */
2432             if (LocalEvent)
2433             {
2434                 ExFreePoolWithTag(Event, TAG_IO);
2435             }
2436 
2437             /* If FO was locked, unlock it */
2438             if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2439             {
2440                 IopUnlockFileObject(FileObject);
2441             }
2442 
2443             /* We're done with FastIO! */
2444             ObDereferenceObject(FileObject);
2445             return KernelIosb.Status;
2446         }
2447     }
2448 
2449     /* Clear the File Object event */
2450     KeClearEvent(&FileObject->Event);
2451 
2452     /* Allocate the IRP */
2453     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2454     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2455 
2456     /* Set the IRP */
2457     Irp->Tail.Overlay.OriginalFileObject = FileObject;
2458     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2459     Irp->RequestorMode = PreviousMode;
2460     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2461     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2462     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2463     Irp->UserEvent = (LocalEvent) ? Event : NULL;
2464     Irp->AssociatedIrp.SystemBuffer = NULL;
2465     Irp->MdlAddress = NULL;
2466     Irp->UserBuffer = FileInformation;
2467 
2468     /* Set the Stack Data */
2469     StackPtr = IoGetNextIrpStackLocation(Irp);
2470     StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2471     StackPtr->FileObject = FileObject;
2472 
2473     /* Enter SEH */
2474     _SEH2_TRY
2475     {
2476         /* Allocate a buffer */
2477         Irp->AssociatedIrp.SystemBuffer =
2478             ExAllocatePoolWithTag(NonPagedPool,
2479                                   Length,
2480                                   TAG_SYSB);
2481     }
2482     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2483     {
2484         /* Allocating failed, clean up and return the exception code */
2485         IopCleanupAfterException(FileObject, Irp, NULL, Event);
2486         _SEH2_YIELD(return _SEH2_GetExceptionCode());
2487     }
2488     _SEH2_END;
2489 
2490     /* Set the flags */
2491     Irp->Flags |= (IRP_BUFFERED_IO |
2492                    IRP_DEALLOCATE_BUFFER |
2493                    IRP_INPUT_OPERATION |
2494                    IRP_DEFER_IO_COMPLETION);
2495 
2496     /* Set the Parameters */
2497     StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2498     StackPtr->Parameters.QueryFile.Length = Length;
2499 
2500     /* Queue the IRP */
2501     IopQueueIrpToThread(Irp);
2502 
2503     /* Update operation counts */
2504     IopUpdateOperationCount(IopOtherTransfer);
2505 
2506     /* Fill in file information before calling the driver.
2507        See 'File System Internals' page 485.*/
2508     if (FileInformationClass == FileAccessInformation)
2509     {
2510         AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2511         AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2512         Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2513         CallDriver = FALSE;
2514     }
2515     else if (FileInformationClass == FileModeInformation)
2516     {
2517         ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2518         ModeBuffer->Mode = IopGetFileMode(FileObject);
2519         Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2520         CallDriver = FALSE;
2521     }
2522     else if (FileInformationClass == FileAlignmentInformation)
2523     {
2524         AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2525         AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2526         Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2527         CallDriver = FALSE;
2528     }
2529     else if (FileInformationClass == FileAllInformation)
2530     {
2531         AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2532         AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2533         AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
2534         AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2535         Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2536                                     sizeof(FILE_MODE_INFORMATION) +
2537                                     sizeof(FILE_ALIGNMENT_INFORMATION);
2538     }
2539 
2540     /* Call the Driver */
2541     if (CallDriver)
2542     {
2543         Status = IoCallDriver(DeviceObject, Irp);
2544     }
2545     else
2546     {
2547         Status = STATUS_SUCCESS;
2548         Irp->IoStatus.Status = STATUS_SUCCESS;
2549     }
2550 
2551     if (Status == STATUS_PENDING)
2552     {
2553         /* Check if this was async I/O */
2554         if (LocalEvent)
2555         {
2556             /* Then to a non-alertable wait */
2557             Status = KeWaitForSingleObject(Event,
2558                                            Executive,
2559                                            PreviousMode,
2560                                            FALSE,
2561                                            NULL);
2562             if (Status == STATUS_USER_APC)
2563             {
2564                 /* Abort the request */
2565                 IopAbortInterruptedIrp(Event, Irp);
2566             }
2567 
2568             /* Set the final status */
2569             Status = KernelIosb.Status;
2570 
2571             /* Enter SEH to write the IOSB back */
2572             _SEH2_TRY
2573             {
2574                 /* Write it back to the caller */
2575                 *IoStatusBlock = KernelIosb;
2576             }
2577             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2578             {
2579                 /* Get the exception code */
2580                 Status = _SEH2_GetExceptionCode();
2581             }
2582             _SEH2_END;
2583 
2584             /* Free the event */
2585             ExFreePoolWithTag(Event, TAG_IO);
2586         }
2587         else
2588         {
2589             /* Wait for the IRP */
2590             Status = KeWaitForSingleObject(&FileObject->Event,
2591                                            Executive,
2592                                            PreviousMode,
2593                                            (FileObject->Flags &
2594                                             FO_ALERTABLE_IO) != 0,
2595                                            NULL);
2596             if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2597             {
2598                 /* Abort the request */
2599                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2600             }
2601 
2602             /* Set the final status */
2603             Status = FileObject->FinalStatus;
2604 
2605             /* Release the file lock */
2606             IopUnlockFileObject(FileObject);
2607         }
2608     }
2609     else
2610     {
2611         /* Free the event if we had one */
2612         if (LocalEvent)
2613         {
2614             /* Clear it in the IRP for completion */
2615             Irp->UserEvent = NULL;
2616             ExFreePoolWithTag(Event, TAG_IO);
2617         }
2618 
2619         /* Set the caller IOSB */
2620         Irp->UserIosb = IoStatusBlock;
2621 
2622         /* The IRP wasn't completed, complete it ourselves */
2623         KeRaiseIrql(APC_LEVEL, &OldIrql);
2624         IopCompleteRequest(&Irp->Tail.Apc,
2625                            &NormalRoutine,
2626                            &NormalContext,
2627                            (PVOID*)&FileObject,
2628                            &NormalContext);
2629         KeLowerIrql(OldIrql);
2630 
2631         /* Release the file object if we had locked it*/
2632         if (!LocalEvent) IopUnlockFileObject(FileObject);
2633     }
2634 
2635     /* Return the Status */
2636     return Status;
2637 }
2638 
2639 /*
2640  * @unimplemented
2641  */
2642 NTSTATUS
2643 NTAPI
2644 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2645                             OUT PIO_STATUS_BLOCK IoStatusBlock,
2646                             OUT PVOID Buffer,
2647                             IN ULONG Length,
2648                             IN BOOLEAN ReturnSingleEntry,
2649                             IN PVOID SidList OPTIONAL,
2650                             IN ULONG SidListLength,
2651                             IN PSID StartSid OPTIONAL,
2652                             IN BOOLEAN RestartScan)
2653 {
2654     UNIMPLEMENTED;
2655     return STATUS_NOT_IMPLEMENTED;
2656 }
2657 
2658 /*
2659  * @implemented
2660  */
2661 NTSTATUS
2662 NTAPI
2663 NtReadFile(IN HANDLE FileHandle,
2664            IN HANDLE Event OPTIONAL,
2665            IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2666            IN PVOID ApcContext OPTIONAL,
2667            OUT PIO_STATUS_BLOCK IoStatusBlock,
2668            OUT PVOID Buffer,
2669            IN ULONG Length,
2670            IN PLARGE_INTEGER ByteOffset OPTIONAL,
2671            IN PULONG Key OPTIONAL)
2672 {
2673     NTSTATUS Status;
2674     PFILE_OBJECT FileObject;
2675     PIRP Irp;
2676     PDEVICE_OBJECT DeviceObject;
2677     PIO_STACK_LOCATION StackPtr;
2678     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2679     PKEVENT EventObject = NULL;
2680     LARGE_INTEGER CapturedByteOffset;
2681     ULONG CapturedKey = 0;
2682     BOOLEAN Synchronous = FALSE;
2683     PMDL Mdl;
2684     PFAST_IO_DISPATCH FastIoDispatch;
2685     IO_STATUS_BLOCK KernelIosb;
2686     BOOLEAN Success;
2687 
2688     PAGED_CODE();
2689     CapturedByteOffset.QuadPart = 0;
2690     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2691 
2692     /* Get File Object */
2693     Status = ObReferenceObjectByHandle(FileHandle,
2694                                        FILE_READ_DATA,
2695                                        IoFileObjectType,
2696                                        PreviousMode,
2697                                        (PVOID*)&FileObject,
2698                                        NULL);
2699     if (!NT_SUCCESS(Status)) return Status;
2700 
2701     /* Get the device object */
2702     DeviceObject = IoGetRelatedDeviceObject(FileObject);
2703 
2704     /* Validate User-Mode Buffers */
2705     if (PreviousMode != KernelMode)
2706     {
2707         _SEH2_TRY
2708         {
2709             /* Probe the status block */
2710             ProbeForWriteIoStatusBlock(IoStatusBlock);
2711 
2712             /* Probe the read buffer */
2713             ProbeForWrite(Buffer, Length, 1);
2714 
2715             /* Check if we got a byte offset */
2716             if (ByteOffset)
2717             {
2718                 /* Capture and probe it */
2719                 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2720             }
2721 
2722             /* Perform additional checks for non-cached file access */
2723             if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
2724             {
2725                 /* Fail if Length is not sector size aligned
2726                  * Perform a quick check for 2^ sector sizes
2727                  * If it fails, try a more standard way
2728                  */
2729                 if ((DeviceObject->SectorSize != 0) &&
2730                     ((DeviceObject->SectorSize - 1) & Length) != 0)
2731                 {
2732                     if (Length % DeviceObject->SectorSize != 0)
2733                     {
2734                         /* Release the file object and and fail */
2735                         ObDereferenceObject(FileObject);
2736                         return STATUS_INVALID_PARAMETER;
2737                     }
2738                 }
2739 
2740                 /* Fail if buffer doesn't match alignment requirements */
2741                 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
2742                 {
2743                     /* Release the file object and and fail */
2744                     ObDereferenceObject(FileObject);
2745                     return STATUS_INVALID_PARAMETER;
2746                 }
2747 
2748                 if (ByteOffset)
2749                 {
2750                     /* Fail if ByteOffset is not sector size aligned */
2751                     if ((DeviceObject->SectorSize != 0) &&
2752                         (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
2753                     {
2754                         /* Release the file object and and fail */
2755                         ObDereferenceObject(FileObject);
2756                         return STATUS_INVALID_PARAMETER;
2757                     }
2758                 }
2759             }
2760 
2761             /* Capture and probe the key */
2762             if (Key) CapturedKey = ProbeForReadUlong(Key);
2763         }
2764         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2765         {
2766             /* Release the file object and return the exception code */
2767             ObDereferenceObject(FileObject);
2768             _SEH2_YIELD(return _SEH2_GetExceptionCode());
2769         }
2770         _SEH2_END;
2771     }
2772     else
2773     {
2774         /* Kernel mode: capture directly */
2775         if (ByteOffset) CapturedByteOffset = *ByteOffset;
2776         if (Key) CapturedKey = *Key;
2777     }
2778 
2779     /* Check for event */
2780     if (Event)
2781     {
2782         /* Reference it */
2783         Status = ObReferenceObjectByHandle(Event,
2784                                            EVENT_MODIFY_STATE,
2785                                            ExEventObjectType,
2786                                            PreviousMode,
2787                                            (PVOID*)&EventObject,
2788                                            NULL);
2789         if (!NT_SUCCESS(Status))
2790         {
2791             /* Fail */
2792             ObDereferenceObject(FileObject);
2793             return Status;
2794         }
2795 
2796         /* Otherwise reset the event */
2797         KeClearEvent(EventObject);
2798     }
2799 
2800     /* Check if we should use Sync IO or not */
2801     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2802     {
2803         /* Lock the file object */
2804         Status = IopLockFileObject(FileObject, PreviousMode);
2805         if (Status != STATUS_SUCCESS)
2806         {
2807             if (EventObject) ObDereferenceObject(EventObject);
2808             ObDereferenceObject(FileObject);
2809             return Status;
2810         }
2811 
2812         /* Check if we don't have a byte offset available */
2813         if (!(ByteOffset) ||
2814             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2815              (CapturedByteOffset.u.HighPart == -1)))
2816         {
2817             /* Use the Current Byte Offset instead */
2818             CapturedByteOffset = FileObject->CurrentByteOffset;
2819         }
2820 
2821         /* If the file is cached, try fast I/O */
2822         if (FileObject->PrivateCacheMap)
2823         {
2824             /* Perform fast read */
2825             FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2826             ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
2827 
2828             Success = FastIoDispatch->FastIoRead(FileObject,
2829                                                  &CapturedByteOffset,
2830                                                  Length,
2831                                                  TRUE,
2832                                                  CapturedKey,
2833                                                  Buffer,
2834                                                  &KernelIosb,
2835                                                  DeviceObject);
2836 
2837             /* Only accept the result if we got a straightforward status */
2838             if (Success &&
2839                 (KernelIosb.Status == STATUS_SUCCESS ||
2840                  KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2841                  KernelIosb.Status == STATUS_END_OF_FILE))
2842             {
2843                 /* Fast path -- update transfer & operation counts */
2844                 IopUpdateOperationCount(IopReadTransfer);
2845                 IopUpdateTransferCount(IopReadTransfer,
2846                                        (ULONG)KernelIosb.Information);
2847 
2848                 /* Enter SEH to write the IOSB back */
2849                 _SEH2_TRY
2850                 {
2851                     /* Write it back to the caller */
2852                     *IoStatusBlock = KernelIosb;
2853                 }
2854                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2855                 {
2856                     /* The caller's IOSB was invalid, so fail */
2857                     if (EventObject) ObDereferenceObject(EventObject);
2858                     IopUnlockFileObject(FileObject);
2859                     ObDereferenceObject(FileObject);
2860                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
2861                 }
2862                 _SEH2_END;
2863 
2864                 /* Signal the completion event */
2865                 if (EventObject)
2866                 {
2867                     KeSetEvent(EventObject, 0, FALSE);
2868                     ObDereferenceObject(EventObject);
2869                 }
2870 
2871                 /* Clean up */
2872                 IopUnlockFileObject(FileObject);
2873                 ObDereferenceObject(FileObject);
2874                 return KernelIosb.Status;
2875             }
2876         }
2877 
2878         /* Remember we are sync */
2879         Synchronous = TRUE;
2880     }
2881     else if (!(ByteOffset) &&
2882              !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2883     {
2884         /* Otherwise, this was async I/O without a byte offset, so fail */
2885         if (EventObject) ObDereferenceObject(EventObject);
2886         ObDereferenceObject(FileObject);
2887         return STATUS_INVALID_PARAMETER;
2888     }
2889 
2890     /* Clear the File Object's event */
2891     KeClearEvent(&FileObject->Event);
2892 
2893     /* Allocate the IRP */
2894     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2895     if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2896 
2897     /* Set the IRP */
2898     Irp->Tail.Overlay.OriginalFileObject = FileObject;
2899     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2900     Irp->RequestorMode = PreviousMode;
2901     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2902     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2903     Irp->UserIosb = IoStatusBlock;
2904     Irp->UserEvent = EventObject;
2905     Irp->PendingReturned = FALSE;
2906     Irp->Cancel = FALSE;
2907     Irp->CancelRoutine = NULL;
2908     Irp->AssociatedIrp.SystemBuffer = NULL;
2909     Irp->MdlAddress = NULL;
2910 
2911     /* Set the Stack Data */
2912     StackPtr = IoGetNextIrpStackLocation(Irp);
2913     StackPtr->MajorFunction = IRP_MJ_READ;
2914     StackPtr->FileObject = FileObject;
2915     StackPtr->Parameters.Read.Key = CapturedKey;
2916     StackPtr->Parameters.Read.Length = Length;
2917     StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2918 
2919     /* Check if this is buffered I/O */
2920     if (DeviceObject->Flags & DO_BUFFERED_IO)
2921     {
2922         /* Check if we have a buffer length */
2923         if (Length)
2924         {
2925             /* Enter SEH */
2926             _SEH2_TRY
2927             {
2928                 /* Allocate a buffer */
2929                 Irp->AssociatedIrp.SystemBuffer =
2930                     ExAllocatePoolWithTag(NonPagedPool,
2931                                           Length,
2932                                           TAG_SYSB);
2933             }
2934             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2935             {
2936                 /* Allocating failed, clean up and return the exception code */
2937                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2938                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2939             }
2940             _SEH2_END;
2941 
2942             /* Set the buffer and flags */
2943             Irp->UserBuffer = Buffer;
2944             Irp->Flags = (IRP_BUFFERED_IO |
2945                           IRP_DEALLOCATE_BUFFER |
2946                           IRP_INPUT_OPERATION);
2947         }
2948         else
2949         {
2950             /* Not reading anything */
2951             Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2952         }
2953     }
2954     else if (DeviceObject->Flags & DO_DIRECT_IO)
2955     {
2956         /* Check if we have a buffer length */
2957         if (Length)
2958         {
2959             _SEH2_TRY
2960             {
2961                 /* Allocate an MDL */
2962                 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2963                 if (!Mdl)
2964                     ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2965                 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2966             }
2967             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2968             {
2969                 /* Allocating failed, clean up and return the exception code */
2970                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2971                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2972             }
2973             _SEH2_END;
2974 
2975         }
2976 
2977         /* No allocation flags */
2978         Irp->Flags = 0;
2979     }
2980     else
2981     {
2982         /* No allocation flags, and use the buffer directly */
2983         Irp->Flags = 0;
2984         Irp->UserBuffer = Buffer;
2985     }
2986 
2987     /* Now set the deferred read flags */
2988     Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2989 #if 0
2990     /* FIXME: VFAT SUCKS */
2991     if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2992 #endif
2993 
2994     /* Perform the call */
2995     return IopPerformSynchronousRequest(DeviceObject,
2996                                         Irp,
2997                                         FileObject,
2998                                         TRUE,
2999                                         PreviousMode,
3000                                         Synchronous,
3001                                         IopReadTransfer);
3002 }
3003 
3004 /*
3005  * @unimplemented
3006  */
3007 NTSTATUS
3008 NTAPI
3009 NtReadFileScatter(IN HANDLE FileHandle,
3010                   IN HANDLE Event OPTIONAL,
3011                   IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3012                   IN PVOID UserApcContext OPTIONAL,
3013                   OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3014                   IN FILE_SEGMENT_ELEMENT BufferDescription [],
3015                   IN ULONG BufferLength,
3016                   IN PLARGE_INTEGER  ByteOffset,
3017                   IN PULONG Key OPTIONAL)
3018 {
3019     UNIMPLEMENTED;
3020     return STATUS_NOT_IMPLEMENTED;
3021 }
3022 
3023 /*
3024  * @unimplemented
3025  */
3026 NTSTATUS
3027 NTAPI
3028 NtSetEaFile(IN HANDLE FileHandle,
3029             IN PIO_STATUS_BLOCK IoStatusBlock,
3030             IN PVOID EaBuffer,
3031             IN ULONG EaBufferSize)
3032 {
3033     UNIMPLEMENTED;
3034     return STATUS_NOT_IMPLEMENTED;
3035 }
3036 
3037 /*
3038  * @implemented
3039  */
3040 NTSTATUS
3041 NTAPI
3042 NtSetInformationFile(IN HANDLE FileHandle,
3043                      OUT PIO_STATUS_BLOCK IoStatusBlock,
3044                      IN PVOID FileInformation,
3045                      IN ULONG Length,
3046                      IN FILE_INFORMATION_CLASS FileInformationClass)
3047 {
3048     PFILE_OBJECT FileObject;
3049     NTSTATUS Status;
3050     PIRP Irp;
3051     PDEVICE_OBJECT DeviceObject;
3052     PIO_STACK_LOCATION StackPtr;
3053     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3054     PKEVENT Event = NULL;
3055     BOOLEAN LocalEvent = FALSE;
3056     PKNORMAL_ROUTINE NormalRoutine;
3057     PVOID NormalContext;
3058     KIRQL OldIrql;
3059     IO_STATUS_BLOCK KernelIosb;
3060     PVOID Queue;
3061     PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
3062     PIO_COMPLETION_CONTEXT Context;
3063     PFILE_RENAME_INFORMATION RenameInfo;
3064     HANDLE TargetHandle = NULL;
3065     PAGED_CODE();
3066     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3067 
3068     /* Check if we're called from user mode */
3069     if (PreviousMode != KernelMode)
3070     {
3071         /* Validate the information class */
3072         if ((FileInformationClass < 0) ||
3073             (FileInformationClass >= FileMaximumInformation) ||
3074             !(IopSetOperationLength[FileInformationClass]))
3075         {
3076             /* Invalid class */
3077             return STATUS_INVALID_INFO_CLASS;
3078         }
3079 
3080         /* Validate the length */
3081         if (Length < IopSetOperationLength[FileInformationClass])
3082         {
3083             /* Invalid length */
3084             return STATUS_INFO_LENGTH_MISMATCH;
3085         }
3086 
3087         /* Enter SEH for probing */
3088         _SEH2_TRY
3089         {
3090             /* Probe the I/O Status block */
3091             ProbeForWriteIoStatusBlock(IoStatusBlock);
3092 
3093             /* Probe the information */
3094             ProbeForRead(FileInformation,
3095                          Length,
3096                          (Length == sizeof(BOOLEAN)) ?
3097                          sizeof(BOOLEAN) : sizeof(ULONG));
3098         }
3099         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3100         {
3101             /* Return the exception code */
3102             _SEH2_YIELD(return _SEH2_GetExceptionCode());
3103         }
3104         _SEH2_END;
3105     }
3106     else
3107     {
3108         /* Validate the information class */
3109         if ((FileInformationClass < 0) ||
3110             (FileInformationClass >= FileMaximumInformation) ||
3111             !(IopSetOperationLength[FileInformationClass]))
3112         {
3113             /* Invalid class */
3114             return STATUS_INVALID_INFO_CLASS;
3115         }
3116 
3117         /* Validate the length */
3118         if (Length < IopSetOperationLength[FileInformationClass])
3119         {
3120             /* Invalid length */
3121             return STATUS_INFO_LENGTH_MISMATCH;
3122         }
3123     }
3124 
3125     /* Reference the Handle */
3126     Status = ObReferenceObjectByHandle(FileHandle,
3127                                        IopSetOperationAccess
3128                                        [FileInformationClass],
3129                                        IoFileObjectType,
3130                                        PreviousMode,
3131                                        (PVOID *)&FileObject,
3132                                        NULL);
3133     if (!NT_SUCCESS(Status)) return Status;
3134 
3135     /* Check if this is a direct open or not */
3136     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3137     {
3138         /* Get the device object */
3139         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3140     }
3141     else
3142     {
3143         /* Get the device object */
3144         DeviceObject = IoGetRelatedDeviceObject(FileObject);
3145     }
3146 
3147     DPRINT("Will call: %p\n", DeviceObject);
3148     DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
3149 
3150     /* Check if this is a file that was opened for Synch I/O */
3151     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3152     {
3153         /* Lock it */
3154         Status = IopLockFileObject(FileObject, PreviousMode);
3155         if (Status != STATUS_SUCCESS)
3156         {
3157             ObDereferenceObject(FileObject);
3158             return Status;
3159         }
3160 
3161         /* Check if the caller just wants the position */
3162         if (FileInformationClass == FilePositionInformation)
3163         {
3164             /* Protect write in SEH */
3165             _SEH2_TRY
3166             {
3167                 /* Write the offset */
3168                 FileObject->CurrentByteOffset =
3169                     ((PFILE_POSITION_INFORMATION)FileInformation)->
3170                     CurrentByteOffset;
3171 
3172                 /* Fill out the I/O Status Block */
3173                 IoStatusBlock->Information = 0;
3174                 Status = IoStatusBlock->Status = STATUS_SUCCESS;
3175             }
3176             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3177             {
3178                 /* Get the exception code */
3179                 Status = _SEH2_GetExceptionCode();
3180             }
3181             _SEH2_END;
3182 
3183             /* Update transfer count */
3184             IopUpdateTransferCount(IopOtherTransfer, Length);
3185 
3186             /* Release the file lock, dereference the file and return */
3187             IopUnlockFileObject(FileObject);
3188             ObDereferenceObject(FileObject);
3189             return Status;
3190         }
3191     }
3192     else
3193     {
3194         /* Use local event */
3195         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3196         if (!Event)
3197         {
3198             ObDereferenceObject(FileObject);
3199             return STATUS_INSUFFICIENT_RESOURCES;
3200         }
3201 
3202         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3203         LocalEvent = TRUE;
3204     }
3205 
3206     /* Clear the File Object event */
3207     KeClearEvent(&FileObject->Event);
3208 
3209     /* Allocate the IRP */
3210     Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
3211     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3212 
3213     /* Set the IRP */
3214     Irp->Tail.Overlay.OriginalFileObject = FileObject;
3215     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3216     Irp->RequestorMode = PreviousMode;
3217     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3218     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3219     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3220     Irp->UserEvent = (LocalEvent) ? Event : NULL;
3221     Irp->AssociatedIrp.SystemBuffer = NULL;
3222     Irp->MdlAddress = NULL;
3223     Irp->UserBuffer = FileInformation;
3224 
3225     /* Set the Stack Data */
3226     StackPtr = IoGetNextIrpStackLocation(Irp);
3227     StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
3228     StackPtr->FileObject = FileObject;
3229 
3230     /* Enter SEH */
3231     _SEH2_TRY
3232     {
3233         /* Allocate a buffer */
3234         Irp->AssociatedIrp.SystemBuffer =
3235             ExAllocatePoolWithTag(NonPagedPool,
3236                                   Length,
3237                                   TAG_SYSB);
3238 
3239         /* Copy the data into it */
3240         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3241                       FileInformation,
3242                       Length);
3243     }
3244     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3245     {
3246         /* Allocating failed, clean up and return the exception code */
3247         IopCleanupAfterException(FileObject, Irp, NULL, Event);
3248         _SEH2_YIELD(return _SEH2_GetExceptionCode());
3249     }
3250     _SEH2_END;
3251 
3252     /* Set the flags */
3253     Irp->Flags |= (IRP_BUFFERED_IO |
3254                    IRP_DEALLOCATE_BUFFER |
3255                    IRP_DEFER_IO_COMPLETION);
3256 
3257     /* Set the Parameters */
3258     StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3259     StackPtr->Parameters.SetFile.Length = Length;
3260 
3261     /* Queue the IRP */
3262     IopQueueIrpToThread(Irp);
3263 
3264     /* Update operation counts */
3265     IopUpdateOperationCount(IopOtherTransfer);
3266 
3267     /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3268     /* Handle IO Completion Port quickly */
3269     if (FileInformationClass == FileCompletionInformation)
3270     {
3271         /* Check if the file object already has a completion port */
3272         if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3273             (FileObject->CompletionContext))
3274         {
3275             /* Fail */
3276             Status = STATUS_INVALID_PARAMETER;
3277         }
3278         else
3279         {
3280             /* Reference the Port */
3281             CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3282             Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3283                                                IO_COMPLETION_MODIFY_STATE,
3284                                                IoCompletionType,
3285                                                PreviousMode,
3286                                                (PVOID*)&Queue,
3287                                                NULL);
3288             if (NT_SUCCESS(Status))
3289             {
3290                 /* Allocate the Context */
3291                 Context = ExAllocatePoolWithTag(PagedPool,
3292                                                 sizeof(IO_COMPLETION_CONTEXT),
3293                                                 IOC_TAG);
3294                 if (Context)
3295                 {
3296                     /* Set the Data */
3297                     Context->Key = CompletionInfo->Key;
3298                     Context->Port = Queue;
3299                     if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
3300                                                           CompletionContext,
3301                                                           Context,
3302                                                           NULL))
3303                     {
3304                         /*
3305                          * Someone else set the completion port in the
3306                          * meanwhile, so dereference the port and fail.
3307                          */
3308                         ExFreePoolWithTag(Context, IOC_TAG);
3309                         ObDereferenceObject(Queue);
3310                         Status = STATUS_INVALID_PARAMETER;
3311                     }
3312                 }
3313                 else
3314                 {
3315                     /* Dereference the Port now */
3316                     ObDereferenceObject(Queue);
3317                     Status = STATUS_INSUFFICIENT_RESOURCES;
3318                 }
3319             }
3320         }
3321 
3322         /* Set the IRP Status */
3323         Irp->IoStatus.Status = Status;
3324         Irp->IoStatus.Information = 0;
3325     }
3326     else if (FileInformationClass == FileRenameInformation ||
3327              FileInformationClass == FileLinkInformation ||
3328              FileInformationClass == FileMoveClusterInformation)
3329     {
3330         /* Get associated information */
3331         RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3332 
3333         /* Only rename if:
3334          * -> We have a name
3335          * -> In unicode
3336          * -> sizes are valid
3337          */
3338         if (RenameInfo->FileNameLength != 0 &&
3339             !(RenameInfo->FileNameLength & 1) &&
3340             (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
3341         {
3342             /* Properly set information received */
3343             if (FileInformationClass == FileMoveClusterInformation)
3344             {
3345                 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3346             }
3347             else
3348             {
3349                 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3350             }
3351 
3352             /* If we got fully path OR relative target, attempt a parent directory open */
3353             if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3354             {
3355                 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
3356                 if (!NT_SUCCESS(Status))
3357                 {
3358                     Irp->IoStatus.Status = Status;
3359                 }
3360                 else
3361                 {
3362                     /* Call the Driver */
3363                     Status = IoCallDriver(DeviceObject, Irp);
3364                 }
3365             }
3366             else
3367             {
3368                 /* Call the Driver */
3369                 Status = IoCallDriver(DeviceObject, Irp);
3370             }
3371         }
3372         else
3373         {
3374             Status = STATUS_INVALID_PARAMETER;
3375             Irp->IoStatus.Status = Status;
3376         }
3377     }
3378     else
3379     {
3380         /* Call the Driver */
3381         Status = IoCallDriver(DeviceObject, Irp);
3382     }
3383 
3384     /* Check if we're waiting for the IRP to complete */
3385     if (Status == STATUS_PENDING)
3386     {
3387         /* Check if this was async I/O */
3388         if (LocalEvent)
3389         {
3390             /* Then to a non-alertable wait */
3391             Status = KeWaitForSingleObject(Event,
3392                                            Executive,
3393                                            PreviousMode,
3394                                            FALSE,
3395                                            NULL);
3396             if (Status == STATUS_USER_APC)
3397             {
3398                 /* Abort the request */
3399                 IopAbortInterruptedIrp(Event, Irp);
3400             }
3401 
3402             /* Set the final status */
3403             Status = KernelIosb.Status;
3404 
3405             /* Enter SEH to write the IOSB back */
3406             _SEH2_TRY
3407             {
3408                 /* Write it back to the caller */
3409                 *IoStatusBlock = KernelIosb;
3410             }
3411             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3412             {
3413                 /* Get the exception code */
3414                 Status = _SEH2_GetExceptionCode();
3415             }
3416             _SEH2_END;
3417 
3418             /* Free the event */
3419             ExFreePoolWithTag(Event, TAG_IO);
3420         }
3421         else
3422         {
3423             /* Wait for the IRP */
3424             Status = KeWaitForSingleObject(&FileObject->Event,
3425                                            Executive,
3426                                            PreviousMode,
3427                                            (FileObject->Flags &
3428                                             FO_ALERTABLE_IO) != 0,
3429                                            NULL);
3430             if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3431             {
3432                 /* Abort the request */
3433                 IopAbortInterruptedIrp(&FileObject->Event, Irp);
3434             }
3435 
3436             /* Set the final status */
3437             Status = FileObject->FinalStatus;
3438 
3439             /* Release the file lock */
3440             IopUnlockFileObject(FileObject);
3441         }
3442     }
3443     else
3444     {
3445         /* Free the event if we had one */
3446         if (LocalEvent)
3447         {
3448             /* Clear it in the IRP for completion */
3449             Irp->UserEvent = NULL;
3450             ExFreePoolWithTag(Event, TAG_IO);
3451         }
3452 
3453         /* Set the caller IOSB */
3454         Irp->UserIosb = IoStatusBlock;
3455 
3456         /* The IRP wasn't completed, complete it ourselves */
3457         KeRaiseIrql(APC_LEVEL, &OldIrql);
3458         IopCompleteRequest(&Irp->Tail.Apc,
3459                            &NormalRoutine,
3460                            &NormalContext,
3461                            (PVOID*)&FileObject,
3462                            &NormalContext);
3463         KeLowerIrql(OldIrql);
3464 
3465         /* Release the file object if we had locked it*/
3466         if (!LocalEvent) IopUnlockFileObject(FileObject);
3467     }
3468 
3469     if (TargetHandle != NULL)
3470     {
3471         ObCloseHandle(TargetHandle, KernelMode);
3472     }
3473 
3474     /* Return the Status */
3475     return Status;
3476 }
3477 
3478 /*
3479  * @unimplemented
3480  */
3481 NTSTATUS
3482 NTAPI
3483 NtSetQuotaInformationFile(IN HANDLE FileHandle,
3484                           OUT PIO_STATUS_BLOCK IoStatusBlock,
3485                           IN PVOID Buffer,
3486                           IN ULONG BufferLength)
3487 {
3488     UNIMPLEMENTED;
3489     return STATUS_NOT_IMPLEMENTED;
3490 }
3491 
3492 /*
3493  * @implemented
3494  */
3495 NTSTATUS
3496 NTAPI
3497 NtUnlockFile(IN HANDLE FileHandle,
3498              OUT PIO_STATUS_BLOCK IoStatusBlock,
3499              IN PLARGE_INTEGER ByteOffset,
3500              IN PLARGE_INTEGER Length,
3501              IN ULONG Key OPTIONAL)
3502 {
3503     PFILE_OBJECT FileObject;
3504     PLARGE_INTEGER LocalLength = NULL;
3505     PIRP Irp;
3506     PIO_STACK_LOCATION StackPtr;
3507     PDEVICE_OBJECT DeviceObject;
3508     PKEVENT Event = NULL;
3509     BOOLEAN LocalEvent = FALSE;
3510     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3511     LARGE_INTEGER CapturedByteOffset, CapturedLength;
3512     NTSTATUS Status;
3513     OBJECT_HANDLE_INFORMATION HandleInformation;
3514     IO_STATUS_BLOCK KernelIosb;
3515     PFAST_IO_DISPATCH FastIoDispatch;
3516     PAGED_CODE();
3517     CapturedByteOffset.QuadPart = 0;
3518     CapturedLength.QuadPart = 0;
3519     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3520 
3521     /* Get File Object */
3522     Status = ObReferenceObjectByHandle(FileHandle,
3523                                        0,
3524                                        IoFileObjectType,
3525                                        PreviousMode,
3526                                        (PVOID*)&FileObject,
3527                                        &HandleInformation);
3528     if (!NT_SUCCESS(Status)) return Status;
3529 
3530     /* Check if we're called from user mode */
3531     if (PreviousMode != KernelMode)
3532     {
3533         /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3534         if (!(HandleInformation.GrantedAccess &
3535             (FILE_WRITE_DATA | FILE_READ_DATA)))
3536         {
3537             ObDereferenceObject(FileObject);
3538             return STATUS_ACCESS_DENIED;
3539         }
3540 
3541         /* Enter SEH for probing */
3542         _SEH2_TRY
3543         {
3544             /* Probe the I/O Status block */
3545             ProbeForWriteIoStatusBlock(IoStatusBlock);
3546 
3547             /* Probe and capture the large integers */
3548             CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3549             CapturedLength = ProbeForReadLargeInteger(Length);
3550         }
3551         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3552         {
3553             /* Dereference the object and return exception code */
3554             ObDereferenceObject(FileObject);
3555             _SEH2_YIELD(return _SEH2_GetExceptionCode());
3556         }
3557         _SEH2_END;
3558     }
3559     else
3560     {
3561         /* Otherwise, capture them directly */
3562         CapturedByteOffset = *ByteOffset;
3563         CapturedLength = *Length;
3564     }
3565 
3566     /* Check if this is a direct open or not */
3567     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3568     {
3569         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3570     }
3571     else
3572     {
3573         DeviceObject = IoGetRelatedDeviceObject(FileObject);
3574     }
3575 
3576     /* Try to do it the FastIO way if possible */
3577     FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3578     if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
3579     {
3580         if (FastIoDispatch->FastIoUnlockSingle(FileObject,
3581                                                &CapturedByteOffset,
3582                                                &CapturedLength,
3583                                                PsGetCurrentProcess(),
3584                                                Key,
3585                                                &KernelIosb,
3586                                                DeviceObject))
3587         {
3588             /* Write the IOSB back */
3589             _SEH2_TRY
3590             {
3591                 *IoStatusBlock = KernelIosb;
3592             }
3593             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3594             {
3595                 KernelIosb.Status = _SEH2_GetExceptionCode();
3596             }
3597             _SEH2_END;
3598 
3599             /* We're done with FastIO! */
3600             ObDereferenceObject(FileObject);
3601             return KernelIosb.Status;
3602         }
3603     }
3604 
3605     /* Check if we should use Sync IO or not */
3606     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3607     {
3608         /* Lock it */
3609         Status = IopLockFileObject(FileObject, PreviousMode);
3610         if (Status != STATUS_SUCCESS)
3611         {
3612             ObDereferenceObject(FileObject);
3613             return Status;
3614         }
3615     }
3616     else
3617     {
3618         /* Use local event */
3619         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3620         if (!Event)
3621         {
3622             ObDereferenceObject(FileObject);
3623             return STATUS_INSUFFICIENT_RESOURCES;
3624         }
3625         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3626         LocalEvent = TRUE;
3627     }
3628 
3629     /* Clear File Object event */
3630     KeClearEvent(&FileObject->Event);
3631 
3632     /* Allocate the IRP */
3633     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3634     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3635 
3636     /* Set up the IRP */
3637     Irp->RequestorMode = PreviousMode;
3638     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3639     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3640     Irp->UserEvent = (LocalEvent) ? Event : NULL;
3641     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3642     Irp->Tail.Overlay.OriginalFileObject = FileObject;
3643     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3644 
3645     /* Set up Stack Data */
3646     StackPtr = IoGetNextIrpStackLocation(Irp);
3647     StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3648     StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3649     StackPtr->FileObject = FileObject;
3650 
3651     /* Enter SEH */
3652     _SEH2_TRY
3653     {
3654         /* Allocate a buffer */
3655         LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3656                                             sizeof(LARGE_INTEGER),
3657                                             TAG_LOCK);
3658 
3659         /* Set the length */
3660         *LocalLength = CapturedLength;
3661         Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3662         StackPtr->Parameters.LockControl.Length = LocalLength;
3663     }
3664     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3665     {
3666         /* Allocating failed, clean up and return the exception code */
3667         IopCleanupAfterException(FileObject, Irp, NULL, Event);
3668         if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3669 
3670         /* Return the exception code */
3671         _SEH2_YIELD(return _SEH2_GetExceptionCode());
3672     }
3673     _SEH2_END;
3674 
3675     /* Set Parameters */
3676     StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3677     StackPtr->Parameters.LockControl.Key = Key;
3678 
3679     /* Call the Driver */
3680     Status = IopPerformSynchronousRequest(DeviceObject,
3681                                           Irp,
3682                                           FileObject,
3683                                           FALSE,
3684                                           PreviousMode,
3685                                           !LocalEvent,
3686                                           IopOtherTransfer);
3687 
3688     /* Check if this was async I/O */
3689     if (LocalEvent)
3690     {
3691         /* It was, finalize this request */
3692         Status = IopFinalizeAsynchronousIo(Status,
3693                                            Event,
3694                                            Irp,
3695                                            PreviousMode,
3696                                            &KernelIosb,
3697                                            IoStatusBlock);
3698     }
3699 
3700     /* Return status */
3701     return Status;
3702 }
3703 
3704 /*
3705  * @implemented
3706  */
3707 NTSTATUS
3708 NTAPI
3709 NtWriteFile(IN HANDLE FileHandle,
3710             IN HANDLE Event OPTIONAL,
3711             IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3712             IN PVOID ApcContext OPTIONAL,
3713             OUT PIO_STATUS_BLOCK IoStatusBlock,
3714             IN PVOID Buffer,
3715             IN ULONG Length,
3716             IN PLARGE_INTEGER ByteOffset OPTIONAL,
3717             IN PULONG Key OPTIONAL)
3718 {
3719     NTSTATUS Status;
3720     PFILE_OBJECT FileObject;
3721     PIRP Irp;
3722     PDEVICE_OBJECT DeviceObject;
3723     PIO_STACK_LOCATION StackPtr;
3724     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3725     PKEVENT EventObject = NULL;
3726     LARGE_INTEGER CapturedByteOffset;
3727     ULONG CapturedKey = 0;
3728     BOOLEAN Synchronous = FALSE;
3729     PMDL Mdl;
3730     OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3731     PFAST_IO_DISPATCH FastIoDispatch;
3732     IO_STATUS_BLOCK KernelIosb;
3733     BOOLEAN Success;
3734 
3735     PAGED_CODE();
3736     CapturedByteOffset.QuadPart = 0;
3737     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3738 
3739     /* Get File Object for write */
3740     Status = ObReferenceFileObjectForWrite(FileHandle,
3741                                            PreviousMode,
3742                                            &FileObject,
3743                                            &ObjectHandleInfo);
3744     if (!NT_SUCCESS(Status)) return Status;
3745 
3746     /* Get the device object */
3747     DeviceObject = IoGetRelatedDeviceObject(FileObject);
3748 
3749     /* Validate User-Mode Buffers */
3750     if (PreviousMode != KernelMode)
3751     {
3752         _SEH2_TRY
3753         {
3754             /* Probe the status block */
3755             ProbeForWriteIoStatusBlock(IoStatusBlock);
3756 
3757             /* Probe the read buffer */
3758             ProbeForRead(Buffer, Length, 1);
3759 
3760             /* Check if we got a byte offset */
3761             if (ByteOffset)
3762             {
3763                 /* Capture and probe it */
3764                 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3765             }
3766 
3767             /* Perform additional checks for non-cached file access */
3768             if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
3769             {
3770                 /* Fail if Length is not sector size aligned
3771                  * Perform a quick check for 2^ sector sizes
3772                  * If it fails, try a more standard way
3773                  */
3774                 if ((DeviceObject->SectorSize != 0) &&
3775                     ((DeviceObject->SectorSize - 1) & Length) != 0)
3776                 {
3777                     if (Length % DeviceObject->SectorSize != 0)
3778                     {
3779                         /* Release the file object and and fail */
3780                         ObDereferenceObject(FileObject);
3781                         return STATUS_INVALID_PARAMETER;
3782                     }
3783                 }
3784 
3785                 /* Fail if buffer doesn't match alignment requirements */
3786                 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
3787                 {
3788                     /* Release the file object and and fail */
3789                     ObDereferenceObject(FileObject);
3790                     return STATUS_INVALID_PARAMETER;
3791                 }
3792 
3793                 if (ByteOffset)
3794                 {
3795                     /* Fail if ByteOffset is not sector size aligned */
3796                     if ((DeviceObject->SectorSize != 0) &&
3797                         (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
3798                     {
3799                         /* Only if that's not specific values for synchronous IO */
3800                         if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) &&
3801                             (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION ||
3802                              !BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)))
3803                         {
3804                             /* Release the file object and and fail */
3805                             ObDereferenceObject(FileObject);
3806                             return STATUS_INVALID_PARAMETER;
3807                         }
3808                     }
3809                 }
3810             }
3811 
3812             /* Capture and probe the key */
3813             if (Key) CapturedKey = ProbeForReadUlong(Key);
3814         }
3815         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3816         {
3817             /* Release the file object and return the exception code */
3818             ObDereferenceObject(FileObject);
3819             _SEH2_YIELD(return _SEH2_GetExceptionCode());
3820         }
3821         _SEH2_END;
3822     }
3823     else
3824     {
3825         /* Kernel mode: capture directly */
3826         if (ByteOffset) CapturedByteOffset = *ByteOffset;
3827         if (Key) CapturedKey = *Key;
3828     }
3829 
3830     /* Check if this is an append operation */
3831     if ((ObjectHandleInfo.GrantedAccess &
3832         (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3833     {
3834         /* Give the drivers something to understand */
3835         CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3836         CapturedByteOffset.u.HighPart = -1;
3837     }
3838 
3839     /* Check for event */
3840     if (Event)
3841     {
3842         /* Reference it */
3843         Status = ObReferenceObjectByHandle(Event,
3844                                            EVENT_MODIFY_STATE,
3845                                            ExEventObjectType,
3846                                            PreviousMode,
3847                                            (PVOID*)&EventObject,
3848                                            NULL);
3849         if (!NT_SUCCESS(Status))
3850         {
3851             /* Fail */
3852             ObDereferenceObject(FileObject);
3853             return Status;
3854         }
3855 
3856         /* Otherwise reset the event */
3857         KeClearEvent(EventObject);
3858     }
3859 
3860     /* Check if we should use Sync IO or not */
3861     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3862     {
3863         /* Lock the file object */
3864         Status = IopLockFileObject(FileObject, PreviousMode);
3865         if (Status != STATUS_SUCCESS)
3866         {
3867             if (EventObject) ObDereferenceObject(EventObject);
3868             ObDereferenceObject(FileObject);
3869             return Status;
3870         }
3871 
3872         /* Check if we don't have a byte offset available */
3873         if (!(ByteOffset) ||
3874             ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3875              (CapturedByteOffset.u.HighPart == -1)))
3876         {
3877             /* Use the Current Byte Offset instead */
3878             CapturedByteOffset = FileObject->CurrentByteOffset;
3879         }
3880 
3881         /* If the file is cached, try fast I/O */
3882         if (FileObject->PrivateCacheMap)
3883         {
3884             /* Perform fast write */
3885             FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3886             ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
3887 
3888             Success = FastIoDispatch->FastIoWrite(FileObject,
3889                                                   &CapturedByteOffset,
3890                                                   Length,
3891                                                   TRUE,
3892                                                   CapturedKey,
3893                                                   Buffer,
3894                                                   &KernelIosb,
3895                                                   DeviceObject);
3896 
3897             /* Only accept the result if it was successful */
3898             if (Success &&
3899                 KernelIosb.Status == STATUS_SUCCESS)
3900             {
3901                 /* Fast path -- update transfer & operation counts */
3902                 IopUpdateOperationCount(IopWriteTransfer);
3903                 IopUpdateTransferCount(IopWriteTransfer,
3904                                        (ULONG)KernelIosb.Information);
3905 
3906                 /* Enter SEH to write the IOSB back */
3907                 _SEH2_TRY
3908                 {
3909                     /* Write it back to the caller */
3910                     *IoStatusBlock = KernelIosb;
3911                 }
3912                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3913                 {
3914                     /* The caller's IOSB was invalid, so fail */
3915                     if (EventObject) ObDereferenceObject(EventObject);
3916                     IopUnlockFileObject(FileObject);
3917                     ObDereferenceObject(FileObject);
3918                     _SEH2_YIELD(return _SEH2_GetExceptionCode());
3919                 }
3920                 _SEH2_END;
3921 
3922                 /* Signal the completion event */
3923                 if (EventObject)
3924                 {
3925                     KeSetEvent(EventObject, 0, FALSE);
3926                     ObDereferenceObject(EventObject);
3927                 }
3928 
3929                 /* Clean up */
3930                 IopUnlockFileObject(FileObject);
3931                 ObDereferenceObject(FileObject);
3932                 return KernelIosb.Status;
3933             }
3934         }
3935 
3936         /* Remember we are sync */
3937         Synchronous = TRUE;
3938     }
3939     else if (!(ByteOffset) &&
3940              !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3941     {
3942         /* Otherwise, this was async I/O without a byte offset, so fail */
3943         if (EventObject) ObDereferenceObject(EventObject);
3944         ObDereferenceObject(FileObject);
3945         return STATUS_INVALID_PARAMETER;
3946     }
3947 
3948     /* Clear the File Object's event */
3949     KeClearEvent(&FileObject->Event);
3950 
3951     /* Allocate the IRP */
3952     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3953     if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
3954 
3955     /* Set the IRP */
3956     Irp->Tail.Overlay.OriginalFileObject = FileObject;
3957     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3958     Irp->RequestorMode = PreviousMode;
3959     Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3960     Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3961     Irp->UserIosb = IoStatusBlock;
3962     Irp->UserEvent = EventObject;
3963     Irp->PendingReturned = FALSE;
3964     Irp->Cancel = FALSE;
3965     Irp->CancelRoutine = NULL;
3966     Irp->AssociatedIrp.SystemBuffer = NULL;
3967     Irp->MdlAddress = NULL;
3968 
3969     /* Set the Stack Data */
3970     StackPtr = IoGetNextIrpStackLocation(Irp);
3971     StackPtr->MajorFunction = IRP_MJ_WRITE;
3972     StackPtr->FileObject = FileObject;
3973     StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3974                       SL_WRITE_THROUGH : 0;
3975     StackPtr->Parameters.Write.Key = CapturedKey;
3976     StackPtr->Parameters.Write.Length = Length;
3977     StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3978 
3979     /* Check if this is buffered I/O */
3980     if (DeviceObject->Flags & DO_BUFFERED_IO)
3981     {
3982         /* Check if we have a buffer length */
3983         if (Length)
3984         {
3985             /* Enter SEH */
3986             _SEH2_TRY
3987             {
3988                 /* Allocate a buffer */
3989                 Irp->AssociatedIrp.SystemBuffer =
3990                     ExAllocatePoolWithTag(NonPagedPool,
3991                                           Length,
3992                                           TAG_SYSB);
3993 
3994                 /* Copy the data into it */
3995                 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3996             }
3997             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3998             {
3999                 /* Allocating failed, clean up and return the exception code */
4000                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4001                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4002             }
4003             _SEH2_END;
4004 
4005             /* Set the flags */
4006             Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
4007         }
4008         else
4009         {
4010             /* Not writing anything */
4011             Irp->Flags = IRP_BUFFERED_IO;
4012         }
4013     }
4014     else if (DeviceObject->Flags & DO_DIRECT_IO)
4015     {
4016         /* Check if we have a buffer length */
4017         if (Length)
4018         {
4019             _SEH2_TRY
4020             {
4021                 /* Allocate an MDL */
4022                 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
4023                 if (!Mdl)
4024                     ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
4025                 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
4026             }
4027             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4028             {
4029                 /* Allocating failed, clean up and return the exception code */
4030                 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4031                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4032             }
4033             _SEH2_END;
4034         }
4035 
4036         /* No allocation flags */
4037         Irp->Flags = 0;
4038     }
4039     else
4040     {
4041         /* No allocation flags, and use the buffer directly */
4042         Irp->Flags = 0;
4043         Irp->UserBuffer = Buffer;
4044     }
4045 
4046     /* Now set the deferred read flags */
4047     Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
4048 #if 0
4049     /* FIXME: VFAT SUCKS */
4050     if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
4051 #endif
4052 
4053     /* Perform the call */
4054     return IopPerformSynchronousRequest(DeviceObject,
4055                                         Irp,
4056                                         FileObject,
4057                                         TRUE,
4058                                         PreviousMode,
4059                                         Synchronous,
4060                                         IopWriteTransfer);
4061 }
4062 
4063 NTSTATUS
4064 NTAPI
4065 NtWriteFileGather(IN HANDLE FileHandle,
4066                   IN HANDLE Event OPTIONAL,
4067                   IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
4068                   IN PVOID UserApcContext OPTIONAL,
4069                   OUT PIO_STATUS_BLOCK UserIoStatusBlock,
4070                   IN FILE_SEGMENT_ELEMENT BufferDescription [],
4071                   IN ULONG BufferLength,
4072                   IN PLARGE_INTEGER ByteOffset,
4073                   IN PULONG Key OPTIONAL)
4074 {
4075     UNIMPLEMENTED;
4076     return STATUS_NOT_IMPLEMENTED;
4077 }
4078 
4079 /*
4080  * @implemented
4081  */
4082 NTSTATUS
4083 NTAPI
4084 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
4085                              OUT PIO_STATUS_BLOCK IoStatusBlock,
4086                              OUT PVOID FsInformation,
4087                              IN ULONG Length,
4088                              IN FS_INFORMATION_CLASS FsInformationClass)
4089 {
4090     PFILE_OBJECT FileObject;
4091     PIRP Irp;
4092     PIO_STACK_LOCATION StackPtr;
4093     PDEVICE_OBJECT DeviceObject;
4094     PKEVENT Event = NULL;
4095     BOOLEAN LocalEvent = FALSE;
4096     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4097     NTSTATUS Status;
4098     IO_STATUS_BLOCK KernelIosb;
4099     PAGED_CODE();
4100     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4101 
4102     /* Check if we're called from user mode */
4103     if (PreviousMode != KernelMode)
4104     {
4105         /* Validate the information class */
4106         if ((FsInformationClass < 0) ||
4107             (FsInformationClass >= FileFsMaximumInformation) ||
4108             !(IopQueryFsOperationLength[FsInformationClass]))
4109         {
4110             /* Invalid class */
4111             return STATUS_INVALID_INFO_CLASS;
4112         }
4113 
4114         /* Validate the length */
4115         if (Length < IopQueryFsOperationLength[FsInformationClass])
4116         {
4117             /* Invalid length */
4118             return STATUS_INFO_LENGTH_MISMATCH;
4119         }
4120 
4121         /* Enter SEH for probing */
4122         _SEH2_TRY
4123         {
4124             /* Probe the I/O Status block */
4125             ProbeForWriteIoStatusBlock(IoStatusBlock);
4126 
4127             /* Probe the information */
4128             ProbeForWrite(FsInformation, Length, sizeof(ULONG));
4129         }
4130         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4131         {
4132             /* Return the exception code */
4133             _SEH2_YIELD(return _SEH2_GetExceptionCode());
4134         }
4135         _SEH2_END;
4136     }
4137 
4138     /* Get File Object */
4139     Status = ObReferenceObjectByHandle(FileHandle,
4140                                        IopQueryFsOperationAccess
4141                                        [FsInformationClass],
4142                                        IoFileObjectType,
4143                                        PreviousMode,
4144                                        (PVOID*)&FileObject,
4145                                        NULL);
4146     if (!NT_SUCCESS(Status)) return Status;
4147 
4148     /* Only allow direct device open for FileFsDeviceInformation */
4149     if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) &&
4150         FsInformationClass != FileFsDeviceInformation)
4151     {
4152         ObDereferenceObject(FileObject);
4153         return STATUS_INVALID_DEVICE_REQUEST;
4154     }
4155 
4156     /* Check if we should use Sync IO or not */
4157     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4158     {
4159         /* Lock it */
4160         Status = IopLockFileObject(FileObject, PreviousMode);
4161         if (Status != STATUS_SUCCESS)
4162         {
4163             ObDereferenceObject(FileObject);
4164             return Status;
4165         }
4166     }
4167 
4168     /*
4169      * Quick path for FileFsDeviceInformation - the kernel has enough
4170      * info to reply instead of the driver, excepted for network file systems
4171      */
4172     if (FsInformationClass == FileFsDeviceInformation &&
4173         (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) || FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM))
4174     {
4175         PFILE_FS_DEVICE_INFORMATION FsDeviceInfo = FsInformation;
4176         DeviceObject = FileObject->DeviceObject;
4177 
4178         _SEH2_TRY
4179         {
4180             FsDeviceInfo->DeviceType = DeviceObject->DeviceType;
4181 
4182             /* Complete characteristcs with mount status if relevant */
4183             FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
4184             if (IopGetMountFlag(DeviceObject))
4185             {
4186                 SetFlag(FsDeviceInfo->Characteristics, FILE_DEVICE_IS_MOUNTED);
4187             }
4188 
4189             IoStatusBlock->Information = sizeof(FILE_FS_DEVICE_INFORMATION);
4190             IoStatusBlock->Status = STATUS_SUCCESS;
4191         }
4192         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4193         {
4194             /* Check if we had a file lock */
4195             if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4196             {
4197                 /* Release it */
4198                 IopUnlockFileObject(FileObject);
4199             }
4200 
4201             /* Dereference the FO */
4202             ObDereferenceObject(FileObject);
4203 
4204             _SEH2_YIELD(return _SEH2_GetExceptionCode());
4205         }
4206         _SEH2_END;
4207 
4208         /* Check if we had a file lock */
4209         if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4210         {
4211             /* Release it */
4212             IopUnlockFileObject(FileObject);
4213         }
4214 
4215         /* Dereference the FO */
4216         ObDereferenceObject(FileObject);
4217 
4218         return STATUS_SUCCESS;
4219     }
4220     /* This is to be handled by the kernel, not by FSD */
4221     else if (FsInformationClass == FileFsDriverPathInformation)
4222     {
4223         PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo;
4224 
4225         _SEH2_TRY
4226         {
4227             /* Allocate our local structure */
4228             DriverPathInfo = ExAllocatePoolWithQuotaTag(NonPagedPool, Length, TAG_IO);
4229 
4230             /* And copy back caller data */
4231             RtlCopyMemory(DriverPathInfo, FsInformation, Length);
4232 
4233             /* Is the driver in the IO path? */
4234             Status = IopGetDriverPathInformation(FileObject, DriverPathInfo, Length);
4235             /* We failed, don't continue execution */
4236             if (!NT_SUCCESS(Status))
4237             {
4238                 RtlRaiseStatus(Status);
4239             }
4240 
4241             /* We succeed, copy back info */
4242             ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath;
4243 
4244             /* We're done */
4245             IoStatusBlock->Information = sizeof(FILE_FS_DRIVER_PATH_INFORMATION);
4246             IoStatusBlock->Status = STATUS_SUCCESS;
4247         }
4248         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4249         {
4250             Status = _SEH2_GetExceptionCode();
4251         }
4252         _SEH2_END;
4253 
4254         /* Don't leak */
4255         if (DriverPathInfo != NULL)
4256         {
4257             ExFreePoolWithTag(DriverPathInfo, TAG_IO);
4258         }
4259 
4260         /* Check if we had a file lock */
4261         if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4262         {
4263             /* Release it */
4264             IopUnlockFileObject(FileObject);
4265         }
4266 
4267         /* Dereference the FO */
4268         ObDereferenceObject(FileObject);
4269 
4270         return Status;
4271     }
4272 
4273     if (!BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4274     {
4275         /* Use local event */
4276         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
4277         if (!Event)
4278         {
4279             ObDereferenceObject(FileObject);
4280             return STATUS_INSUFFICIENT_RESOURCES;
4281         }
4282         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
4283         LocalEvent = TRUE;
4284     }
4285 
4286     /* Get the device object */
4287     DeviceObject = IoGetRelatedDeviceObject(FileObject);
4288 
4289     /* Clear File Object event */
4290     KeClearEvent(&FileObject->Event);
4291 
4292     /* Allocate the IRP */
4293     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4294     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
4295 
4296     /* Set up the IRP */
4297     Irp->RequestorMode = PreviousMode;
4298     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4299     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4300     Irp->UserEvent = (LocalEvent) ? Event : NULL;
4301     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4302     Irp->Tail.Overlay.OriginalFileObject = FileObject;
4303     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4304     Irp->UserBuffer = FsInformation;
4305     Irp->AssociatedIrp.SystemBuffer = NULL;
4306     Irp->MdlAddress = NULL;
4307 
4308     /* Set up Stack Data */
4309     StackPtr = IoGetNextIrpStackLocation(Irp);
4310     StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
4311     StackPtr->FileObject = FileObject;
4312 
4313     /* Enter SEH */
4314     _SEH2_TRY
4315     {
4316         /* Allocate a buffer */
4317         Irp->AssociatedIrp.SystemBuffer =
4318             ExAllocatePoolWithTag(NonPagedPool,
4319                                   Length,
4320                                   TAG_SYSB);
4321     }
4322     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4323     {
4324         /* Allocating failed, clean up and return the exception code */
4325         IopCleanupAfterException(FileObject, Irp, NULL, Event);
4326         _SEH2_YIELD(return _SEH2_GetExceptionCode());
4327     }
4328     _SEH2_END;
4329 
4330     /* Set the flags for this buffered + deferred I/O */
4331     Irp->Flags |= (IRP_BUFFERED_IO |
4332                    IRP_DEALLOCATE_BUFFER |
4333                    IRP_INPUT_OPERATION |
4334                    IRP_DEFER_IO_COMPLETION);
4335 
4336     /* Set Parameters */
4337     StackPtr->Parameters.QueryVolume.Length = Length;
4338     StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
4339 
4340     /* Call the Driver */
4341     Status = IopPerformSynchronousRequest(DeviceObject,
4342                                           Irp,
4343                                           FileObject,
4344                                           TRUE,
4345                                           PreviousMode,
4346                                           !LocalEvent,
4347                                           IopOtherTransfer);
4348 
4349     /* Check if this was async I/O */
4350     if (LocalEvent)
4351     {
4352         /* It was, finalize this request */
4353         Status = IopFinalizeAsynchronousIo(Status,
4354                                            Event,
4355                                            Irp,
4356                                            PreviousMode,
4357                                            &KernelIosb,
4358                                            IoStatusBlock);
4359     }
4360 
4361     /* Return status */
4362     return Status;
4363 }
4364 
4365 /*
4366  * @implemented
4367  */
4368 NTSTATUS
4369 NTAPI
4370 NtSetVolumeInformationFile(IN HANDLE FileHandle,
4371                            OUT PIO_STATUS_BLOCK IoStatusBlock,
4372                            IN PVOID FsInformation,
4373                            IN ULONG Length,
4374                            IN FS_INFORMATION_CLASS FsInformationClass)
4375 {
4376     PFILE_OBJECT FileObject;
4377     PIRP Irp;
4378     PIO_STACK_LOCATION StackPtr;
4379     PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
4380     PKEVENT Event = NULL;
4381     BOOLEAN LocalEvent = FALSE;
4382     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4383     NTSTATUS Status;
4384     IO_STATUS_BLOCK KernelIosb;
4385     TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
4386     PAGED_CODE();
4387     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4388 
4389     /* Check if we're called from user mode */
4390     if (PreviousMode != KernelMode)
4391     {
4392         /* Validate the information class */
4393         if ((FsInformationClass < 0) ||
4394             (FsInformationClass >= FileFsMaximumInformation) ||
4395             !(IopSetFsOperationLength[FsInformationClass]))
4396         {
4397             /* Invalid class */
4398             return STATUS_INVALID_INFO_CLASS;
4399         }
4400 
4401         /* Validate the length */
4402         if (Length < IopSetFsOperationLength[FsInformationClass])
4403         {
4404             /* Invalid length */
4405             return STATUS_INFO_LENGTH_MISMATCH;
4406         }
4407 
4408         /* Enter SEH for probing */
4409         _SEH2_TRY
4410         {
4411             /* Probe the I/O Status block */
4412             ProbeForWriteIoStatusBlock(IoStatusBlock);
4413 
4414             /* Probe the information */
4415             ProbeForRead(FsInformation, Length, sizeof(ULONG));
4416         }
4417         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4418         {
4419             /* Return the exception code */
4420             _SEH2_YIELD(return _SEH2_GetExceptionCode());
4421         }
4422         _SEH2_END;
4423     }
4424 
4425     /* Get File Object */
4426     Status = ObReferenceObjectByHandle(FileHandle,
4427                                        IopSetFsOperationAccess
4428                                        [FsInformationClass],
4429                                        IoFileObjectType,
4430                                        PreviousMode,
4431                                        (PVOID*)&FileObject,
4432                                        NULL);
4433     if (!NT_SUCCESS(Status)) return Status;
4434 
4435     /* Get target device for notification */
4436     Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
4437     if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
4438 
4439     /* Check if we should use Sync IO or not */
4440     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4441     {
4442         /* Lock it */
4443         Status = IopLockFileObject(FileObject, PreviousMode);
4444         if (Status != STATUS_SUCCESS)
4445         {
4446             ObDereferenceObject(FileObject);
4447             if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4448             return Status;
4449         }
4450     }
4451     else
4452     {
4453         /* Use local event */
4454         Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
4455         if (!Event)
4456         {
4457             ObDereferenceObject(FileObject);
4458             if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4459             return STATUS_INSUFFICIENT_RESOURCES;
4460         }
4461         KeInitializeEvent(Event, SynchronizationEvent, FALSE);
4462         LocalEvent = TRUE;
4463     }
4464 
4465     /* Get the device object */
4466     DeviceObject = IoGetRelatedDeviceObject(FileObject);
4467 
4468     /* Clear File Object event */
4469     KeClearEvent(&FileObject->Event);
4470 
4471     /* Allocate the IRP */
4472     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4473     if (!Irp)
4474     {
4475         if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4476         return IopCleanupFailedIrp(FileObject, NULL, Event);
4477     }
4478 
4479     /* Set up the IRP */
4480     Irp->RequestorMode = PreviousMode;
4481     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4482     Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4483     Irp->UserEvent = (LocalEvent) ? Event : NULL;
4484     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4485     Irp->Tail.Overlay.OriginalFileObject = FileObject;
4486     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4487     Irp->UserBuffer = FsInformation;
4488     Irp->AssociatedIrp.SystemBuffer = NULL;
4489     Irp->MdlAddress = NULL;
4490 
4491     /* Set up Stack Data */
4492     StackPtr = IoGetNextIrpStackLocation(Irp);
4493     StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
4494     StackPtr->FileObject = FileObject;
4495 
4496     /* Enter SEH */
4497     _SEH2_TRY
4498     {
4499         /* Allocate a buffer */
4500         Irp->AssociatedIrp.SystemBuffer =
4501             ExAllocatePoolWithTag(NonPagedPool,
4502                                   Length,
4503                                   TAG_SYSB);
4504 
4505         /* Copy the data into it */
4506         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
4507     }
4508     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4509     {
4510         /* Allocating failed, clean up and return the exception code */
4511         IopCleanupAfterException(FileObject, Irp, NULL, Event);
4512         if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4513         _SEH2_YIELD(return _SEH2_GetExceptionCode());
4514     }
4515     _SEH2_END;
4516 
4517     /* Set the flags for this buffered + deferred I/O */
4518     Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
4519 
4520     /* Set Parameters */
4521     StackPtr->Parameters.SetVolume.Length = Length;
4522     StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
4523 
4524     /* Call the Driver */
4525     Status = IopPerformSynchronousRequest(DeviceObject,
4526                                           Irp,
4527                                           FileObject,
4528                                           FALSE,
4529                                           PreviousMode,
4530                                           !LocalEvent,
4531                                           IopOtherTransfer);
4532 
4533     /* Check if this was async I/O */
4534     if (LocalEvent)
4535     {
4536         /* It was, finalize this request */
4537         Status = IopFinalizeAsynchronousIo(Status,
4538                                            Event,
4539                                            Irp,
4540                                            PreviousMode,
4541                                            &KernelIosb,
4542                                            IoStatusBlock);
4543     }
4544 
4545     if (TargetDeviceObject && NT_SUCCESS(Status))
4546     {
4547         /* Time to report change */
4548         NotificationStructure.Version = 1;
4549         NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
4550         NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
4551         NotificationStructure.FileObject = NULL;
4552         NotificationStructure.NameBufferOffset = - 1;
4553         Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
4554     }
4555 
4556     /* Return status */
4557     return Status;
4558 }
4559 
4560 /*
4561  * @unimplemented
4562  */
4563 NTSTATUS
4564 NTAPI
4565 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
4566 {
4567     UNIMPLEMENTED;
4568     return STATUS_NOT_IMPLEMENTED;
4569 }
4570 
4571 /*
4572  * @unimplemented
4573  */
4574 NTSTATUS
4575 NTAPI
4576 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
4577 {
4578     UNIMPLEMENTED;
4579     return STATUS_NOT_IMPLEMENTED;
4580 }
4581