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