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