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