[NTOS:IO]
[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're to dismount a volume, increaase the dismount count */
388 if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
389 {
390 InterlockedExchangeAdd((PLONG)&SharedUserData->DismountCount, 1);
391 }
392
393 /* Call the FSD */
394 if (FastIoDispatch->FastIoDeviceControl(FileObject,
395 TRUE,
396 InputBuffer,
397 InputBufferLength,
398 OutputBuffer,
399 OutputBufferLength,
400 IoControlCode,
401 &KernelIosb,
402 DeviceObject))
403 {
404 IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
405
406 /* Write the IOSB back */
407 _SEH2_TRY
408 {
409 *IoStatusBlock = KernelIosb;
410
411 }
412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
413 {
414 KernelIosb.Status = _SEH2_GetExceptionCode();
415 }
416 _SEH2_END;
417
418 /* Backup our complete context in case it exists */
419 if (FileObject->CompletionContext)
420 {
421 CompletionInfo = *(FileObject->CompletionContext);
422 }
423
424 /* If we had an event, signal it */
425 if (Event)
426 {
427 KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
428 ObDereferenceObject(EventObject);
429 }
430
431 /* If FO was locked, unlock it */
432 if (LockedForSynch)
433 {
434 IopUnlockFileObject(FileObject);
435 }
436
437 /* Set completion if required */
438 if (CompletionInfo.Port != NULL && UserApcContext != NULL)
439 {
440 if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
441 CompletionInfo.Key,
442 UserApcContext,
443 KernelIosb.Status,
444 KernelIosb.Information,
445 TRUE)))
446 {
447 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
448 }
449 }
450
451 /* We're done with FastIO! */
452 ObDereferenceObject(FileObject);
453 return KernelIosb.Status;
454 }
455 }
456 }
457
458 /* Clear the event */
459 KeClearEvent(&FileObject->Event);
460
461 /* Allocate IRP */
462 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
463 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
464
465 /* Setup the IRP */
466 Irp->UserIosb = IoStatusBlock;
467 Irp->UserEvent = EventObject;
468 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
469 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
470 Irp->Cancel = FALSE;
471 Irp->CancelRoutine = NULL;
472 Irp->PendingReturned = FALSE;
473 Irp->RequestorMode = PreviousMode;
474 Irp->MdlAddress = NULL;
475 Irp->AssociatedIrp.SystemBuffer = NULL;
476 Irp->Flags = 0;
477 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
478 Irp->Tail.Overlay.OriginalFileObject = FileObject;
479 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
480
481 /* Set stack location settings */
482 StackPtr = IoGetNextIrpStackLocation(Irp);
483 StackPtr->FileObject = FileObject;
484 StackPtr->MajorFunction = IsDevIoCtl ?
485 IRP_MJ_DEVICE_CONTROL :
486 IRP_MJ_FILE_SYSTEM_CONTROL;
487 StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
488 StackPtr->Control = 0;
489 StackPtr->Flags = 0;
490 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
491
492 /* Set the IOCTL Data */
493 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
494 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
495 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
496 OutputBufferLength;
497
498 /* Handle the Methods */
499 switch (AccessType)
500 {
501 /* Buffered I/O */
502 case METHOD_BUFFERED:
503
504 /* Enter SEH for allocations */
505 _SEH2_TRY
506 {
507 /* Select the right Buffer Length */
508 BufferLength = (InputBufferLength > OutputBufferLength) ?
509 InputBufferLength : OutputBufferLength;
510
511 /* Make sure there is one */
512 if (BufferLength)
513 {
514 /* Allocate the System Buffer */
515 Irp->AssociatedIrp.SystemBuffer =
516 ExAllocatePoolWithTag(NonPagedPool,
517 BufferLength,
518 TAG_SYS_BUF);
519
520 /* Check if we got a buffer */
521 if (InputBuffer)
522 {
523 /* Copy into the System Buffer */
524 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
525 InputBuffer,
526 InputBufferLength);
527 }
528
529 /* Write the flags */
530 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
531 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
532
533 /* Save the Buffer */
534 Irp->UserBuffer = OutputBuffer;
535 }
536 else
537 {
538 /* Clear the Flags and Buffer */
539 Irp->UserBuffer = NULL;
540 }
541 }
542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
543 {
544 /* Cleanup after exception and return */
545 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
546 _SEH2_YIELD(return _SEH2_GetExceptionCode());
547 }
548 _SEH2_END;
549 break;
550
551 /* Direct I/O */
552 case METHOD_IN_DIRECT:
553 case METHOD_OUT_DIRECT:
554
555 /* Enter SEH */
556 _SEH2_TRY
557 {
558 /* Check if we got an input buffer */
559 if ((InputBufferLength) && (InputBuffer))
560 {
561 /* Allocate the System Buffer */
562 Irp->AssociatedIrp.SystemBuffer =
563 ExAllocatePoolWithTag(NonPagedPool,
564 InputBufferLength,
565 TAG_SYS_BUF);
566
567 /* Copy into the System Buffer */
568 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
569 InputBuffer,
570 InputBufferLength);
571
572 /* Write the flags */
573 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
574 }
575
576 /* Check if we got an output buffer */
577 if (OutputBuffer)
578 {
579 /* Allocate the System Buffer */
580 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
581 OutputBufferLength,
582 FALSE,
583 FALSE,
584 Irp);
585 if (!Irp->MdlAddress)
586 {
587 /* Raise exception we'll catch */
588 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
589 }
590
591 /* Do the probe */
592 MmProbeAndLockPages(Irp->MdlAddress,
593 PreviousMode,
594 (AccessType == METHOD_IN_DIRECT) ?
595 IoReadAccess : IoWriteAccess);
596 }
597 }
598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
599 {
600 /* Cleanup after exception and return */
601 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
602 _SEH2_YIELD(return _SEH2_GetExceptionCode());
603 }
604 _SEH2_END;
605 break;
606
607 case METHOD_NEITHER:
608
609 /* Just save the Buffer */
610 Irp->UserBuffer = OutputBuffer;
611 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
612 }
613
614 /* Use deferred completion for FS I/O */
615 Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
616
617 /* If we're to dismount a volume, increaase the dismount count */
618 if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
619 {
620 InterlockedExchangeAdd((PLONG)&SharedUserData->DismountCount, 1);
621 }
622
623 /* Perform the call */
624 return IopPerformSynchronousRequest(DeviceObject,
625 Irp,
626 FileObject,
627 !IsDevIoCtl,
628 PreviousMode,
629 LockedForSynch,
630 IopOtherTransfer);
631 }
632
633 NTSTATUS
634 NTAPI
635 IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
636 IN ULONG InformationClass,
637 IN ULONG Length,
638 OUT PVOID Information,
639 OUT PULONG ReturnedLength,
640 IN BOOLEAN File)
641 {
642 IO_STATUS_BLOCK IoStatusBlock;
643 PIRP Irp;
644 PDEVICE_OBJECT DeviceObject;
645 PIO_STACK_LOCATION StackPtr;
646 BOOLEAN LocalEvent = FALSE;
647 KEVENT Event;
648 NTSTATUS Status;
649 PAGED_CODE();
650 IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
651 FileObject, InformationClass, File);
652
653 /* Reference the object */
654 ObReferenceObject(FileObject);
655
656 /* Check if this is a file that was opened for Synch I/O */
657 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
658 {
659 /* Lock it */
660 IopLockFileObject(FileObject);
661
662 /* Use File Object event */
663 KeClearEvent(&FileObject->Event);
664 }
665 else
666 {
667 /* Use local event */
668 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
669 LocalEvent = TRUE;
670 }
671
672 /* Get the Device Object */
673 DeviceObject = IoGetRelatedDeviceObject(FileObject);
674
675 /* Allocate the IRP */
676 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
677 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
678
679 /* Set the IRP */
680 Irp->Tail.Overlay.OriginalFileObject = FileObject;
681 Irp->RequestorMode = KernelMode;
682 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
683 Irp->UserIosb = &IoStatusBlock;
684 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
685 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
686 Irp->Flags |= IRP_BUFFERED_IO;
687 Irp->AssociatedIrp.SystemBuffer = Information;
688 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
689
690 /* Set the Stack Data */
691 StackPtr = IoGetNextIrpStackLocation(Irp);
692 StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION:
693 IRP_MJ_QUERY_VOLUME_INFORMATION;
694 StackPtr->FileObject = FileObject;
695
696 /* Check which type this is */
697 if (File)
698 {
699 /* Set Parameters */
700 StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
701 StackPtr->Parameters.QueryFile.Length = Length;
702 }
703 else
704 {
705 /* Set Parameters */
706 StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
707 StackPtr->Parameters.QueryVolume.Length = Length;
708 }
709
710 /* Queue the IRP */
711 IopQueueIrpToThread(Irp);
712
713 /* Call the Driver */
714 Status = IoCallDriver(DeviceObject, Irp);
715
716 /* Check if this was synch I/O */
717 if (!LocalEvent)
718 {
719 /* Check if the request is pending */
720 if (Status == STATUS_PENDING)
721 {
722 /* Wait on the file object */
723 Status = KeWaitForSingleObject(&FileObject->Event,
724 Executive,
725 KernelMode,
726 (FileObject->Flags &
727 FO_ALERTABLE_IO) != 0,
728 NULL);
729 if (Status == STATUS_ALERTED)
730 {
731 /* Abort the operation */
732 IopAbortInterruptedIrp(&FileObject->Event, Irp);
733 }
734
735 /* Get the final status */
736 Status = FileObject->FinalStatus;
737 }
738
739 /* Release the file lock */
740 IopUnlockFileObject(FileObject);
741 }
742 else if (Status == STATUS_PENDING)
743 {
744 /* Wait on the local event and get the final status */
745 KeWaitForSingleObject(&Event,
746 Executive,
747 KernelMode,
748 FALSE,
749 NULL);
750 Status = IoStatusBlock.Status;
751 }
752
753 /* Return the Length and Status. ReturnedLength is NOT optional */
754 *ReturnedLength = (ULONG)IoStatusBlock.Information;
755 return Status;
756 }
757
758 NTSTATUS
759 NTAPI
760 IopGetFileInformation(IN PFILE_OBJECT FileObject,
761 IN ULONG Length,
762 IN FILE_INFORMATION_CLASS FileInfoClass,
763 OUT PVOID Buffer,
764 OUT PULONG ReturnedLength)
765 {
766 PIRP Irp;
767 KEVENT Event;
768 NTSTATUS Status;
769 PIO_STACK_LOCATION Stack;
770 PDEVICE_OBJECT DeviceObject;
771 IO_STATUS_BLOCK IoStatusBlock;
772
773 PAGED_CODE();
774
775 /* Allocate an IRP */
776 ObReferenceObject(FileObject);
777 DeviceObject = IoGetRelatedDeviceObject(FileObject);
778 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
779 if (Irp == NULL)
780 {
781 ObDereferenceObject(FileObject);
782 return STATUS_INSUFFICIENT_RESOURCES;
783 }
784
785 /* Init event */
786 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
787
788 /* Setup the IRP */
789 Irp->UserIosb = &IoStatusBlock;
790 Irp->UserEvent = &Event;
791 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
792 Irp->RequestorMode = KernelMode;
793 Irp->AssociatedIrp.SystemBuffer = Buffer;
794 Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME;
795 Irp->Tail.Overlay.OriginalFileObject = FileObject;
796 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
797
798 Stack = IoGetNextIrpStackLocation(Irp);
799 Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
800 Stack->FileObject = FileObject;
801 Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
802 Stack->Parameters.QueryFile.Length = Length;
803
804
805 /* Queue the IRP */
806 IopQueueIrpToThread(Irp);
807
808 /* Call the driver */
809 Status = IoCallDriver(DeviceObject, Irp);
810 if (Status == STATUS_PENDING)
811 {
812 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
813 Status = IoStatusBlock.Status;
814 }
815
816 *ReturnedLength = IoStatusBlock.Information;
817 return Status;
818 }
819
820 NTSTATUS
821 NTAPI
822 IopGetBasicInformationFile(IN PFILE_OBJECT FileObject,
823 OUT PFILE_BASIC_INFORMATION BasicInfo)
824 {
825 ULONG ReturnedLength;
826 PDEVICE_OBJECT DeviceObject;
827 IO_STATUS_BLOCK IoStatusBlock;
828
829 PAGED_CODE();
830
831 /* Try to do it the fast way if possible */
832 DeviceObject = IoGetRelatedDeviceObject(FileObject);
833 if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
834 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
835 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
836 ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
837 BasicInfo,
838 &IoStatusBlock,
839 DeviceObject))
840 {
841 return IoStatusBlock.Status;
842 }
843
844 /* In case it failed, fall back to IRP-based method */
845 return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength);
846 }
847
848 NTSTATUS
849 NTAPI
850 IopOpenLinkOrRenameTarget(OUT PHANDLE Handle,
851 IN PIRP Irp,
852 IN PFILE_RENAME_INFORMATION RenameInfo,
853 IN PFILE_OBJECT FileObject)
854 {
855 NTSTATUS Status;
856 HANDLE TargetHandle;
857 UNICODE_STRING FileName;
858 PIO_STACK_LOCATION Stack;
859 PFILE_OBJECT TargetFileObject;
860 IO_STATUS_BLOCK IoStatusBlock;
861 FILE_BASIC_INFORMATION BasicInfo;
862 OBJECT_ATTRIBUTES ObjectAttributes;
863 OBJECT_HANDLE_INFORMATION HandleInformation;
864 ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
865
866 PAGED_CODE();
867
868 /* First, establish whether our target is a directory */
869 if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
870 {
871 Status = IopGetBasicInformationFile(FileObject, &BasicInfo);
872 if (!NT_SUCCESS(Status))
873 {
874 return Status;
875 }
876
877 if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
878 DesiredAccess = FILE_ADD_SUBDIRECTORY;
879 }
880 }
881
882 /* Setup the string to the target */
883 FileName.Buffer = RenameInfo->FileName;
884 FileName.Length = RenameInfo->FileNameLength;
885 FileName.MaximumLength = RenameInfo->FileNameLength;
886
887 InitializeObjectAttributes(&ObjectAttributes,
888 &FileName,
889 (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE,
890 RenameInfo->RootDirectory,
891 NULL);
892
893 /* And open its parent directory */
894 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
895 {
896 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
897 #if 0
898 /* Commented out - we don't support FO extension yet
899 * FIXME: Corrected last arg when it's supported
900 */
901 Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
902 DesiredAccess | SYNCHRONIZE,
903 &ObjectAttributes,
904 &IoStatusBlock,
905 NULL,
906 0,
907 FILE_SHARE_READ | FILE_SHARE_WRITE,
908 FILE_OPEN,
909 FILE_OPEN_FOR_BACKUP_INTENT,
910 NULL,
911 0,
912 CreateFileTypeNone,
913 NULL,
914 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
915 FileObject->DeviceObject);
916 #else
917 ASSERT(FALSE);
918 UNIMPLEMENTED;
919 return STATUS_NOT_IMPLEMENTED;
920 #endif
921 }
922 else
923 {
924 Status = IoCreateFile(&TargetHandle,
925 DesiredAccess | SYNCHRONIZE,
926 &ObjectAttributes,
927 &IoStatusBlock,
928 NULL,
929 0,
930 FILE_SHARE_READ | FILE_SHARE_WRITE,
931 FILE_OPEN,
932 FILE_OPEN_FOR_BACKUP_INTENT,
933 NULL,
934 0,
935 CreateFileTypeNone,
936 NULL,
937 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING);
938 }
939
940 if (!NT_SUCCESS(Status))
941 {
942 return Status;
943 }
944
945 /* Once open, continue only if:
946 * Target exists and we're allowed to overwrite it
947 */
948 Stack = IoGetNextIrpStackLocation(Irp);
949 if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
950 !RenameInfo->ReplaceIfExists &&
951 IoStatusBlock.Information == FILE_EXISTS)
952 {
953 ObCloseHandle(TargetHandle, KernelMode);
954 return STATUS_OBJECT_NAME_COLLISION;
955 }
956
957 /* Now, we'll get the associated device of the target, to check for same device location
958 * So, get the FO first
959 */
960 Status = ObReferenceObjectByHandle(TargetHandle,
961 FILE_WRITE_DATA,
962 IoFileObjectType,
963 KernelMode,
964 (PVOID *)&TargetFileObject,
965 &HandleInformation);
966 if (!NT_SUCCESS(Status))
967 {
968 ObCloseHandle(TargetHandle, KernelMode);
969 return Status;
970 }
971
972 /* We can dereference, we have the handle */
973 ObDereferenceObject(TargetFileObject);
974 /* If we're not on the same device, error out **/
975 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
976 {
977 ObCloseHandle(TargetHandle, KernelMode);
978 return STATUS_NOT_SAME_DEVICE;
979 }
980
981 /* Return parent directory file object and handle */
982 Stack->Parameters.SetFile.FileObject = TargetFileObject;
983 *Handle = TargetHandle;
984
985 return STATUS_SUCCESS;
986 }
987
988 static
989 ULONG
990 IopGetFileMode(IN PFILE_OBJECT FileObject)
991 {
992 ULONG Mode = 0;
993
994 if (FileObject->Flags & FO_WRITE_THROUGH)
995 Mode |= FILE_WRITE_THROUGH;
996
997 if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
998 Mode |= FILE_SEQUENTIAL_ONLY;
999
1000 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
1001 Mode |= FILE_NO_INTERMEDIATE_BUFFERING;
1002
1003 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1004 {
1005 if (FileObject->Flags & FO_ALERTABLE_IO)
1006 Mode |= FILE_SYNCHRONOUS_IO_ALERT;
1007 else
1008 Mode |= FILE_SYNCHRONOUS_IO_NONALERT;
1009 }
1010
1011 if (FileObject->Flags & FO_DELETE_ON_CLOSE)
1012 Mode |= FILE_DELETE_ON_CLOSE;
1013
1014 return Mode;
1015 }
1016
1017 /* PUBLIC FUNCTIONS **********************************************************/
1018
1019 /*
1020 * @implemented
1021 */
1022 NTSTATUS
1023 NTAPI
1024 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject,
1025 IN PMDL Mdl,
1026 IN PLARGE_INTEGER Offset,
1027 IN PKEVENT Event,
1028 IN PIO_STATUS_BLOCK StatusBlock)
1029 {
1030 PIRP Irp;
1031 PIO_STACK_LOCATION StackPtr;
1032 PDEVICE_OBJECT DeviceObject;
1033 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
1034 FileObject, Mdl, Offset);
1035
1036 /* Get the Device Object */
1037 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1038
1039 /* Allocate IRP */
1040 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1041 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1042
1043 /* Get the Stack */
1044 StackPtr = IoGetNextIrpStackLocation(Irp);
1045
1046 /* Create the IRP Settings */
1047 Irp->MdlAddress = Mdl;
1048 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1049 Irp->UserIosb = StatusBlock;
1050 Irp->UserEvent = Event;
1051 Irp->RequestorMode = KernelMode;
1052 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
1053 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1054 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1055
1056 /* Set the Stack Settings */
1057 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
1058 StackPtr->Parameters.Write.ByteOffset = *Offset;
1059 StackPtr->MajorFunction = IRP_MJ_WRITE;
1060 StackPtr->FileObject = FileObject;
1061
1062 /* Call the Driver */
1063 return IoCallDriver(DeviceObject, Irp);
1064 }
1065
1066 /*
1067 * @implemented
1068 */
1069 NTSTATUS
1070 NTAPI
1071 IoPageRead(IN PFILE_OBJECT FileObject,
1072 IN PMDL Mdl,
1073 IN PLARGE_INTEGER Offset,
1074 IN PKEVENT Event,
1075 IN PIO_STATUS_BLOCK StatusBlock)
1076 {
1077 PIRP Irp;
1078 PIO_STACK_LOCATION StackPtr;
1079 PDEVICE_OBJECT DeviceObject;
1080 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
1081 FileObject, Mdl, Offset);
1082
1083 /* Get the Device Object */
1084 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1085
1086 /* Allocate IRP */
1087 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1088 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1089
1090 /* Get the Stack */
1091 StackPtr = IoGetNextIrpStackLocation(Irp);
1092
1093 /* Create the IRP Settings */
1094 Irp->MdlAddress = Mdl;
1095 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1096 Irp->UserIosb = StatusBlock;
1097 Irp->UserEvent = Event;
1098 Irp->RequestorMode = KernelMode;
1099 Irp->Flags = IRP_PAGING_IO |
1100 IRP_NOCACHE |
1101 IRP_SYNCHRONOUS_PAGING_IO |
1102 IRP_INPUT_OPERATION;
1103 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1104 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1105
1106 /* Set the Stack Settings */
1107 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
1108 StackPtr->Parameters.Read.ByteOffset = *Offset;
1109 StackPtr->MajorFunction = IRP_MJ_READ;
1110 StackPtr->FileObject = FileObject;
1111
1112 /* Call the Driver */
1113 return IoCallDriver(DeviceObject, Irp);
1114 }
1115
1116 /*
1117 * @implemented
1118 */
1119 NTSTATUS
1120 NTAPI
1121 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
1122 IN FILE_INFORMATION_CLASS FileInformationClass,
1123 IN ULONG Length,
1124 OUT PVOID FileInformation,
1125 OUT PULONG ReturnedLength)
1126 {
1127 /* Call the shared routine */
1128 return IopQueryDeviceInformation(FileObject,
1129 FileInformationClass,
1130 Length,
1131 FileInformation,
1132 ReturnedLength,
1133 TRUE);
1134 }
1135
1136 /*
1137 * @implemented
1138 */
1139 NTSTATUS
1140 NTAPI
1141 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
1142 IN FS_INFORMATION_CLASS FsInformationClass,
1143 IN ULONG Length,
1144 OUT PVOID FsInformation,
1145 OUT PULONG ReturnedLength)
1146 {
1147 /* Call the shared routine */
1148 return IopQueryDeviceInformation(FileObject,
1149 FsInformationClass,
1150 Length,
1151 FsInformation,
1152 ReturnedLength,
1153 FALSE);
1154 }
1155
1156 /*
1157 * @implemented
1158 */
1159 NTSTATUS
1160 NTAPI
1161 IoSetInformation(IN PFILE_OBJECT FileObject,
1162 IN FILE_INFORMATION_CLASS FileInformationClass,
1163 IN ULONG Length,
1164 IN PVOID FileInformation)
1165 {
1166 IO_STATUS_BLOCK IoStatusBlock;
1167 PIRP Irp;
1168 PDEVICE_OBJECT DeviceObject;
1169 PIO_STACK_LOCATION StackPtr;
1170 BOOLEAN LocalEvent = FALSE;
1171 KEVENT Event;
1172 NTSTATUS Status;
1173 PAGED_CODE();
1174 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n",
1175 FileObject, FileInformationClass, Length);
1176
1177 /* Reference the object */
1178 ObReferenceObject(FileObject);
1179
1180 /* Check if this is a file that was opened for Synch I/O */
1181 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1182 {
1183 /* Lock it */
1184 IopLockFileObject(FileObject);
1185
1186 /* Use File Object event */
1187 KeClearEvent(&FileObject->Event);
1188 }
1189 else
1190 {
1191 /* Use local event */
1192 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1193 LocalEvent = TRUE;
1194 }
1195
1196 /* Get the Device Object */
1197 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1198
1199 /* Allocate the IRP */
1200 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1201 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1202
1203 /* Set the IRP */
1204 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1205 Irp->RequestorMode = KernelMode;
1206 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1207 Irp->UserIosb = &IoStatusBlock;
1208 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1209 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1210 Irp->Flags |= IRP_BUFFERED_IO;
1211 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1212 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1213
1214 /* Set the Stack Data */
1215 StackPtr = IoGetNextIrpStackLocation(Irp);
1216 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
1217 StackPtr->FileObject = FileObject;
1218
1219 /* Set Parameters */
1220 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1221 StackPtr->Parameters.SetFile.Length = Length;
1222
1223 /* Queue the IRP */
1224 IopQueueIrpToThread(Irp);
1225
1226 /* Call the Driver */
1227 Status = IoCallDriver(DeviceObject, Irp);
1228
1229 /* Check if this was synch I/O */
1230 if (!LocalEvent)
1231 {
1232 /* Check if the request is pending */
1233 if (Status == STATUS_PENDING)
1234 {
1235 /* Wait on the file object */
1236 Status = KeWaitForSingleObject(&FileObject->Event,
1237 Executive,
1238 KernelMode,
1239 (FileObject->Flags &
1240 FO_ALERTABLE_IO) != 0,
1241 NULL);
1242 if (Status == STATUS_ALERTED)
1243 {
1244 /* Abort the operation */
1245 IopAbortInterruptedIrp(&FileObject->Event, Irp);
1246 }
1247
1248 /* Get the final status */
1249 Status = FileObject->FinalStatus;
1250 }
1251
1252 /* Release the file lock */
1253 IopUnlockFileObject(FileObject);
1254 }
1255 else if (Status == STATUS_PENDING)
1256 {
1257 /* Wait on the local event and get the final status */
1258 KeWaitForSingleObject(&Event,
1259 Executive,
1260 KernelMode,
1261 FALSE,
1262 NULL);
1263 Status = IoStatusBlock.Status;
1264 }
1265
1266 /* Return the status */
1267 return Status;
1268 }
1269
1270 /* NATIVE SERVICES ***********************************************************/
1271
1272 /*
1273 * @implemented
1274 */
1275 NTSTATUS
1276 NTAPI
1277 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
1278 IN HANDLE Event OPTIONAL,
1279 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1280 IN PVOID UserApcContext OPTIONAL,
1281 OUT PIO_STATUS_BLOCK IoStatusBlock,
1282 IN ULONG IoControlCode,
1283 IN PVOID InputBuffer,
1284 IN ULONG InputBufferLength OPTIONAL,
1285 OUT PVOID OutputBuffer,
1286 IN ULONG OutputBufferLength OPTIONAL)
1287 {
1288 /* Call the Generic Function */
1289 return IopDeviceFsIoControl(DeviceHandle,
1290 Event,
1291 UserApcRoutine,
1292 UserApcContext,
1293 IoStatusBlock,
1294 IoControlCode,
1295 InputBuffer,
1296 InputBufferLength,
1297 OutputBuffer,
1298 OutputBufferLength,
1299 TRUE);
1300 }
1301
1302 /*
1303 * @implemented
1304 */
1305 NTSTATUS
1306 NTAPI
1307 NtFsControlFile(IN HANDLE DeviceHandle,
1308 IN HANDLE Event OPTIONAL,
1309 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1310 IN PVOID UserApcContext OPTIONAL,
1311 OUT PIO_STATUS_BLOCK IoStatusBlock,
1312 IN ULONG IoControlCode,
1313 IN PVOID InputBuffer,
1314 IN ULONG InputBufferLength OPTIONAL,
1315 OUT PVOID OutputBuffer,
1316 IN ULONG OutputBufferLength OPTIONAL)
1317 {
1318 /* Call the Generic Function */
1319 return IopDeviceFsIoControl(DeviceHandle,
1320 Event,
1321 UserApcRoutine,
1322 UserApcContext,
1323 IoStatusBlock,
1324 IoControlCode,
1325 InputBuffer,
1326 InputBufferLength,
1327 OutputBuffer,
1328 OutputBufferLength,
1329 FALSE);
1330 }
1331
1332 NTSTATUS
1333 NTAPI
1334 NtFlushBuffersFile(IN HANDLE FileHandle,
1335 OUT PIO_STATUS_BLOCK IoStatusBlock)
1336 {
1337 PFILE_OBJECT FileObject;
1338 PIRP Irp;
1339 PIO_STACK_LOCATION StackPtr;
1340 NTSTATUS Status;
1341 PDEVICE_OBJECT DeviceObject;
1342 PKEVENT Event = NULL;
1343 BOOLEAN LocalEvent = FALSE;
1344 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1345 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1346 IO_STATUS_BLOCK KernelIosb;
1347 PAGED_CODE();
1348 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1349
1350 if (PreviousMode != KernelMode)
1351 {
1352 /* Protect probes */
1353 _SEH2_TRY
1354 {
1355 /* Probe the I/O Status block */
1356 ProbeForWriteIoStatusBlock(IoStatusBlock);
1357 }
1358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1359 {
1360 /* Return the exception code */
1361 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1362 }
1363 _SEH2_END;
1364 }
1365
1366 /* Get the File Object */
1367 Status = ObReferenceObjectByHandle(FileHandle,
1368 0,
1369 IoFileObjectType,
1370 PreviousMode,
1371 (PVOID*)&FileObject,
1372 &ObjectHandleInfo);
1373 if (!NT_SUCCESS(Status)) return Status;
1374
1375 /*
1376 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1377 * granted. However, if this is a named pipe, make sure we don't ask for
1378 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1379 * access right!
1380 */
1381 if (!(ObjectHandleInfo.GrantedAccess &
1382 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1383 FILE_WRITE_DATA)))
1384 {
1385 /* We failed */
1386 ObDereferenceObject(FileObject);
1387 return STATUS_ACCESS_DENIED;
1388 }
1389
1390 /* Check if we should use Sync IO or not */
1391 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1392 {
1393 /* Lock it */
1394 IopLockFileObject(FileObject);
1395 }
1396 else
1397 {
1398 /* Use local event */
1399 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1400 if (!Event)
1401 {
1402 /* We failed */
1403 ObDereferenceObject(FileObject);
1404 return STATUS_INSUFFICIENT_RESOURCES;
1405 }
1406 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1407 LocalEvent = TRUE;
1408 }
1409
1410 /* Get the Device Object */
1411 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1412
1413 /* Clear the event */
1414 KeClearEvent(&FileObject->Event);
1415
1416 /* Allocate the IRP */
1417 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1418 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1419
1420 /* Set up the IRP */
1421 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1422 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1423 Irp->UserEvent = (LocalEvent) ? Event : NULL;
1424 Irp->RequestorMode = PreviousMode;
1425 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1426 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1427 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1428
1429 /* Set up Stack Data */
1430 StackPtr = IoGetNextIrpStackLocation(Irp);
1431 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1432 StackPtr->FileObject = FileObject;
1433
1434 /* Call the Driver */
1435 Status = IopPerformSynchronousRequest(DeviceObject,
1436 Irp,
1437 FileObject,
1438 FALSE,
1439 PreviousMode,
1440 !LocalEvent,
1441 IopOtherTransfer);
1442
1443 /* Check if this was async I/O */
1444 if (LocalEvent)
1445 {
1446 /* It was, finalize this request */
1447 Status = IopFinalizeAsynchronousIo(Status,
1448 Event,
1449 Irp,
1450 PreviousMode,
1451 &KernelIosb,
1452 IoStatusBlock);
1453 }
1454
1455 /* Return the Status */
1456 return Status;
1457 }
1458
1459 /*
1460 * @implemented
1461 */
1462 NTSTATUS
1463 NTAPI
1464 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1465 IN HANDLE EventHandle OPTIONAL,
1466 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1467 IN PVOID ApcContext OPTIONAL,
1468 OUT PIO_STATUS_BLOCK IoStatusBlock,
1469 OUT PVOID Buffer,
1470 IN ULONG BufferSize,
1471 IN ULONG CompletionFilter,
1472 IN BOOLEAN WatchTree)
1473 {
1474 PIRP Irp;
1475 PKEVENT Event = NULL;
1476 PDEVICE_OBJECT DeviceObject;
1477 PFILE_OBJECT FileObject;
1478 PIO_STACK_LOCATION IoStack;
1479 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1480 NTSTATUS Status;
1481 BOOLEAN LockedForSync = FALSE;
1482 PAGED_CODE();
1483 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1484
1485 /* Check if we're called from user mode */
1486 if (PreviousMode != KernelMode)
1487 {
1488 /* Enter SEH for probing */
1489 _SEH2_TRY
1490 {
1491 /* Probe the I/O STatus block */
1492 ProbeForWriteIoStatusBlock(IoStatusBlock);
1493
1494 /* Probe the buffer */
1495 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
1496 }
1497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1498 {
1499 /* Return the exception code */
1500 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1501 }
1502 _SEH2_END;
1503
1504 /* Check if CompletionFilter is valid */
1505 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
1506 {
1507 return STATUS_INVALID_PARAMETER;
1508 }
1509 }
1510
1511 /* Get File Object */
1512 Status = ObReferenceObjectByHandle(FileHandle,
1513 FILE_LIST_DIRECTORY,
1514 IoFileObjectType,
1515 PreviousMode,
1516 (PVOID*)&FileObject,
1517 NULL);
1518 if (!NT_SUCCESS(Status)) return Status;
1519
1520 /* Check if we have an event handle */
1521 if (EventHandle)
1522 {
1523 /* Reference it */
1524 Status = ObReferenceObjectByHandle(EventHandle,
1525 EVENT_MODIFY_STATE,
1526 ExEventObjectType,
1527 PreviousMode,
1528 (PVOID *)&Event,
1529 NULL);
1530 if (Status != STATUS_SUCCESS)
1531 {
1532 ObDereferenceObject(FileObject);
1533 return Status;
1534 }
1535 KeClearEvent(Event);
1536 }
1537
1538 /* Check if we should use Sync IO or not */
1539 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1540 {
1541 /* Lock it */
1542 IopLockFileObject(FileObject);
1543 LockedForSync = TRUE;
1544 }
1545
1546 /* Clear File Object event */
1547 KeClearEvent(&FileObject->Event);
1548
1549 /* Get the device object */
1550 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1551
1552 /* Allocate the IRP */
1553 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1554 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1555
1556 /* Set up the IRP */
1557 Irp->RequestorMode = PreviousMode;
1558 Irp->UserIosb = IoStatusBlock;
1559 Irp->UserEvent = Event;
1560 Irp->UserBuffer = Buffer;
1561 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1562 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1563 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1564 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1565
1566 /* Set up Stack Data */
1567 IoStack = IoGetNextIrpStackLocation(Irp);
1568 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1569 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
1570 IoStack->FileObject = FileObject;
1571
1572 /* Set parameters */
1573 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1574 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1575 if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1576
1577 /* Perform the call */
1578 return IopPerformSynchronousRequest(DeviceObject,
1579 Irp,
1580 FileObject,
1581 FALSE,
1582 PreviousMode,
1583 LockedForSync,
1584 IopOtherTransfer);
1585 }
1586
1587 /*
1588 * @implemented
1589 */
1590 NTSTATUS
1591 NTAPI
1592 NtLockFile(IN HANDLE FileHandle,
1593 IN HANDLE EventHandle OPTIONAL,
1594 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1595 IN PVOID ApcContext OPTIONAL,
1596 OUT PIO_STATUS_BLOCK IoStatusBlock,
1597 IN PLARGE_INTEGER ByteOffset,
1598 IN PLARGE_INTEGER Length,
1599 IN ULONG Key,
1600 IN BOOLEAN FailImmediately,
1601 IN BOOLEAN ExclusiveLock)
1602 {
1603 PFILE_OBJECT FileObject;
1604 PLARGE_INTEGER LocalLength = NULL;
1605 PIRP Irp;
1606 PIO_STACK_LOCATION StackPtr;
1607 PDEVICE_OBJECT DeviceObject;
1608 PKEVENT Event = NULL;
1609 BOOLEAN LockedForSync = FALSE;
1610 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1611 LARGE_INTEGER CapturedByteOffset, CapturedLength;
1612 NTSTATUS Status;
1613 OBJECT_HANDLE_INFORMATION HandleInformation;
1614 PFAST_IO_DISPATCH FastIoDispatch;
1615 PAGED_CODE();
1616 CapturedByteOffset.QuadPart = 0;
1617 CapturedLength.QuadPart = 0;
1618 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1619
1620 /* Get File Object */
1621 Status = ObReferenceObjectByHandle(FileHandle,
1622 0,
1623 IoFileObjectType,
1624 PreviousMode,
1625 (PVOID*)&FileObject,
1626 &HandleInformation);
1627 if (!NT_SUCCESS(Status)) return Status;
1628
1629 /* Check if we're called from user mode */
1630 if (PreviousMode != KernelMode)
1631 {
1632 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1633 if (!(HandleInformation.GrantedAccess &
1634 (FILE_WRITE_DATA | FILE_READ_DATA)))
1635 {
1636 ObDereferenceObject(FileObject);
1637 return STATUS_ACCESS_DENIED;
1638 }
1639
1640 /* Enter SEH for probing */
1641 _SEH2_TRY
1642 {
1643 /* Probe the I/O STatus block */
1644 ProbeForWriteIoStatusBlock(IoStatusBlock);
1645
1646 /* Probe and capture the large integers */
1647 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1648 CapturedLength = ProbeForReadLargeInteger(Length);
1649 }
1650 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1651 {
1652 /* Dereference the object and return exception code */
1653 ObDereferenceObject(FileObject);
1654 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1655 }
1656 _SEH2_END;
1657 }
1658 else
1659 {
1660 /* Otherwise, capture them directly */
1661 CapturedByteOffset = *ByteOffset;
1662 CapturedLength = *Length;
1663 }
1664
1665 /* Check if we have an event handle */
1666 if (EventHandle)
1667 {
1668 /* Reference it */
1669 Status = ObReferenceObjectByHandle(EventHandle,
1670 EVENT_MODIFY_STATE,
1671 ExEventObjectType,
1672 PreviousMode,
1673 (PVOID *)&Event,
1674 NULL);
1675 if (Status != STATUS_SUCCESS) return Status;
1676 KeClearEvent(Event);
1677 }
1678
1679 /* Get the device object */
1680 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1681
1682 /* Try to do it the FastIO way if possible */
1683 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
1684 if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
1685 {
1686 IO_STATUS_BLOCK KernelIosb;
1687
1688 if (FastIoDispatch->FastIoLock(FileObject,
1689 &CapturedByteOffset,
1690 &CapturedLength,
1691 PsGetCurrentProcess(),
1692 Key,
1693 FailImmediately,
1694 ExclusiveLock,
1695 &KernelIosb,
1696 DeviceObject))
1697 {
1698 /* Write the IOSB back */
1699 _SEH2_TRY
1700 {
1701 *IoStatusBlock = KernelIosb;
1702 }
1703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1704 {
1705 KernelIosb.Status = _SEH2_GetExceptionCode();
1706 }
1707 _SEH2_END;
1708
1709 /* If we had an event, signal it */
1710 if (EventHandle)
1711 {
1712 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1713 ObDereferenceObject(Event);
1714 }
1715
1716 /* Set completion if required */
1717 if (FileObject->CompletionContext != NULL && ApcContext != NULL)
1718 {
1719 if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
1720 FileObject->CompletionContext->Key,
1721 ApcContext,
1722 KernelIosb.Status,
1723 KernelIosb.Information,
1724 TRUE)))
1725 {
1726 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
1727 }
1728 }
1729
1730 FileObject->LockOperation = TRUE;
1731
1732 /* We're done with FastIO! */
1733 ObDereferenceObject(FileObject);
1734 return KernelIosb.Status;
1735 }
1736 }
1737
1738 /* Check if we should use Sync IO or not */
1739 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1740 {
1741 /* Lock it */
1742 IopLockFileObject(FileObject);
1743 LockedForSync = TRUE;
1744 }
1745
1746 /* Clear File Object event */
1747 KeClearEvent(&FileObject->Event);
1748 FileObject->LockOperation = TRUE;
1749
1750 /* Allocate the IRP */
1751 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1752 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1753
1754 /* Set up the IRP */
1755 Irp->RequestorMode = PreviousMode;
1756 Irp->UserIosb = IoStatusBlock;
1757 Irp->UserEvent = Event;
1758 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1759 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1760 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1761 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1762
1763 /* Set up Stack Data */
1764 StackPtr = IoGetNextIrpStackLocation(Irp);
1765 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1766 StackPtr->MinorFunction = IRP_MN_LOCK;
1767 StackPtr->FileObject = FileObject;
1768
1769 /* Allocate local buffer */
1770 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1771 sizeof(LARGE_INTEGER),
1772 TAG_LOCK);
1773 if (!LocalLength)
1774 {
1775 /* Allocating failed, clean up and return failure */
1776 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1777 return STATUS_INSUFFICIENT_RESOURCES;
1778 }
1779
1780 /* Set the length */
1781 *LocalLength = CapturedLength;
1782 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1783 StackPtr->Parameters.LockControl.Length = LocalLength;
1784
1785 /* Set Parameters */
1786 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1787 StackPtr->Parameters.LockControl.Key = Key;
1788
1789 /* Set Flags */
1790 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1791 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1792
1793 /* Perform the call */
1794 return IopPerformSynchronousRequest(DeviceObject,
1795 Irp,
1796 FileObject,
1797 FALSE,
1798 PreviousMode,
1799 LockedForSync,
1800 IopOtherTransfer);
1801 }
1802
1803 /*
1804 * @implemented
1805 */
1806 NTSTATUS
1807 NTAPI
1808 NtQueryDirectoryFile(IN HANDLE FileHandle,
1809 IN HANDLE EventHandle OPTIONAL,
1810 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1811 IN PVOID ApcContext OPTIONAL,
1812 OUT PIO_STATUS_BLOCK IoStatusBlock,
1813 OUT PVOID FileInformation,
1814 IN ULONG Length,
1815 IN FILE_INFORMATION_CLASS FileInformationClass,
1816 IN BOOLEAN ReturnSingleEntry,
1817 IN PUNICODE_STRING FileName OPTIONAL,
1818 IN BOOLEAN RestartScan)
1819 {
1820 PIRP Irp;
1821 PDEVICE_OBJECT DeviceObject;
1822 PFILE_OBJECT FileObject;
1823 PIO_STACK_LOCATION StackPtr;
1824 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1825 NTSTATUS Status;
1826 BOOLEAN LockedForSynch = FALSE;
1827 PKEVENT Event = NULL;
1828 volatile PVOID AuxBuffer = NULL;
1829 PMDL Mdl;
1830 UNICODE_STRING CapturedFileName;
1831 PUNICODE_STRING SearchPattern;
1832 PAGED_CODE();
1833 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1834
1835 /* Check if we came from user mode */
1836 if (PreviousMode != KernelMode)
1837 {
1838 /* Enter SEH for probing */
1839 _SEH2_TRY
1840 {
1841 /* Probe the I/O Status Block */
1842 ProbeForWriteIoStatusBlock(IoStatusBlock);
1843
1844 /* Probe the file information */
1845 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1846
1847 /* Check if we have a file name */
1848 if (FileName)
1849 {
1850 /* Capture it */
1851 CapturedFileName = ProbeForReadUnicodeString(FileName);
1852 if (CapturedFileName.Length)
1853 {
1854 /* Probe its buffer */
1855 ProbeForRead(CapturedFileName.Buffer,
1856 CapturedFileName.Length,
1857 1);
1858 }
1859
1860 /* Allocate the auxiliary buffer */
1861 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
1862 CapturedFileName.Length +
1863 sizeof(UNICODE_STRING),
1864 TAG_SYSB);
1865 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
1866 sizeof(UNICODE_STRING)),
1867 CapturedFileName.Buffer,
1868 CapturedFileName.Length);
1869
1870 /* Setup the search pattern */
1871 SearchPattern = (PUNICODE_STRING)AuxBuffer;
1872 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
1873 sizeof(UNICODE_STRING));
1874 SearchPattern->Length = CapturedFileName.Length;
1875 SearchPattern->MaximumLength = CapturedFileName.Length;
1876 }
1877 }
1878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1879 {
1880 /* Free buffer and return the exception code */
1881 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1882 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1883 }
1884 _SEH2_END;
1885 }
1886
1887 /* Get File Object */
1888 Status = ObReferenceObjectByHandle(FileHandle,
1889 FILE_LIST_DIRECTORY,
1890 IoFileObjectType,
1891 PreviousMode,
1892 (PVOID *)&FileObject,
1893 NULL);
1894 if (!NT_SUCCESS(Status))
1895 {
1896 /* Fail */
1897 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1898 return Status;
1899 }
1900
1901 /* Check if we have an even handle */
1902 if (EventHandle)
1903 {
1904 /* Get its pointer */
1905 Status = ObReferenceObjectByHandle(EventHandle,
1906 EVENT_MODIFY_STATE,
1907 ExEventObjectType,
1908 PreviousMode,
1909 (PVOID *)&Event,
1910 NULL);
1911 if (!NT_SUCCESS(Status))
1912 {
1913 /* Fail */
1914 ObDereferenceObject(FileObject);
1915 return Status;
1916 }
1917
1918 /* Clear it */
1919 KeClearEvent(Event);
1920 }
1921
1922 /* Check if this is a file that was opened for Synch I/O */
1923 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1924 {
1925 /* Lock it */
1926 IopLockFileObject(FileObject);
1927
1928 /* Remember to unlock later */
1929 LockedForSynch = TRUE;
1930 }
1931
1932 /* Get the device object */
1933 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1934
1935 /* Clear the File Object's event */
1936 KeClearEvent(&FileObject->Event);
1937
1938 /* Allocate the IRP */
1939 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1940 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
1941
1942 /* Set up the IRP */
1943 Irp->RequestorMode = PreviousMode;
1944 Irp->UserIosb = IoStatusBlock;
1945 Irp->UserEvent = Event;
1946 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1947 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1948 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1949 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1950 Irp->MdlAddress = NULL;
1951 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
1952 Irp->AssociatedIrp.SystemBuffer = NULL;
1953
1954 /* Check if this is buffered I/O */
1955 if (DeviceObject->Flags & DO_BUFFERED_IO)
1956 {
1957 /* Allocate a buffer */
1958 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
1959 Length,
1960 TAG_SYSB);
1961 if (!Irp->AssociatedIrp.SystemBuffer)
1962 {
1963 /* Allocating failed, clean up and return the exception code */
1964 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1965 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1966
1967 /* Return the exception code */
1968 return STATUS_INSUFFICIENT_RESOURCES;
1969 }
1970
1971 /* Set the buffer and flags */
1972 Irp->UserBuffer = FileInformation;
1973 Irp->Flags = (IRP_BUFFERED_IO |
1974 IRP_DEALLOCATE_BUFFER |
1975 IRP_INPUT_OPERATION);
1976 }
1977 else if (DeviceObject->Flags & DO_DIRECT_IO)
1978 {
1979 _SEH2_TRY
1980 {
1981 /* Allocate an MDL */
1982 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
1983 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
1984 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
1985 }
1986 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1987 {
1988 /* Allocating failed, clean up and return the exception code */
1989 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1990 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1991 }
1992 _SEH2_END;
1993 }
1994 else
1995 {
1996 /* No allocation flags, and use the buffer directly */
1997 Irp->UserBuffer = FileInformation;
1998 }
1999
2000 /* Set up Stack Data */
2001 StackPtr = IoGetNextIrpStackLocation(Irp);
2002 StackPtr->FileObject = FileObject;
2003 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2004 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
2005
2006 /* Set Parameters */
2007 StackPtr->Parameters.QueryDirectory.FileInformationClass =
2008 FileInformationClass;
2009 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
2010 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2011 StackPtr->Parameters.QueryDirectory.Length = Length;
2012 StackPtr->Flags = 0;
2013 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2014 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
2015
2016 /* Set deferred I/O */
2017 Irp->Flags |= IRP_DEFER_IO_COMPLETION;
2018
2019 /* Perform the call */
2020 return IopPerformSynchronousRequest(DeviceObject,
2021 Irp,
2022 FileObject,
2023 TRUE,
2024 PreviousMode,
2025 LockedForSynch,
2026 IopOtherTransfer);
2027 }
2028
2029 /*
2030 * @unimplemented
2031 */
2032 NTSTATUS
2033 NTAPI
2034 NtQueryEaFile(IN HANDLE FileHandle,
2035 OUT PIO_STATUS_BLOCK IoStatusBlock,
2036 OUT PVOID Buffer,
2037 IN ULONG Length,
2038 IN BOOLEAN ReturnSingleEntry,
2039 IN PVOID EaList OPTIONAL,
2040 IN ULONG EaListLength,
2041 IN PULONG EaIndex OPTIONAL,
2042 IN BOOLEAN RestartScan)
2043 {
2044 UNIMPLEMENTED;
2045 return STATUS_NOT_IMPLEMENTED;
2046 }
2047
2048 /*
2049 * @implemented
2050 */
2051 NTSTATUS
2052 NTAPI
2053 NtQueryInformationFile(IN HANDLE FileHandle,
2054 OUT PIO_STATUS_BLOCK IoStatusBlock,
2055 IN PVOID FileInformation,
2056 IN ULONG Length,
2057 IN FILE_INFORMATION_CLASS FileInformationClass)
2058 {
2059 OBJECT_HANDLE_INFORMATION HandleInformation;
2060 PFILE_OBJECT FileObject;
2061 NTSTATUS Status;
2062 PIRP Irp;
2063 PDEVICE_OBJECT DeviceObject;
2064 PIO_STACK_LOCATION StackPtr;
2065 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2066 PKEVENT Event = NULL;
2067 BOOLEAN LocalEvent = FALSE;
2068 PKNORMAL_ROUTINE NormalRoutine;
2069 PVOID NormalContext;
2070 KIRQL OldIrql;
2071 IO_STATUS_BLOCK KernelIosb;
2072 BOOLEAN CallDriver = TRUE;
2073 PFILE_ACCESS_INFORMATION AccessBuffer;
2074 PFILE_MODE_INFORMATION ModeBuffer;
2075 PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
2076 PFILE_ALL_INFORMATION AllBuffer;
2077 PFAST_IO_DISPATCH FastIoDispatch;
2078 PAGED_CODE();
2079 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2080
2081 /* Check if we're called from user mode */
2082 if (PreviousMode != KernelMode)
2083 {
2084 /* Validate the information class */
2085 if ((FileInformationClass >= FileMaximumInformation) ||
2086 !(IopQueryOperationLength[FileInformationClass]))
2087 {
2088 /* Invalid class */
2089 return STATUS_INVALID_INFO_CLASS;
2090 }
2091
2092 /* Validate the length */
2093 if (Length < IopQueryOperationLength[FileInformationClass])
2094 {
2095 /* Invalid length */
2096 return STATUS_INFO_LENGTH_MISMATCH;
2097 }
2098
2099 /* Enter SEH for probing */
2100 _SEH2_TRY
2101 {
2102 /* Probe the I/O Status block */
2103 ProbeForWriteIoStatusBlock(IoStatusBlock);
2104
2105 /* Probe the information */
2106 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
2107 }
2108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2109 {
2110 /* Return the exception code */
2111 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2112 }
2113 _SEH2_END;
2114 }
2115 else
2116 {
2117 /* Validate the information class */
2118 if ((FileInformationClass >= FileMaximumInformation) ||
2119 !(IopQueryOperationLength[FileInformationClass]))
2120 {
2121 /* Invalid class */
2122 return STATUS_INVALID_INFO_CLASS;
2123 }
2124
2125 /* Validate the length */
2126 if (Length < IopQueryOperationLength[FileInformationClass])
2127 {
2128 /* Invalid length */
2129 return STATUS_INFO_LENGTH_MISMATCH;
2130 }
2131 }
2132
2133 /* Reference the Handle */
2134 Status = ObReferenceObjectByHandle(FileHandle,
2135 IopQueryOperationAccess
2136 [FileInformationClass],
2137 IoFileObjectType,
2138 PreviousMode,
2139 (PVOID *)&FileObject,
2140 &HandleInformation);
2141 if (!NT_SUCCESS(Status)) return Status;
2142
2143 /* Check if this is a direct open or not */
2144 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2145 {
2146 /* Get the device object */
2147 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2148 }
2149 else
2150 {
2151 /* Get the device object */
2152 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2153 }
2154
2155 /* Check if this is a file that was opened for Synch I/O */
2156 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2157 {
2158 /* Lock it */
2159 IopLockFileObject(FileObject);
2160
2161 /* Check if the caller just wants the position */
2162 if (FileInformationClass == FilePositionInformation)
2163 {
2164 /* Protect write in SEH */
2165 _SEH2_TRY
2166 {
2167 /* Write the offset */
2168 ((PFILE_POSITION_INFORMATION)FileInformation)->
2169 CurrentByteOffset = FileObject->CurrentByteOffset;
2170
2171 /* Fill out the I/O Status Block */
2172 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
2173 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2174 }
2175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2176 {
2177 /* Get the exception code */
2178 Status = _SEH2_GetExceptionCode();
2179 }
2180 _SEH2_END;
2181
2182 /* Release the file lock, dereference the file and return */
2183 IopUnlockFileObject(FileObject);
2184 ObDereferenceObject(FileObject);
2185 return Status;
2186 }
2187 }
2188 else
2189 {
2190 /* Use local event */
2191 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2192 if (!Event)
2193 {
2194 ObDereferenceObject(FileObject);
2195 return STATUS_INSUFFICIENT_RESOURCES;
2196 }
2197 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2198 LocalEvent = TRUE;
2199 }
2200
2201 /* Check if FastIO is possible for the two available information classes */
2202 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2203 if (FastIoDispatch != NULL &&
2204 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
2205 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
2206 {
2207 BOOLEAN Success = FALSE;
2208
2209 if (FileInformationClass == FileBasicInformation)
2210 {
2211 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
2212 FileInformation,
2213 &KernelIosb,
2214 DeviceObject);
2215 }
2216 else
2217 {
2218 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
2219 FileInformation,
2220 &KernelIosb,
2221 DeviceObject);
2222 }
2223
2224 /* If call succeed */
2225 if (Success)
2226 {
2227 /* Write the IOSB back */
2228 _SEH2_TRY
2229 {
2230 *IoStatusBlock = KernelIosb;
2231 }
2232 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2233 {
2234 KernelIosb.Status = _SEH2_GetExceptionCode();
2235 }
2236 _SEH2_END;
2237
2238 /* Unlock FO */
2239 IopUnlockFileObject(FileObject);
2240
2241 /* We're done with FastIO! */
2242 ObDereferenceObject(FileObject);
2243 return KernelIosb.Status;
2244 }
2245 }
2246
2247 /* Clear the File Object event */
2248 KeClearEvent(&FileObject->Event);
2249
2250 /* Allocate the IRP */
2251 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2252 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2253
2254 /* Set the IRP */
2255 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2256 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2257 Irp->RequestorMode = PreviousMode;
2258 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2259 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2260 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2261 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2262 Irp->AssociatedIrp.SystemBuffer = NULL;
2263 Irp->MdlAddress = NULL;
2264 Irp->UserBuffer = FileInformation;
2265
2266 /* Set the Stack Data */
2267 StackPtr = IoGetNextIrpStackLocation(Irp);
2268 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2269 StackPtr->FileObject = FileObject;
2270
2271 /* Enter SEH */
2272 _SEH2_TRY
2273 {
2274 /* Allocate a buffer */
2275 Irp->AssociatedIrp.SystemBuffer =
2276 ExAllocatePoolWithTag(NonPagedPool,
2277 Length,
2278 TAG_SYSB);
2279 }
2280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2281 {
2282 /* Allocating failed, clean up and return the exception code */
2283 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2284 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2285 }
2286 _SEH2_END;
2287
2288 /* Set the flags */
2289 Irp->Flags |= (IRP_BUFFERED_IO |
2290 IRP_DEALLOCATE_BUFFER |
2291 IRP_INPUT_OPERATION |
2292 IRP_DEFER_IO_COMPLETION);
2293
2294 /* Set the Parameters */
2295 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2296 StackPtr->Parameters.QueryFile.Length = Length;
2297
2298 /* Queue the IRP */
2299 IopQueueIrpToThread(Irp);
2300
2301 /* Update operation counts */
2302 IopUpdateOperationCount(IopOtherTransfer);
2303
2304 /* Fill in file information before calling the driver.
2305 See 'File System Internals' page 485.*/
2306 if (FileInformationClass == FileAccessInformation)
2307 {
2308 AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2309 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2310 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2311 CallDriver = FALSE;
2312 }
2313 else if (FileInformationClass == FileModeInformation)
2314 {
2315 ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2316 ModeBuffer->Mode = IopGetFileMode(FileObject);
2317 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2318 CallDriver = FALSE;
2319 }
2320 else if (FileInformationClass == FileAlignmentInformation)
2321 {
2322 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2323 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2324 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2325 CallDriver = FALSE;
2326 }
2327 else if (FileInformationClass == FileAllInformation)
2328 {
2329 AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2330 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2331 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
2332 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2333 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2334 sizeof(FILE_MODE_INFORMATION) +
2335 sizeof(FILE_ALIGNMENT_INFORMATION);
2336 }
2337
2338 /* Call the Driver */
2339 if (CallDriver)
2340 {
2341 Status = IoCallDriver(DeviceObject, Irp);
2342 }
2343 else
2344 {
2345 Status = STATUS_SUCCESS;
2346 Irp->IoStatus.Status = STATUS_SUCCESS;
2347 }
2348
2349 if (Status == STATUS_PENDING)
2350 {
2351 /* Check if this was async I/O */
2352 if (LocalEvent)
2353 {
2354 /* Then to a non-alertable wait */
2355 Status = KeWaitForSingleObject(Event,
2356 Executive,
2357 PreviousMode,
2358 FALSE,
2359 NULL);
2360 if (Status == STATUS_USER_APC)
2361 {
2362 /* Abort the request */
2363 IopAbortInterruptedIrp(Event, Irp);
2364 }
2365
2366 /* Set the final status */
2367 Status = KernelIosb.Status;
2368
2369 /* Enter SEH to write the IOSB back */
2370 _SEH2_TRY
2371 {
2372 /* Write it back to the caller */
2373 *IoStatusBlock = KernelIosb;
2374 }
2375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2376 {
2377 /* Get the exception code */
2378 Status = _SEH2_GetExceptionCode();
2379 }
2380 _SEH2_END;
2381
2382 /* Free the event */
2383 ExFreePoolWithTag(Event, TAG_IO);
2384 }
2385 else
2386 {
2387 /* Wait for the IRP */
2388 Status = KeWaitForSingleObject(&FileObject->Event,
2389 Executive,
2390 PreviousMode,
2391 (FileObject->Flags &
2392 FO_ALERTABLE_IO) != 0,
2393 NULL);
2394 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2395 {
2396 /* Abort the request */
2397 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2398 }
2399
2400 /* Set the final status */
2401 Status = FileObject->FinalStatus;
2402
2403 /* Release the file lock */
2404 IopUnlockFileObject(FileObject);
2405 }
2406 }
2407 else
2408 {
2409 /* Free the event if we had one */
2410 if (LocalEvent)
2411 {
2412 /* Clear it in the IRP for completion */
2413 Irp->UserEvent = NULL;
2414 ExFreePoolWithTag(Event, TAG_IO);
2415 }
2416
2417 /* Set the caller IOSB */
2418 Irp->UserIosb = IoStatusBlock;
2419
2420 /* The IRP wasn't completed, complete it ourselves */
2421 KeRaiseIrql(APC_LEVEL, &OldIrql);
2422 IopCompleteRequest(&Irp->Tail.Apc,
2423 &NormalRoutine,
2424 &NormalContext,
2425 (PVOID*)&FileObject,
2426 &NormalContext);
2427 KeLowerIrql(OldIrql);
2428
2429 /* Release the file object if we had locked it*/
2430 if (!LocalEvent) IopUnlockFileObject(FileObject);
2431 }
2432
2433 /* Return the Status */
2434 return Status;
2435 }
2436
2437 /*
2438 * @unimplemented
2439 */
2440 NTSTATUS
2441 NTAPI
2442 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2443 OUT PIO_STATUS_BLOCK IoStatusBlock,
2444 OUT PVOID Buffer,
2445 IN ULONG Length,
2446 IN BOOLEAN ReturnSingleEntry,
2447 IN PVOID SidList OPTIONAL,
2448 IN ULONG SidListLength,
2449 IN PSID StartSid OPTIONAL,
2450 IN BOOLEAN RestartScan)
2451 {
2452 UNIMPLEMENTED;
2453 return STATUS_NOT_IMPLEMENTED;
2454 }
2455
2456 /*
2457 * @implemented
2458 */
2459 NTSTATUS
2460 NTAPI
2461 NtReadFile(IN HANDLE FileHandle,
2462 IN HANDLE Event OPTIONAL,
2463 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2464 IN PVOID ApcContext OPTIONAL,
2465 OUT PIO_STATUS_BLOCK IoStatusBlock,
2466 OUT PVOID Buffer,
2467 IN ULONG Length,
2468 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2469 IN PULONG Key OPTIONAL)
2470 {
2471 NTSTATUS Status;
2472 PFILE_OBJECT FileObject;
2473 PIRP Irp;
2474 PDEVICE_OBJECT DeviceObject;
2475 PIO_STACK_LOCATION StackPtr;
2476 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2477 PKEVENT EventObject = NULL;
2478 LARGE_INTEGER CapturedByteOffset;
2479 ULONG CapturedKey = 0;
2480 BOOLEAN Synchronous = FALSE;
2481 PMDL Mdl;
2482 PFAST_IO_DISPATCH FastIoDispatch;
2483 IO_STATUS_BLOCK KernelIosb;
2484 BOOLEAN Success;
2485
2486 PAGED_CODE();
2487 CapturedByteOffset.QuadPart = 0;
2488 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2489
2490 /* Validate User-Mode Buffers */
2491 if (PreviousMode != KernelMode)
2492 {
2493 _SEH2_TRY
2494 {
2495 /* Probe the status block */
2496 ProbeForWriteIoStatusBlock(IoStatusBlock);
2497
2498 /* Probe the read buffer */
2499 ProbeForWrite(Buffer, Length, 1);
2500
2501 /* Check if we got a byte offset */
2502 if (ByteOffset)
2503 {
2504 /* Capture and probe it */
2505 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2506 }
2507
2508 /* Capture and probe the key */
2509 if (Key) CapturedKey = ProbeForReadUlong(Key);
2510 }
2511 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2512 {
2513 /* Return the exception code */
2514 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2515 }
2516 _SEH2_END;
2517 }
2518 else
2519 {
2520 /* Kernel mode: capture directly */
2521 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2522 if (Key) CapturedKey = *Key;
2523 }
2524
2525 /* Get File Object */
2526 Status = ObReferenceObjectByHandle(FileHandle,
2527 FILE_READ_DATA,
2528 IoFileObjectType,
2529 PreviousMode,
2530 (PVOID*)&FileObject,
2531 NULL);
2532 if (!NT_SUCCESS(Status)) return Status;
2533
2534 /* Check for event */
2535 if (Event)
2536 {
2537 /* Reference it */
2538 Status = ObReferenceObjectByHandle(Event,
2539 EVENT_MODIFY_STATE,
2540 ExEventObjectType,
2541 PreviousMode,
2542 (PVOID*)&EventObject,
2543 NULL);
2544 if (!NT_SUCCESS(Status))
2545 {
2546 /* Fail */
2547 ObDereferenceObject(FileObject);
2548 return Status;
2549 }
2550
2551 /* Otherwise reset the event */
2552 KeClearEvent(EventObject);
2553 }
2554
2555 /* Get the device object */
2556 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2557
2558 /* Check if we should use Sync IO or not */
2559 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2560 {
2561 /* Lock the file object */
2562 IopLockFileObject(FileObject);
2563
2564 /* Check if we don't have a byte offset available */
2565 if (!(ByteOffset) ||
2566 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2567 (CapturedByteOffset.u.HighPart == -1)))
2568 {
2569 /* Use the Current Byte Offset instead */
2570 CapturedByteOffset = FileObject->CurrentByteOffset;
2571 }
2572
2573 /* If the file is cached, try fast I/O */
2574 if (FileObject->PrivateCacheMap)
2575 {
2576 /* Perform fast read */
2577 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2578 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
2579
2580 Success = FastIoDispatch->FastIoRead(FileObject,
2581 &CapturedByteOffset,
2582 Length,
2583 TRUE,
2584 CapturedKey,
2585 Buffer,
2586 &KernelIosb,
2587 DeviceObject);
2588
2589 /* Only accept the result if we got a straightforward status */
2590 if (Success &&
2591 (KernelIosb.Status == STATUS_SUCCESS ||
2592 KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2593 KernelIosb.Status == STATUS_END_OF_FILE))
2594 {
2595 /* Fast path -- update transfer & operation counts */
2596 IopUpdateOperationCount(IopReadTransfer);
2597 IopUpdateTransferCount(IopReadTransfer,
2598 (ULONG)KernelIosb.Information);
2599
2600 /* Enter SEH to write the IOSB back */
2601 _SEH2_TRY
2602 {
2603 /* Write it back to the caller */
2604 *IoStatusBlock = KernelIosb;
2605 }
2606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2607 {
2608 /* The caller's IOSB was invalid, so fail */
2609 if (EventObject) ObDereferenceObject(EventObject);
2610 IopUnlockFileObject(FileObject);
2611 ObDereferenceObject(FileObject);
2612 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2613 }
2614 _SEH2_END;
2615
2616 /* Signal the completion event */
2617 if (EventObject)
2618 {
2619 KeSetEvent(EventObject, 0, FALSE);
2620 ObDereferenceObject(EventObject);
2621 }
2622
2623 /* Clean up */
2624 IopUnlockFileObject(FileObject);
2625 ObDereferenceObject(FileObject);
2626 return KernelIosb.Status;
2627 }
2628 }
2629
2630 /* Remember we are sync */
2631 Synchronous = TRUE;
2632 }
2633 else if (!(ByteOffset) &&
2634 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2635 {
2636 /* Otherwise, this was async I/O without a byte offset, so fail */
2637 if (EventObject) ObDereferenceObject(EventObject);
2638 ObDereferenceObject(FileObject);
2639 return STATUS_INVALID_PARAMETER;
2640 }
2641
2642 /* Clear the File Object's event */
2643 KeClearEvent(&FileObject->Event);
2644
2645 /* Allocate the IRP */
2646 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2647 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2648
2649 /* Set the IRP */
2650 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2651 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2652 Irp->RequestorMode = PreviousMode;
2653 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2654 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2655 Irp->UserIosb = IoStatusBlock;
2656 Irp->UserEvent = EventObject;
2657 Irp->PendingReturned = FALSE;
2658 Irp->Cancel = FALSE;
2659 Irp->CancelRoutine = NULL;
2660 Irp->AssociatedIrp.SystemBuffer = NULL;
2661 Irp->MdlAddress = NULL;
2662
2663 /* Set the Stack Data */
2664 StackPtr = IoGetNextIrpStackLocation(Irp);
2665 StackPtr->MajorFunction = IRP_MJ_READ;
2666 StackPtr->FileObject = FileObject;
2667 StackPtr->Parameters.Read.Key = CapturedKey;
2668 StackPtr->Parameters.Read.Length = Length;
2669 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2670
2671 /* Check if this is buffered I/O */
2672 if (DeviceObject->Flags & DO_BUFFERED_IO)
2673 {
2674 /* Check if we have a buffer length */
2675 if (Length)
2676 {
2677 /* Enter SEH */
2678 _SEH2_TRY
2679 {
2680 /* Allocate a buffer */
2681 Irp->AssociatedIrp.SystemBuffer =
2682 ExAllocatePoolWithTag(NonPagedPool,
2683 Length,
2684 TAG_SYSB);
2685 }
2686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2687 {
2688 /* Allocating failed, clean up and return the exception code */
2689 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2690 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2691 }
2692 _SEH2_END;
2693
2694 /* Set the buffer and flags */
2695 Irp->UserBuffer = Buffer;
2696 Irp->Flags = (IRP_BUFFERED_IO |
2697 IRP_DEALLOCATE_BUFFER |
2698 IRP_INPUT_OPERATION);
2699 }
2700 else
2701 {
2702 /* Not reading anything */
2703 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2704 }
2705 }
2706 else if (DeviceObject->Flags & DO_DIRECT_IO)
2707 {
2708 /* Check if we have a buffer length */
2709 if (Length)
2710 {
2711 _SEH2_TRY
2712 {
2713 /* Allocate an MDL */
2714 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2715 if (!Mdl)
2716 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2717 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2718 }
2719 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2720 {
2721 /* Allocating failed, clean up and return the exception code */
2722 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2723 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2724 }
2725 _SEH2_END;
2726
2727 }
2728
2729 /* No allocation flags */
2730 Irp->Flags = 0;
2731 }
2732 else
2733 {
2734 /* No allocation flags, and use the buffer directly */
2735 Irp->Flags = 0;
2736 Irp->UserBuffer = Buffer;
2737 }
2738
2739 /* Now set the deferred read flags */
2740 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2741 #if 0
2742 /* FIXME: VFAT SUCKS */
2743 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2744 #endif
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;