01a956505f3190e4f868903daea521546bcd0991
[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 if ((DeviceObject->SectorSize != 0) &&
2617 (Length % DeviceObject->SectorSize != 0))
2618 {
2619 /* Release the file object and and fail */
2620 ObDereferenceObject(FileObject);
2621 return STATUS_INVALID_PARAMETER;
2622 }
2623
2624 /* Fail if buffer doesn't match alignment requirements */
2625 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
2626 {
2627 /* Release the file object and and fail */
2628 ObDereferenceObject(FileObject);
2629 return STATUS_INVALID_PARAMETER;
2630 }
2631
2632 if (ByteOffset)
2633 {
2634 /* Fail if ByteOffset is not sector size aligned */
2635 if ((DeviceObject->SectorSize != 0) &&
2636 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
2637 {
2638 /* Release the file object and and fail */
2639 ObDereferenceObject(FileObject);
2640 return STATUS_INVALID_PARAMETER;
2641 }
2642 }
2643 }
2644
2645 /* Capture and probe the key */
2646 if (Key) CapturedKey = ProbeForReadUlong(Key);
2647 }
2648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2649 {
2650 /* Release the file object and return the exception code */
2651 ObDereferenceObject(FileObject);
2652 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2653 }
2654 _SEH2_END;
2655 }
2656 else
2657 {
2658 /* Kernel mode: capture directly */
2659 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2660 if (Key) CapturedKey = *Key;
2661 }
2662
2663 /* Check for event */
2664 if (Event)
2665 {
2666 /* Reference it */
2667 Status = ObReferenceObjectByHandle(Event,
2668 EVENT_MODIFY_STATE,
2669 ExEventObjectType,
2670 PreviousMode,
2671 (PVOID*)&EventObject,
2672 NULL);
2673 if (!NT_SUCCESS(Status))
2674 {
2675 /* Fail */
2676 ObDereferenceObject(FileObject);
2677 return Status;
2678 }
2679
2680 /* Otherwise reset the event */
2681 KeClearEvent(EventObject);
2682 }
2683
2684 /* Check if we should use Sync IO or not */
2685 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2686 {
2687 /* Lock the file object */
2688 Status = IopLockFileObject(FileObject, PreviousMode);
2689 if (Status != STATUS_SUCCESS)
2690 {
2691 if (EventObject) ObDereferenceObject(EventObject);
2692 ObDereferenceObject(FileObject);
2693 return Status;
2694 }
2695
2696 /* Check if we don't have a byte offset available */
2697 if (!(ByteOffset) ||
2698 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2699 (CapturedByteOffset.u.HighPart == -1)))
2700 {
2701 /* Use the Current Byte Offset instead */
2702 CapturedByteOffset = FileObject->CurrentByteOffset;
2703 }
2704
2705 /* If the file is cached, try fast I/O */
2706 if (FileObject->PrivateCacheMap)
2707 {
2708 /* Perform fast read */
2709 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2710 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
2711
2712 Success = FastIoDispatch->FastIoRead(FileObject,
2713 &CapturedByteOffset,
2714 Length,
2715 TRUE,
2716 CapturedKey,
2717 Buffer,
2718 &KernelIosb,
2719 DeviceObject);
2720
2721 /* Only accept the result if we got a straightforward status */
2722 if (Success &&
2723 (KernelIosb.Status == STATUS_SUCCESS ||
2724 KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2725 KernelIosb.Status == STATUS_END_OF_FILE))
2726 {
2727 /* Fast path -- update transfer & operation counts */
2728 IopUpdateOperationCount(IopReadTransfer);
2729 IopUpdateTransferCount(IopReadTransfer,
2730 (ULONG)KernelIosb.Information);
2731
2732 /* Enter SEH to write the IOSB back */
2733 _SEH2_TRY
2734 {
2735 /* Write it back to the caller */
2736 *IoStatusBlock = KernelIosb;
2737 }
2738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2739 {
2740 /* The caller's IOSB was invalid, so fail */
2741 if (EventObject) ObDereferenceObject(EventObject);
2742 IopUnlockFileObject(FileObject);
2743 ObDereferenceObject(FileObject);
2744 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2745 }
2746 _SEH2_END;
2747
2748 /* Signal the completion event */
2749 if (EventObject)
2750 {
2751 KeSetEvent(EventObject, 0, FALSE);
2752 ObDereferenceObject(EventObject);
2753 }
2754
2755 /* Clean up */
2756 IopUnlockFileObject(FileObject);
2757 ObDereferenceObject(FileObject);
2758 return KernelIosb.Status;
2759 }
2760 }
2761
2762 /* Remember we are sync */
2763 Synchronous = TRUE;
2764 }
2765 else if (!(ByteOffset) &&
2766 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2767 {
2768 /* Otherwise, this was async I/O without a byte offset, so fail */
2769 if (EventObject) ObDereferenceObject(EventObject);
2770 ObDereferenceObject(FileObject);
2771 return STATUS_INVALID_PARAMETER;
2772 }
2773
2774 /* Clear the File Object's event */
2775 KeClearEvent(&FileObject->Event);
2776
2777 /* Allocate the IRP */
2778 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2779 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2780
2781 /* Set the IRP */
2782 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2783 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2784 Irp->RequestorMode = PreviousMode;
2785 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2786 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2787 Irp->UserIosb = IoStatusBlock;
2788 Irp->UserEvent = EventObject;
2789 Irp->PendingReturned = FALSE;
2790 Irp->Cancel = FALSE;
2791 Irp->CancelRoutine = NULL;
2792 Irp->AssociatedIrp.SystemBuffer = NULL;
2793 Irp->MdlAddress = NULL;
2794
2795 /* Set the Stack Data */
2796 StackPtr = IoGetNextIrpStackLocation(Irp);
2797 StackPtr->MajorFunction = IRP_MJ_READ;
2798 StackPtr->FileObject = FileObject;
2799 StackPtr->Parameters.Read.Key = CapturedKey;
2800 StackPtr->Parameters.Read.Length = Length;
2801 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2802
2803 /* Check if this is buffered I/O */
2804 if (DeviceObject->Flags & DO_BUFFERED_IO)
2805 {
2806 /* Check if we have a buffer length */
2807 if (Length)
2808 {
2809 /* Enter SEH */
2810 _SEH2_TRY
2811 {
2812 /* Allocate a buffer */
2813 Irp->AssociatedIrp.SystemBuffer =
2814 ExAllocatePoolWithTag(NonPagedPool,
2815 Length,
2816 TAG_SYSB);
2817 }
2818 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2819 {
2820 /* Allocating failed, clean up and return the exception code */
2821 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2822 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2823 }
2824 _SEH2_END;
2825
2826 /* Set the buffer and flags */
2827 Irp->UserBuffer = Buffer;
2828 Irp->Flags = (IRP_BUFFERED_IO |
2829 IRP_DEALLOCATE_BUFFER |
2830 IRP_INPUT_OPERATION);
2831 }
2832 else
2833 {
2834 /* Not reading anything */
2835 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2836 }
2837 }
2838 else if (DeviceObject->Flags & DO_DIRECT_IO)
2839 {
2840 /* Check if we have a buffer length */
2841 if (Length)
2842 {
2843 _SEH2_TRY
2844 {
2845 /* Allocate an MDL */
2846 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2847 if (!Mdl)
2848 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2849 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2850 }
2851 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2852 {
2853 /* Allocating failed, clean up and return the exception code */
2854 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2855 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2856 }
2857 _SEH2_END;
2858
2859 }
2860
2861 /* No allocation flags */
2862 Irp->Flags = 0;
2863 }
2864 else
2865 {
2866 /* No allocation flags, and use the buffer directly */
2867 Irp->Flags = 0;
2868 Irp->UserBuffer = Buffer;
2869 }
2870
2871 /* Now set the deferred read flags */
2872 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2873 #if 0
2874 /* FIXME: VFAT SUCKS */
2875 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2876 #endif
2877
2878 /* Perform the call */
2879 return IopPerformSynchronousRequest(DeviceObject,
2880 Irp,
2881 FileObject,
2882 TRUE,
2883 PreviousMode,
2884 Synchronous,
2885 IopReadTransfer);
2886 }
2887
2888 /*
2889 * @unimplemented
2890 */
2891 NTSTATUS
2892 NTAPI
2893 NtReadFileScatter(IN HANDLE FileHandle,
2894 IN HANDLE Event OPTIONAL,
2895 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2896 IN PVOID UserApcContext OPTIONAL,
2897 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2898 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2899 IN ULONG BufferLength,
2900 IN PLARGE_INTEGER ByteOffset,
2901 IN PULONG Key OPTIONAL)
2902 {
2903 UNIMPLEMENTED;
2904 return STATUS_NOT_IMPLEMENTED;
2905 }
2906
2907 /*
2908 * @unimplemented
2909 */
2910 NTSTATUS
2911 NTAPI
2912 NtSetEaFile(IN HANDLE FileHandle,
2913 IN PIO_STATUS_BLOCK IoStatusBlock,
2914 IN PVOID EaBuffer,
2915 IN ULONG EaBufferSize)
2916 {
2917 UNIMPLEMENTED;
2918 return STATUS_NOT_IMPLEMENTED;
2919 }
2920
2921 /*
2922 * @implemented
2923 */
2924 NTSTATUS
2925 NTAPI
2926 NtSetInformationFile(IN HANDLE FileHandle,
2927 OUT PIO_STATUS_BLOCK IoStatusBlock,
2928 IN PVOID FileInformation,
2929 IN ULONG Length,
2930 IN FILE_INFORMATION_CLASS FileInformationClass)
2931 {
2932 PFILE_OBJECT FileObject;
2933 NTSTATUS Status;
2934 PIRP Irp;
2935 PDEVICE_OBJECT DeviceObject;
2936 PIO_STACK_LOCATION StackPtr;
2937 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2938 PKEVENT Event = NULL;
2939 BOOLEAN LocalEvent = FALSE;
2940 PKNORMAL_ROUTINE NormalRoutine;
2941 PVOID NormalContext;
2942 KIRQL OldIrql;
2943 IO_STATUS_BLOCK KernelIosb;
2944 PVOID Queue;
2945 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2946 PIO_COMPLETION_CONTEXT Context;
2947 PFILE_RENAME_INFORMATION RenameInfo;
2948 HANDLE TargetHandle = NULL;
2949 PAGED_CODE();
2950 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2951
2952 /* Check if we're called from user mode */
2953 if (PreviousMode != KernelMode)
2954 {
2955 /* Validate the information class */
2956 if ((FileInformationClass >= FileMaximumInformation) ||
2957 !(IopSetOperationLength[FileInformationClass]))
2958 {
2959 /* Invalid class */
2960 return STATUS_INVALID_INFO_CLASS;
2961 }
2962
2963 /* Validate the length */
2964 if (Length < IopSetOperationLength[FileInformationClass])
2965 {
2966 /* Invalid length */
2967 return STATUS_INFO_LENGTH_MISMATCH;
2968 }
2969
2970 /* Enter SEH for probing */
2971 _SEH2_TRY
2972 {
2973 /* Probe the I/O Status block */
2974 ProbeForWriteIoStatusBlock(IoStatusBlock);
2975
2976 /* Probe the information */
2977 ProbeForRead(FileInformation,
2978 Length,
2979 (Length == sizeof(BOOLEAN)) ?
2980 sizeof(BOOLEAN) : sizeof(ULONG));
2981 }
2982 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2983 {
2984 /* Return the exception code */
2985 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2986 }
2987 _SEH2_END;
2988 }
2989 else
2990 {
2991 /* Validate the information class */
2992 if ((FileInformationClass >= FileMaximumInformation) ||
2993 !(IopSetOperationLength[FileInformationClass]))
2994 {
2995 /* Invalid class */
2996 return STATUS_INVALID_INFO_CLASS;
2997 }
2998
2999 /* Validate the length */
3000 if (Length < IopSetOperationLength[FileInformationClass])
3001 {
3002 /* Invalid length */
3003 return STATUS_INFO_LENGTH_MISMATCH;
3004 }
3005 }
3006
3007 /* Reference the Handle */
3008 Status = ObReferenceObjectByHandle(FileHandle,
3009 IopSetOperationAccess
3010 [FileInformationClass],
3011 IoFileObjectType,
3012 PreviousMode,
3013 (PVOID *)&FileObject,
3014 NULL);
3015 if (!NT_SUCCESS(Status)) return Status;
3016
3017 /* Check if this is a direct open or not */
3018 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3019 {
3020 /* Get the device object */
3021 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3022 }
3023 else
3024 {
3025 /* Get the device object */
3026 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3027 }
3028
3029 DPRINT("Will call: %p\n", DeviceObject);
3030 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
3031
3032 /* Check if this is a file that was opened for Synch I/O */
3033 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3034 {
3035 /* Lock it */
3036 Status = IopLockFileObject(FileObject, PreviousMode);
3037 if (Status != STATUS_SUCCESS)
3038 {
3039 ObDereferenceObject(FileObject);
3040 return Status;
3041 }
3042
3043 /* Check if the caller just wants the position */
3044 if (FileInformationClass == FilePositionInformation)
3045 {
3046 /* Protect write in SEH */
3047 _SEH2_TRY
3048 {
3049 /* Write the offset */
3050 FileObject->CurrentByteOffset =
3051 ((PFILE_POSITION_INFORMATION)FileInformation)->
3052 CurrentByteOffset;
3053
3054 /* Fill out the I/O Status Block */
3055 IoStatusBlock->Information = 0;
3056 Status = IoStatusBlock->Status = STATUS_SUCCESS;
3057 }
3058 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3059 {
3060 /* Get the exception code */
3061 Status = _SEH2_GetExceptionCode();
3062 }
3063 _SEH2_END;
3064
3065 /* Update transfer count */
3066 IopUpdateTransferCount(IopOtherTransfer, Length);
3067
3068 /* Release the file lock, dereference the file and return */
3069 IopUnlockFileObject(FileObject);
3070 ObDereferenceObject(FileObject);
3071 return Status;
3072 }
3073 }
3074 else
3075 {
3076 /* Use local event */
3077 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3078 if (!Event)
3079 {
3080 ObDereferenceObject(FileObject);
3081 return STATUS_INSUFFICIENT_RESOURCES;
3082 }
3083
3084 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3085 LocalEvent = TRUE;
3086 }
3087
3088 /* Clear the File Object event */
3089 KeClearEvent(&FileObject->Event);
3090
3091 /* Allocate the IRP */
3092 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
3093 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3094
3095 /* Set the IRP */
3096 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3097 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3098 Irp->RequestorMode = PreviousMode;
3099 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3100 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3101 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3102 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3103 Irp->AssociatedIrp.SystemBuffer = NULL;
3104 Irp->MdlAddress = NULL;
3105 Irp->UserBuffer = FileInformation;
3106
3107 /* Set the Stack Data */
3108 StackPtr = IoGetNextIrpStackLocation(Irp);
3109 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
3110 StackPtr->FileObject = FileObject;
3111
3112 /* Enter SEH */
3113 _SEH2_TRY
3114 {
3115 /* Allocate a buffer */
3116 Irp->AssociatedIrp.SystemBuffer =
3117 ExAllocatePoolWithTag(NonPagedPool,
3118 Length,
3119 TAG_SYSB);
3120
3121 /* Copy the data into it */
3122 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3123 FileInformation,
3124 Length);
3125 }
3126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3127 {
3128 /* Allocating failed, clean up and return the exception code */
3129 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3130 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3131 }
3132 _SEH2_END;
3133
3134 /* Set the flags */
3135 Irp->Flags |= (IRP_BUFFERED_IO |
3136 IRP_DEALLOCATE_BUFFER |
3137 IRP_DEFER_IO_COMPLETION);
3138
3139 /* Set the Parameters */
3140 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3141 StackPtr->Parameters.SetFile.Length = Length;
3142
3143 /* Queue the IRP */
3144 IopQueueIrpToThread(Irp);
3145
3146 /* Update operation counts */
3147 IopUpdateOperationCount(IopOtherTransfer);
3148
3149 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3150 /* Handle IO Completion Port quickly */
3151 if (FileInformationClass == FileCompletionInformation)
3152 {
3153 /* Check if the file object already has a completion port */
3154 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3155 (FileObject->CompletionContext))
3156 {
3157 /* Fail */
3158 Status = STATUS_INVALID_PARAMETER;
3159 }
3160 else
3161 {
3162 /* Reference the Port */
3163 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3164 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3165 IO_COMPLETION_MODIFY_STATE,
3166 IoCompletionType,
3167 PreviousMode,
3168 (PVOID*)&Queue,
3169 NULL);
3170 if (NT_SUCCESS(Status))
3171 {
3172 /* Allocate the Context */
3173 Context = ExAllocatePoolWithTag(PagedPool,
3174 sizeof(IO_COMPLETION_CONTEXT),
3175 IOC_TAG);
3176 if (Context)
3177 {
3178 /* Set the Data */
3179 Context->Key = CompletionInfo->Key;
3180 Context->Port = Queue;
3181 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
3182 CompletionContext,
3183 Context,
3184 NULL))
3185 {
3186 /*
3187 * Someone else set the completion port in the
3188 * meanwhile, so dereference the port and fail.
3189 */
3190 ExFreePoolWithTag(Context, IOC_TAG);
3191 ObDereferenceObject(Queue);
3192 Status = STATUS_INVALID_PARAMETER;
3193 }
3194 }
3195 else
3196 {
3197 /* Dereference the Port now */
3198 ObDereferenceObject(Queue);
3199 Status = STATUS_INSUFFICIENT_RESOURCES;
3200 }
3201 }
3202 }
3203
3204 /* Set the IRP Status */
3205 Irp->IoStatus.Status = Status;
3206 Irp->IoStatus.Information = 0;
3207 }
3208 else if (FileInformationClass == FileRenameInformation ||
3209 FileInformationClass == FileLinkInformation ||
3210 FileInformationClass == FileMoveClusterInformation)
3211 {
3212 /* Get associated information */
3213 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3214
3215 /* Only rename if:
3216 * -> We have a name
3217 * -> In unicode
3218 * -> sizes are valid
3219 */
3220 if (RenameInfo->FileNameLength != 0 &&
3221 !(RenameInfo->FileNameLength & 1) &&
3222 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
3223 {
3224 /* Properly set information received */
3225 if (FileInformationClass == FileMoveClusterInformation)
3226 {
3227 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3228 }
3229 else
3230 {
3231 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3232 }
3233
3234 /* If we got fully path OR relative target, attempt a parent directory open */
3235 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3236 {
3237 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
3238 if (!NT_SUCCESS(Status))
3239 {
3240 Irp->IoStatus.Status = Status;
3241 }
3242 else
3243 {
3244 /* Call the Driver */
3245 Status = IoCallDriver(DeviceObject, Irp);
3246 }
3247 }
3248 else
3249 {
3250 /* Call the Driver */
3251 Status = IoCallDriver(DeviceObject, Irp);
3252 }
3253 }
3254 else
3255 {
3256 Status = STATUS_INVALID_PARAMETER;
3257 Irp->IoStatus.Status = Status;
3258 }
3259 }
3260 else
3261 {
3262 /* Call the Driver */
3263 Status = IoCallDriver(DeviceObject, Irp);
3264 }
3265
3266 /* Check if we're waiting for the IRP to complete */
3267 if (Status == STATUS_PENDING)
3268 {
3269 /* Check if this was async I/O */
3270 if (LocalEvent)
3271 {
3272 /* Then to a non-alertable wait */
3273 Status = KeWaitForSingleObject(Event,
3274 Executive,
3275 PreviousMode,
3276 FALSE,
3277 NULL);
3278 if (Status == STATUS_USER_APC)
3279 {
3280 /* Abort the request */
3281 IopAbortInterruptedIrp(Event, Irp);
3282 }
3283
3284 /* Set the final status */
3285 Status = KernelIosb.Status;
3286
3287 /* Enter SEH to write the IOSB back */
3288 _SEH2_TRY
3289 {
3290 /* Write it back to the caller */
3291 *IoStatusBlock = KernelIosb;
3292 }
3293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3294 {
3295 /* Get the exception code */
3296 Status = _SEH2_GetExceptionCode();
3297 }
3298 _SEH2_END;
3299
3300 /* Free the event */
3301 ExFreePoolWithTag(Event, TAG_IO);
3302 }
3303 else
3304 {
3305 /* Wait for the IRP */
3306 Status = KeWaitForSingleObject(&FileObject->Event,
3307 Executive,
3308 PreviousMode,
3309 (FileObject->Flags &
3310 FO_ALERTABLE_IO) != 0,
3311 NULL);
3312 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3313 {
3314 /* Abort the request */
3315 IopAbortInterruptedIrp(&FileObject->Event, Irp);
3316 }
3317
3318 /* Set the final status */
3319 Status = FileObject->FinalStatus;
3320
3321 /* Release the file lock */
3322 IopUnlockFileObject(FileObject);
3323 }
3324 }
3325 else
3326 {
3327 /* Free the event if we had one */
3328 if (LocalEvent)
3329 {
3330 /* Clear it in the IRP for completion */
3331 Irp->UserEvent = NULL;
3332 ExFreePoolWithTag(Event, TAG_IO);
3333 }
3334
3335 /* Set the caller IOSB */
3336 Irp->UserIosb = IoStatusBlock;
3337
3338 /* The IRP wasn't completed, complete it ourselves */
3339 KeRaiseIrql(APC_LEVEL, &OldIrql);
3340 IopCompleteRequest(&Irp->Tail.Apc,
3341 &NormalRoutine,
3342 &NormalContext,
3343 (PVOID*)&FileObject,
3344 &NormalContext);
3345 KeLowerIrql(OldIrql);
3346
3347 /* Release the file object if we had locked it*/
3348 if (!LocalEvent) IopUnlockFileObject(FileObject);
3349 }
3350
3351 if (TargetHandle != NULL)
3352 {
3353 ObCloseHandle(TargetHandle, KernelMode);
3354 }
3355
3356 /* Return the Status */
3357 return Status;
3358 }
3359
3360 /*
3361 * @unimplemented
3362 */
3363 NTSTATUS
3364 NTAPI
3365 NtSetQuotaInformationFile(IN HANDLE FileHandle,
3366 OUT PIO_STATUS_BLOCK IoStatusBlock,
3367 IN PVOID Buffer,
3368 IN ULONG BufferLength)
3369 {
3370 UNIMPLEMENTED;
3371 return STATUS_NOT_IMPLEMENTED;
3372 }
3373
3374 /*
3375 * @implemented
3376 */
3377 NTSTATUS
3378 NTAPI
3379 NtUnlockFile(IN HANDLE FileHandle,
3380 OUT PIO_STATUS_BLOCK IoStatusBlock,
3381 IN PLARGE_INTEGER ByteOffset,
3382 IN PLARGE_INTEGER Length,
3383 IN ULONG Key OPTIONAL)
3384 {
3385 PFILE_OBJECT FileObject;
3386 PLARGE_INTEGER LocalLength = NULL;
3387 PIRP Irp;
3388 PIO_STACK_LOCATION StackPtr;
3389 PDEVICE_OBJECT DeviceObject;
3390 PKEVENT Event = NULL;
3391 BOOLEAN LocalEvent = FALSE;
3392 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3393 LARGE_INTEGER CapturedByteOffset, CapturedLength;
3394 NTSTATUS Status;
3395 OBJECT_HANDLE_INFORMATION HandleInformation;
3396 IO_STATUS_BLOCK KernelIosb;
3397 PFAST_IO_DISPATCH FastIoDispatch;
3398 PAGED_CODE();
3399 CapturedByteOffset.QuadPart = 0;
3400 CapturedLength.QuadPart = 0;
3401 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3402
3403 /* Get File Object */
3404 Status = ObReferenceObjectByHandle(FileHandle,
3405 0,
3406 IoFileObjectType,
3407 PreviousMode,
3408 (PVOID*)&FileObject,
3409 &HandleInformation);
3410 if (!NT_SUCCESS(Status)) return Status;
3411
3412 /* Check if we're called from user mode */
3413 if (PreviousMode != KernelMode)
3414 {
3415 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3416 if (!(HandleInformation.GrantedAccess &
3417 (FILE_WRITE_DATA | FILE_READ_DATA)))
3418 {
3419 ObDereferenceObject(FileObject);
3420 return STATUS_ACCESS_DENIED;
3421 }
3422
3423 /* Enter SEH for probing */
3424 _SEH2_TRY
3425 {
3426 /* Probe the I/O Status block */
3427 ProbeForWriteIoStatusBlock(IoStatusBlock);
3428
3429 /* Probe and capture the large integers */
3430 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3431 CapturedLength = ProbeForReadLargeInteger(Length);
3432 }
3433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3434 {
3435 /* Dereference the object and return exception code */
3436 ObDereferenceObject(FileObject);
3437 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3438 }
3439 _SEH2_END;
3440 }
3441 else
3442 {
3443 /* Otherwise, capture them directly */
3444 CapturedByteOffset = *ByteOffset;
3445 CapturedLength = *Length;
3446 }
3447
3448 /* Check if this is a direct open or not */
3449 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3450 {
3451 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3452 }
3453 else
3454 {
3455 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3456 }
3457
3458 /* Try to do it the FastIO way if possible */
3459 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3460 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
3461 {
3462 if (FastIoDispatch->FastIoUnlockSingle(FileObject,
3463 &CapturedByteOffset,
3464 &CapturedLength,
3465 PsGetCurrentProcess(),
3466 Key,
3467 &KernelIosb,
3468 DeviceObject))
3469 {
3470 /* Write the IOSB back */
3471 _SEH2_TRY
3472 {
3473 *IoStatusBlock = KernelIosb;
3474 }
3475 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3476 {
3477 KernelIosb.Status = _SEH2_GetExceptionCode();
3478 }
3479 _SEH2_END;
3480
3481 /* We're done with FastIO! */
3482 ObDereferenceObject(FileObject);
3483 return KernelIosb.Status;
3484 }
3485 }
3486
3487 /* Check if we should use Sync IO or not */
3488 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3489 {
3490 /* Lock it */
3491 Status = IopLockFileObject(FileObject, PreviousMode);
3492 if (Status != STATUS_SUCCESS)
3493 {
3494 ObDereferenceObject(FileObject);
3495 return Status;
3496 }
3497 }
3498 else
3499 {
3500 /* Use local event */
3501 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3502 if (!Event)
3503 {
3504 ObDereferenceObject(FileObject);
3505 return STATUS_INSUFFICIENT_RESOURCES;
3506 }
3507 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3508 LocalEvent = TRUE;
3509 }
3510
3511 /* Clear File Object event */
3512 KeClearEvent(&FileObject->Event);
3513
3514 /* Allocate the IRP */
3515 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3516 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3517
3518 /* Set up the IRP */
3519 Irp->RequestorMode = PreviousMode;
3520 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3521 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3522 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3523 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3524 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3525 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3526
3527 /* Set up Stack Data */
3528 StackPtr = IoGetNextIrpStackLocation(Irp);
3529 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3530 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3531 StackPtr->FileObject = FileObject;
3532
3533 /* Enter SEH */
3534 _SEH2_TRY
3535 {
3536 /* Allocate a buffer */
3537 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3538 sizeof(LARGE_INTEGER),
3539 TAG_LOCK);
3540
3541 /* Set the length */
3542 *LocalLength = CapturedLength;
3543 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3544 StackPtr->Parameters.LockControl.Length = LocalLength;
3545 }
3546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3547 {
3548 /* Allocating failed, clean up and return the exception code */
3549 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3550 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3551
3552 /* Return the exception code */
3553 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3554 }
3555 _SEH2_END;
3556
3557 /* Set Parameters */
3558 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3559 StackPtr->Parameters.LockControl.Key = Key;
3560
3561 /* Call the Driver */
3562 Status = IopPerformSynchronousRequest(DeviceObject,
3563 Irp,
3564 FileObject,
3565 FALSE,
3566 PreviousMode,
3567 !LocalEvent,
3568 IopOtherTransfer);
3569
3570 /* Check if this was async I/O */
3571 if (LocalEvent)
3572 {
3573 /* It was, finalize this request */
3574 Status = IopFinalizeAsynchronousIo(Status,
3575 Event,
3576 Irp,
3577 PreviousMode,
3578 &KernelIosb,
3579 IoStatusBlock);
3580 }
3581
3582 /* Return status */
3583 return Status;
3584 }
3585
3586 /*
3587 * @implemented
3588 */
3589 NTSTATUS
3590 NTAPI
3591 NtWriteFile(IN HANDLE FileHandle,
3592 IN HANDLE Event OPTIONAL,
3593 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3594 IN PVOID ApcContext OPTIONAL,
3595 OUT PIO_STATUS_BLOCK IoStatusBlock,
3596 IN PVOID Buffer,
3597 IN ULONG Length,
3598 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3599 IN PULONG Key OPTIONAL)
3600 {
3601 NTSTATUS Status;
3602 PFILE_OBJECT FileObject;
3603 PIRP Irp;
3604 PDEVICE_OBJECT DeviceObject;
3605 PIO_STACK_LOCATION StackPtr;
3606 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3607 PKEVENT EventObject = NULL;
3608 LARGE_INTEGER CapturedByteOffset;
3609 ULONG CapturedKey = 0;
3610 BOOLEAN Synchronous = FALSE;
3611 PMDL Mdl;
3612 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3613 PFAST_IO_DISPATCH FastIoDispatch;
3614 IO_STATUS_BLOCK KernelIosb;
3615 BOOLEAN Success;
3616
3617 PAGED_CODE();
3618 CapturedByteOffset.QuadPart = 0;
3619 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3620
3621 /* Get File Object for write */
3622 Status = ObReferenceFileObjectForWrite(FileHandle,
3623 PreviousMode,
3624 &FileObject,
3625 &ObjectHandleInfo);
3626 if (!NT_SUCCESS(Status)) return Status;
3627
3628 /* Get the device object */
3629 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3630
3631 /* Validate User-Mode Buffers */
3632 if (PreviousMode != KernelMode)
3633 {
3634 _SEH2_TRY
3635 {
3636 /* Probe the status block */
3637 ProbeForWriteIoStatusBlock(IoStatusBlock);
3638
3639 /* Probe the read buffer */
3640 ProbeForRead(Buffer, Length, 1);
3641
3642 /* Check if we got a byte offset */
3643 if (ByteOffset)
3644 {
3645 /* Capture and probe it */
3646 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3647 }
3648
3649 /* Perform additional checks for non-cached file access */
3650 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
3651 {
3652 /* Fail if Length is not sector size aligned */
3653 if ((DeviceObject->SectorSize != 0) &&
3654 (Length % DeviceObject->SectorSize != 0))
3655 {
3656 /* Release the file object and and fail */
3657 ObDereferenceObject(FileObject);
3658 return STATUS_INVALID_PARAMETER;
3659 }
3660
3661 /* Fail if buffer doesn't match alignment requirements */
3662 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
3663 {
3664 /* Release the file object and and fail */
3665 ObDereferenceObject(FileObject);
3666 return STATUS_INVALID_PARAMETER;
3667 }
3668
3669 if (ByteOffset)
3670 {
3671 /* Fail if ByteOffset is not sector size aligned */
3672 if ((DeviceObject->SectorSize != 0) &&
3673 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
3674 {
3675 /* Only if that's not specific values for synchronous IO */
3676 if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) &&
3677 (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION ||
3678 !BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)))
3679 {
3680 /* Release the file object and and fail */
3681 ObDereferenceObject(FileObject);
3682 return STATUS_INVALID_PARAMETER;
3683 }
3684 }
3685 }
3686 }
3687
3688 /* Capture and probe the key */
3689 if (Key) CapturedKey = ProbeForReadUlong(Key);
3690 }
3691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3692 {
3693 /* Release the file object and return the exception code */
3694 ObDereferenceObject(FileObject);
3695 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3696 }
3697 _SEH2_END;
3698 }
3699 else
3700 {
3701 /* Kernel mode: capture directly */
3702 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3703 if (Key) CapturedKey = *Key;
3704 }
3705
3706 /* Check if this is an append operation */
3707 if ((ObjectHandleInfo.GrantedAccess &
3708 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3709 {
3710 /* Give the drivers something to understand */
3711 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3712 CapturedByteOffset.u.HighPart = -1;
3713 }
3714
3715 /* Check for event */
3716 if (Event)
3717 {
3718 /* Reference it */
3719 Status = ObReferenceObjectByHandle(Event,
3720 EVENT_MODIFY_STATE,
3721 ExEventObjectType,
3722 PreviousMode,
3723 (PVOID*)&EventObject,
3724 NULL);
3725 if (!NT_SUCCESS(Status))
3726 {
3727 /* Fail */
3728 ObDereferenceObject(FileObject);
3729 return Status;
3730 }
3731
3732 /* Otherwise reset the event */
3733 KeClearEvent(EventObject);
3734 }
3735
3736 /* Check if we should use Sync IO or not */
3737 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3738 {
3739 /* Lock the file object */
3740 Status = IopLockFileObject(FileObject, PreviousMode);
3741 if (Status != STATUS_SUCCESS)
3742 {
3743 if (EventObject) ObDereferenceObject(EventObject);
3744 ObDereferenceObject(FileObject);
3745 return Status;
3746 }
3747
3748 /* Check if we don't have a byte offset available */
3749 if (!(ByteOffset) ||
3750 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3751 (CapturedByteOffset.u.HighPart == -1)))
3752 {
3753 /* Use the Current Byte Offset instead */
3754 CapturedByteOffset = FileObject->CurrentByteOffset;
3755 }
3756
3757 /* If the file is cached, try fast I/O */
3758 if (FileObject->PrivateCacheMap)
3759 {
3760 /* Perform fast write */
3761 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3762 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
3763
3764 Success = FastIoDispatch->FastIoWrite(FileObject,
3765 &CapturedByteOffset,
3766 Length,
3767 TRUE,
3768 CapturedKey,
3769 Buffer,
3770 &KernelIosb,
3771 DeviceObject);
3772
3773 /* Only accept the result if it was successful */
3774 if (Success &&
3775 KernelIosb.Status == STATUS_SUCCESS)
3776 {
3777 /* Fast path -- update transfer & operation counts */
3778 IopUpdateOperationCount(IopWriteTransfer);
3779 IopUpdateTransferCount(IopWriteTransfer,
3780 (ULONG)KernelIosb.Information);
3781
3782 /* Enter SEH to write the IOSB back */
3783 _SEH2_TRY
3784 {
3785 /* Write it back to the caller */
3786 *IoStatusBlock = KernelIosb;
3787 }
3788 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3789 {
3790 /* The caller's IOSB was invalid, so fail */
3791 if (EventObject) ObDereferenceObject(EventObject);
3792 IopUnlockFileObject(FileObject);
3793 ObDereferenceObject(FileObject);
3794 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3795 }
3796 _SEH2_END;
3797
3798 /* Signal the completion event */
3799 if (EventObject)
3800 {
3801 KeSetEvent(EventObject, 0, FALSE);
3802 ObDereferenceObject(EventObject);
3803 }
3804
3805 /* Clean up */
3806 IopUnlockFileObject(FileObject);
3807 ObDereferenceObject(FileObject);
3808 return KernelIosb.Status;
3809 }
3810 }
3811
3812 /* Remember we are sync */
3813 Synchronous = TRUE;
3814 }
3815 else if (!(ByteOffset) &&
3816 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3817 {
3818 /* Otherwise, this was async I/O without a byte offset, so fail */
3819 if (EventObject) ObDereferenceObject(EventObject);
3820 ObDereferenceObject(FileObject);
3821 return STATUS_INVALID_PARAMETER;
3822 }
3823
3824 /* Clear the File Object's event */
3825 KeClearEvent(&FileObject->Event);
3826
3827 /* Allocate the IRP */
3828 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3829 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
3830
3831 /* Set the IRP */
3832 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3833 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3834 Irp->RequestorMode = PreviousMode;
3835 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3836 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3837 Irp->UserIosb = IoStatusBlock;
3838 Irp->UserEvent = EventObject;
3839 Irp->PendingReturned = FALSE;
3840 Irp->Cancel = FALSE;
3841 Irp->CancelRoutine = NULL;
3842 Irp->AssociatedIrp.SystemBuffer = NULL;
3843 Irp->MdlAddress = NULL;
3844
3845 /* Set the Stack Data */
3846 StackPtr = IoGetNextIrpStackLocation(Irp);
3847 StackPtr->MajorFunction = IRP_MJ_WRITE;
3848 StackPtr->FileObject = FileObject;
3849 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3850 SL_WRITE_THROUGH : 0;
3851 StackPtr->Parameters.Write.Key = CapturedKey;
3852 StackPtr->Parameters.Write.Length = Length;
3853 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3854
3855 /* Check if this is buffered I/O */
3856 if (DeviceObject->Flags & DO_BUFFERED_IO)
3857 {
3858 /* Check if we have a buffer length */
3859 if (Length)
3860 {
3861 /* Enter SEH */
3862 _SEH2_TRY
3863 {
3864 /* Allocate a buffer */
3865 Irp->AssociatedIrp.SystemBuffer =
3866 ExAllocatePoolWithTag(NonPagedPool,
3867 Length,
3868 TAG_SYSB);
3869
3870 /* Copy the data into it */
3871 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3872 }
3873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3874 {
3875 /* Allocating failed, clean up and return the exception code */
3876 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3877 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3878 }
3879 _SEH2_END;
3880
3881 /* Set the flags */
3882 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3883 }
3884 else
3885 {
3886 /* Not writing anything */
3887 Irp->Flags = IRP_BUFFERED_IO;
3888 }
3889 }
3890 else if (DeviceObject->Flags & DO_DIRECT_IO)
3891 {
3892 /* Check if we have a buffer length */
3893 if (Length)
3894 {
3895 _SEH2_TRY
3896 {
3897 /* Allocate an MDL */
3898 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
3899 if (!Mdl)
3900 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
3901 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
3902 }
3903 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3904 {
3905 /* Allocating failed, clean up and return the exception code */
3906 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3907 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3908 }
3909 _SEH2_END;
3910 }
3911
3912 /* No allocation flags */
3913 Irp->Flags = 0;
3914 }
3915 else
3916 {
3917 /* No allocation flags, and use the buffer directly */
3918 Irp->Flags = 0;
3919 Irp->UserBuffer = Buffer;
3920 }
3921
3922 /* Now set the deferred read flags */
3923 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
3924 #if 0
3925 /* FIXME: VFAT SUCKS */
3926 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3927 #endif
3928
3929 /* Perform the call */
3930 return IopPerformSynchronousRequest(DeviceObject,
3931 Irp,
3932 FileObject,
3933 TRUE,
3934 PreviousMode,
3935 Synchronous,
3936 IopWriteTransfer);
3937 }
3938
3939 NTSTATUS
3940 NTAPI
3941 NtWriteFileGather(IN HANDLE FileHandle,
3942 IN HANDLE Event OPTIONAL,
3943 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3944 IN PVOID UserApcContext OPTIONAL,
3945 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3946 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3947 IN ULONG BufferLength,
3948 IN PLARGE_INTEGER ByteOffset,
3949 IN PULONG Key OPTIONAL)
3950 {
3951 UNIMPLEMENTED;
3952 return STATUS_NOT_IMPLEMENTED;
3953 }
3954
3955 /*
3956 * @implemented
3957 */
3958 NTSTATUS
3959 NTAPI
3960 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
3961 OUT PIO_STATUS_BLOCK IoStatusBlock,
3962 OUT PVOID FsInformation,
3963 IN ULONG Length,
3964 IN FS_INFORMATION_CLASS FsInformationClass)
3965 {
3966 PFILE_OBJECT FileObject;
3967 PIRP Irp;
3968 PIO_STACK_LOCATION StackPtr;
3969 PDEVICE_OBJECT DeviceObject;
3970 PKEVENT Event = NULL;
3971 BOOLEAN LocalEvent = FALSE;
3972 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3973 NTSTATUS Status;
3974 IO_STATUS_BLOCK KernelIosb;
3975 PAGED_CODE();
3976 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3977
3978 /* Check if we're called from user mode */
3979 if (PreviousMode != KernelMode)
3980 {
3981 /* Validate the information class */
3982 if ((FsInformationClass >= FileFsMaximumInformation) ||
3983 !(IopQueryFsOperationLength[FsInformationClass]))
3984 {
3985 /* Invalid class */
3986 return STATUS_INVALID_INFO_CLASS;
3987 }
3988
3989 /* Validate the length */
3990 if (Length < IopQueryFsOperationLength[FsInformationClass])
3991 {
3992 /* Invalid length */
3993 return STATUS_INFO_LENGTH_MISMATCH;
3994 }
3995
3996 /* Enter SEH for probing */
3997 _SEH2_TRY
3998 {
3999 /* Probe the I/O Status block */
4000 ProbeForWriteIoStatusBlock(IoStatusBlock);
4001
4002 /* Probe the information */
4003 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
4004 }
4005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4006 {
4007 /* Return the exception code */
4008 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4009 }
4010 _SEH2_END;
4011 }
4012
4013 /* Get File Object */
4014 Status = ObReferenceObjectByHandle(FileHandle,
4015 IopQueryFsOperationAccess
4016 [FsInformationClass],
4017 IoFileObjectType,
4018 PreviousMode,
4019 (PVOID*)&FileObject,
4020 NULL);
4021 if (!NT_SUCCESS(Status)) return Status;
4022
4023 /* Check if we should use Sync IO or not */
4024 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4025 {
4026 /* Lock it */
4027 Status = IopLockFileObject(FileObject, PreviousMode);
4028 if (Status != STATUS_SUCCESS)
4029 {
4030 ObDereferenceObject(FileObject);
4031 return Status;
4032 }
4033 }
4034 else
4035 {
4036 /* Use local event */
4037 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
4038 if (!Event)
4039 {
4040 ObDereferenceObject(FileObject);
4041 return STATUS_INSUFFICIENT_RESOURCES;
4042 }
4043 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
4044 LocalEvent = TRUE;
4045 }
4046
4047 /* Get the device object */
4048 DeviceObject = IoGetRelatedDeviceObject(FileObject);
4049
4050 /* Clear File Object event */
4051 KeClearEvent(&FileObject->Event);
4052
4053 /* Allocate the IRP */
4054 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4055 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
4056
4057 /* Set up the IRP */
4058 Irp->RequestorMode = PreviousMode;
4059 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4060 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4061 Irp->UserEvent = (LocalEvent) ? Event : NULL;