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