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