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