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