b9bf75736f51cfe4f776eec918367c4cf0583805
[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 NormalRoutine = NULL;
152 NormalContext = NULL;
153 ASSERT(!Irp->PendingReturned);
154 KeRaiseIrql(APC_LEVEL, &OldIrql);
155 IopCompleteRequest(&Irp->Tail.Apc,
156 &NormalRoutine,
157 &NormalContext,
158 (PVOID*)&FileObject,
159 &NormalContext);
160 KeLowerIrql(OldIrql);
161 }
162 }
163
164 /* Check if this was synch I/O */
165 if (SynchIo)
166 {
167 /* Make sure the IRP was completed, but returned pending */
168 if (Status == STATUS_PENDING)
169 {
170 /* Wait for the IRP */
171 Status = KeWaitForSingleObject(&FileObject->Event,
172 Executive,
173 PreviousMode,
174 (FileObject->Flags &
175 FO_ALERTABLE_IO) != 0,
176 NULL);
177 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
178 {
179 /* Abort the request */
180 IopAbortInterruptedIrp(&FileObject->Event, Irp);
181 }
182
183 /* Set the final status */
184 Status = FileObject->FinalStatus;
185 }
186
187 /* Release the file lock */
188 IopUnlockFileObject(FileObject);
189 }
190
191 /* Return status */
192 return Status;
193 }
194
195 NTSTATUS
196 NTAPI
197 IopDeviceFsIoControl(IN HANDLE DeviceHandle,
198 IN HANDLE Event OPTIONAL,
199 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
200 IN PVOID UserApcContext OPTIONAL,
201 OUT PIO_STATUS_BLOCK IoStatusBlock,
202 IN ULONG IoControlCode,
203 IN PVOID InputBuffer,
204 IN ULONG InputBufferLength OPTIONAL,
205 OUT PVOID OutputBuffer,
206 IN ULONG OutputBufferLength OPTIONAL,
207 IN BOOLEAN IsDevIoCtl)
208 {
209 NTSTATUS Status;
210 PFILE_OBJECT FileObject;
211 PDEVICE_OBJECT DeviceObject;
212 PIRP Irp;
213 PIO_STACK_LOCATION StackPtr;
214 PKEVENT EventObject = NULL;
215 BOOLEAN LockedForSynch = FALSE;
216 ULONG AccessType;
217 OBJECT_HANDLE_INFORMATION HandleInformation;
218 ACCESS_MASK DesiredAccess;
219 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
220 ULONG BufferLength;
221 POOL_TYPE PoolType;
222
223 PAGED_CODE();
224
225 IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx\n",
226 DeviceHandle, IoControlCode, IsDevIoCtl);
227
228 /* Get the access type */
229 AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
230
231 /* Check if we came from user mode */
232 if (PreviousMode != KernelMode)
233 {
234 _SEH2_TRY
235 {
236 /* Probe the status block */
237 ProbeForWriteIoStatusBlock(IoStatusBlock);
238
239 /* Check if this is buffered I/O */
240 if (AccessType == METHOD_BUFFERED)
241 {
242 /* Check if we have an output buffer */
243 if (OutputBuffer)
244 {
245 /* Probe the output buffer */
246 ProbeForWrite(OutputBuffer,
247 OutputBufferLength,
248 sizeof(CHAR));
249 }
250 else
251 {
252 /* Make sure the caller can't fake this as we depend on this */
253 OutputBufferLength = 0;
254 }
255 }
256
257 /* Check if we we have an input buffer I/O */
258 if (AccessType != METHOD_NEITHER)
259 {
260 /* Check if we have an input buffer */
261 if (InputBuffer)
262 {
263 /* Probe the input buffer */
264 ProbeForRead(InputBuffer, InputBufferLength, sizeof(CHAR));
265 }
266 else
267 {
268 /* Make sure the caller can't fake this as we depend on this */
269 InputBufferLength = 0;
270 }
271 }
272 }
273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
274 {
275 /* Return the exception code */
276 _SEH2_YIELD(return _SEH2_GetExceptionCode());
277 }
278 _SEH2_END;
279 }
280
281 /* Don't check for access rights right now, KernelMode can do anything */
282 Status = ObReferenceObjectByHandle(DeviceHandle,
283 0,
284 IoFileObjectType,
285 PreviousMode,
286 (PVOID*)&FileObject,
287 &HandleInformation);
288 if (!NT_SUCCESS(Status)) return Status;
289
290 /* Can't use an I/O completion port and an APC in the same time */
291 if ((FileObject->CompletionContext) && (UserApcRoutine))
292 {
293 /* Fail */
294 ObDereferenceObject(FileObject);
295 return STATUS_INVALID_PARAMETER;
296 }
297
298 /* Check if we from user mode */
299 if (PreviousMode != KernelMode)
300 {
301 /* Get the access mask */
302 DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
303
304 /* Check if we can open it */
305 if ((DesiredAccess != FILE_ANY_ACCESS) &&
306 (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
307 {
308 /* Dereference the file object and fail */
309 ObDereferenceObject(FileObject);
310 return STATUS_ACCESS_DENIED;
311 }
312 }
313
314 /* Check for an event */
315 if (Event)
316 {
317 /* Reference it */
318 Status = ObReferenceObjectByHandle(Event,
319 EVENT_MODIFY_STATE,
320 ExEventObjectType,
321 PreviousMode,
322 (PVOID*)&EventObject,
323 NULL);
324 if (!NT_SUCCESS(Status))
325 {
326 /* Dereference the file object and fail */
327 ObDereferenceObject(FileObject);
328 return Status;
329 }
330
331 /* Clear it */
332 KeClearEvent(EventObject);
333 }
334
335 /* Check if this is a file that was opened for Synch I/O */
336 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
337 {
338 /* Lock it */
339 Status = IopLockFileObject(FileObject, PreviousMode);
340 if (Status != STATUS_SUCCESS)
341 {
342 if (EventObject) ObDereferenceObject(EventObject);
343 ObDereferenceObject(FileObject);
344 return Status;
345 }
346
347 /* Remember to unlock later */
348 LockedForSynch = TRUE;
349 }
350
351 /* Check if this is a direct open or not */
352 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
353 {
354 /* It's a direct open, get the attached device */
355 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
356 }
357 else
358 {
359 /* Otherwise get the related device */
360 DeviceObject = IoGetRelatedDeviceObject(FileObject);
361 }
362
363 /* If this is a device I/O, try to do it with FastIO path */
364 if (IsDevIoCtl)
365 {
366 PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
367
368 /* Check whether FSD is FastIO aware and provide an appropriate routine */
369 if (FastIoDispatch != NULL && FastIoDispatch->FastIoDeviceControl != NULL)
370 {
371 IO_STATUS_BLOCK KernelIosb;
372
373 /* If we have an output buffer coming from usermode */
374 if (PreviousMode != KernelMode && OutputBuffer != NULL)
375 {
376 /* Probe it according to its usage */
377 _SEH2_TRY
378 {
379 if (AccessType == METHOD_IN_DIRECT)
380 {
381 ProbeForRead(OutputBuffer, OutputBufferLength, sizeof(CHAR));
382 }
383 else if (AccessType == METHOD_OUT_DIRECT)
384 {
385 ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(CHAR));
386 }
387 }
388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
389 {
390 /* Cleanup after exception and return */
391 IopCleanupAfterException(FileObject, NULL, EventObject, NULL);
392
393 /* Return the exception code */
394 _SEH2_YIELD(return _SEH2_GetExceptionCode());
395 }
396 _SEH2_END;
397 }
398
399 /* If we are dismounting a volume, increase the dismount count */
400 if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
401 {
402 InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
403 }
404
405 /* Call the FSD */
406 if (FastIoDispatch->FastIoDeviceControl(FileObject,
407 TRUE,
408 InputBuffer,
409 InputBufferLength,
410 OutputBuffer,
411 OutputBufferLength,
412 IoControlCode,
413 &KernelIosb,
414 DeviceObject))
415 {
416 IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
417
418 /* Write the IOSB back */
419 _SEH2_TRY
420 {
421 *IoStatusBlock = KernelIosb;
422
423 }
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
425 {
426 KernelIosb.Status = _SEH2_GetExceptionCode();
427 }
428 _SEH2_END;
429
430 /* Backup our complete context in case it exists */
431 if (FileObject->CompletionContext)
432 {
433 CompletionInfo = *(FileObject->CompletionContext);
434 }
435
436 /* If we had an event, signal it */
437 if (Event)
438 {
439 KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
440 ObDereferenceObject(EventObject);
441 }
442
443 /* If FO was locked, unlock it */
444 if (LockedForSynch)
445 {
446 IopUnlockFileObject(FileObject);
447 }
448
449 /* Set completion if required */
450 if (CompletionInfo.Port != NULL && UserApcContext != NULL)
451 {
452 if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
453 CompletionInfo.Key,
454 UserApcContext,
455 KernelIosb.Status,
456 KernelIosb.Information,
457 TRUE)))
458 {
459 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
460 }
461 }
462
463 /* We're done with FastIO! */
464 ObDereferenceObject(FileObject);
465 return KernelIosb.Status;
466 }
467 }
468 }
469
470 /* Clear the event */
471 KeClearEvent(&FileObject->Event);
472
473 /* Allocate IRP */
474 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
475 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
476
477 /* Setup the IRP */
478 Irp->UserIosb = IoStatusBlock;
479 Irp->UserEvent = EventObject;
480 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
481 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
482 Irp->Cancel = FALSE;
483 Irp->CancelRoutine = NULL;
484 Irp->PendingReturned = FALSE;
485 Irp->RequestorMode = PreviousMode;
486 Irp->MdlAddress = NULL;
487 Irp->AssociatedIrp.SystemBuffer = NULL;
488 Irp->Flags = 0;
489 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
490 Irp->Tail.Overlay.OriginalFileObject = FileObject;
491 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
492
493 /* Set stack location settings */
494 StackPtr = IoGetNextIrpStackLocation(Irp);
495 StackPtr->FileObject = FileObject;
496 StackPtr->MajorFunction = IsDevIoCtl ?
497 IRP_MJ_DEVICE_CONTROL :
498 IRP_MJ_FILE_SYSTEM_CONTROL;
499 StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
500 StackPtr->Control = 0;
501 StackPtr->Flags = 0;
502 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
503
504 /* Set the IOCTL Data */
505 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
506 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
507 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
508 OutputBufferLength;
509
510 PoolType = IsDevIoCtl ? NonPagedPoolCacheAligned : NonPagedPool;
511
512 /* Handle the Methods */
513 switch (AccessType)
514 {
515 /* Buffered I/O */
516 case METHOD_BUFFERED:
517
518 /* Enter SEH for allocations */
519 _SEH2_TRY
520 {
521 /* Select the right Buffer Length */
522 BufferLength = (InputBufferLength > OutputBufferLength) ?
523 InputBufferLength : OutputBufferLength;
524
525 /* Make sure there is one */
526 if (BufferLength)
527 {
528 /* Allocate the System Buffer */
529 Irp->AssociatedIrp.SystemBuffer =
530 ExAllocatePoolWithQuotaTag(PoolType,
531 BufferLength,
532 TAG_SYS_BUF);
533
534 /* Check if we got a buffer */
535 if (InputBuffer)
536 {
537 /* Copy into the System Buffer */
538 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
539 InputBuffer,
540 InputBufferLength);
541 }
542
543 /* Write the flags */
544 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
545 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
546
547 /* Save the Buffer */
548 Irp->UserBuffer = OutputBuffer;
549 }
550 else
551 {
552 /* Clear the Flags and Buffer */
553 Irp->UserBuffer = NULL;
554 }
555 }
556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
557 {
558 /* Cleanup after exception and return */
559 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
560 _SEH2_YIELD(return _SEH2_GetExceptionCode());
561 }
562 _SEH2_END;
563 break;
564
565 /* Direct I/O */
566 case METHOD_IN_DIRECT:
567 case METHOD_OUT_DIRECT:
568
569 /* Enter SEH */
570 _SEH2_TRY
571 {
572 /* Check if we got an input buffer */
573 if ((InputBufferLength) && (InputBuffer))
574 {
575 /* Allocate the System Buffer */
576 Irp->AssociatedIrp.SystemBuffer =
577 ExAllocatePoolWithQuotaTag(PoolType,
578 InputBufferLength,
579 TAG_SYS_BUF);
580
581 /* Copy into the System Buffer */
582 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
583 InputBuffer,
584 InputBufferLength);
585
586 /* Write the flags */
587 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
588 }
589
590 /* Check if we got an output buffer */
591 if (OutputBufferLength)
592 {
593 /* Allocate the System Buffer */
594 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
595 OutputBufferLength,
596 FALSE,
597 FALSE,
598 Irp);
599 if (!Irp->MdlAddress)
600 {
601 /* Raise exception we'll catch */
602 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
603 }
604
605 /* Do the probe */
606 MmProbeAndLockPages(Irp->MdlAddress,
607 PreviousMode,
608 (AccessType == METHOD_IN_DIRECT) ?
609 IoReadAccess : IoWriteAccess);
610 }
611 }
612 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
613 {
614 /* Cleanup after exception and return */
615 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
616 _SEH2_YIELD(return _SEH2_GetExceptionCode());
617 }
618 _SEH2_END;
619 break;
620
621 case METHOD_NEITHER:
622
623 /* Just save the Buffer */
624 Irp->UserBuffer = OutputBuffer;
625 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
626 }
627
628 /* Use deferred completion for FS I/O */
629 if (!IsDevIoCtl)
630 {
631 Irp->Flags |= IRP_DEFER_IO_COMPLETION;
632 }
633
634 /* If we are dismounting a volume, increaase the dismount count */
635 if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
636 {
637 InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
638 }
639
640 /* Perform the call */
641 return IopPerformSynchronousRequest(DeviceObject,
642 Irp,
643 FileObject,
644 !IsDevIoCtl,
645 PreviousMode,
646 LockedForSynch,
647 IopOtherTransfer);
648 }
649
650 NTSTATUS
651 NTAPI
652 IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
653 IN ULONG InformationClass,
654 IN ULONG Length,
655 OUT PVOID Information,
656 OUT PULONG ReturnedLength,
657 IN BOOLEAN File)
658 {
659 IO_STATUS_BLOCK IoStatusBlock;
660 PIRP Irp;
661 PDEVICE_OBJECT DeviceObject;
662 PIO_STACK_LOCATION StackPtr;
663 BOOLEAN LocalEvent = FALSE;
664 KEVENT Event;
665 NTSTATUS Status;
666 PAGED_CODE();
667 IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx\n",
668 FileObject, InformationClass, File);
669
670 /* Reference the object */
671 ObReferenceObject(FileObject);
672
673 /* Check if this is a file that was opened for Synch I/O */
674 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
675 {
676 /* Lock it */
677 (void)IopLockFileObject(FileObject, KernelMode);
678
679 /* Use File Object event */
680 KeClearEvent(&FileObject->Event);
681 }
682 else
683 {
684 /* Use local event */
685 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
686 LocalEvent = TRUE;
687 }
688
689 /* Get the Device Object */
690 DeviceObject = IoGetRelatedDeviceObject(FileObject);
691
692 /* Allocate the IRP */
693 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
694 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
695
696 /* Set the IRP */
697 Irp->Tail.Overlay.OriginalFileObject = FileObject;
698 Irp->RequestorMode = KernelMode;
699 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
700 Irp->UserIosb = &IoStatusBlock;
701 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
702 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
703 Irp->Flags |= IRP_BUFFERED_IO;
704 Irp->AssociatedIrp.SystemBuffer = Information;
705 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
706
707 /* Set the Stack Data */
708 StackPtr = IoGetNextIrpStackLocation(Irp);
709 StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION:
710 IRP_MJ_QUERY_VOLUME_INFORMATION;
711 StackPtr->FileObject = FileObject;
712
713 /* Check which type this is */
714 if (File)
715 {
716 /* Set Parameters */
717 StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
718 StackPtr->Parameters.QueryFile.Length = Length;
719 }
720 else
721 {
722 /* Set Parameters */
723 StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
724 StackPtr->Parameters.QueryVolume.Length = Length;
725 }
726
727 /* Queue the IRP */
728 IopQueueIrpToThread(Irp);
729
730 /* Call the Driver */
731 Status = IoCallDriver(DeviceObject, Irp);
732
733 /* Check if this was synch I/O */
734 if (!LocalEvent)
735 {
736 /* Check if the request is pending */
737 if (Status == STATUS_PENDING)
738 {
739 /* Wait on the file object */
740 Status = KeWaitForSingleObject(&FileObject->Event,
741 Executive,
742 KernelMode,
743 (FileObject->Flags &
744 FO_ALERTABLE_IO) != 0,
745 NULL);
746 if (Status == STATUS_ALERTED)
747 {
748 /* Abort the operation */
749 IopAbortInterruptedIrp(&FileObject->Event, Irp);
750 }
751
752 /* Get the final status */
753 Status = FileObject->FinalStatus;
754 }
755
756 /* Release the file lock */
757 IopUnlockFileObject(FileObject);
758 }
759 else if (Status == STATUS_PENDING)
760 {
761 /* Wait on the local event and get the final status */
762 KeWaitForSingleObject(&Event,
763 Executive,
764 KernelMode,
765 FALSE,
766 NULL);
767 Status = IoStatusBlock.Status;
768 }
769
770 /* Return the Length and Status. ReturnedLength is NOT optional */
771 *ReturnedLength = (ULONG)IoStatusBlock.Information;
772 return Status;
773 }
774
775 NTSTATUS
776 NTAPI
777 IopGetFileInformation(IN PFILE_OBJECT FileObject,
778 IN ULONG Length,
779 IN FILE_INFORMATION_CLASS FileInfoClass,
780 OUT PVOID Buffer,
781 OUT PULONG ReturnedLength)
782 {
783 PIRP Irp;
784 KEVENT Event;
785 NTSTATUS Status;
786 PIO_STACK_LOCATION Stack;
787 PDEVICE_OBJECT DeviceObject;
788 IO_STATUS_BLOCK IoStatusBlock;
789
790 PAGED_CODE();
791
792 /* Allocate an IRP */
793 ObReferenceObject(FileObject);
794 DeviceObject = IoGetRelatedDeviceObject(FileObject);
795 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
796 if (Irp == NULL)
797 {
798 ObDereferenceObject(FileObject);
799 return STATUS_INSUFFICIENT_RESOURCES;
800 }
801
802 /* Init event */
803 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
804
805 /* Setup the IRP */
806 Irp->UserIosb = &IoStatusBlock;
807 Irp->UserEvent = &Event;
808 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
809 Irp->RequestorMode = KernelMode;
810 Irp->AssociatedIrp.SystemBuffer = Buffer;
811 Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME;
812 Irp->Tail.Overlay.OriginalFileObject = FileObject;
813 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
814
815 Stack = IoGetNextIrpStackLocation(Irp);
816 Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
817 Stack->FileObject = FileObject;
818 Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
819 Stack->Parameters.QueryFile.Length = Length;
820
821
822 /* Queue the IRP */
823 IopQueueIrpToThread(Irp);
824
825 /* Call the driver */
826 Status = IoCallDriver(DeviceObject, Irp);
827 if (Status == STATUS_PENDING)
828 {
829 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
830 Status = IoStatusBlock.Status;
831 }
832
833 *ReturnedLength = IoStatusBlock.Information;
834 return Status;
835 }
836
837 NTSTATUS
838 NTAPI
839 IopGetBasicInformationFile(IN PFILE_OBJECT FileObject,
840 OUT PFILE_BASIC_INFORMATION BasicInfo)
841 {
842 ULONG ReturnedLength;
843 PDEVICE_OBJECT DeviceObject;
844 IO_STATUS_BLOCK IoStatusBlock;
845
846 PAGED_CODE();
847
848 /* Try to do it the fast way if possible */
849 DeviceObject = IoGetRelatedDeviceObject(FileObject);
850 if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
851 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
852 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
853 ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
854 BasicInfo,
855 &IoStatusBlock,
856 DeviceObject))
857 {
858 return IoStatusBlock.Status;
859 }
860
861 /* In case it failed, fall back to IRP-based method */
862 return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength);
863 }
864
865 NTSTATUS
866 NTAPI
867 IopOpenLinkOrRenameTarget(OUT PHANDLE Handle,
868 IN PIRP Irp,
869 IN PFILE_RENAME_INFORMATION RenameInfo,
870 IN PFILE_OBJECT FileObject)
871 {
872 NTSTATUS Status;
873 HANDLE TargetHandle;
874 UNICODE_STRING FileName;
875 PIO_STACK_LOCATION Stack;
876 PFILE_OBJECT TargetFileObject;
877 IO_STATUS_BLOCK IoStatusBlock;
878 FILE_BASIC_INFORMATION BasicInfo;
879 OBJECT_ATTRIBUTES ObjectAttributes;
880 OBJECT_HANDLE_INFORMATION HandleInformation;
881 ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
882
883 PAGED_CODE();
884
885 /* First, establish whether our target is a directory */
886 if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
887 {
888 Status = IopGetBasicInformationFile(FileObject, &BasicInfo);
889 if (!NT_SUCCESS(Status))
890 {
891 return Status;
892 }
893
894 if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
895 DesiredAccess = FILE_ADD_SUBDIRECTORY;
896 }
897 }
898
899 /* Setup the string to the target */
900 FileName.Buffer = RenameInfo->FileName;
901 FileName.Length = RenameInfo->FileNameLength;
902 FileName.MaximumLength = RenameInfo->FileNameLength;
903
904 InitializeObjectAttributes(&ObjectAttributes,
905 &FileName,
906 (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE,
907 RenameInfo->RootDirectory,
908 NULL);
909
910 /* And open its parent directory
911 * Use hint if specified
912 */
913 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
914 {
915 PFILE_OBJECT_EXTENSION FileObjectExtension;
916
917 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
918
919 FileObjectExtension = FileObject->FileObjectExtension;
920 Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
921 DesiredAccess | SYNCHRONIZE,
922 &ObjectAttributes,
923 &IoStatusBlock,
924 NULL,
925 0,
926 FILE_SHARE_READ | FILE_SHARE_WRITE,
927 FILE_OPEN,
928 FILE_OPEN_FOR_BACKUP_INTENT,
929 NULL,
930 0,
931 CreateFileTypeNone,
932 NULL,
933 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
934 FileObjectExtension->TopDeviceObjectHint);
935 }
936 else
937 {
938 Status = IoCreateFile(&TargetHandle,
939 DesiredAccess | SYNCHRONIZE,
940 &ObjectAttributes,
941 &IoStatusBlock,
942 NULL,
943 0,
944 FILE_SHARE_READ | FILE_SHARE_WRITE,
945 FILE_OPEN,
946 FILE_OPEN_FOR_BACKUP_INTENT,
947 NULL,
948 0,
949 CreateFileTypeNone,
950 NULL,
951 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING);
952 }
953
954 if (!NT_SUCCESS(Status))
955 {
956 return Status;
957 }
958
959 /* Once open, continue only if:
960 * Target exists and we're allowed to overwrite it
961 */
962 Stack = IoGetNextIrpStackLocation(Irp);
963 if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
964 !RenameInfo->ReplaceIfExists &&
965 IoStatusBlock.Information == FILE_EXISTS)
966 {
967 ObCloseHandle(TargetHandle, KernelMode);
968 return STATUS_OBJECT_NAME_COLLISION;
969 }
970
971 /* Now, we'll get the associated device of the target, to check for same device location
972 * So, get the FO first
973 */
974 Status = ObReferenceObjectByHandle(TargetHandle,
975 FILE_WRITE_DATA,
976 IoFileObjectType,
977 KernelMode,
978 (PVOID *)&TargetFileObject,
979 &HandleInformation);
980 if (!NT_SUCCESS(Status))
981 {
982 ObCloseHandle(TargetHandle, KernelMode);
983 return Status;
984 }
985
986 /* We can dereference, we have the handle */
987 ObDereferenceObject(TargetFileObject);
988 /* If we're not on the same device, error out **/
989 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
990 {
991 ObCloseHandle(TargetHandle, KernelMode);
992 return STATUS_NOT_SAME_DEVICE;
993 }
994
995 /* Return parent directory file object and handle */
996 Stack->Parameters.SetFile.FileObject = TargetFileObject;
997 *Handle = TargetHandle;
998
999 return STATUS_SUCCESS;
1000 }
1001
1002 static
1003 ULONG
1004 IopGetFileMode(IN PFILE_OBJECT FileObject)
1005 {
1006 ULONG Mode = 0;
1007
1008 if (FileObject->Flags & FO_WRITE_THROUGH)
1009 Mode |= FILE_WRITE_THROUGH;
1010
1011 if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
1012 Mode |= FILE_SEQUENTIAL_ONLY;
1013
1014 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
1015 Mode |= FILE_NO_INTERMEDIATE_BUFFERING;
1016
1017 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1018 {
1019 if (FileObject->Flags & FO_ALERTABLE_IO)
1020 Mode |= FILE_SYNCHRONOUS_IO_ALERT;
1021 else
1022 Mode |= FILE_SYNCHRONOUS_IO_NONALERT;
1023 }
1024
1025 if (FileObject->Flags & FO_DELETE_ON_CLOSE)
1026 Mode |= FILE_DELETE_ON_CLOSE;
1027
1028 return Mode;
1029 }
1030
1031 static
1032 BOOLEAN
1033 IopGetMountFlag(IN PDEVICE_OBJECT DeviceObject)
1034 {
1035 KIRQL OldIrql;
1036 PVPB Vpb;
1037 BOOLEAN Mounted;
1038
1039 /* Assume not mounted */
1040 Mounted = FALSE;
1041
1042 /* Check whether we have the mount flag */
1043 IoAcquireVpbSpinLock(&OldIrql);
1044
1045 Vpb = DeviceObject->Vpb;
1046 if (Vpb != NULL &&
1047 BooleanFlagOn(Vpb->Flags, VPB_MOUNTED))
1048 {
1049 Mounted = TRUE;
1050 }
1051
1052 IoReleaseVpbSpinLock(OldIrql);
1053
1054 return Mounted;
1055 }
1056
1057 static
1058 BOOLEAN
1059 IopVerifyDriverObjectOnStack(IN PDEVICE_OBJECT DeviceObject,
1060 IN PDRIVER_OBJECT DriverObject)
1061 {
1062 PDEVICE_OBJECT StackDO;
1063
1064 /* Browse our whole device stack, trying to find the appropriate driver */
1065 StackDO = IopGetDeviceAttachmentBase(DeviceObject);
1066 while (StackDO != NULL)
1067 {
1068 /* We've found the driver, return success */
1069 if (StackDO->DriverObject == DriverObject)
1070 {
1071 return TRUE;
1072 }
1073
1074 /* Move to the next */
1075 StackDO = StackDO->AttachedDevice;
1076 }
1077
1078 /* We only reach there if driver was not found */
1079 return FALSE;
1080 }
1081
1082 static
1083 NTSTATUS
1084 IopGetDriverPathInformation(IN PFILE_OBJECT FileObject,
1085 IN PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo,
1086 IN ULONG Length)
1087 {
1088 KIRQL OldIrql;
1089 NTSTATUS Status;
1090 UNICODE_STRING DriverName;
1091 PDRIVER_OBJECT DriverObject;
1092
1093 /* Make sure the structure is consistent (ie, driver name fits into the buffer) */
1094 if (Length - FIELD_OFFSET(FILE_FS_DRIVER_PATH_INFORMATION, DriverName) < DriverPathInfo->DriverNameLength)
1095 {
1096 return STATUS_INVALID_PARAMETER;
1097 }
1098
1099 /* Setup the whole driver name */
1100 DriverName.Length = DriverPathInfo->DriverNameLength;
1101 DriverName.MaximumLength = DriverPathInfo->DriverNameLength;
1102 DriverName.Buffer = &DriverPathInfo->DriverName[0];
1103
1104 /* Ask Ob for such driver */
1105 Status = ObReferenceObjectByName(&DriverName,
1106 OBJ_CASE_INSENSITIVE,
1107 NULL,
1108 0,
1109 IoDriverObjectType,
1110 KernelMode,
1111 NULL,
1112 (PVOID*)&DriverObject);
1113 /* No such driver, bail out */
1114 if (!NT_SUCCESS(Status))
1115 {
1116 return Status;
1117 }
1118
1119 /* Lock the devices database, we'll browse it */
1120 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1121 /* If we have a VPB, browse the stack from the volume */
1122 if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL)
1123 {
1124 DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->Vpb->DeviceObject, DriverObject);
1125 }
1126 /* Otherwise, do it from the normal device */
1127 else
1128 {
1129 DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->DeviceObject, DriverObject);
1130 }
1131 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1132
1133 /* No longer needed */
1134 ObDereferenceObject(DriverObject);
1135
1136 return STATUS_SUCCESS;
1137 }
1138
1139 /* PUBLIC FUNCTIONS **********************************************************/
1140
1141 /*
1142 * @implemented
1143 */
1144 NTSTATUS
1145 NTAPI
1146 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject,
1147 IN PMDL Mdl,
1148 IN PLARGE_INTEGER Offset,
1149 IN PKEVENT Event,
1150 IN PIO_STATUS_BLOCK StatusBlock)
1151 {
1152 PIRP Irp;
1153 PIO_STACK_LOCATION StackPtr;
1154 PDEVICE_OBJECT DeviceObject;
1155 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p\n",
1156 FileObject, Mdl, Offset);
1157
1158 /* Is the write originating from Cc? */
1159 if (FileObject->SectionObjectPointer != NULL &&
1160 FileObject->SectionObjectPointer->SharedCacheMap != NULL)
1161 {
1162 ++CcDataFlushes;
1163 CcDataPages += BYTES_TO_PAGES(MmGetMdlByteCount(Mdl));
1164 }
1165
1166 /* Get the Device Object */
1167 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1168
1169 /* Allocate IRP */
1170 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1171 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1172
1173 /* Get the Stack */
1174 StackPtr = IoGetNextIrpStackLocation(Irp);
1175
1176 /* Create the IRP Settings */
1177 Irp->MdlAddress = Mdl;
1178 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1179 Irp->UserIosb = StatusBlock;
1180 Irp->UserEvent = Event;
1181 Irp->RequestorMode = KernelMode;
1182 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
1183 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1184 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1185
1186 /* Set the Stack Settings */
1187 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
1188 StackPtr->Parameters.Write.ByteOffset = *Offset;
1189 StackPtr->MajorFunction = IRP_MJ_WRITE;
1190 StackPtr->FileObject = FileObject;
1191
1192 /* Call the Driver */
1193 return IoCallDriver(DeviceObject, Irp);
1194 }
1195
1196 /*
1197 * @implemented
1198 */
1199 NTSTATUS
1200 NTAPI
1201 IoPageRead(IN PFILE_OBJECT FileObject,
1202 IN PMDL Mdl,
1203 IN PLARGE_INTEGER Offset,
1204 IN PKEVENT Event,
1205 IN PIO_STATUS_BLOCK StatusBlock)
1206 {
1207 PIRP Irp;
1208 PIO_STACK_LOCATION StackPtr;
1209 PDEVICE_OBJECT DeviceObject;
1210 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p\n",
1211 FileObject, Mdl, Offset);
1212
1213 /* Get the Device Object */
1214 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1215
1216 /* Allocate IRP */
1217 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1218 /* If allocation failed, try to see whether we can use
1219 * the reserve IRP
1220 */
1221 if (Irp == NULL)
1222 {
1223 /* We will use it only for paging file */
1224 if (MmIsFileObjectAPagingFile(FileObject))
1225 {
1226 InterlockedExchangeAdd(&IoPageReadIrpAllocationFailure, 1);
1227 Irp = IopAllocateReserveIrp(DeviceObject->StackSize);
1228 }
1229 else
1230 {
1231 InterlockedExchangeAdd(&IoPageReadNonPagefileIrpAllocationFailure, 1);
1232 }
1233
1234 /* If allocation failed (not a paging file or too big stack size)
1235 * Fail for real
1236 */
1237 if (Irp == NULL)
1238 {
1239 return STATUS_INSUFFICIENT_RESOURCES;
1240 }
1241 }
1242
1243 /* Get the Stack */
1244 StackPtr = IoGetNextIrpStackLocation(Irp);
1245
1246 /* Create the IRP Settings */
1247 Irp->MdlAddress = Mdl;
1248 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1249 Irp->UserIosb = StatusBlock;
1250 Irp->UserEvent = Event;
1251 Irp->RequestorMode = KernelMode;
1252 Irp->Flags = IRP_PAGING_IO |
1253 IRP_NOCACHE |
1254 IRP_SYNCHRONOUS_PAGING_IO |
1255 IRP_INPUT_OPERATION;
1256 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1257 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1258
1259 /* Set the Stack Settings */
1260 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
1261 StackPtr->Parameters.Read.ByteOffset = *Offset;
1262 StackPtr->MajorFunction = IRP_MJ_READ;
1263 StackPtr->FileObject = FileObject;
1264
1265 /* Call the Driver */
1266 return IoCallDriver(DeviceObject, Irp);
1267 }
1268
1269 /*
1270 * @implemented
1271 */
1272 NTSTATUS
1273 NTAPI
1274 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
1275 IN FILE_INFORMATION_CLASS FileInformationClass,
1276 IN ULONG Length,
1277 OUT PVOID FileInformation,
1278 OUT PULONG ReturnedLength)
1279 {
1280 /* Call the shared routine */
1281 return IopQueryDeviceInformation(FileObject,
1282 FileInformationClass,
1283 Length,
1284 FileInformation,
1285 ReturnedLength,
1286 TRUE);
1287 }
1288
1289 /*
1290 * @implemented
1291 */
1292 NTSTATUS
1293 NTAPI
1294 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
1295 IN FS_INFORMATION_CLASS FsInformationClass,
1296 IN ULONG Length,
1297 OUT PVOID FsInformation,
1298 OUT PULONG ReturnedLength)
1299 {
1300 /* Call the shared routine */
1301 return IopQueryDeviceInformation(FileObject,
1302 FsInformationClass,
1303 Length,
1304 FsInformation,
1305 ReturnedLength,
1306 FALSE);
1307 }
1308
1309 /*
1310 * @implemented
1311 */
1312 NTSTATUS
1313 NTAPI
1314 IoSetInformation(IN PFILE_OBJECT FileObject,
1315 IN FILE_INFORMATION_CLASS FileInformationClass,
1316 IN ULONG Length,
1317 IN PVOID FileInformation)
1318 {
1319 IO_STATUS_BLOCK IoStatusBlock;
1320 PIRP Irp;
1321 PDEVICE_OBJECT DeviceObject;
1322 PIO_STACK_LOCATION StackPtr;
1323 BOOLEAN LocalEvent = FALSE;
1324 KEVENT Event;
1325 NTSTATUS Status;
1326 PAGED_CODE();
1327 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx\n",
1328 FileObject, FileInformationClass, Length);
1329
1330 /* Reference the object */
1331 ObReferenceObject(FileObject);
1332
1333 /* Check if this is a file that was opened for Synch I/O */
1334 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1335 {
1336 /* Lock it */
1337 (void)IopLockFileObject(FileObject, KernelMode);
1338
1339 /* Use File Object event */
1340 KeClearEvent(&FileObject->Event);
1341 }
1342 else
1343 {
1344 /* Use local event */
1345 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1346 LocalEvent = TRUE;
1347 }
1348
1349 /* Get the Device Object */
1350 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1351
1352 /* Allocate the IRP */
1353 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1354 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1355
1356 /* Set the IRP */
1357 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1358 Irp->RequestorMode = KernelMode;
1359 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1360 Irp->UserIosb = &IoStatusBlock;
1361 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1362 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1363 Irp->Flags |= IRP_BUFFERED_IO;
1364 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1365 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1366
1367 /* Set the Stack Data */
1368 StackPtr = IoGetNextIrpStackLocation(Irp);
1369 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
1370 StackPtr->FileObject = FileObject;
1371
1372 /* Set Parameters */
1373 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1374 StackPtr->Parameters.SetFile.Length = Length;
1375
1376 /* Queue the IRP */
1377 IopQueueIrpToThread(Irp);
1378
1379 /* Call the Driver */
1380 Status = IoCallDriver(DeviceObject, Irp);
1381
1382 /* Check if this was synch I/O */
1383 if (!LocalEvent)
1384 {
1385 /* Check if the request is pending */
1386 if (Status == STATUS_PENDING)
1387 {
1388 /* Wait on the file object */
1389 Status = KeWaitForSingleObject(&FileObject->Event,
1390 Executive,
1391 KernelMode,
1392 (FileObject->Flags &
1393 FO_ALERTABLE_IO) != 0,
1394 NULL);
1395 if (Status == STATUS_ALERTED)
1396 {
1397 /* Abort the operation */
1398 IopAbortInterruptedIrp(&FileObject->Event, Irp);
1399 }
1400
1401 /* Get the final status */
1402 Status = FileObject->FinalStatus;
1403 }
1404
1405 /* Release the file lock */
1406 IopUnlockFileObject(FileObject);
1407 }
1408 else if (Status == STATUS_PENDING)
1409 {
1410 /* Wait on the local event and get the final status */
1411 KeWaitForSingleObject(&Event,
1412 Executive,
1413 KernelMode,
1414 FALSE,
1415 NULL);
1416 Status = IoStatusBlock.Status;
1417 }
1418
1419 /* Return the status */
1420 return Status;
1421 }
1422
1423 /* NATIVE SERVICES ***********************************************************/
1424
1425 /*
1426 * @implemented
1427 */
1428 NTSTATUS
1429 NTAPI
1430 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
1431 IN HANDLE Event OPTIONAL,
1432 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1433 IN PVOID UserApcContext OPTIONAL,
1434 OUT PIO_STATUS_BLOCK IoStatusBlock,
1435 IN ULONG IoControlCode,
1436 IN PVOID InputBuffer,
1437 IN ULONG InputBufferLength OPTIONAL,
1438 OUT PVOID OutputBuffer,
1439 IN ULONG OutputBufferLength OPTIONAL)
1440 {
1441 /* Call the Generic Function */
1442 return IopDeviceFsIoControl(DeviceHandle,
1443 Event,
1444 UserApcRoutine,
1445 UserApcContext,
1446 IoStatusBlock,
1447 IoControlCode,
1448 InputBuffer,
1449 InputBufferLength,
1450 OutputBuffer,
1451 OutputBufferLength,
1452 TRUE);
1453 }
1454
1455 /*
1456 * @implemented
1457 */
1458 NTSTATUS
1459 NTAPI
1460 NtFsControlFile(IN HANDLE DeviceHandle,
1461 IN HANDLE Event OPTIONAL,
1462 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1463 IN PVOID UserApcContext OPTIONAL,
1464 OUT PIO_STATUS_BLOCK IoStatusBlock,
1465 IN ULONG IoControlCode,
1466 IN PVOID InputBuffer,
1467 IN ULONG InputBufferLength OPTIONAL,
1468 OUT PVOID OutputBuffer,
1469 IN ULONG OutputBufferLength OPTIONAL)
1470 {
1471 /* Call the Generic Function */
1472 return IopDeviceFsIoControl(DeviceHandle,
1473 Event,
1474 UserApcRoutine,
1475 UserApcContext,
1476 IoStatusBlock,
1477 IoControlCode,
1478 InputBuffer,
1479 InputBufferLength,
1480 OutputBuffer,
1481 OutputBufferLength,
1482 FALSE);
1483 }
1484
1485 NTSTATUS
1486 NTAPI
1487 NtFlushBuffersFile(IN HANDLE FileHandle,
1488 OUT PIO_STATUS_BLOCK IoStatusBlock)
1489 {
1490 PFILE_OBJECT FileObject;
1491 PIRP Irp;
1492 PIO_STACK_LOCATION StackPtr;
1493 NTSTATUS Status;
1494 PDEVICE_OBJECT DeviceObject;
1495 PKEVENT Event = NULL;
1496 BOOLEAN LocalEvent = FALSE;
1497 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1498 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1499 IO_STATUS_BLOCK KernelIosb;
1500 PAGED_CODE();
1501 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1502
1503 if (PreviousMode != KernelMode)
1504 {
1505 /* Protect probes */
1506 _SEH2_TRY
1507 {
1508 /* Probe the I/O Status block */
1509 ProbeForWriteIoStatusBlock(IoStatusBlock);
1510 }
1511 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1512 {
1513 /* Return the exception code */
1514 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1515 }
1516 _SEH2_END;
1517 }
1518
1519 /* Get the File Object */
1520 Status = ObReferenceObjectByHandle(FileHandle,
1521 0,
1522 IoFileObjectType,
1523 PreviousMode,
1524 (PVOID*)&FileObject,
1525 &ObjectHandleInfo);
1526 if (!NT_SUCCESS(Status)) return Status;
1527
1528 /*
1529 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1530 * granted. However, if this is a named pipe, make sure we don't ask for
1531 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1532 * access right!
1533 */
1534 if (!(ObjectHandleInfo.GrantedAccess &
1535 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1536 FILE_WRITE_DATA)))
1537 {
1538 /* We failed */
1539 ObDereferenceObject(FileObject);
1540 return STATUS_ACCESS_DENIED;
1541 }
1542
1543 /* Check if we should use Sync IO or not */
1544 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1545 {
1546 /* Lock it */
1547 Status = IopLockFileObject(FileObject, PreviousMode);
1548 if (Status != STATUS_SUCCESS)
1549 {
1550 ObDereferenceObject(FileObject);
1551 return Status;
1552 }
1553 }
1554 else
1555 {
1556 /* Use local event */
1557 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1558 if (!Event)
1559 {
1560 /* We failed */
1561 ObDereferenceObject(FileObject);
1562 return STATUS_INSUFFICIENT_RESOURCES;
1563 }
1564 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1565 LocalEvent = TRUE;
1566 }
1567
1568 /* Get the Device Object */
1569 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1570
1571 /* Clear the event */
1572 KeClearEvent(&FileObject->Event);
1573
1574 /* Allocate the IRP */
1575 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1576 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1577
1578 /* Set up the IRP */
1579 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1580 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1581 Irp->UserEvent = (LocalEvent) ? Event : NULL;
1582 Irp->RequestorMode = PreviousMode;
1583 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1584 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1585 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1586
1587 /* Set up Stack Data */
1588 StackPtr = IoGetNextIrpStackLocation(Irp);
1589 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1590 StackPtr->FileObject = FileObject;
1591
1592 /* Call the Driver */
1593 Status = IopPerformSynchronousRequest(DeviceObject,
1594 Irp,
1595 FileObject,
1596 FALSE,
1597 PreviousMode,
1598 !LocalEvent,
1599 IopOtherTransfer);
1600
1601 /* Check if this was async I/O */
1602 if (LocalEvent)
1603 {
1604 /* It was, finalize this request */
1605 Status = IopFinalizeAsynchronousIo(Status,
1606 Event,
1607 Irp,
1608 PreviousMode,
1609 &KernelIosb,
1610 IoStatusBlock);
1611 }
1612
1613 /* Return the Status */
1614 return Status;
1615 }
1616
1617 /*
1618 * @implemented
1619 */
1620 NTSTATUS
1621 NTAPI
1622 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1623 IN HANDLE EventHandle OPTIONAL,
1624 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1625 IN PVOID ApcContext OPTIONAL,
1626 OUT PIO_STATUS_BLOCK IoStatusBlock,
1627 OUT PVOID Buffer,
1628 IN ULONG BufferSize,
1629 IN ULONG CompletionFilter,
1630 IN BOOLEAN WatchTree)
1631 {
1632 PIRP Irp;
1633 PKEVENT Event = NULL;
1634 PDEVICE_OBJECT DeviceObject;
1635 PFILE_OBJECT FileObject;
1636 PIO_STACK_LOCATION IoStack;
1637 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1638 NTSTATUS Status;
1639 BOOLEAN LockedForSync = FALSE;
1640 PAGED_CODE();
1641 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1642
1643 /* Check if we're called from user mode */
1644 if (PreviousMode != KernelMode)
1645 {
1646 /* Enter SEH for probing */
1647 _SEH2_TRY
1648 {
1649 /* Probe the I/O STatus block */
1650 ProbeForWriteIoStatusBlock(IoStatusBlock);
1651
1652 /* Probe the buffer */
1653 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
1654 }
1655 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1656 {
1657 /* Return the exception code */
1658 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1659 }
1660 _SEH2_END;
1661
1662 /* Check if CompletionFilter is valid */
1663 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
1664 {
1665 return STATUS_INVALID_PARAMETER;
1666 }
1667 }
1668
1669 /* Get File Object */
1670 Status = ObReferenceObjectByHandle(FileHandle,
1671 FILE_LIST_DIRECTORY,
1672 IoFileObjectType,
1673 PreviousMode,
1674 (PVOID*)&FileObject,
1675 NULL);
1676 if (!NT_SUCCESS(Status)) return Status;
1677
1678 /* Check if we have an event handle */
1679 if (EventHandle)
1680 {
1681 /* Reference it */
1682 Status = ObReferenceObjectByHandle(EventHandle,
1683 EVENT_MODIFY_STATE,
1684 ExEventObjectType,
1685 PreviousMode,
1686 (PVOID *)&Event,
1687 NULL);
1688 if (Status != STATUS_SUCCESS)
1689 {
1690 ObDereferenceObject(FileObject);
1691 return Status;
1692 }
1693 KeClearEvent(Event);
1694 }
1695
1696 /* Check if we should use Sync IO or not */
1697 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1698 {
1699 /* Lock it */
1700 Status = IopLockFileObject(FileObject, PreviousMode);
1701 if (Status != STATUS_SUCCESS)
1702 {
1703 if (Event) ObDereferenceObject(Event);
1704 ObDereferenceObject(FileObject);
1705 return Status;
1706 }
1707 LockedForSync = TRUE;
1708 }
1709
1710 /* Clear File Object event */
1711 KeClearEvent(&FileObject->Event);
1712
1713 /* Get the device object */
1714 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1715
1716 /* Allocate the IRP */
1717 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1718 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1719
1720 /* Set up the IRP */
1721 Irp->RequestorMode = PreviousMode;
1722 Irp->UserIosb = IoStatusBlock;
1723 Irp->UserEvent = Event;
1724 Irp->UserBuffer = Buffer;
1725 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1726 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1727 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1728 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1729
1730 /* Set up Stack Data */
1731 IoStack = IoGetNextIrpStackLocation(Irp);
1732 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1733 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
1734 IoStack->FileObject = FileObject;
1735
1736 /* Set parameters */
1737 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1738 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1739 if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1740
1741 /* Perform the call */
1742 return IopPerformSynchronousRequest(DeviceObject,
1743 Irp,
1744 FileObject,
1745 FALSE,
1746 PreviousMode,
1747 LockedForSync,
1748 IopOtherTransfer);
1749 }
1750
1751 /*
1752 * @implemented
1753 */
1754 NTSTATUS
1755 NTAPI
1756 NtLockFile(IN HANDLE FileHandle,
1757 IN HANDLE EventHandle OPTIONAL,
1758 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1759 IN PVOID ApcContext OPTIONAL,
1760 OUT PIO_STATUS_BLOCK IoStatusBlock,
1761 IN PLARGE_INTEGER ByteOffset,
1762 IN PLARGE_INTEGER Length,
1763 IN ULONG Key,
1764 IN BOOLEAN FailImmediately,
1765 IN BOOLEAN ExclusiveLock)
1766 {
1767 PFILE_OBJECT FileObject;
1768 PLARGE_INTEGER LocalLength = NULL;
1769 PIRP Irp;
1770 PIO_STACK_LOCATION StackPtr;
1771 PDEVICE_OBJECT DeviceObject;
1772 PKEVENT Event = NULL;
1773 BOOLEAN LockedForSync = FALSE;
1774 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1775 LARGE_INTEGER CapturedByteOffset, CapturedLength;
1776 NTSTATUS Status;
1777 OBJECT_HANDLE_INFORMATION HandleInformation;
1778 PFAST_IO_DISPATCH FastIoDispatch;
1779 PAGED_CODE();
1780 CapturedByteOffset.QuadPart = 0;
1781 CapturedLength.QuadPart = 0;
1782 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1783
1784 /* Get File Object */
1785 Status = ObReferenceObjectByHandle(FileHandle,
1786 0,
1787 IoFileObjectType,
1788 PreviousMode,
1789 (PVOID*)&FileObject,
1790 &HandleInformation);
1791 if (!NT_SUCCESS(Status)) return Status;
1792
1793 /* Check if we're called from user mode */
1794 if (PreviousMode != KernelMode)
1795 {
1796 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1797 if (!(HandleInformation.GrantedAccess &
1798 (FILE_WRITE_DATA | FILE_READ_DATA)))
1799 {
1800 ObDereferenceObject(FileObject);
1801 return STATUS_ACCESS_DENIED;
1802 }
1803
1804 /* Enter SEH for probing */
1805 _SEH2_TRY
1806 {
1807 /* Probe the I/O STatus block */
1808 ProbeForWriteIoStatusBlock(IoStatusBlock);
1809
1810 /* Probe and capture the large integers */
1811 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1812 CapturedLength = ProbeForReadLargeInteger(Length);
1813 }
1814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1815 {
1816 /* Dereference the object and return exception code */
1817 ObDereferenceObject(FileObject);
1818 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1819 }
1820 _SEH2_END;
1821 }
1822 else
1823 {
1824 /* Otherwise, capture them directly */
1825 CapturedByteOffset = *ByteOffset;
1826 CapturedLength = *Length;
1827 }
1828
1829 /* Check if we have an event handle */
1830 if (EventHandle)
1831 {
1832 /* Reference it */
1833 Status = ObReferenceObjectByHandle(EventHandle,
1834 EVENT_MODIFY_STATE,
1835 ExEventObjectType,
1836 PreviousMode,
1837 (PVOID *)&Event,
1838 NULL);
1839 if (Status != STATUS_SUCCESS) return Status;
1840 KeClearEvent(Event);
1841 }
1842
1843 /* Get the device object */
1844 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1845
1846 /* Try to do it the FastIO way if possible */
1847 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
1848 if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
1849 {
1850 IO_STATUS_BLOCK KernelIosb;
1851
1852 if (FastIoDispatch->FastIoLock(FileObject,
1853 &CapturedByteOffset,
1854 &CapturedLength,
1855 PsGetCurrentProcess(),
1856 Key,
1857 FailImmediately,
1858 ExclusiveLock,
1859 &KernelIosb,
1860 DeviceObject))
1861 {
1862 /* Write the IOSB back */
1863 _SEH2_TRY
1864 {
1865 *IoStatusBlock = KernelIosb;
1866 }
1867 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1868 {
1869 KernelIosb.Status = _SEH2_GetExceptionCode();
1870 }
1871 _SEH2_END;
1872
1873 /* If we had an event, signal it */
1874 if (EventHandle)
1875 {
1876 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1877 ObDereferenceObject(Event);
1878 }
1879
1880 /* Set completion if required */
1881 if (FileObject->CompletionContext != NULL && ApcContext != NULL)
1882 {
1883 if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
1884 FileObject->CompletionContext->Key,
1885 ApcContext,
1886 KernelIosb.Status,
1887 KernelIosb.Information,
1888 TRUE)))
1889 {
1890 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
1891 }
1892 }
1893
1894 FileObject->LockOperation = TRUE;
1895
1896 /* We're done with FastIO! */
1897 ObDereferenceObject(FileObject);
1898 return KernelIosb.Status;
1899 }
1900 }
1901
1902 /* Check if we should use Sync IO or not */
1903 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1904 {
1905 /* Lock it */
1906 Status = IopLockFileObject(FileObject, PreviousMode);
1907 if (Status != STATUS_SUCCESS)
1908 {
1909 if (Event) ObDereferenceObject(Event);
1910 ObDereferenceObject(FileObject);
1911 return Status;
1912 }
1913 LockedForSync = TRUE;
1914 }
1915
1916 /* Clear File Object event */
1917 KeClearEvent(&FileObject->Event);
1918 FileObject->LockOperation = TRUE;
1919
1920 /* Allocate the IRP */
1921 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1922 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1923
1924 /* Set up the IRP */
1925 Irp->RequestorMode = PreviousMode;
1926 Irp->UserIosb = IoStatusBlock;
1927 Irp->UserEvent = Event;
1928 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1929 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1930 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1931 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1932
1933 /* Set up Stack Data */
1934 StackPtr = IoGetNextIrpStackLocation(Irp);
1935 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1936 StackPtr->MinorFunction = IRP_MN_LOCK;
1937 StackPtr->FileObject = FileObject;
1938
1939 /* Allocate local buffer */
1940 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1941 sizeof(LARGE_INTEGER),
1942 TAG_LOCK);
1943 if (!LocalLength)
1944 {
1945 /* Allocating failed, clean up and return failure */
1946 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1947 return STATUS_INSUFFICIENT_RESOURCES;
1948 }
1949
1950 /* Set the length */
1951 *LocalLength = CapturedLength;
1952 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1953 StackPtr->Parameters.LockControl.Length = LocalLength;
1954
1955 /* Set Parameters */
1956 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1957 StackPtr->Parameters.LockControl.Key = Key;
1958
1959 /* Set Flags */
1960 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1961 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1962
1963 /* Perform the call */
1964 return IopPerformSynchronousRequest(DeviceObject,
1965 Irp,
1966 FileObject,
1967 FALSE,
1968 PreviousMode,
1969 LockedForSync,
1970 IopOtherTransfer);
1971 }
1972
1973 /*
1974 * @implemented
1975 */
1976 NTSTATUS
1977 NTAPI
1978 NtQueryDirectoryFile(IN HANDLE FileHandle,
1979 IN HANDLE EventHandle OPTIONAL,
1980 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1981 IN PVOID ApcContext OPTIONAL,
1982 OUT PIO_STATUS_BLOCK IoStatusBlock,
1983 OUT PVOID FileInformation,
1984 IN ULONG Length,
1985 IN FILE_INFORMATION_CLASS FileInformationClass,
1986 IN BOOLEAN ReturnSingleEntry,
1987 IN PUNICODE_STRING FileName OPTIONAL,
1988 IN BOOLEAN RestartScan)
1989 {
1990 PIRP Irp;
1991 PDEVICE_OBJECT DeviceObject;
1992 PFILE_OBJECT FileObject;
1993 PIO_STACK_LOCATION StackPtr;
1994 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1995 NTSTATUS Status;
1996 BOOLEAN LockedForSynch = FALSE;
1997 PKEVENT Event = NULL;
1998 volatile PVOID AuxBuffer = NULL;
1999 PMDL Mdl;
2000 UNICODE_STRING CapturedFileName;
2001 PUNICODE_STRING SearchPattern;
2002 PAGED_CODE();
2003 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2004
2005 /* Check if we came from user mode */
2006 if (PreviousMode != KernelMode)
2007 {
2008 /* Enter SEH for probing */
2009 _SEH2_TRY
2010 {
2011 /* Probe the I/O Status Block */
2012 ProbeForWriteIoStatusBlock(IoStatusBlock);
2013
2014 /* Probe the file information */
2015 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
2016
2017 /* Check if we have a file name */
2018 if (FileName)
2019 {
2020 /* Capture it */
2021 CapturedFileName = ProbeForReadUnicodeString(FileName);
2022 if (CapturedFileName.Length)
2023 {
2024 /* Probe its buffer */
2025 ProbeForRead(CapturedFileName.Buffer,
2026 CapturedFileName.Length,
2027 1);
2028 }
2029
2030 /* Allocate the auxiliary buffer */
2031 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
2032 CapturedFileName.Length +
2033 sizeof(UNICODE_STRING),
2034 TAG_SYSB);
2035 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
2036 sizeof(UNICODE_STRING)),
2037 CapturedFileName.Buffer,
2038 CapturedFileName.Length);
2039
2040 /* Setup the search pattern */
2041 SearchPattern = (PUNICODE_STRING)AuxBuffer;
2042 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
2043 sizeof(UNICODE_STRING));
2044 SearchPattern->Length = CapturedFileName.Length;
2045 SearchPattern->MaximumLength = CapturedFileName.Length;
2046 }
2047 }
2048 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2049 {
2050 /* Free buffer and return the exception code */
2051 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2052 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2053 }
2054 _SEH2_END;
2055 }
2056
2057 /* Check input parameters */
2058
2059 switch (FileInformationClass)
2060 {
2061 #define CHECK_LENGTH(class, struct) \
2062 case class: \
2063 if (Length < sizeof(struct)) \
2064 return STATUS_INFO_LENGTH_MISMATCH; \
2065 break
2066 CHECK_LENGTH(FileDirectoryInformation, FILE_DIRECTORY_INFORMATION);
2067 CHECK_LENGTH(FileFullDirectoryInformation, FILE_FULL_DIR_INFORMATION);
2068 CHECK_LENGTH(FileIdFullDirectoryInformation, FILE_ID_FULL_DIR_INFORMATION);
2069 CHECK_LENGTH(FileNamesInformation, FILE_NAMES_INFORMATION);
2070 CHECK_LENGTH(FileBothDirectoryInformation, FILE_BOTH_DIR_INFORMATION);
2071 CHECK_LENGTH(FileIdBothDirectoryInformation, FILE_ID_BOTH_DIR_INFORMATION);
2072 default:
2073 break;
2074 #undef CHECK_LENGTH
2075 }
2076
2077 /* Get File Object */
2078 Status = ObReferenceObjectByHandle(FileHandle,
2079 FILE_LIST_DIRECTORY,
2080 IoFileObjectType,
2081 PreviousMode,
2082 (PVOID *)&FileObject,
2083 NULL);
2084 if (!NT_SUCCESS(Status))
2085 {
2086 /* Fail */
2087 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2088 return Status;
2089 }
2090
2091 /* Are there two associated completion routines? */
2092 if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
2093 {
2094 ObDereferenceObject(FileObject);
2095 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2096 return STATUS_INVALID_PARAMETER;
2097 }
2098
2099 /* Check if we have an even handle */
2100 if (EventHandle)
2101 {
2102 /* Get its pointer */
2103 Status = ObReferenceObjectByHandle(EventHandle,
2104 EVENT_MODIFY_STATE,
2105 ExEventObjectType,
2106 PreviousMode,
2107 (PVOID *)&Event,
2108 NULL);
2109 if (!NT_SUCCESS(Status))
2110 {
2111 /* Fail */
2112 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2113 ObDereferenceObject(FileObject);
2114 return Status;
2115 }
2116
2117 /* Clear it */
2118 KeClearEvent(Event);
2119 }
2120
2121 /* Check if this is a file that was opened for Synch I/O */
2122 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2123 {
2124 /* Lock it */
2125 Status = IopLockFileObject(FileObject, PreviousMode);
2126 if (Status != STATUS_SUCCESS)
2127 {
2128 if (Event) ObDereferenceObject(Event);
2129 ObDereferenceObject(FileObject);
2130 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2131 return Status;
2132 }
2133
2134 /* Remember to unlock later */
2135 LockedForSynch = TRUE;
2136 }
2137
2138 /* Get the device object */
2139 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2140
2141 /* Clear the File Object's event */
2142 KeClearEvent(&FileObject->Event);
2143
2144 /* Allocate the IRP */
2145 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2146 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
2147
2148 /* Set up the IRP */
2149 Irp->RequestorMode = PreviousMode;
2150 Irp->UserIosb = IoStatusBlock;
2151 Irp->UserEvent = Event;
2152 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2153 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2154 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2155 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2156 Irp->MdlAddress = NULL;
2157 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
2158 Irp->AssociatedIrp.SystemBuffer = NULL;
2159
2160 /* Check if this is buffered I/O */
2161 if (DeviceObject->Flags & DO_BUFFERED_IO)
2162 {
2163 /* Allocate a buffer */
2164 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2165 Length,
2166 TAG_SYSB);
2167 if (!Irp->AssociatedIrp.SystemBuffer)
2168 {
2169 /* Allocating failed, clean up and return the exception code */
2170 IopCleanupAfterException(FileObject, Irp, Event, NULL);
2171 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2172
2173 /* Return the exception code */
2174 return STATUS_INSUFFICIENT_RESOURCES;
2175 }
2176
2177 /* Set the buffer and flags */
2178 Irp->UserBuffer = FileInformation;
2179 Irp->Flags = (IRP_BUFFERED_IO |
2180 IRP_DEALLOCATE_BUFFER |
2181 IRP_INPUT_OPERATION);
2182 }
2183 else if (DeviceObject->Flags & DO_DIRECT_IO)
2184 {
2185 _SEH2_TRY
2186 {
2187 /* Allocate an MDL */
2188 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
2189 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2190 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2191 }
2192 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2193 {
2194 /* Allocating failed, clean up and return the exception code */
2195 IopCleanupAfterException(FileObject, Irp, Event, NULL);
2196 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2197 }
2198 _SEH2_END;
2199 }
2200 else
2201 {
2202 /* No allocation flags, and use the buffer directly */
2203 Irp->UserBuffer = FileInformation;
2204 }
2205
2206 /* Set up Stack Data */
2207 StackPtr = IoGetNextIrpStackLocation(Irp);
2208 StackPtr->FileObject = FileObject;
2209 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2210 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
2211
2212 /* Set Parameters */
2213 StackPtr->Parameters.QueryDirectory.FileInformationClass =
2214 FileInformationClass;
2215 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
2216 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2217 StackPtr->Parameters.QueryDirectory.Length = Length;
2218 StackPtr->Flags = 0;
2219 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2220 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
2221
2222 /* Set deferred I/O */
2223 Irp->Flags |= IRP_DEFER_IO_COMPLETION;
2224
2225 /* Perform the call */
2226 return IopPerformSynchronousRequest(DeviceObject,
2227 Irp,
2228 FileObject,
2229 TRUE,
2230 PreviousMode,
2231 LockedForSynch,
2232 IopOtherTransfer);
2233 }
2234
2235 /*
2236 * @unimplemented
2237 */
2238 NTSTATUS
2239 NTAPI
2240 NtQueryEaFile(IN HANDLE FileHandle,
2241 OUT PIO_STATUS_BLOCK IoStatusBlock,
2242 OUT PVOID Buffer,
2243 IN ULONG Length,
2244 IN BOOLEAN ReturnSingleEntry,
2245 IN PVOID EaList OPTIONAL,
2246 IN ULONG EaListLength,
2247 IN PULONG EaIndex OPTIONAL,
2248 IN BOOLEAN RestartScan)
2249 {
2250 UNIMPLEMENTED;
2251 return STATUS_NOT_IMPLEMENTED;
2252 }
2253
2254 /*
2255 * @implemented
2256 */
2257 NTSTATUS
2258 NTAPI
2259 NtQueryInformationFile(IN HANDLE FileHandle,
2260 OUT PIO_STATUS_BLOCK IoStatusBlock,
2261 IN PVOID FileInformation,
2262 IN ULONG Length,
2263 IN FILE_INFORMATION_CLASS FileInformationClass)
2264 {
2265 OBJECT_HANDLE_INFORMATION HandleInformation;
2266 PFILE_OBJECT FileObject;
2267 NTSTATUS Status;
2268 PIRP Irp;
2269 PDEVICE_OBJECT DeviceObject;
2270 PIO_STACK_LOCATION StackPtr;
2271 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2272 PKEVENT Event = NULL;
2273 BOOLEAN LocalEvent = FALSE;
2274 PKNORMAL_ROUTINE NormalRoutine;
2275 PVOID NormalContext;
2276 KIRQL OldIrql;
2277 IO_STATUS_BLOCK KernelIosb;
2278 BOOLEAN CallDriver = TRUE;
2279 PFILE_ACCESS_INFORMATION AccessBuffer;
2280 PFILE_MODE_INFORMATION ModeBuffer;
2281 PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
2282 PFILE_ALL_INFORMATION AllBuffer;
2283 PFAST_IO_DISPATCH FastIoDispatch;
2284 PAGED_CODE();
2285 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2286
2287 /* Check if we're called from user mode */
2288 if (PreviousMode != KernelMode)
2289 {
2290 /* Validate the information class */
2291 if ((FileInformationClass < 0) ||
2292 (FileInformationClass >= FileMaximumInformation) ||
2293 !(IopQueryOperationLength[FileInformationClass]))
2294 {
2295 /* Invalid class */
2296 return STATUS_INVALID_INFO_CLASS;
2297 }
2298
2299 /* Validate the length */
2300 if (Length < IopQueryOperationLength[FileInformationClass])
2301 {
2302 /* Invalid length */
2303 return STATUS_INFO_LENGTH_MISMATCH;
2304 }
2305
2306 /* Enter SEH for probing */
2307 _SEH2_TRY
2308 {
2309 /* Probe the I/O Status block */
2310 ProbeForWriteIoStatusBlock(IoStatusBlock);
2311
2312 /* Probe the information */
2313 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
2314 }
2315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2316 {
2317 /* Return the exception code */
2318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2319 }
2320 _SEH2_END;
2321 }
2322 #if DBG
2323 else
2324 {
2325 /* Validate the information class */
2326 if ((FileInformationClass < 0) ||
2327 (FileInformationClass >= FileMaximumInformation) ||
2328 !(IopQueryOperationLength[FileInformationClass]))
2329 {
2330 /* Invalid class */
2331 return STATUS_INVALID_INFO_CLASS;
2332 }
2333
2334 /* Validate the length */
2335 if (Length < IopQueryOperationLength[FileInformationClass])
2336 {
2337 /* Invalid length */
2338 return STATUS_INFO_LENGTH_MISMATCH;
2339 }
2340 }
2341 #endif
2342
2343 /* Reference the Handle */
2344 Status = ObReferenceObjectByHandle(FileHandle,
2345 IopQueryOperationAccess
2346 [FileInformationClass],
2347 IoFileObjectType,
2348 PreviousMode,
2349 (PVOID *)&FileObject,
2350 &HandleInformation);
2351 if (!NT_SUCCESS(Status)) return Status;
2352
2353 /* Check if this is a direct open or not */
2354 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2355 {
2356 /* Get the device object */
2357 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2358 }
2359 else
2360 {
2361 /* Get the device object */
2362 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2363 }
2364
2365 /* Check if this is a file that was opened for Synch I/O */
2366 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2367 {
2368 /* Lock it */
2369 Status = IopLockFileObject(FileObject, PreviousMode);
2370 if (Status != STATUS_SUCCESS)
2371 {
2372 ObDereferenceObject(FileObject);
2373 return Status;
2374 }
2375
2376 /* Check if the caller just wants the position */
2377 if (FileInformationClass == FilePositionInformation)
2378 {
2379 /* Protect write in SEH */
2380 _SEH2_TRY
2381 {
2382 /* Write the offset */
2383 ((PFILE_POSITION_INFORMATION)FileInformation)->
2384 CurrentByteOffset = FileObject->CurrentByteOffset;
2385
2386 /* Fill out the I/O Status Block */
2387 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
2388 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2389 }
2390 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2391 {
2392 /* Get the exception code */
2393 Status = _SEH2_GetExceptionCode();
2394 }
2395 _SEH2_END;
2396
2397 /* Release the file lock, dereference the file and return */
2398 IopUnlockFileObject(FileObject);
2399 ObDereferenceObject(FileObject);
2400 return Status;
2401 }
2402 }
2403 else
2404 {
2405 /* Use local event */
2406 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2407 if (!Event)
2408 {
2409 ObDereferenceObject(FileObject);
2410 return STATUS_INSUFFICIENT_RESOURCES;
2411 }
2412 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2413 LocalEvent = TRUE;
2414 }
2415
2416 /* Check if FastIO is possible for the two available information classes */
2417 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2418 if (FastIoDispatch != NULL &&
2419 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
2420 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
2421 {
2422 BOOLEAN Success = FALSE;
2423
2424 if (FileInformationClass == FileBasicInformation)
2425 {
2426 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
2427 FileInformation,
2428 &KernelIosb,
2429 DeviceObject);
2430 }
2431 else
2432 {
2433 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
2434 FileInformation,
2435 &KernelIosb,
2436 DeviceObject);
2437 }
2438
2439 /* If call succeed */
2440 if (Success)
2441 {
2442 /* Write the IOSB back */
2443 _SEH2_TRY
2444 {
2445 *IoStatusBlock = KernelIosb;
2446 }
2447 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2448 {
2449 KernelIosb.Status = _SEH2_GetExceptionCode();
2450 }
2451 _SEH2_END;
2452
2453 /* Free the event if we had one */
2454 if (LocalEvent)
2455 {
2456 ExFreePoolWithTag(Event, TAG_IO);
2457 }
2458
2459 /* If FO was locked, unlock it */
2460 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2461 {
2462 IopUnlockFileObject(FileObject);
2463 }
2464
2465 /* We're done with FastIO! */
2466 ObDereferenceObject(FileObject);
2467 return KernelIosb.Status;
2468 }
2469 }
2470
2471 /* Clear the File Object event */
2472 KeClearEvent(&FileObject->Event);
2473
2474 /* Allocate the IRP */
2475 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2476 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2477
2478 /* Set the IRP */
2479 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2480 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2481 Irp->RequestorMode = PreviousMode;
2482 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2483 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2484 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2485 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2486 Irp->AssociatedIrp.SystemBuffer = NULL;
2487 Irp->MdlAddress = NULL;
2488 Irp->UserBuffer = FileInformation;
2489
2490 /* Set the Stack Data */
2491 StackPtr = IoGetNextIrpStackLocation(Irp);
2492 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2493 StackPtr->FileObject = FileObject;
2494
2495 /* Enter SEH */
2496 _SEH2_TRY
2497 {
2498 /* Allocate a buffer */
2499 Irp->AssociatedIrp.SystemBuffer =
2500 ExAllocatePoolWithTag(NonPagedPool,
2501 Length,
2502 TAG_SYSB);
2503 }
2504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2505 {
2506 /* Allocating failed, clean up and return the exception code */
2507 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2508 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2509 }
2510 _SEH2_END;
2511
2512 /* Set the flags */
2513 Irp->Flags |= (IRP_BUFFERED_IO |
2514 IRP_DEALLOCATE_BUFFER |
2515 IRP_INPUT_OPERATION |
2516 IRP_DEFER_IO_COMPLETION);
2517
2518 /* Set the Parameters */
2519 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2520 StackPtr->Parameters.QueryFile.Length = Length;
2521
2522 /* Queue the IRP */
2523 IopQueueIrpToThread(Irp);
2524
2525 /* Update operation counts */
2526 IopUpdateOperationCount(IopOtherTransfer);
2527
2528 /* Fill in file information before calling the driver.
2529 See 'File System Internals' page 485.*/
2530 if (FileInformationClass == FileAccessInformation)
2531 {
2532 AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2533 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2534 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2535 CallDriver = FALSE;
2536 }
2537 else if (FileInformationClass == FileModeInformation)
2538 {
2539 ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2540 ModeBuffer->Mode = IopGetFileMode(FileObject);
2541 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2542 CallDriver = FALSE;
2543 }
2544 else if (FileInformationClass == FileAlignmentInformation)
2545 {
2546 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2547 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2548 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2549 CallDriver = FALSE;
2550 }
2551 else if (FileInformationClass == FileAllInformation)
2552 {
2553 AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2554 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2555 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
2556 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2557 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2558 sizeof(FILE_MODE_INFORMATION) +
2559 sizeof(FILE_ALIGNMENT_INFORMATION);
2560 }
2561
2562 /* Call the Driver */
2563 if (CallDriver)
2564 {
2565 Status = IoCallDriver(DeviceObject, Irp);
2566 }
2567 else
2568 {
2569 Status = STATUS_SUCCESS;
2570 Irp->IoStatus.Status = STATUS_SUCCESS;
2571 }
2572
2573 if (Status == STATUS_PENDING)
2574 {
2575 /* Check if this was async I/O */
2576 if (LocalEvent)
2577 {
2578 /* Then to a non-alertable wait */
2579 Status = KeWaitForSingleObject(Event,
2580 Executive,
2581 PreviousMode,
2582 FALSE,
2583 NULL);
2584 if (Status == STATUS_USER_APC)
2585 {
2586 /* Abort the request */
2587 IopAbortInterruptedIrp(Event, Irp);
2588 }
2589
2590 /* Set the final status */
2591 Status = KernelIosb.Status;
2592
2593 /* Enter SEH to write the IOSB back */
2594 _SEH2_TRY
2595 {
2596 /* Write it back to the caller */
2597 *IoStatusBlock = KernelIosb;
2598 }
2599 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2600 {
2601 /* Get the exception code */
2602 Status = _SEH2_GetExceptionCode();
2603 }
2604 _SEH2_END;
2605
2606 /* Free the event */
2607 ExFreePoolWithTag(Event, TAG_IO);
2608 }
2609 else
2610 {
2611 /* Wait for the IRP */
2612 Status = KeWaitForSingleObject(&FileObject->Event,
2613 Executive,
2614 PreviousMode,
2615 (FileObject->Flags &
2616 FO_ALERTABLE_IO) != 0,
2617 NULL);
2618 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2619 {
2620 /* Abort the request */
2621 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2622 }
2623
2624 /* Set the final status */
2625 Status = FileObject->FinalStatus;
2626
2627 /* Release the file lock */
2628 IopUnlockFileObject(FileObject);
2629 }
2630 }
2631 else
2632 {
2633 /* Free the event if we had one */
2634 if (LocalEvent)
2635 {
2636 /* Clear it in the IRP for completion */
2637 Irp->UserEvent = NULL;
2638 ExFreePoolWithTag(Event, TAG_IO);
2639 }
2640
2641 /* Set the caller IOSB */
2642 Irp->UserIosb = IoStatusBlock;
2643
2644 /* The IRP wasn't completed, complete it ourselves */
2645 NormalRoutine = NULL;
2646 NormalContext = NULL;
2647 KeRaiseIrql(APC_LEVEL, &OldIrql);
2648 IopCompleteRequest(&Irp->Tail.Apc,
2649 &NormalRoutine,
2650 &NormalContext,
2651 (PVOID*)&FileObject,
2652 &NormalContext);
2653 KeLowerIrql(OldIrql);
2654
2655 /* Release the file object if we had locked it*/
2656 if (!LocalEvent) IopUnlockFileObject(FileObject);
2657 }
2658
2659 /* Return the Status */
2660 return Status;
2661 }
2662
2663 /*
2664 * @unimplemented
2665 */
2666 NTSTATUS
2667 NTAPI
2668 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2669 OUT PIO_STATUS_BLOCK IoStatusBlock,
2670 OUT PVOID Buffer,
2671 IN ULONG Length,
2672 IN BOOLEAN ReturnSingleEntry,
2673 IN PVOID SidList OPTIONAL,
2674 IN ULONG SidListLength,
2675 IN PSID StartSid OPTIONAL,
2676 IN BOOLEAN RestartScan)
2677 {
2678 UNIMPLEMENTED;
2679 return STATUS_NOT_IMPLEMENTED;
2680 }
2681
2682 /*
2683 * @implemented
2684 */
2685 NTSTATUS
2686 NTAPI
2687 NtReadFile(IN HANDLE FileHandle,
2688 IN HANDLE Event OPTIONAL,
2689 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2690 IN PVOID ApcContext OPTIONAL,
2691 OUT PIO_STATUS_BLOCK IoStatusBlock,
2692 OUT PVOID Buffer,
2693 IN ULONG Length,
2694 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2695 IN PULONG Key OPTIONAL)
2696 {
2697 NTSTATUS Status;
2698 PFILE_OBJECT FileObject;
2699 PIRP Irp;
2700 PDEVICE_OBJECT DeviceObject;
2701 PIO_STACK_LOCATION StackPtr;
2702 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2703 PKEVENT EventObject = NULL;
2704 LARGE_INTEGER CapturedByteOffset;
2705 ULONG CapturedKey = 0;
2706 BOOLEAN Synchronous = FALSE;
2707 PMDL Mdl;
2708 PFAST_IO_DISPATCH FastIoDispatch;
2709 IO_STATUS_BLOCK KernelIosb;
2710 BOOLEAN Success;
2711
2712 PAGED_CODE();
2713 CapturedByteOffset.QuadPart = 0;
2714 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2715
2716 /* Get File Object */
2717 Status = ObReferenceObjectByHandle(FileHandle,
2718 FILE_READ_DATA,
2719 IoFileObjectType,
2720 PreviousMode,
2721 (PVOID*)&FileObject,
2722 NULL);
2723 if (!NT_SUCCESS(Status)) return Status;
2724
2725 /* Get the device object */
2726 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2727
2728 /* Validate User-Mode Buffers */
2729 if (PreviousMode != KernelMode)
2730 {
2731 _SEH2_TRY
2732 {
2733 /* Probe the status block */
2734 ProbeForWriteIoStatusBlock(IoStatusBlock);
2735
2736 /* Probe the read buffer */
2737 ProbeForWrite(Buffer, Length, 1);
2738
2739 /* Check if we got a byte offset */
2740 if (ByteOffset)
2741 {
2742 /* Capture and probe it */
2743 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2744 }
2745
2746 /* Perform additional checks for non-cached file access */
2747 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
2748 {
2749 /* Fail if Length is not sector size aligned
2750 * Perform a quick check for 2^ sector sizes
2751 * If it fails, try a more standard way
2752 */
2753 if ((DeviceObject->SectorSize != 0) &&
2754 ((DeviceObject->SectorSize - 1) & Length) != 0)
2755 {
2756 if (Length % DeviceObject->SectorSize != 0)
2757 {
2758 /* Release the file object and and fail */
2759 ObDereferenceObject(FileObject);
2760 return STATUS_INVALID_PARAMETER;
2761 }
2762 }
2763
2764 /* Fail if buffer doesn't match alignment requirements */
2765 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
2766 {
2767 /* Release the file object and and fail */
2768 ObDereferenceObject(FileObject);
2769 return STATUS_INVALID_PARAMETER;
2770 }
2771
2772 if (ByteOffset)
2773 {
2774 /* Fail if ByteOffset is not sector size aligned */
2775 if ((DeviceObject->SectorSize != 0) &&
2776 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
2777 {
2778 /* Release the file object and and fail */
2779 ObDereferenceObject(FileObject);
2780 return STATUS_INVALID_PARAMETER;
2781 }
2782 }
2783 }
2784
2785 /* Capture and probe the key */
2786 if (Key) CapturedKey = ProbeForReadUlong(Key);
2787 }
2788 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2789 {
2790 /* Release the file object and return the exception code */
2791 ObDereferenceObject(FileObject);
2792 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2793 }
2794 _SEH2_END;
2795 }
2796 else
2797 {
2798 /* Kernel mode: capture directly */
2799 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2800 if (Key) CapturedKey = *Key;
2801 }
2802
2803 /* Check for invalid offset */
2804 if ((CapturedByteOffset.QuadPart < 0) && (CapturedByteOffset.QuadPart != -2))
2805 {
2806 /* -2 is FILE_USE_FILE_POINTER_POSITION */
2807 ObDereferenceObject(FileObject);
2808 return STATUS_INVALID_PARAMETER;
2809 }
2810
2811 /* Check for event */
2812 if (Event)
2813 {
2814 /* Reference it */
2815 Status = ObReferenceObjectByHandle(Event,
2816 EVENT_MODIFY_STATE,
2817 ExEventObjectType,
2818 PreviousMode,
2819 (PVOID*)&EventObject,
2820 NULL);
2821 if (!NT_SUCCESS(Status))
2822 {
2823 /* Fail */
2824 ObDereferenceObject(FileObject);
2825 return Status;
2826 }
2827
2828 /* Otherwise reset the event */
2829 KeClearEvent(EventObject);
2830 }
2831
2832 /* Check if we should use Sync IO or not */
2833 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2834 {
2835 /* Lock the file object */
2836 Status = IopLockFileObject(FileObject, PreviousMode);
2837 if (Status != STATUS_SUCCESS)
2838 {
2839 if (EventObject) ObDereferenceObject(EventObject);
2840 ObDereferenceObject(FileObject);
2841 return Status;
2842 }
2843
2844 /* Check if we don't have a byte offset available */
2845 if (!(ByteOffset) ||
2846 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2847 (CapturedByteOffset.u.HighPart == -1)))
2848 {
2849 /* Use the Current Byte Offset instead */
2850 CapturedByteOffset = FileObject->CurrentByteOffset;
2851 }
2852
2853 /* If the file is cached, try fast I/O */
2854 if (FileObject->PrivateCacheMap)
2855 {
2856 /* Perform fast read */
2857 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2858 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
2859
2860 Success = FastIoDispatch->FastIoRead(FileObject,
2861 &CapturedByteOffset,
2862 Length,
2863 TRUE,
2864 CapturedKey,
2865 Buffer,
2866 &KernelIosb,
2867 DeviceObject);
2868
2869 /* Only accept the result if we got a straightforward status */
2870 if (Success &&
2871 (KernelIosb.Status == STATUS_SUCCESS ||
2872 KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2873 KernelIosb.Status == STATUS_END_OF_FILE))
2874 {
2875 /* Fast path -- update transfer & operation counts */
2876 IopUpdateOperationCount(IopReadTransfer);
2877 IopUpdateTransferCount(IopReadTransfer,
2878 (ULONG)KernelIosb.Information);
2879
2880 /* Enter SEH to write the IOSB back */
2881 _SEH2_TRY
2882 {
2883 /* Write it back to the caller */
2884 *IoStatusBlock = KernelIosb;
2885 }
2886 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2887 {
2888 /* The caller's IOSB was invalid, so fail */
2889 if (EventObject) ObDereferenceObject(EventObject);
2890 IopUnlockFileObject(FileObject);
2891 ObDereferenceObject(FileObject);
2892 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2893 }
2894 _SEH2_END;
2895
2896 /* Signal the completion event */
2897 if (EventObject)
2898 {
2899 KeSetEvent(EventObject, 0, FALSE);
2900 ObDereferenceObject(EventObject);
2901 }
2902
2903 /* Clean up */
2904 IopUnlockFileObject(FileObject);
2905 ObDereferenceObject(FileObject);
2906 return KernelIosb.Status;
2907 }
2908 }
2909
2910 /* Remember we are sync */
2911 Synchronous = TRUE;
2912 }
2913 else if (!(ByteOffset) &&
2914 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2915 {
2916 /* Otherwise, this was async I/O without a byte offset, so fail */
2917 if (EventObject) ObDereferenceObject(EventObject);
2918 ObDereferenceObject(FileObject);
2919 return STATUS_INVALID_PARAMETER;
2920 }
2921
2922 /* Clear the File Object's event */
2923 KeClearEvent(&FileObject->Event);
2924
2925 /* Allocate the IRP */
2926 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2927 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2928
2929 /* Set the IRP */
2930 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2931 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2932 Irp->RequestorMode = PreviousMode;
2933 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2934 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2935 Irp->UserIosb = IoStatusBlock;
2936 Irp->UserEvent = EventObject;
2937 Irp->PendingReturned = FALSE;
2938 Irp->Cancel = FALSE;
2939 Irp->CancelRoutine = NULL;
2940 Irp->AssociatedIrp.SystemBuffer = NULL;
2941 Irp->MdlAddress = NULL;
2942
2943 /* Set the Stack Data */
2944 StackPtr = IoGetNextIrpStackLocation(Irp);
2945 StackPtr->MajorFunction = IRP_MJ_READ;
2946 StackPtr->FileObject = FileObject;
2947 StackPtr->Parameters.Read.Key = CapturedKey;
2948 StackPtr->Parameters.Read.Length = Length;
2949 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2950
2951 /* Check if this is buffered I/O */
2952 if (DeviceObject->Flags & DO_BUFFERED_IO)
2953 {
2954 /* Check if we have a buffer length */
2955 if (Length)
2956 {
2957 /* Enter SEH */
2958 _SEH2_TRY
2959 {
2960 /* Allocate a buffer */
2961 Irp->AssociatedIrp.SystemBuffer =
2962 ExAllocatePoolWithTag(NonPagedPool,
2963 Length,
2964 TAG_SYSB);
2965 }
2966 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2967 {
2968 /* Allocating failed, clean up and return the exception code */
2969 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2970 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2971 }
2972 _SEH2_END;
2973
2974 /* Set the buffer and flags */
2975 Irp->UserBuffer = Buffer;
2976 Irp->Flags = (IRP_BUFFERED_IO |
2977 IRP_DEALLOCATE_BUFFER |
2978 IRP_INPUT_OPERATION);
2979 }
2980 else
2981 {
2982 /* Not reading anything */
2983 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2984 }
2985 }
2986 else if (DeviceObject->Flags & DO_DIRECT_IO)
2987 {
2988 /* Check if we have a buffer length */
2989 if (Length)
2990 {
2991 _SEH2_TRY
2992 {
2993 /* Allocate an MDL */
2994 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2995 if (!Mdl)
2996 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2997 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2998 }
2999 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3000 {
3001 /* Allocating failed, clean up and return the exception code */
3002 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3003 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3004 }
3005 _SEH2_END;
3006
3007 }
3008
3009 /* No allocation flags */
3010 Irp->Flags = 0;
3011 }
3012 else
3013 {
3014 /* No allocation flags, and use the buffer directly */
3015 Irp->Flags = 0;
3016 Irp->UserBuffer = Buffer;
3017 }
3018
3019 /* Now set the deferred read flags */
3020 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
3021
3022 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3023
3024 /* Perform the call */
3025 return IopPerformSynchronousRequest(DeviceObject,
3026 Irp,
3027 FileObject,
3028 TRUE,
3029 PreviousMode,
3030 Synchronous,
3031 IopReadTransfer);
3032 }
3033
3034 /*
3035 * @unimplemented
3036 */
3037 NTSTATUS
3038 NTAPI
3039 NtReadFileScatter(IN HANDLE FileHandle,
3040 IN HANDLE Event OPTIONAL,
3041 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3042 IN PVOID UserApcContext OPTIONAL,
3043 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3044 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3045 IN ULONG BufferLength,
3046 IN PLARGE_INTEGER ByteOffset,
3047 IN PULONG Key OPTIONAL)
3048 {
3049 UNIMPLEMENTED;
3050 return STATUS_NOT_IMPLEMENTED;
3051 }
3052
3053 /*
3054 * @unimplemented
3055 */
3056 NTSTATUS
3057 NTAPI
3058 NtSetEaFile(IN HANDLE FileHandle,
3059 IN PIO_STATUS_BLOCK IoStatusBlock,
3060 IN PVOID EaBuffer,
3061 IN ULONG EaBufferSize)
3062 {
3063 UNIMPLEMENTED;
3064 return STATUS_NOT_IMPLEMENTED;
3065 }
3066
3067 /*
3068 * @implemented
3069 */
3070 NTSTATUS
3071 NTAPI
3072 NtSetInformationFile(IN HANDLE FileHandle,
3073 OUT PIO_STATUS_BLOCK IoStatusBlock,
3074 IN PVOID FileInformation,
3075 IN ULONG Length,
3076 IN FILE_INFORMATION_CLASS FileInformationClass)
3077 {
3078 PFILE_OBJECT FileObject;
3079 NTSTATUS Status;
3080 PIRP Irp;
3081 PDEVICE_OBJECT DeviceObject;
3082 PIO_STACK_LOCATION StackPtr;
3083 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
3084 PKEVENT Event = NULL;
3085 BOOLEAN LocalEvent = FALSE;
3086 PKNORMAL_ROUTINE NormalRoutine;
3087 PVOID NormalContext;
3088 KIRQL OldIrql;
3089 IO_STATUS_BLOCK KernelIosb;
3090 PVOID Queue;
3091 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
3092 PIO_COMPLETION_CONTEXT Context;
3093 PFILE_RENAME_INFORMATION RenameInfo;
3094 HANDLE TargetHandle = NULL;
3095 PAGED_CODE();
3096 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3097
3098 /* Check if we're called from user mode */
3099 if (PreviousMode != KernelMode)
3100 {
3101 /* Validate the information class */
3102 if ((FileInformationClass < 0) ||
3103 (FileInformationClass >= FileMaximumInformation) ||
3104 !(IopSetOperationLength[FileInformationClass]))
3105 {
3106 /* Invalid class */
3107 return STATUS_INVALID_INFO_CLASS;
3108 }
3109
3110 /* Validate the length */
3111 if (Length < IopSetOperationLength[FileInformationClass])
3112 {
3113 /* Invalid length */
3114 return STATUS_INFO_LENGTH_MISMATCH;
3115 }
3116
3117 /* Enter SEH for probing */
3118 _SEH2_TRY
3119 {
3120 /* Probe the I/O Status block */
3121 ProbeForWriteIoStatusBlock(IoStatusBlock);
3122
3123 /* Probe the information */
3124 ProbeForRead(FileInformation,
3125 Length,
3126 (Length == sizeof(BOOLEAN)) ?
3127 sizeof(BOOLEAN) : sizeof(ULONG));
3128 }
3129 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3130 {
3131 /* Return the exception code */
3132 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3133 }
3134 _SEH2_END;
3135 }
3136 else
3137 {
3138 /* Validate the information class */
3139 if ((FileInformationClass < 0) ||
3140 (FileInformationClass >= FileMaximumInformation) ||
3141 !(IopSetOperationLength[FileInformationClass]))
3142 {
3143 /* Invalid class */
3144 return STATUS_INVALID_INFO_CLASS;
3145 }
3146
3147 /* Validate the length */
3148 if (Length < IopSetOperationLength[FileInformationClass])
3149 {
3150 /* Invalid length */
3151 return STATUS_INFO_LENGTH_MISMATCH;
3152 }
3153 }
3154
3155 /* Reference the Handle */
3156 Status = ObReferenceObjectByHandle(FileHandle,
3157 IopSetOperationAccess
3158 [FileInformationClass],
3159 IoFileObjectType,
3160 PreviousMode,
3161 (PVOID *)&FileObject,
3162 NULL);
3163 if (!NT_SUCCESS(Status)) return Status;
3164
3165 /* Check if this is a direct open or not */
3166 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3167 {
3168 /* Get the device object */
3169 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3170 }
3171 else
3172 {
3173 /* Get the device object */
3174 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3175 }
3176
3177 DPRINT("Will call: %p\n", DeviceObject);
3178 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
3179
3180 /* Check if this is a file that was opened for Synch I/O */
3181 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3182 {
3183 /* Lock it */
3184 Status = IopLockFileObject(FileObject, PreviousMode);
3185 if (Status != STATUS_SUCCESS)
3186 {
3187 ObDereferenceObject(FileObject);
3188 return Status;
3189 }
3190
3191 /* Check if the caller just wants the position */
3192 if (FileInformationClass == FilePositionInformation)
3193 {
3194 /* Protect write in SEH */
3195 _SEH2_TRY
3196 {
3197 /* Write the offset */
3198 FileObject->CurrentByteOffset =
3199 ((PFILE_POSITION_INFORMATION)FileInformation)->
3200 CurrentByteOffset;
3201
3202 /* Fill out the I/O Status Block */
3203 IoStatusBlock->Information = 0;
3204 Status = IoStatusBlock->Status = STATUS_SUCCESS;
3205 }
3206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3207 {
3208 /* Get the exception code */
3209 Status = _SEH2_GetExceptionCode();
3210 }
3211 _SEH2_END;
3212
3213 /* Update transfer count */
3214 IopUpdateTransferCount(IopOtherTransfer, Length);
3215
3216 /* Release the file lock, dereference the file and return */
3217 IopUnlockFileObject(FileObject);
3218 ObDereferenceObject(FileObject);
3219 return Status;
3220 }
3221 }
3222 else
3223 {
3224 /* Use local event */
3225 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3226 if (!Event)
3227 {
3228 ObDereferenceObject(FileObject);
3229 return STATUS_INSUFFICIENT_RESOURCES;
3230 }
3231
3232 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3233 LocalEvent = TRUE;
3234 }
3235
3236 /* Clear the File Object event */
3237 KeClearEvent(&FileObject->Event);
3238
3239 /* Allocate the IRP */
3240 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
3241 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3242
3243 /* Set the IRP */
3244 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3245 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3246 Irp->RequestorMode = PreviousMode;
3247 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3248 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3249 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3250 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3251 Irp->AssociatedIrp.SystemBuffer = NULL;
3252 Irp->MdlAddress = NULL;
3253 Irp->UserBuffer = FileInformation;
3254
3255 /* Set the Stack Data */
3256 StackPtr = IoGetNextIrpStackLocation(Irp);
3257 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
3258 StackPtr->FileObject = FileObject;
3259
3260 /* Enter SEH */
3261 _SEH2_TRY
3262 {
3263 /* Allocate a buffer */
3264 Irp->AssociatedIrp.SystemBuffer =
3265 ExAllocatePoolWithTag(NonPagedPool,
3266 Length,
3267 TAG_SYSB);
3268
3269 /* Copy the data into it */
3270 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3271 FileInformation,
3272 Length);
3273 }
3274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3275 {
3276 /* Allocating failed, clean up and return the exception code */
3277 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3278 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3279 }
3280 _SEH2_END;
3281
3282 /* Set the flags */
3283 Irp->Flags |= (IRP_BUFFERED_IO |
3284 IRP_DEALLOCATE_BUFFER |
3285 IRP_DEFER_IO_COMPLETION);
3286
3287 /* Set the Parameters */
3288 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3289 StackPtr->Parameters.SetFile.Length = Length;
3290
3291 /* Queue the IRP */
3292 IopQueueIrpToThread(Irp);
3293
3294 /* Update operation counts */
3295 IopUpdateOperationCount(IopOtherTransfer);
3296
3297 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3298 /* Handle IO Completion Port quickly */
3299 if (FileInformationClass == FileCompletionInformation)
3300 {
3301 /* Check if the file object already has a completion port */
3302 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3303 (FileObject->CompletionContext))
3304 {
3305 /* Fail */
3306 Status = STATUS_INVALID_PARAMETER;
3307 }
3308 else
3309 {
3310 /* Reference the Port */
3311 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3312 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3313 IO_COMPLETION_MODIFY_STATE,
3314 IoCompletionType,
3315 PreviousMode,
3316 (PVOID*)&Queue,
3317 NULL);
3318 if (NT_SUCCESS(Status))
3319 {
3320 /* Allocate the Context */
3321 Context = ExAllocatePoolWithTag(PagedPool,
3322 sizeof(IO_COMPLETION_CONTEXT),
3323 IOC_TAG);
3324 if (Context)
3325 {
3326 /* Set the Data */
3327 Context->Key = CompletionInfo->Key;
3328 Context->Port = Queue;
3329 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
3330 CompletionContext,
3331 Context,
3332 NULL))
3333 {
3334 /*
3335 * Someone else set the completion port in the
3336 * meanwhile, so dereference the port and fail.
3337 */
3338 ExFreePoolWithTag(Context, IOC_TAG);
3339 ObDereferenceObject(Queue);
3340 Status = STATUS_INVALID_PARAMETER;
3341 }
3342 }
3343 else
3344 {
3345 /* Dereference the Port now */
3346 ObDereferenceObject(Queue);
3347 Status = STATUS_INSUFFICIENT_RESOURCES;
3348 }
3349 }
3350 }
3351
3352 /* Set the IRP Status */
3353 Irp->IoStatus.Status = Status;
3354 Irp->IoStatus.Information = 0;
3355 }
3356 else if (FileInformationClass == FileRenameInformation ||
3357 FileInformationClass == FileLinkInformation ||
3358 FileInformationClass == FileMoveClusterInformation)
3359 {
3360 /* Get associated information */
3361 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3362
3363 /* Only rename if:
3364 * -> We have a name
3365 * -> In unicode
3366 * -> sizes are valid
3367 */
3368 if (RenameInfo->FileNameLength != 0 &&
3369 !(RenameInfo->FileNameLength & 1) &&
3370 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
3371 {
3372 /* Properly set information received */
3373 if (FileInformationClass == FileMoveClusterInformation)
3374 {
3375 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3376 }
3377 else
3378 {
3379 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3380 }
3381
3382 /* If we got fully path OR relative target, attempt a parent directory open */
3383 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3384 {
3385 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
3386 if (!NT_SUCCESS(Status))
3387 {
3388 Irp->IoStatus.Status = Status;
3389 }
3390 else
3391 {
3392 /* Call the Driver */
3393 Status = IoCallDriver(DeviceObject, Irp);
3394 }
3395 }
3396 else
3397 {
3398 /* Call the Driver */
3399 Status = IoCallDriver(DeviceObject, Irp);
3400 }
3401 }
3402 else
3403 {
3404 Status = STATUS_INVALID_PARAMETER;
3405 Irp->IoStatus.Status = Status;
3406 }
3407 }
3408 else
3409 {
3410 /* Call the Driver */
3411 Status = IoCallDriver(DeviceObject, Irp);
3412 }
3413
3414 /* Check if we're waiting for the IRP to complete */
3415 if (Status == STATUS_PENDING)
3416 {
3417 /* Check if this was async I/O */
3418 if (LocalEvent)
3419 {
3420 /* Then to a non-alertable wait */
3421 Status = KeWaitForSingleObject(Event,
3422 Executive,
3423 PreviousMode,
3424 FALSE,
3425 NULL);
3426 if (Status == STATUS_USER_APC)
3427 {
3428 /* Abort the request */
3429 IopAbortInterruptedIrp(Event, Irp);
3430 }
3431
3432 /* Set the final status */
3433 Status = KernelIosb.Status;
3434
3435 /* Enter SEH to write the IOSB back */
3436 _SEH2_TRY
3437 {
3438 /* Write it back to the caller */
3439 *IoStatusBlock = KernelIosb;
3440 }
3441 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3442 {
3443 /* Get the exception code */
3444 Status = _SEH2_GetExceptionCode();
3445 }
3446 _SEH2_END;
3447
3448 /* Free the event */
3449 ExFreePoolWithTag(Event, TAG_IO);
3450 }
3451 else
3452 {
3453 /* Wait for the IRP */
3454 Status = KeWaitForSingleObject(&FileObject->Event,
3455 Executive,
3456 PreviousMode,
3457 (FileObject->Flags &
3458 FO_ALERTABLE_IO) != 0,
3459 NULL);
3460 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3461 {
3462 /* Abort the request */
3463 IopAbortInterruptedIrp(&FileObject->Event, Irp);
3464 }
3465
3466 /* Set the final status */
3467 Status = FileObject->FinalStatus;
3468
3469 /* Release the file lock */
3470 IopUnlockFileObject(FileObject);
3471 }
3472 }
3473 else
3474 {
3475 /* Free the event if we had one */
3476 if (LocalEvent)
3477 {
3478 /* Clear it in the IRP for completion */
3479 Irp->UserEvent = NULL;
3480 ExFreePoolWithTag(Event, TAG_IO);
3481 }
3482
3483 /* Set the caller IOSB */
3484 Irp->UserIosb = IoStatusBlock;
3485
3486 /* The IRP wasn't completed, complete it ourselves */
3487 NormalRoutine = NULL;
3488 NormalContext = NULL;
3489 KeRaiseIrql(APC_LEVEL, &OldIrql);
3490 IopCompleteRequest(&Irp->Tail.Apc,
3491 &NormalRoutine,
3492 &NormalContext,
3493 (PVOID*)&FileObject,
3494 &NormalContext);
3495 KeLowerIrql(OldIrql);
3496
3497 /* Release the file object if we had locked it*/
3498 if (!LocalEvent) IopUnlockFileObject(FileObject);
3499 }
3500
3501 if (TargetHandle != NULL)
3502 {
3503 ObCloseHandle(TargetHandle, KernelMode);
3504 }
3505
3506 /* Return the Status */
3507 return Status;
3508 }
3509
3510 /*
3511 * @unimplemented
3512 */
3513 NTSTATUS
3514 NTAPI
3515 NtSetQuotaInformationFile(IN HANDLE FileHandle,
3516 OUT PIO_STATUS_BLOCK IoStatusBlock,
3517 IN PVOID Buffer,
3518 IN ULONG BufferLength)
3519 {
3520 UNIMPLEMENTED;
3521 return STATUS_NOT_IMPLEMENTED;
3522 }
3523
3524 /*
3525 * @implemented
3526 */
3527 NTSTATUS
3528 NTAPI
3529 NtUnlockFile(IN HANDLE FileHandle,
3530 OUT PIO_STATUS_BLOCK IoStatusBlock,
3531 IN PLARGE_INTEGER ByteOffset,
3532 IN PLARGE_INTEGER Length,
3533 IN ULONG Key OPTIONAL)
3534 {
3535 PFILE_OBJECT FileObject;
3536 PLARGE_INTEGER LocalLength = NULL;
3537 PIRP Irp;
3538 PIO_STACK_LOCATION StackPtr;
3539 PDEVICE_OBJECT DeviceObject;
3540 PKEVENT Event = NULL;
3541 BOOLEAN LocalEvent = FALSE;
3542 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3543 LARGE_INTEGER CapturedByteOffset, CapturedLength;
3544 NTSTATUS Status;
3545 OBJECT_HANDLE_INFORMATION HandleInformation;
3546 IO_STATUS_BLOCK KernelIosb;
3547 PFAST_IO_DISPATCH FastIoDispatch;
3548 PAGED_CODE();
3549 CapturedByteOffset.QuadPart = 0;
3550 CapturedLength.QuadPart = 0;
3551 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3552
3553 /* Get File Object */
3554 Status = ObReferenceObjectByHandle(FileHandle,
3555 0,
3556 IoFileObjectType,
3557 PreviousMode,
3558 (PVOID*)&FileObject,
3559 &HandleInformation);
3560 if (!NT_SUCCESS(Status)) return Status;
3561
3562 /* Check if we're called from user mode */
3563 if (PreviousMode != KernelMode)
3564 {
3565 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3566 if (!(HandleInformation.GrantedAccess &
3567 (FILE_WRITE_DATA | FILE_READ_DATA)))
3568 {
3569 ObDereferenceObject(FileObject);
3570 return STATUS_ACCESS_DENIED;
3571 }
3572
3573 /* Enter SEH for probing */
3574 _SEH2_TRY
3575 {
3576 /* Probe the I/O Status block */
3577 ProbeForWriteIoStatusBlock(IoStatusBlock);
3578
3579 /* Probe and capture the large integers */
3580 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3581 CapturedLength = ProbeForReadLargeInteger(Length);
3582 }
3583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3584 {
3585 /* Dereference the object and return exception code */
3586 ObDereferenceObject(FileObject);
3587 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3588 }
3589 _SEH2_END;
3590 }
3591 else
3592 {
3593 /* Otherwise, capture them directly */
3594 CapturedByteOffset = *ByteOffset;
3595 CapturedLength = *Length;
3596 }
3597
3598 /* Check if this is a direct open or not */
3599 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3600 {
3601 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3602 }
3603 else
3604 {
3605 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3606 }
3607
3608 /* Try to do it the FastIO way if possible */
3609 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3610 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
3611 {
3612 if (FastIoDispatch->FastIoUnlockSingle(FileObject,
3613 &CapturedByteOffset,
3614 &CapturedLength,
3615 PsGetCurrentProcess(),
3616 Key,
3617 &KernelIosb,
3618 DeviceObject))
3619 {
3620 /* Write the IOSB back */
3621 _SEH2_TRY
3622 {
3623 *IoStatusBlock = KernelIosb;
3624 }
3625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3626 {
3627 KernelIosb.Status = _SEH2_GetExceptionCode();
3628 }
3629 _SEH2_END;
3630
3631 /* We're done with FastIO! */
3632 ObDereferenceObject(FileObject);
3633 return KernelIosb.Status;
3634 }
3635 }
3636
3637 /* Check if we should use Sync IO or not */
3638 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3639 {
3640 /* Lock it */
3641 Status = IopLockFileObject(FileObject, PreviousMode);
3642 if (Status != STATUS_SUCCESS)
3643 {
3644 ObDereferenceObject(FileObject);
3645 return Status;
3646 }
3647 }
3648 else
3649 {
3650 /* Use local event */
3651 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3652 if (!Event)
3653 {
3654 ObDereferenceObject(FileObject);
3655 return STATUS_INSUFFICIENT_RESOURCES;
3656 }
3657 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3658 LocalEvent = TRUE;
3659 }
3660
3661 /* Clear File Object event */
3662 KeClearEvent(&FileObject->Event);
3663
3664 /* Allocate the IRP */
3665 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3666 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3667
3668 /* Set up the IRP */
3669 Irp->RequestorMode = PreviousMode;
3670 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3671 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3672 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3673 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3674 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3675 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3676
3677 /* Set up Stack Data */
3678 StackPtr = IoGetNextIrpStackLocation(Irp);
3679 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3680 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3681 StackPtr->FileObject = FileObject;
3682
3683 /* Enter SEH */
3684 _SEH2_TRY
3685 {
3686 /* Allocate a buffer */
3687 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3688 sizeof(LARGE_INTEGER),
3689 TAG_LOCK);
3690
3691 /* Set the length */
3692 *LocalLength = CapturedLength;
3693 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3694 StackPtr->Parameters.LockControl.Length = LocalLength;
3695 }
3696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3697 {
3698 /* Allocating failed, clean up and return the exception code */
3699 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3700 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3701
3702 /* Return the exception code */
3703 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3704 }
3705 _SEH2_END;
3706
3707 /* Set Parameters */
3708 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3709 StackPtr->Parameters.LockControl.Key = Key;
3710
3711 /* Call the Driver */
3712 Status = IopPerformSynchronousRequest(DeviceObject,
3713 Irp,
3714 FileObject,
3715 FALSE,
3716 PreviousMode,
3717 !LocalEvent,
3718 IopOtherTransfer);
3719
3720 /* Check if this was async I/O */
3721 if (LocalEvent)
3722 {
3723 /* It was, finalize this request */
3724 Status = IopFinalizeAsynchronousIo(Status,
3725 Event,
3726 Irp,
3727 PreviousMode,
3728 &KernelIosb,
3729 IoStatusBlock);
3730 }
3731
3732 /* Return status */
3733 return Status;
3734 }
3735
3736 /*
3737 * @implemented
3738 */
3739 NTSTATUS
3740 NTAPI
3741 NtWriteFile(IN HANDLE FileHandle,
3742 IN HANDLE Event OPTIONAL,
3743 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3744 IN PVOID ApcContext OPTIONAL,
3745 OUT PIO_STATUS_BLOCK IoStatusBlock,
3746 IN PVOID Buffer,
3747 IN ULONG Length,
3748 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3749 IN PULONG Key OPTIONAL)
3750 {
3751 NTSTATUS Status;
3752 PFILE_OBJECT FileObject;
3753 PIRP Irp;
3754 PDEVICE_OBJECT DeviceObject;
3755 PIO_STACK_LOCATION StackPtr;
3756 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3757 PKEVENT EventObject = NULL;
3758 LARGE_INTEGER CapturedByteOffset;
3759 ULONG CapturedKey = 0;
3760 BOOLEAN Synchronous = FALSE;
3761 PMDL Mdl;
3762 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3763 PFAST_IO_DISPATCH FastIoDispatch;
3764 IO_STATUS_BLOCK KernelIosb;
3765 BOOLEAN Success;
3766
3767 PAGED_CODE();
3768 CapturedByteOffset.QuadPart = 0;
3769 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3770
3771 /* Get File Object for write */
3772 Status = ObReferenceFileObjectForWrite(FileHandle,
3773 PreviousMode,
3774 &FileObject,
3775 &ObjectHandleInfo);
3776 if (!NT_SUCCESS(Status)) return Status;
3777
3778 /* Get the device object */
3779 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3780
3781 /* Validate User-Mode Buffers */
3782 if (PreviousMode != KernelMode)
3783 {
3784 _SEH2_TRY
3785 {
3786 /* Probe the status block */
3787 ProbeForWriteIoStatusBlock(IoStatusBlock);
3788
3789 /* Probe the read buffer */
3790 ProbeForRead(Buffer, Length, 1);
3791
3792 /* Check if we got a byte offset */
3793 if (ByteOffset)
3794 {
3795 /* Capture and probe it */
3796 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3797 }
3798
3799 /* Perform additional checks for non-cached file access */
3800 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
3801 {
3802 /* Fail if Length is not sector size aligned
3803 * Perform a quick check for 2^ sector sizes
3804 * If it fails, try a more standard way
3805 */
3806 if ((DeviceObject->SectorSize != 0) &&
3807 ((DeviceObject->SectorSize - 1) & Length) != 0)
3808 {
3809 if (Length % DeviceObject->SectorSize != 0)
3810 {
3811 /* Release the file object and and fail */
3812 ObDereferenceObject(FileObject);
3813 return STATUS_INVALID_PARAMETER;
3814 }
3815 }
3816
3817 /* Fail if buffer doesn't match alignment requirements */
3818 if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
3819 {
3820 /* Release the file object and and fail */
3821 ObDereferenceObject(FileObject);
3822 return STATUS_INVALID_PARAMETER;
3823 }
3824
3825 if (ByteOffset)
3826 {
3827 /* Fail if ByteOffset is not sector size aligned */
3828 if ((DeviceObject->SectorSize != 0) &&
3829 (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
3830 {
3831 /* Only if that's not specific values for synchronous IO */
3832 if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) &&
3833 (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION ||
3834 !BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)))
3835 {
3836 /* Release the file object and and fail */
3837 ObDereferenceObject(FileObject);
3838 return STATUS_INVALID_PARAMETER;
3839 }
3840 }
3841 }
3842 }
3843
3844 /* Capture and probe the key */
3845 if (Key) CapturedKey = ProbeForReadUlong(Key);
3846 }
3847 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3848 {
3849 /* Release the file object and return the exception code */
3850 ObDereferenceObject(FileObject);
3851 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3852 }
3853 _SEH2_END;
3854 }
3855 else
3856 {
3857 /* Kernel mode: capture directly */
3858 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3859 if (Key) CapturedKey = *Key;
3860 }
3861
3862 /* Check for invalid offset */
3863 if (CapturedByteOffset.QuadPart < -2)
3864 {
3865 /* -1 is FILE_WRITE_TO_END_OF_FILE */
3866 /* -2 is FILE_USE_FILE_POINTER_POSITION */
3867 ObDereferenceObject(FileObject);
3868 return STATUS_INVALID_PARAMETER;
3869 }
3870
3871 /* Check if this is an append operation */
3872 if ((ObjectHandleInfo.GrantedAccess &
3873 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3874 {
3875 /* Give the drivers something to understand */
3876 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3877 CapturedByteOffset.u.HighPart = -1;
3878 }
3879
3880 /* Check for event */
3881 if (Event)
3882 {
3883 /* Reference it */
3884 Status = ObReferenceObjectByHandle(Event,
3885 EVENT_MODIFY_STATE,
3886 ExEventObjectType,
3887 PreviousMode,
3888 (PVOID*)&EventObject,
3889 NULL);
3890 if (!NT_SUCCESS(Status))
3891 {
3892 /* Fail */
3893 ObDereferenceObject(FileObject);
3894 return Status;
3895 }
3896
3897 /* Otherwise reset the event */
3898 KeClearEvent(EventObject);
3899 }
3900
3901 /* Check if we should use Sync IO or not */
3902 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3903 {
3904 /* Lock the file object */
3905 Status = IopLockFileObject(FileObject, PreviousMode);
3906 if (Status != STATUS_SUCCESS)
3907 {
3908 if (EventObject) ObDereferenceObject(EventObject);
3909 ObDereferenceObject(FileObject);
3910 return Status;
3911 }
3912
3913 /* Check if we don't have a byte offset available */
3914 if (!(ByteOffset) ||
3915 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3916 (CapturedByteOffset.u.HighPart == -1)))
3917 {
3918 /* Use the Current Byte Offset instead */
3919 CapturedByteOffset = FileObject->CurrentByteOffset;
3920 }
3921
3922 /* If the file is cached, try fast I/O */
3923 if (FileObject->PrivateCacheMap)
3924 {
3925 /* Perform fast write */
3926 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3927 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
3928
3929 Success = FastIoDispatch->FastIoWrite(FileObject,
3930 &CapturedByteOffset,
3931 Length,
3932 TRUE,
3933 CapturedKey,
3934 Buffer,
3935 &KernelIosb,
3936 DeviceObject);
3937
3938 /* Only accept the result if it was successful */
3939 if (Success &&
3940 KernelIosb.Status == STATUS_SUCCESS)
3941 {
3942 /* Fast path -- update transfer & operation counts */
3943 IopUpdateOperationCount(IopWriteTransfer);
3944 IopUpdateTransferCount(IopWriteTransfer,
3945 (ULONG)KernelIosb.Information);
3946
3947 /* Enter SEH to write the IOSB back */
3948 _SEH2_TRY
3949 {
3950 /* Write it back to the caller */
3951 *IoStatusBlock = KernelIosb;
3952 }
3953 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3954 {
3955 /* The caller's IOSB was invalid, so fail */
3956 if (EventObject) ObDereferenceObject(EventObject);
3957 IopUnlockFileObject(FileObject);
3958 ObDereferenceObject(FileObject);
3959 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3960 }
3961 _SEH2_END;
3962
3963 /* Signal the completion event */
3964 if (EventObject)
3965 {
3966 KeSetEvent(EventObject, 0, FALSE);
3967 ObDereferenceObject(EventObject);
3968 }
3969
3970 /* Clean up */
3971 IopUnlockFileObject(FileObject);
3972 ObDereferenceObject(FileObject);
3973 return KernelIosb.Status;
3974 }
3975 }
3976
3977 /* Remember we are sync */
3978 Synchronous = TRUE;
3979 }
3980 else if (!(ByteOffset) &&
3981 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3982 {
3983 /* Otherwise, this was async I/O without a byte offset, so fail */
3984 if (EventObject) ObDereferenceObject(EventObject);
3985 ObDereferenceObject(FileObject);
3986 return STATUS_INVALID_PARAMETER;
3987 }
3988
3989 /* Clear the File Object's event */
3990 KeClearEvent(&FileObject->Event);
3991
3992 /* Allocate the IRP */
3993 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3994 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
3995
3996 /* Set the IRP */
3997 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3998 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3999 Irp->RequestorMode = PreviousMode;
4000 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
4001 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
4002 Irp->UserIosb = IoStatusBlock;
4003 Irp->UserEvent = EventObject;
4004 Irp->PendingReturned = FALSE;
4005 Irp->Cancel = FALSE;
4006 Irp->CancelRoutine = NULL;
4007 Irp->AssociatedIrp.SystemBuffer = NULL;
4008 Irp->MdlAddress = NULL;
4009
4010 /* Set the Stack Data */
4011 StackPtr = IoGetNextIrpStackLocation(Irp);
4012 StackPtr->MajorFunction = IRP_MJ_WRITE;
4013 StackPtr->FileObject = FileObject;
4014 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
4015 SL_WRITE_THROUGH : 0;
4016 StackPtr->Parameters.Write.Key = CapturedKey;
4017 StackPtr->Parameters.Write.Length = Length;
4018 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
4019
4020 /* Check if this is buffered I/O */
4021 if (DeviceObject->Flags & DO_BUFFERED_IO)
4022 {
4023 /* Check if we have a buffer length */
4024 if (Length)
4025 {
4026 /* Enter SEH */
4027 _SEH2_TRY
4028 {
4029 /* Allocate a buffer */
4030 Irp->AssociatedIrp.SystemBuffer =
4031 ExAllocatePoolWithTag(NonPagedPool,
4032 Length,
4033 TAG_SYSB);
4034
4035 /* Copy the data into it */
4036 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
4037 }
4038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4039 {
4040 /* Allocating failed, clean up and return the exception code */
4041 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4042 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4043 }
4044 _SEH2_END;
4045
4046 /* Set the flags */
4047 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
4048 }
4049 else
4050 {
4051 /* Not writing anything */
4052 Irp->Flags = IRP_BUFFERED_IO;
4053 }
4054 }
4055 else if (DeviceObject->Flags & DO_DIRECT_IO)
4056 {
4057 /* Check if we have a buffer length */
4058 if (Length)
4059 {
4060 _SEH2_TRY
4061 {
4062 /* Allocate an MDL */
4063 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
4064 if (!Mdl)
4065 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
4066 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
4067 }
4068 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4069 {
4070 /* Allocating failed, clean up and return the exception code */
4071 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4072 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4073 }
4074 _SEH2_END;
4075 }
4076
4077 /* No allocation flags */
4078 Irp->Flags = 0;
4079 }
4080 else
4081 {
4082 /* No allocation flags, and use the buffer directly */
4083 Irp->Flags = 0;
4084 Irp->UserBuffer = Buffer;
4085 }
4086
4087 /* Now set the deferred read flags */
4088 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
4089
4090 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
4091
4092 /* Perform the call */
4093 return IopPerformSynchronousRequest(DeviceObject,
4094 Irp,
4095 FileObject,
4096 TRUE,
4097 PreviousMode,
4098 Synchronous,
4099 IopWriteTransfer);
4100 }
4101
4102 NTSTATUS
4103 NTAPI
4104 NtWriteFileGather(IN HANDLE FileHandle,
4105 IN HANDLE Event OPTIONAL,
4106 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
4107 IN PVOID UserApcContext OPTIONAL,
4108 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
4109 IN FILE_SEGMENT_ELEMENT BufferDescription [],
4110 IN ULONG BufferLength,
4111 IN PLARGE_INTEGER ByteOffset,
4112 IN PULONG Key OPTIONAL)
4113 {
4114 UNIMPLEMENTED;
4115 return STATUS_NOT_IMPLEMENTED;
4116 }
4117
4118 /*
4119 * @implemented
4120 */
4121 NTSTATUS
4122 NTAPI
4123 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
4124 OUT PIO_STATUS_BLOCK IoStatusBlock,
4125 OUT PVOID FsInformation,
4126 IN ULONG Length,
4127 IN FS_INFORMATION_CLASS FsInformationClass)
4128 {
4129 PFILE_OBJECT FileObject;
4130 PIRP Irp;
4131 PIO_STACK_LOCATION StackPtr;
4132 PDEVICE_OBJECT DeviceObject;
4133 PKEVENT Event = NULL;
4134 BOOLEAN LocalEvent = FALSE;
4135 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4136 NTSTATUS Status;
4137 IO_STATUS_BLOCK KernelIosb;
4138 PAGED_CODE();
4139 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4140
4141 /* Check if we're called from user mode */
4142 if (PreviousMode != KernelMode)
4143 {
4144 /* Validate the information class */
4145 if ((FsInformationClass < 0) ||
4146 (FsInformationClass >= FileFsMaximumInformation) ||
4147 !(IopQueryFsOperationLength[FsInformationClass]))
4148 {
4149 /* Invalid class */
4150 return STATUS_INVALID_INFO_CLASS;
4151 }
4152
4153 /* Validate the length */
4154 if (Length < IopQueryFsOperationLength[FsInformationClass])
4155 {
4156 /* Invalid length */
4157 return STATUS_INFO_LENGTH_MISMATCH;
4158 }
4159
4160 /* Enter SEH for probing */
4161 _SEH2_TRY
4162 {
4163 /* Probe the I/O Status block */
4164 ProbeForWriteIoStatusBlock(IoStatusBlock);
4165
4166 /* Probe the information */
4167 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
4168 }
4169 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4170 {
4171 /* Return the exception code */
4172 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4173 }
4174 _SEH2_END;
4175 }
4176
4177 /* Get File Object */
4178 Status = ObReferenceObjectByHandle(FileHandle,
4179 IopQueryFsOperationAccess
4180 [FsInformationClass],
4181 IoFileObjectType,
4182 PreviousMode,
4183 (PVOID*)&FileObject,
4184 NULL);
4185 if (!NT_SUCCESS(Status)) return Status;
4186
4187 /* Only allow direct device open for FileFsDeviceInformation */
4188 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) &&
4189 FsInformationClass != FileFsDeviceInformation)
4190 {
4191 ObDereferenceObject(FileObject);
4192 return STATUS_INVALID_DEVICE_REQUEST;
4193 }
4194
4195 /* Check if we should use Sync IO or not */
4196 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4197 {
4198 /* Lock it */
4199 Status = IopLockFileObject(FileObject, PreviousMode);
4200 if (Status != STATUS_SUCCESS)
4201 {
4202 ObDereferenceObject(FileObject);
4203 return Status;
4204 }
4205 }
4206
4207 /*
4208 * Quick path for FileFsDeviceInformation - the kernel has enough
4209 * info to reply instead of the driver, excepted for network file systems
4210 */
4211 if (FsInformationClass == FileFsDeviceInformation &&
4212 (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN) || FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM))
4213 {
4214 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo = FsInformation;
4215 DeviceObject = FileObject->DeviceObject;
4216
4217 _SEH2_TRY
4218 {
4219 FsDeviceInfo->DeviceType = DeviceObject->DeviceType;
4220
4221 /* Complete characteristcs with mount status if relevant */
4222 FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
4223 if (IopGetMountFlag(DeviceObject))
4224 {
4225 SetFlag(FsDeviceInfo->Characteristics, FILE_DEVICE_IS_MOUNTED);
4226 }
4227
4228 IoStatusBlock->Information = sizeof(FILE_FS_DEVICE_INFORMATION);
4229 IoStatusBlock->Status = STATUS_SUCCESS;
4230 }
4231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4232 {
4233 /* Check if we had a file lock */
4234 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4235 {
4236 /* Release it */
4237 IopUnlockFileObject(FileObject);
4238 }
4239
4240 /* Dereference the FO */
4241 ObDereferenceObject(FileObject);
4242
4243 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4244 }
4245 _SEH2_END;
4246
4247 /* Check if we had a file lock */
4248 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4249 {
4250 /* Release it */
4251 IopUnlockFileObject(FileObject);
4252 }
4253
4254 /* Dereference the FO */
4255 ObDereferenceObject(FileObject);
4256
4257 return STATUS_SUCCESS;
4258 }
4259 /* This is to be handled by the kernel, not by FSD */
4260 else if (FsInformationClass == FileFsDriverPathInformation)
4261 {
4262 _SEH2_VOLATILE PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo = NULL;
4263
4264 _SEH2_TRY
4265 {
4266 /* Allocate our local structure */
4267 DriverPathInfo = ExAllocatePoolWithQuotaTag(NonPagedPool, Length, TAG_IO);
4268
4269 /* And copy back caller data */
4270 RtlCopyMemory(DriverPathInfo, FsInformation, Length);
4271
4272 /* Is the driver in the IO path? */
4273 Status = IopGetDriverPathInformation(FileObject,
4274 (PFILE_FS_DRIVER_PATH_INFORMATION)DriverPathInfo,
4275 Length);
4276 /* We failed, don't continue execution */
4277 if (!NT_SUCCESS(Status))
4278 {
4279 RtlRaiseStatus(Status);
4280 }
4281
4282 /* We succeed, copy back info */
4283 ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath;
4284
4285 /* We're done */
4286 IoStatusBlock->Information = sizeof(FILE_FS_DRIVER_PATH_INFORMATION);
4287 IoStatusBlock->Status = STATUS_SUCCESS;
4288 }
4289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4290 {
4291 Status = _SEH2_GetExceptionCode();
4292 }
4293 _SEH2_END;
4294
4295 /* Don't leak */
4296 if (DriverPathInfo != NULL)
4297 {
4298 ExFreePoolWithTag(DriverPathInfo, TAG_IO);
4299 }
4300
4301 /* Check if we had a file lock */
4302 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4303 {
4304 /* Release it */
4305 IopUnlockFileObject(FileObject);
4306 }
4307
4308 /* Dereference the FO */
4309 ObDereferenceObject(FileObject);
4310
4311 return Status;
4312 }
4313
4314 if (!BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
4315 {
4316 /* Use local event */
4317 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
4318 if (!Event)
4319 {
4320 ObDereferenceObject(FileObject);
4321 return STATUS_INSUFFICIENT_RESOURCES;
4322 }
4323 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
4324 LocalEvent = TRUE;
4325 }
4326
4327 /* Get the device object */
4328 DeviceObject = IoGetRelatedDeviceObject(FileObject);
4329
4330 /* Clear File Object event */
4331 KeClearEvent(&FileObject->Event);
4332
4333 /* Allocate the IRP */
4334 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4335 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
4336
4337 /* Set up the IRP */
4338 Irp->RequestorMode = PreviousMode;
4339 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4340 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4341 Irp->UserEvent = (LocalEvent) ? Event : NULL;
4342 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4343 Irp->Tail.Overlay.OriginalFileObject = FileObject;
4344 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4345 Irp->UserBuffer = FsInformation;
4346 Irp->AssociatedIrp.SystemBuffer = NULL;
4347 Irp->MdlAddress = NULL;
4348
4349 /* Set up Stack Data */
4350 StackPtr = IoGetNextIrpStackLocation(Irp);
4351 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
4352 StackPtr->FileObject = FileObject;
4353
4354 /* Enter SEH */
4355 _SEH2_TRY
4356 {
4357 /* Allocate a buffer */
4358 Irp->AssociatedIrp.SystemBuffer =
4359 ExAllocatePoolWithTag(NonPagedPool,
4360 Length,
4361 TAG_SYSB);
4362 }
4363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4364 {
4365 /* Allocating failed, clean up and return the exception code */
4366 IopCleanupAfterException(FileObject, Irp, NULL, Event);
4367 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4368 }
4369 _SEH2_END;
4370
4371 /* Set the flags for this buffered + deferred I/O */
4372 Irp->Flags |= (IRP_BUFFERED_IO |
4373 IRP_DEALLOCATE_BUFFER |
4374 IRP_INPUT_OPERATION |
4375 IRP_DEFER_IO_COMPLETION);
4376
4377 /* Set Parameters */
4378 StackPtr->Parameters.QueryVolume.Length = Length;
4379 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
4380
4381 /* Call the Driver */
4382 Status = IopPerformSynchronousRequest(DeviceObject,
4383 Irp,
4384 FileObject,
4385 TRUE,
4386 PreviousMode,
4387 !LocalEvent,
4388 IopOtherTransfer);
4389
4390 /* Check if this was async I/O */
4391 if (LocalEvent)
4392 {
4393 /* It was, finalize this request */
4394 Status = IopFinalizeAsynchronousIo(Status,
4395 Event,
4396 Irp,
4397 PreviousMode,
4398 &KernelIosb,
4399 IoStatusBlock);
4400 }
4401
4402 /* Return status */
4403 return Status;
4404 }
4405
4406 /*
4407 * @implemented
4408 */
4409 NTSTATUS
4410 NTAPI
4411 NtSetVolumeInformationFile(IN HANDLE FileHandle,
4412 OUT PIO_STATUS_BLOCK IoStatusBlock,
4413 IN PVOID FsInformation,
4414 IN ULONG Length,
4415 IN FS_INFORMATION_CLASS FsInformationClass)
4416 {
4417 PFILE_OBJECT FileObject;
4418 PIRP Irp;
4419 PIO_STACK_LOCATION StackPtr;
4420 PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
4421 PKEVENT Event = NULL;
4422 BOOLEAN LocalEvent = FALSE;
4423 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4424 NTSTATUS Status;
4425 IO_STATUS_BLOCK KernelIosb;
4426 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
4427 PAGED_CODE();
4428 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4429
4430 /* Check if we're called from user mode */
4431 if (PreviousMode != KernelMode)
4432 {
4433 /* Validate the information class */
4434 if ((FsInformationClass < 0) ||
4435 (FsInformationClass >= FileFsMaximumInformation) ||
4436 !(IopSetFsOperationLength[FsInformationClass]))
4437 {
4438 /* Invalid class */
4439 return STATUS_INVALID_INFO_CLASS;
4440 }
4441
4442 /* Validate the length */
4443 if (Length < IopSetFsOperationLength[FsInformationClass])
4444 {
4445 /* Invalid length */
4446 return STATUS_INFO_LENGTH_MISMATCH;
4447 }
4448
4449 /* Enter SEH for probing */
4450 _SEH2_TRY
4451 {
4452 /* Probe the I/O Status block */
4453 ProbeForWriteIoStatusBlock(IoStatusBlock);
4454
4455 /* Probe the information */
4456 ProbeForRead(FsInformation, Length, sizeof(ULONG));
4457 }
4458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4459 {
4460 /* Return the exception code */
4461 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4462 }
4463 _SEH2_END;
4464 }
4465
4466 /* Get File Object */
4467 Status = ObReferenceObjectByHandle(FileHandle,
4468 IopSetFsOperationAccess
4469 [FsInformationClass],
4470 IoFileObjectType,
4471 PreviousMode,
4472 (PVOID*)&FileObject,
4473 NULL);
4474 if (!NT_SUCCESS(Status)) return Status;
4475
4476 /* Get target device for notification */
4477 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
4478 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
4479
4480 /* Check if we should use Sync IO or not */
4481 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4482 {
4483 /* Lock it */
4484 Status = IopLockFileObject(FileObject, PreviousMode);
4485 if (Status != STATUS_SUCCESS)
4486 {
4487 ObDereferenceObject(FileObject);
4488 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4489 return Status;
4490 }
4491 }
4492 else
4493 {
4494 /* Use local event */
4495 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
4496 if (!Event)
4497 {
4498 ObDereferenceObject(FileObject);
4499 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4500 return STATUS_INSUFFICIENT_RESOURCES;
4501 }
4502 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
4503 LocalEvent = TRUE;
4504 }
4505
4506 /* Get the device object */
4507 DeviceObject = IoGetRelatedDeviceObject(FileObject);
4508
4509 /* Clear File Object event */
4510 KeClearEvent(&FileObject->Event);
4511
4512 /* Allocate the IRP */
4513 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4514 if (!Irp)
4515 {
4516 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4517 return IopCleanupFailedIrp(FileObject, NULL, Event);
4518 }
4519
4520 /* Set up the IRP */
4521 Irp->RequestorMode = PreviousMode;
4522 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4523 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4524 Irp->UserEvent = (LocalEvent) ? Event : NULL;
4525 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4526 Irp->Tail.Overlay.OriginalFileObject = FileObject;
4527 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4528 Irp->UserBuffer = FsInformation;
4529 Irp->AssociatedIrp.SystemBuffer = NULL;
4530 Irp->MdlAddress = NULL;
4531
4532 /* Set up Stack Data */
4533 StackPtr = IoGetNextIrpStackLocation(Irp);
4534 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
4535 StackPtr->FileObject = FileObject;
4536
4537 /* Enter SEH */
4538 _SEH2_TRY
4539 {
4540 /* Allocate a buffer */
4541 Irp->AssociatedIrp.SystemBuffer =
4542 ExAllocatePoolWithTag(NonPagedPool,
4543 Length,
4544 TAG_SYSB);
4545
4546 /* Copy the data into it */
4547 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
4548 }
4549 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4550 {
4551 /* Allocating failed, clean up and return the exception code */
4552 IopCleanupAfterException(FileObject, Irp, NULL, Event);
4553 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4554 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4555 }
4556 _SEH2_END;
4557
4558 /* Set the flags for this buffered + deferred I/O */
4559 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
4560
4561 /* Set Parameters */
4562 StackPtr->Parameters.SetVolume.Length = Length;
4563 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
4564
4565 /* Call the Driver */
4566 Status = IopPerformSynchronousRequest(DeviceObject,
4567 Irp,
4568 FileObject,
4569 FALSE,
4570 PreviousMode,
4571 !LocalEvent,
4572 IopOtherTransfer);
4573
4574 /* Check if this was async I/O */
4575 if (LocalEvent)
4576 {
4577 /* It was, finalize this request */
4578 Status = IopFinalizeAsynchronousIo(Status,
4579 Event,
4580 Irp,
4581 PreviousMode,
4582 &KernelIosb,
4583 IoStatusBlock);
4584 }
4585
4586 if (TargetDeviceObject && NT_SUCCESS(Status))
4587 {
4588 /* Time to report change */
4589 NotificationStructure.Version = 1;
4590 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
4591 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
4592 NotificationStructure.FileObject = NULL;
4593 NotificationStructure.NameBufferOffset = - 1;
4594 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
4595 }
4596
4597 /* Return status */
4598 return Status;
4599 }
4600
4601 /*
4602 * @unimplemented
4603 */
4604 NTSTATUS
4605 NTAPI
4606 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
4607 {
4608 UNIMPLEMENTED;
4609 return STATUS_NOT_IMPLEMENTED;
4610 }
4611
4612 /*
4613 * @unimplemented
4614 */
4615 NTSTATUS
4616 NTAPI
4617 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
4618 {
4619 UNIMPLEMENTED;
4620 return STATUS_NOT_IMPLEMENTED;
4621 }