9d99a82476bbc6443bcbb9d1f4a297afc0e843a6
[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 #if DBG
2119 else
2120 {
2121 /* Validate the information class */
2122 if ((FileInformationClass >= FileMaximumInformation) ||
2123 !(IopQueryOperationLength[FileInformationClass]))
2124 {
2125 /* Invalid class */
2126 return STATUS_INVALID_INFO_CLASS;
2127 }
2128
2129 /* Validate the length */
2130 if (Length < IopQueryOperationLength[FileInformationClass])
2131 {
2132 /* Invalid length */
2133 return STATUS_INFO_LENGTH_MISMATCH;
2134 }
2135 }
2136 #endif
2137
2138 /* Reference the Handle */
2139 Status = ObReferenceObjectByHandle(FileHandle,
2140 IopQueryOperationAccess
2141 [FileInformationClass],
2142 IoFileObjectType,
2143 PreviousMode,
2144 (PVOID *)&FileObject,
2145 &HandleInformation);
2146 if (!NT_SUCCESS(Status)) return Status;
2147
2148 /* Check if this is a direct open or not */
2149 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2150 {
2151 /* Get the device object */
2152 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2153 }
2154 else
2155 {
2156 /* Get the device object */
2157 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2158 }
2159
2160 /* Check if this is a file that was opened for Synch I/O */
2161 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2162 {
2163 /* Lock it */
2164 IopLockFileObject(FileObject);
2165
2166 /* Check if the caller just wants the position */
2167 if (FileInformationClass == FilePositionInformation)
2168 {
2169 /* Protect write in SEH */
2170 _SEH2_TRY
2171 {
2172 /* Write the offset */
2173 ((PFILE_POSITION_INFORMATION)FileInformation)->
2174 CurrentByteOffset = FileObject->CurrentByteOffset;
2175
2176 /* Fill out the I/O Status Block */
2177 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
2178 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2179 }
2180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2181 {
2182 /* Get the exception code */
2183 Status = _SEH2_GetExceptionCode();
2184 }
2185 _SEH2_END;
2186
2187 /* Release the file lock, dereference the file and return */
2188 IopUnlockFileObject(FileObject);
2189 ObDereferenceObject(FileObject);
2190 return Status;
2191 }
2192 }
2193 else
2194 {
2195 /* Use local event */
2196 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2197 if (!Event)
2198 {
2199 ObDereferenceObject(FileObject);
2200 return STATUS_INSUFFICIENT_RESOURCES;
2201 }
2202 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2203 LocalEvent = TRUE;
2204 }
2205
2206 /* Check if FastIO is possible for the two available information classes */
2207 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2208 if (FastIoDispatch != NULL &&
2209 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
2210 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
2211 {
2212 BOOLEAN Success = FALSE;
2213
2214 if (FileInformationClass == FileBasicInformation)
2215 {
2216 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
2217 FileInformation,
2218 &KernelIosb,
2219 DeviceObject);
2220 }
2221 else
2222 {
2223 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
2224 FileInformation,
2225 &KernelIosb,
2226 DeviceObject);
2227 }
2228
2229 /* If call succeed */
2230 if (Success)
2231 {
2232 /* Write the IOSB back */
2233 _SEH2_TRY
2234 {
2235 *IoStatusBlock = KernelIosb;
2236 }
2237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2238 {
2239 KernelIosb.Status = _SEH2_GetExceptionCode();
2240 }
2241 _SEH2_END;
2242
2243 /* Unlock FO */
2244 IopUnlockFileObject(FileObject);
2245
2246 /* We're done with FastIO! */
2247 ObDereferenceObject(FileObject);
2248 return KernelIosb.Status;
2249 }
2250 }
2251
2252 /* Clear the File Object event */
2253 KeClearEvent(&FileObject->Event);
2254
2255 /* Allocate the IRP */
2256 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2257 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2258
2259 /* Set the IRP */
2260 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2261 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2262 Irp->RequestorMode = PreviousMode;
2263 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2264 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2265 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2266 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2267 Irp->AssociatedIrp.SystemBuffer = NULL;
2268 Irp->MdlAddress = NULL;
2269 Irp->UserBuffer = FileInformation;
2270
2271 /* Set the Stack Data */
2272 StackPtr = IoGetNextIrpStackLocation(Irp);
2273 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2274 StackPtr->FileObject = FileObject;
2275
2276 /* Enter SEH */
2277 _SEH2_TRY
2278 {
2279 /* Allocate a buffer */
2280 Irp->AssociatedIrp.SystemBuffer =
2281 ExAllocatePoolWithTag(NonPagedPool,
2282 Length,
2283 TAG_SYSB);
2284 }
2285 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2286 {
2287 /* Allocating failed, clean up and return the exception code */
2288 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2289 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2290 }
2291 _SEH2_END;
2292
2293 /* Set the flags */
2294 Irp->Flags |= (IRP_BUFFERED_IO |
2295 IRP_DEALLOCATE_BUFFER |
2296 IRP_INPUT_OPERATION |
2297 IRP_DEFER_IO_COMPLETION);
2298
2299 /* Set the Parameters */
2300 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2301 StackPtr->Parameters.QueryFile.Length = Length;
2302
2303 /* Queue the IRP */
2304 IopQueueIrpToThread(Irp);
2305
2306 /* Update operation counts */
2307 IopUpdateOperationCount(IopOtherTransfer);
2308
2309 /* Fill in file information before calling the driver.
2310 See 'File System Internals' page 485.*/
2311 if (FileInformationClass == FileAccessInformation)
2312 {
2313 AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2314 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2315 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2316 CallDriver = FALSE;
2317 }
2318 else if (FileInformationClass == FileModeInformation)
2319 {
2320 ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2321 ModeBuffer->Mode = IopGetFileMode(FileObject);
2322 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2323 CallDriver = FALSE;
2324 }
2325 else if (FileInformationClass == FileAlignmentInformation)
2326 {
2327 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2328 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2329 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2330 CallDriver = FALSE;
2331 }
2332 else if (FileInformationClass == FileAllInformation)
2333 {
2334 AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2335 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2336 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
2337 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2338 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2339 sizeof(FILE_MODE_INFORMATION) +
2340 sizeof(FILE_ALIGNMENT_INFORMATION);
2341 }
2342
2343 /* Call the Driver */
2344 if (CallDriver)
2345 {
2346 Status = IoCallDriver(DeviceObject, Irp);
2347 }
2348 else
2349 {
2350 Status = STATUS_SUCCESS;
2351 Irp->IoStatus.Status = STATUS_SUCCESS;
2352 }
2353
2354 if (Status == STATUS_PENDING)
2355 {
2356 /* Check if this was async I/O */
2357 if (LocalEvent)
2358 {
2359 /* Then to a non-alertable wait */
2360 Status = KeWaitForSingleObject(Event,
2361 Executive,
2362 PreviousMode,
2363 FALSE,
2364 NULL);
2365 if (Status == STATUS_USER_APC)
2366 {
2367 /* Abort the request */
2368 IopAbortInterruptedIrp(Event, Irp);
2369 }
2370
2371 /* Set the final status */
2372 Status = KernelIosb.Status;
2373
2374 /* Enter SEH to write the IOSB back */
2375 _SEH2_TRY
2376 {
2377 /* Write it back to the caller */
2378 *IoStatusBlock = KernelIosb;
2379 }
2380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2381 {
2382 /* Get the exception code */
2383 Status = _SEH2_GetExceptionCode();
2384 }
2385 _SEH2_END;
2386
2387 /* Free the event */
2388 ExFreePoolWithTag(Event, TAG_IO);
2389 }
2390 else
2391 {
2392 /* Wait for the IRP */
2393 Status = KeWaitForSingleObject(&FileObject->Event,
2394 Executive,
2395 PreviousMode,
2396 (FileObject->Flags &
2397 FO_ALERTABLE_IO) != 0,
2398 NULL);
2399 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2400 {
2401 /* Abort the request */
2402 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2403 }
2404
2405 /* Set the final status */
2406 Status = FileObject->FinalStatus;
2407
2408 /* Release the file lock */
2409 IopUnlockFileObject(FileObject);
2410 }
2411 }
2412 else
2413 {
2414 /* Free the event if we had one */
2415 if (LocalEvent)
2416 {
2417 /* Clear it in the IRP for completion */
2418 Irp->UserEvent = NULL;
2419 ExFreePoolWithTag(Event, TAG_IO);
2420 }
2421
2422 /* Set the caller IOSB */
2423 Irp->UserIosb = IoStatusBlock;
2424
2425 /* The IRP wasn't completed, complete it ourselves */
2426 KeRaiseIrql(APC_LEVEL, &OldIrql);
2427 IopCompleteRequest(&Irp->Tail.Apc,
2428 &NormalRoutine,
2429 &NormalContext,
2430 (PVOID*)&FileObject,
2431 &NormalContext);
2432 KeLowerIrql(OldIrql);
2433
2434 /* Release the file object if we had locked it*/
2435 if (!LocalEvent) IopUnlockFileObject(FileObject);
2436 }
2437
2438 /* Return the Status */
2439 return Status;
2440 }
2441
2442 /*
2443 * @unimplemented
2444 */
2445 NTSTATUS
2446 NTAPI
2447 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2448 OUT PIO_STATUS_BLOCK IoStatusBlock,
2449 OUT PVOID Buffer,
2450 IN ULONG Length,
2451 IN BOOLEAN ReturnSingleEntry,
2452 IN PVOID SidList OPTIONAL,
2453 IN ULONG SidListLength,
2454 IN PSID StartSid OPTIONAL,
2455 IN BOOLEAN RestartScan)
2456 {
2457 UNIMPLEMENTED;
2458 return STATUS_NOT_IMPLEMENTED;
2459 }
2460
2461 /*
2462 * @implemented
2463 */
2464 NTSTATUS
2465 NTAPI
2466 NtReadFile(IN HANDLE FileHandle,
2467 IN HANDLE Event OPTIONAL,
2468 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2469 IN PVOID ApcContext OPTIONAL,
2470 OUT PIO_STATUS_BLOCK IoStatusBlock,
2471 OUT PVOID Buffer,
2472 IN ULONG Length,
2473 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2474 IN PULONG Key OPTIONAL)
2475 {
2476 NTSTATUS Status;
2477 PFILE_OBJECT FileObject;
2478 PIRP Irp;
2479 PDEVICE_OBJECT DeviceObject;
2480 PIO_STACK_LOCATION StackPtr;
2481 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2482 PKEVENT EventObject = NULL;
2483 LARGE_INTEGER CapturedByteOffset;
2484 ULONG CapturedKey = 0;
2485 BOOLEAN Synchronous = FALSE;
2486 PMDL Mdl;
2487 PFAST_IO_DISPATCH FastIoDispatch;
2488 IO_STATUS_BLOCK KernelIosb;
2489 BOOLEAN Success;
2490
2491 PAGED_CODE();
2492 CapturedByteOffset.QuadPart = 0;
2493 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2494
2495 /* Validate User-Mode Buffers */
2496 if (PreviousMode != KernelMode)
2497 {
2498 _SEH2_TRY
2499 {
2500 /* Probe the status block */
2501 ProbeForWriteIoStatusBlock(IoStatusBlock);
2502
2503 /* Probe the read buffer */
2504 ProbeForWrite(Buffer, Length, 1);
2505
2506 /* Check if we got a byte offset */
2507 if (ByteOffset)
2508 {
2509 /* Capture and probe it */
2510 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2511 }
2512
2513 /* Capture and probe the key */
2514 if (Key) CapturedKey = ProbeForReadUlong(Key);
2515 }
2516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2517 {
2518 /* Return the exception code */
2519 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2520 }
2521 _SEH2_END;
2522 }
2523 else
2524 {
2525 /* Kernel mode: capture directly */
2526 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2527 if (Key) CapturedKey = *Key;
2528 }
2529
2530 /* Get File Object */
2531 Status = ObReferenceObjectByHandle(FileHandle,
2532 FILE_READ_DATA,
2533 IoFileObjectType,
2534 PreviousMode,
2535 (PVOID*)&FileObject,
2536 NULL);
2537 if (!NT_SUCCESS(Status)) return Status;
2538
2539 /* Check for event */
2540 if (Event)
2541 {
2542 /* Reference it */
2543 Status = ObReferenceObjectByHandle(Event,
2544 EVENT_MODIFY_STATE,
2545 ExEventObjectType,
2546 PreviousMode,
2547 (PVOID*)&EventObject,
2548 NULL);
2549 if (!NT_SUCCESS(Status))
2550 {
2551 /* Fail */
2552 ObDereferenceObject(FileObject);
2553 return Status;
2554 }
2555
2556 /* Otherwise reset the event */
2557 KeClearEvent(EventObject);
2558 }
2559
2560 /* Get the device object */
2561 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2562
2563 /* Check if we should use Sync IO or not */
2564 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2565 {
2566 /* Lock the file object */
2567 IopLockFileObject(FileObject);
2568
2569 /* Check if we don't have a byte offset available */
2570 if (!(ByteOffset) ||
2571 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2572 (CapturedByteOffset.u.HighPart == -1)))
2573 {
2574 /* Use the Current Byte Offset instead */
2575 CapturedByteOffset = FileObject->CurrentByteOffset;
2576 }
2577
2578 /* If the file is cached, try fast I/O */
2579 if (FileObject->PrivateCacheMap)
2580 {
2581 /* Perform fast read */
2582 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2583 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
2584
2585 Success = FastIoDispatch->FastIoRead(FileObject,
2586 &CapturedByteOffset,
2587 Length,
2588 TRUE,
2589 CapturedKey,
2590 Buffer,
2591 &KernelIosb,
2592 DeviceObject);
2593
2594 /* Only accept the result if we got a straightforward status */
2595 if (Success &&
2596 (KernelIosb.Status == STATUS_SUCCESS ||
2597 KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2598 KernelIosb.Status == STATUS_END_OF_FILE))
2599 {
2600 /* Fast path -- update transfer & operation counts */
2601 IopUpdateOperationCount(IopReadTransfer);
2602 IopUpdateTransferCount(IopReadTransfer,
2603 (ULONG)KernelIosb.Information);
2604
2605 /* Enter SEH to write the IOSB back */
2606 _SEH2_TRY
2607 {
2608 /* Write it back to the caller */
2609 *IoStatusBlock = KernelIosb;
2610 }
2611 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2612 {
2613 /* The caller's IOSB was invalid, so fail */
2614 if (EventObject) ObDereferenceObject(EventObject);
2615 IopUnlockFileObject(FileObject);
2616 ObDereferenceObject(FileObject);
2617 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2618 }
2619 _SEH2_END;
2620
2621 /* Signal the completion event */
2622 if (EventObject)
2623 {
2624 KeSetEvent(EventObject, 0, FALSE);
2625 ObDereferenceObject(EventObject);
2626 }
2627
2628 /* Clean up */
2629 IopUnlockFileObject(FileObject);
2630 ObDereferenceObject(FileObject);
2631 return KernelIosb.Status;
2632 }
2633 }
2634
2635 /* Remember we are sync */
2636 Synchronous = TRUE;
2637 }
2638 else if (!(ByteOffset) &&
2639 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2640 {
2641 /* Otherwise, this was async I/O without a byte offset, so fail */
2642 if (EventObject) ObDereferenceObject(EventObject);
2643 ObDereferenceObject(FileObject);
2644 return STATUS_INVALID_PARAMETER;
2645 }
2646
2647 /* Clear the File Object's event */
2648 KeClearEvent(&FileObject->Event);
2649
2650 /* Allocate the IRP */
2651 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2652 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2653
2654 /* Set the IRP */
2655 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2656 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2657 Irp->RequestorMode = PreviousMode;
2658 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2659 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2660 Irp->UserIosb = IoStatusBlock;
2661 Irp->UserEvent = EventObject;
2662 Irp->PendingReturned = FALSE;
2663 Irp->Cancel = FALSE;
2664 Irp->CancelRoutine = NULL;
2665 Irp->AssociatedIrp.SystemBuffer = NULL;
2666 Irp->MdlAddress = NULL;
2667
2668 /* Set the Stack Data */
2669 StackPtr = IoGetNextIrpStackLocation(Irp);
2670 StackPtr->MajorFunction = IRP_MJ_READ;
2671 StackPtr->FileObject = FileObject;
2672 StackPtr->Parameters.Read.Key = CapturedKey;
2673 StackPtr->Parameters.Read.Length = Length;
2674 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2675
2676 /* Check if this is buffered I/O */
2677 if (DeviceObject->Flags & DO_BUFFERED_IO)
2678 {
2679 /* Check if we have a buffer length */
2680 if (Length)
2681 {
2682 /* Enter SEH */
2683 _SEH2_TRY
2684 {
2685 /* Allocate a buffer */
2686 Irp->AssociatedIrp.SystemBuffer =
2687 ExAllocatePoolWithTag(NonPagedPool,
2688 Length,
2689 TAG_SYSB);
2690 }
2691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2692 {
2693 /* Allocating failed, clean up and return the exception code */
2694 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2695 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2696 }
2697 _SEH2_END;
2698
2699 /* Set the buffer and flags */
2700 Irp->UserBuffer = Buffer;
2701 Irp->Flags = (IRP_BUFFERED_IO |
2702 IRP_DEALLOCATE_BUFFER |
2703 IRP_INPUT_OPERATION);
2704 }
2705 else
2706 {
2707 /* Not reading anything */
2708 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2709 }
2710 }
2711 else if (DeviceObject->Flags & DO_DIRECT_IO)
2712 {
2713 /* Check if we have a buffer length */
2714 if (Length)
2715 {
2716 _SEH2_TRY
2717 {
2718 /* Allocate an MDL */
2719 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2720 if (!Mdl)
2721 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2722 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2723 }
2724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2725 {
2726 /* Allocating failed, clean up and return the exception code */
2727 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2728 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2729 }
2730 _SEH2_END;
2731
2732 }
2733
2734 /* No allocation flags */
2735 Irp->Flags = 0;
2736 }
2737 else
2738 {
2739 /* No allocation flags, and use the buffer directly */
2740 Irp->Flags = 0;
2741 Irp->UserBuffer = Buffer;
2742 }
2743
2744 /* Now set the deferred read flags */
2745 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2746 #if 0
2747 /* FIXME: VFAT SUCKS */
2748 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2749 #endif
2750
2751 /* Perform the call */
2752 return IopPerformSynchronousRequest(DeviceObject,
2753 Irp,
2754 FileObject,
2755 TRUE,
2756 PreviousMode,
2757 Synchronous,
2758 IopReadTransfer);
2759 }
2760
2761 /*
2762 * @unimplemented
2763 */
2764 NTSTATUS
2765 NTAPI
2766 NtReadFileScatter(IN HANDLE FileHandle,
2767 IN HANDLE Event OPTIONAL,
2768 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2769 IN PVOID UserApcContext OPTIONAL,
2770 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2771 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2772 IN ULONG BufferLength,
2773 IN PLARGE_INTEGER ByteOffset,
2774 IN PULONG Key OPTIONAL)
2775 {
2776 UNIMPLEMENTED;
2777 return STATUS_NOT_IMPLEMENTED;
2778 }
2779
2780 /*
2781 * @unimplemented
2782 */
2783 NTSTATUS
2784 NTAPI
2785 NtSetEaFile(IN HANDLE FileHandle,
2786 IN PIO_STATUS_BLOCK IoStatusBlock,
2787 IN PVOID EaBuffer,
2788 IN ULONG EaBufferSize)
2789 {
2790 UNIMPLEMENTED;
2791 return STATUS_NOT_IMPLEMENTED;
2792 }
2793
2794 /*
2795 * @implemented
2796 */
2797 NTSTATUS
2798 NTAPI
2799 NtSetInformationFile(IN HANDLE FileHandle,
2800 OUT PIO_STATUS_BLOCK IoStatusBlock,
2801 IN PVOID FileInformation,
2802 IN ULONG Length,
2803 IN FILE_INFORMATION_CLASS FileInformationClass)
2804 {
2805 PFILE_OBJECT FileObject;
2806 NTSTATUS Status;
2807 PIRP Irp;
2808 PDEVICE_OBJECT DeviceObject;
2809 PIO_STACK_LOCATION StackPtr;
2810 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2811 PKEVENT Event = NULL;
2812 BOOLEAN LocalEvent = FALSE;
2813 PKNORMAL_ROUTINE NormalRoutine;
2814 PVOID NormalContext;
2815 KIRQL OldIrql;
2816 IO_STATUS_BLOCK KernelIosb;
2817 PVOID Queue;
2818 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2819 PIO_COMPLETION_CONTEXT Context;
2820 PFILE_RENAME_INFORMATION RenameInfo;
2821 HANDLE TargetHandle = NULL;
2822 PAGED_CODE();
2823 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2824
2825 /* Check if we're called from user mode */
2826 if (PreviousMode != KernelMode)
2827 {
2828 /* Validate the information class */
2829 if ((FileInformationClass >= FileMaximumInformation) ||
2830 !(IopSetOperationLength[FileInformationClass]))
2831 {
2832 /* Invalid class */
2833 return STATUS_INVALID_INFO_CLASS;
2834 }
2835
2836 /* Validate the length */
2837 if (Length < IopSetOperationLength[FileInformationClass])
2838 {
2839 /* Invalid length */
2840 return STATUS_INFO_LENGTH_MISMATCH;
2841 }
2842
2843 /* Enter SEH for probing */
2844 _SEH2_TRY
2845 {
2846 /* Probe the I/O Status block */
2847 ProbeForWriteIoStatusBlock(IoStatusBlock);
2848
2849 /* Probe the information */
2850 ProbeForRead(FileInformation,
2851 Length,
2852 (Length == sizeof(BOOLEAN)) ?
2853 sizeof(BOOLEAN) : sizeof(ULONG));
2854 }
2855 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2856 {
2857 /* Return the exception code */
2858 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2859 }
2860 _SEH2_END;
2861 }
2862 else
2863 {
2864 /* Validate the information class */
2865 if ((FileInformationClass >= FileMaximumInformation) ||
2866 !(IopSetOperationLength[FileInformationClass]))
2867 {
2868 /* Invalid class */
2869 return STATUS_INVALID_INFO_CLASS;
2870 }
2871
2872 /* Validate the length */
2873 if (Length < IopSetOperationLength[FileInformationClass])
2874 {
2875 /* Invalid length */
2876 return STATUS_INFO_LENGTH_MISMATCH;
2877 }
2878 }
2879
2880 /* Reference the Handle */
2881 Status = ObReferenceObjectByHandle(FileHandle,
2882 IopSetOperationAccess
2883 [FileInformationClass],
2884 IoFileObjectType,
2885 PreviousMode,
2886 (PVOID *)&FileObject,
2887 NULL);
2888 if (!NT_SUCCESS(Status)) return Status;
2889
2890 /* Check if this is a direct open or not */
2891 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2892 {
2893 /* Get the device object */
2894 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2895 }
2896 else
2897 {
2898 /* Get the device object */
2899 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2900 }
2901
2902 DPRINT("Will call: %p\n", DeviceObject);
2903 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
2904
2905 /* Check if this is a file that was opened for Synch I/O */
2906 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2907 {
2908 /* Lock it */
2909 IopLockFileObject(FileObject);
2910
2911 /* Check if the caller just wants the position */
2912 if (FileInformationClass == FilePositionInformation)
2913 {
2914 /* Protect write in SEH */
2915 _SEH2_TRY
2916 {
2917 /* Write the offset */
2918 FileObject->CurrentByteOffset =
2919 ((PFILE_POSITION_INFORMATION)FileInformation)->
2920 CurrentByteOffset;
2921
2922 /* Fill out the I/O Status Block */
2923 IoStatusBlock->Information = 0;
2924 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2925 }
2926 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2927 {
2928 /* Get the exception code */
2929 Status = _SEH2_GetExceptionCode();
2930 }
2931 _SEH2_END;
2932
2933 /* Update transfer count */
2934 IopUpdateTransferCount(IopOtherTransfer, Length);
2935
2936 /* Release the file lock, dereference the file and return */
2937 IopUnlockFileObject(FileObject);
2938 ObDereferenceObject(FileObject);
2939 return Status;
2940 }
2941 }
2942 else
2943 {
2944 /* Use local event */
2945 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2946 if (!Event)
2947 {
2948 ObDereferenceObject(FileObject);
2949 return STATUS_INSUFFICIENT_RESOURCES;
2950 }
2951
2952 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2953 LocalEvent = TRUE;
2954 }
2955
2956 /* Clear the File Object event */
2957 KeClearEvent(&FileObject->Event);
2958
2959 /* Allocate the IRP */
2960 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2961 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2962
2963 /* Set the IRP */
2964 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2965 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2966 Irp->RequestorMode = PreviousMode;
2967 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2968 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2969 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2970 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2971 Irp->AssociatedIrp.SystemBuffer = NULL;
2972 Irp->MdlAddress = NULL;
2973 Irp->UserBuffer = FileInformation;
2974
2975 /* Set the Stack Data */
2976 StackPtr = IoGetNextIrpStackLocation(Irp);
2977 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
2978 StackPtr->FileObject = FileObject;
2979
2980 /* Enter SEH */
2981 _SEH2_TRY
2982 {
2983 /* Allocate a buffer */
2984 Irp->AssociatedIrp.SystemBuffer =
2985 ExAllocatePoolWithTag(NonPagedPool,
2986 Length,
2987 TAG_SYSB);
2988
2989 /* Copy the data into it */
2990 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2991 FileInformation,
2992 Length);
2993 }
2994 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2995 {
2996 /* Allocating failed, clean up and return the exception code */
2997 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2998 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2999 }
3000 _SEH2_END;
3001
3002 /* Set the flags */
3003 Irp->Flags |= (IRP_BUFFERED_IO |
3004 IRP_DEALLOCATE_BUFFER |
3005 IRP_DEFER_IO_COMPLETION);
3006
3007 /* Set the Parameters */
3008 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3009 StackPtr->Parameters.SetFile.Length = Length;
3010
3011 /* Queue the IRP */
3012 IopQueueIrpToThread(Irp);
3013
3014 /* Update operation counts */
3015 IopUpdateOperationCount(IopOtherTransfer);
3016
3017 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3018 /* Handle IO Completion Port quickly */
3019 if (FileInformationClass == FileCompletionInformation)
3020 {
3021 /* Check if the file object already has a completion port */
3022 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3023 (FileObject->CompletionContext))
3024 {
3025 /* Fail */
3026 Status = STATUS_INVALID_PARAMETER;
3027 }
3028 else
3029 {
3030 /* Reference the Port */
3031 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3032 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3033 IO_COMPLETION_MODIFY_STATE,
3034 IoCompletionType,
3035 PreviousMode,
3036 (PVOID*)&Queue,
3037 NULL);
3038 if (NT_SUCCESS(Status))
3039 {
3040 /* Allocate the Context */
3041 Context = ExAllocatePoolWithTag(PagedPool,
3042 sizeof(IO_COMPLETION_CONTEXT),
3043 IOC_TAG);
3044 if (Context)
3045 {
3046 /* Set the Data */
3047 Context->Key = CompletionInfo->Key;
3048 Context->Port = Queue;
3049 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
3050 CompletionContext,
3051 Context,
3052 NULL))
3053 {
3054 /*
3055 * Someone else set the completion port in the
3056 * meanwhile, so dereference the port and fail.
3057 */
3058 ExFreePoolWithTag(Context, IOC_TAG);
3059 ObDereferenceObject(Queue);
3060 Status = STATUS_INVALID_PARAMETER;
3061 }
3062 }
3063 else
3064 {
3065 /* Dereference the Port now */
3066 ObDereferenceObject(Queue);
3067 Status = STATUS_INSUFFICIENT_RESOURCES;
3068 }
3069 }
3070 }
3071
3072 /* Set the IRP Status */
3073 Irp->IoStatus.Status = Status;
3074 Irp->IoStatus.Information = 0;
3075 }
3076 else if (FileInformationClass == FileRenameInformation ||
3077 FileInformationClass == FileLinkInformation ||
3078 FileInformationClass == FileMoveClusterInformation)
3079 {
3080 /* Get associated information */
3081 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3082
3083 /* Only rename if:
3084 * -> We have a name
3085 * -> In unicode
3086 * -> sizes are valid
3087 */
3088 if (RenameInfo->FileNameLength != 0 &&
3089 !(RenameInfo->FileNameLength & 1) &&
3090 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
3091 {
3092 /* Properly set information received */
3093 if (FileInformationClass == FileMoveClusterInformation)
3094 {
3095 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3096 }
3097 else
3098 {
3099 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3100 }
3101
3102 /* If we got fully path OR relative target, attempt a parent directory open */
3103 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3104 {
3105 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
3106 if (!NT_SUCCESS(Status))
3107 {
3108 Irp->IoStatus.Status = Status;
3109 }
3110 else
3111 {
3112 /* Call the Driver */
3113 Status = IoCallDriver(DeviceObject, Irp);
3114 }
3115 }
3116 else
3117 {
3118 /* Call the Driver */
3119 Status = IoCallDriver(DeviceObject, Irp);
3120 }
3121 }
3122 else
3123 {
3124 Status = STATUS_INVALID_PARAMETER;
3125 Irp->IoStatus.Status = Status;
3126 }
3127 }
3128 else
3129 {
3130 /* Call the Driver */
3131 Status = IoCallDriver(DeviceObject, Irp);
3132 }
3133
3134 /* Check if we're waiting for the IRP to complete */
3135 if (Status == STATUS_PENDING)
3136 {
3137 /* Check if this was async I/O */
3138 if (LocalEvent)
3139 {
3140 /* Then to a non-alertable wait */
3141 Status = KeWaitForSingleObject(Event,
3142 Executive,
3143 PreviousMode,
3144 FALSE,
3145 NULL);
3146 if (Status == STATUS_USER_APC)
3147 {
3148 /* Abort the request */
3149 IopAbortInterruptedIrp(Event, Irp);
3150 }
3151
3152 /* Set the final status */
3153 Status = KernelIosb.Status;
3154
3155 /* Enter SEH to write the IOSB back */
3156 _SEH2_TRY
3157 {
3158 /* Write it back to the caller */
3159 *IoStatusBlock = KernelIosb;
3160 }
3161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3162 {
3163 /* Get the exception code */
3164 Status = _SEH2_GetExceptionCode();
3165 }
3166 _SEH2_END;
3167
3168 /* Free the event */
3169 ExFreePoolWithTag(Event, TAG_IO);
3170 }
3171 else
3172 {
3173 /* Wait for the IRP */
3174 Status = KeWaitForSingleObject(&FileObject->Event,
3175 Executive,
3176 PreviousMode,
3177 (FileObject->Flags &
3178 FO_ALERTABLE_IO) != 0,
3179 NULL);
3180 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3181 {
3182 /* Abort the request */
3183 IopAbortInterruptedIrp(&FileObject->Event, Irp);
3184 }
3185
3186 /* Set the final status */
3187 Status = FileObject->FinalStatus;
3188
3189 /* Release the file lock */
3190 IopUnlockFileObject(FileObject);
3191 }
3192 }
3193 else
3194 {
3195 /* Free the event if we had one */
3196 if (LocalEvent)
3197 {
3198 /* Clear it in the IRP for completion */
3199 Irp->UserEvent = NULL;
3200 ExFreePoolWithTag(Event, TAG_IO);
3201 }
3202
3203 /* Set the caller IOSB */
3204 Irp->UserIosb = IoStatusBlock;
3205
3206 /* The IRP wasn't completed, complete it ourselves */
3207 KeRaiseIrql(APC_LEVEL, &OldIrql);
3208 IopCompleteRequest(&Irp->Tail.Apc,
3209 &NormalRoutine,
3210 &NormalContext,
3211 (PVOID*)&FileObject,
3212 &NormalContext);
3213 KeLowerIrql(OldIrql);
3214
3215 /* Release the file object if we had locked it*/
3216 if (!LocalEvent) IopUnlockFileObject(FileObject);
3217 }
3218
3219 if (TargetHandle != NULL)
3220 {
3221 ObCloseHandle(TargetHandle, KernelMode);
3222 }
3223
3224 /* Return the Status */
3225 return Status;
3226 }
3227
3228 /*
3229 * @unimplemented
3230 */
3231 NTSTATUS
3232 NTAPI
3233 NtSetQuotaInformationFile(IN HANDLE FileHandle,
3234 OUT PIO_STATUS_BLOCK IoStatusBlock,
3235 IN PVOID Buffer,
3236 IN ULONG BufferLength)
3237 {
3238 UNIMPLEMENTED;
3239 return STATUS_NOT_IMPLEMENTED;
3240 }
3241
3242 /*
3243 * @implemented
3244 */
3245 NTSTATUS
3246 NTAPI
3247 NtUnlockFile(IN HANDLE FileHandle,
3248 OUT PIO_STATUS_BLOCK IoStatusBlock,
3249 IN PLARGE_INTEGER ByteOffset,
3250 IN PLARGE_INTEGER Length,
3251 IN ULONG Key OPTIONAL)
3252 {
3253 PFILE_OBJECT FileObject;
3254 PLARGE_INTEGER LocalLength = NULL;
3255 PIRP Irp;
3256 PIO_STACK_LOCATION StackPtr;
3257 PDEVICE_OBJECT DeviceObject;
3258 PKEVENT Event = NULL;
3259 BOOLEAN LocalEvent = FALSE;
3260 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3261 LARGE_INTEGER CapturedByteOffset, CapturedLength;
3262 NTSTATUS Status;
3263 OBJECT_HANDLE_INFORMATION HandleInformation;
3264 IO_STATUS_BLOCK KernelIosb;
3265 PFAST_IO_DISPATCH FastIoDispatch;
3266 PAGED_CODE();
3267 CapturedByteOffset.QuadPart = 0;
3268 CapturedLength.QuadPart = 0;
3269 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3270
3271 /* Get File Object */
3272 Status = ObReferenceObjectByHandle(FileHandle,
3273 0,
3274 IoFileObjectType,
3275 PreviousMode,
3276 (PVOID*)&FileObject,
3277 &HandleInformation);
3278 if (!NT_SUCCESS(Status)) return Status;
3279
3280 /* Check if we're called from user mode */
3281 if (PreviousMode != KernelMode)
3282 {
3283 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3284 if (!(HandleInformation.GrantedAccess &
3285 (FILE_WRITE_DATA | FILE_READ_DATA)))
3286 {
3287 ObDereferenceObject(FileObject);
3288 return STATUS_ACCESS_DENIED;
3289 }
3290
3291 /* Enter SEH for probing */
3292 _SEH2_TRY
3293 {
3294 /* Probe the I/O Status block */
3295 ProbeForWriteIoStatusBlock(IoStatusBlock);
3296
3297 /* Probe and capture the large integers */
3298 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3299 CapturedLength = ProbeForReadLargeInteger(Length);
3300 }
3301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3302 {
3303 /* Dereference the object and return exception code */
3304 ObDereferenceObject(FileObject);
3305 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3306 }
3307 _SEH2_END;
3308 }
3309 else
3310 {
3311 /* Otherwise, capture them directly */
3312 CapturedByteOffset = *ByteOffset;
3313 CapturedLength = *Length;
3314 }
3315
3316 /* Check if this is a direct open or not */
3317 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3318 {
3319 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3320 }
3321 else
3322 {
3323 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3324 }
3325
3326 /* Try to do it the FastIO way if possible */
3327 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3328 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
3329 {
3330 if (FastIoDispatch->FastIoUnlockSingle(FileObject,
3331 &CapturedByteOffset,
3332 &CapturedLength,
3333 PsGetCurrentProcess(),
3334 Key,
3335 &KernelIosb,
3336 DeviceObject))
3337 {
3338 /* Write the IOSB back */
3339 _SEH2_TRY
3340 {
3341 *IoStatusBlock = KernelIosb;
3342 }
3343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3344 {
3345 KernelIosb.Status = _SEH2_GetExceptionCode();
3346 }
3347 _SEH2_END;
3348
3349 /* We're done with FastIO! */
3350 ObDereferenceObject(FileObject);
3351 return KernelIosb.Status;
3352 }
3353 }
3354
3355 /* Check if we should use Sync IO or not */
3356 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3357 {
3358 /* Lock it */
3359 IopLockFileObject(FileObject);
3360 }
3361 else
3362 {
3363 /* Use local event */
3364 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3365 if (!Event)
3366 {
3367 ObDereferenceObject(FileObject);
3368 return STATUS_INSUFFICIENT_RESOURCES;
3369 }
3370 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3371 LocalEvent = TRUE;
3372 }
3373
3374 /* Clear File Object event */
3375 KeClearEvent(&FileObject->Event);
3376
3377 /* Allocate the IRP */
3378 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3379 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3380
3381 /* Set up the IRP */
3382 Irp->RequestorMode = PreviousMode;
3383 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3384 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3385 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3386 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3387 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3388 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3389
3390 /* Set up Stack Data */
3391 StackPtr = IoGetNextIrpStackLocation(Irp);
3392 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3393 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3394 StackPtr->FileObject = FileObject;
3395
3396 /* Enter SEH */
3397 _SEH2_TRY
3398 {
3399 /* Allocate a buffer */
3400 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3401 sizeof(LARGE_INTEGER),
3402 TAG_LOCK);
3403
3404 /* Set the length */
3405 *LocalLength = CapturedLength;
3406 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3407 StackPtr->Parameters.LockControl.Length = LocalLength;
3408 }
3409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3410 {
3411 /* Allocating failed, clean up and return the exception code */
3412 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3413 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3414
3415 /* Return the exception code */
3416 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3417 }
3418 _SEH2_END;
3419
3420 /* Set Parameters */
3421 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3422 StackPtr->Parameters.LockControl.Key = Key;
3423
3424 /* Call the Driver */
3425 Status = IopPerformSynchronousRequest(DeviceObject,
3426 Irp,
3427 FileObject,
3428 FALSE,
3429 PreviousMode,
3430 !LocalEvent,
3431 IopOtherTransfer);
3432
3433 /* Check if this was async I/O */
3434 if (LocalEvent)
3435 {
3436 /* It was, finalize this request */
3437 Status = IopFinalizeAsynchronousIo(Status,
3438 Event,
3439 Irp,
3440 PreviousMode,
3441 &KernelIosb,
3442 IoStatusBlock);
3443 }
3444
3445 /* Return status */
3446 return Status;
3447 }
3448
3449 /*
3450 * @implemented
3451 */
3452 NTSTATUS
3453 NTAPI
3454 NtWriteFile(IN HANDLE FileHandle,
3455 IN HANDLE Event OPTIONAL,
3456 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3457 IN PVOID ApcContext OPTIONAL,
3458 OUT PIO_STATUS_BLOCK IoStatusBlock,
3459 IN PVOID Buffer,
3460 IN ULONG Length,
3461 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3462 IN PULONG Key OPTIONAL)
3463 {
3464 NTSTATUS Status;
3465 PFILE_OBJECT FileObject;
3466 PIRP Irp;
3467 PDEVICE_OBJECT DeviceObject;
3468 PIO_STACK_LOCATION StackPtr;
3469 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3470 PKEVENT EventObject = NULL;
3471 LARGE_INTEGER CapturedByteOffset;
3472 ULONG CapturedKey = 0;
3473 BOOLEAN Synchronous = FALSE;
3474 PMDL Mdl;
3475 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3476 PFAST_IO_DISPATCH FastIoDispatch;
3477 IO_STATUS_BLOCK KernelIosb;
3478 BOOLEAN Success;
3479
3480 PAGED_CODE();
3481 CapturedByteOffset.QuadPart = 0;
3482 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3483
3484 /* Get File Object */
3485 Status = ObReferenceObjectByHandle(FileHandle,
3486 0,
3487 IoFileObjectType,
3488 PreviousMode,
3489 (PVOID*)&FileObject,
3490 &ObjectHandleInfo);
3491 if (!NT_SUCCESS(Status)) return Status;
3492
3493 /* Validate User-Mode Buffers */
3494 if (PreviousMode != KernelMode)
3495 {
3496 _SEH2_TRY
3497 {
3498 /*
3499 * Check if the handle has either FILE_WRITE_DATA or
3500 * FILE_APPEND_DATA granted. However, if this is a named pipe,
3501 * make sure we don't ask for FILE_APPEND_DATA as it interferes
3502 * with the FILE_CREATE_PIPE_INSTANCE access right!
3503 */
3504 if (!(ObjectHandleInfo.GrantedAccess &
3505 ((!(FileObject->Flags & FO_NAMED_PIPE) ?
3506 FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
3507 {
3508 /* We failed */
3509 ObDereferenceObject(FileObject);
3510 _SEH2_YIELD(return STATUS_ACCESS_DENIED);
3511 }
3512
3513 /* Probe the status block */
3514 ProbeForWriteIoStatusBlock(IoStatusBlock);
3515
3516 /* Probe the read buffer */
3517 ProbeForRead(Buffer, Length, 1);
3518
3519 /* Check if we got a byte offset */
3520 if (ByteOffset)
3521 {
3522 /* Capture and probe it */
3523 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3524 }
3525
3526 /* Capture and probe the key */
3527 if (Key) CapturedKey = ProbeForReadUlong(Key);
3528 }
3529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3530 {
3531 /* Release the file object and return the exception code */
3532 ObDereferenceObject(FileObject);
3533 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3534 }
3535 _SEH2_END;
3536 }
3537 else
3538 {
3539 /* Kernel mode: capture directly */
3540 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3541 if (Key) CapturedKey = *Key;
3542 }
3543
3544 /* Check if this is an append operation */
3545 if ((ObjectHandleInfo.GrantedAccess &
3546 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3547 {
3548 /* Give the drivers something to understand */
3549 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3550 CapturedByteOffset.u.HighPart = -1;
3551 }
3552
3553 /* Check for event */
3554 if (Event)
3555 {
3556 /* Reference it */
3557 Status = ObReferenceObjectByHandle(Event,
3558 EVENT_MODIFY_STATE,
3559 ExEventObjectType,
3560 PreviousMode,
3561 (PVOID*)&EventObject,
3562 NULL);
3563 if (!NT_SUCCESS(Status))
3564 {
3565 /* Fail */
3566 ObDereferenceObject(FileObject);
3567 return Status;
3568 }
3569
3570 /* Otherwise reset the event */
3571 KeClearEvent(EventObject);
3572 }
3573
3574 /* Get the device object */
3575 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3576
3577 /* Check if we should use Sync IO or not */
3578 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3579 {
3580 /* Lock the file object */
3581 IopLockFileObject(FileObject);
3582
3583 /* Check if we don't have a byte offset available */
3584 if (!(ByteOffset) ||
3585 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3586 (CapturedByteOffset.u.HighPart == -1)))
3587 {
3588 /* Use the Current Byte Offset instead */
3589 CapturedByteOffset = FileObject->CurrentByteOffset;
3590 }
3591
3592 /* If the file is cached, try fast I/O */
3593 if (FileObject->PrivateCacheMap)
3594 {
3595 /* Perform fast write */
3596 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3597 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
3598
3599 Success = FastIoDispatch->FastIoWrite(FileObject,
3600 &CapturedByteOffset,
3601 Length,
3602 TRUE,
3603 CapturedKey,
3604 Buffer,
3605 &KernelIosb,
3606 DeviceObject);
3607
3608 /* Only accept the result if it was successful */
3609 if (Success &&
3610 KernelIosb.Status == STATUS_SUCCESS)
3611 {
3612 /* Fast path -- update transfer & operation counts */
3613 IopUpdateOperationCount(IopWriteTransfer);
3614 IopUpdateTransferCount(IopWriteTransfer,
3615 (ULONG)KernelIosb.Information);
3616
3617 /* Enter SEH to write the IOSB back */
3618 _SEH2_TRY
3619 {
3620 /* Write it back to the caller */
3621 *IoStatusBlock = KernelIosb;
3622 }
3623 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3624 {
3625 /* The caller's IOSB was invalid, so fail */
3626 if (EventObject) ObDereferenceObject(EventObject);
3627 IopUnlockFileObject(FileObject);
3628 ObDereferenceObject(FileObject);
3629 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3630 }
3631 _SEH2_END;
3632
3633 /* Signal the completion event */
3634 if (EventObject)
3635 {
3636 KeSetEvent(EventObject, 0, FALSE);
3637 ObDereferenceObject(EventObject);
3638 }
3639
3640 /* Clean up */
3641 IopUnlockFileObject(FileObject);
3642 ObDereferenceObject(FileObject);
3643 return KernelIosb.Status;
3644 }
3645 }
3646
3647 /* Remember we are sync */
3648 Synchronous = TRUE;
3649 }
3650 else if (!(ByteOffset) &&
3651 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3652 {
3653 /* Otherwise, this was async I/O without a byte offset, so fail */
3654 if (EventObject) ObDereferenceObject(EventObject);
3655 ObDereferenceObject(FileObject);
3656 return STATUS_INVALID_PARAMETER;
3657 }
3658
3659 /* Clear the File Object's event */
3660 KeClearEvent(&FileObject->Event);
3661
3662 /* Allocate the IRP */
3663 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3664 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
3665
3666 /* Set the IRP */
3667 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3668 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3669 Irp->RequestorMode = PreviousMode;
3670 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3671 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3672 Irp->UserIosb = IoStatusBlock;
3673 Irp->UserEvent = EventObject;
3674 Irp->PendingReturned = FALSE;
3675 Irp->Cancel = FALSE;
3676 Irp->CancelRoutine = NULL;
3677 Irp->AssociatedIrp.SystemBuffer = NULL;
3678 Irp->MdlAddress = NULL;
3679
3680 /* Set the Stack Data */
3681 StackPtr = IoGetNextIrpStackLocation(Irp);
3682 StackPtr->MajorFunction = IRP_MJ_WRITE;
3683 StackPtr->FileObject = FileObject;
3684 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3685 SL_WRITE_THROUGH : 0;
3686 StackPtr->Parameters.Write.Key = CapturedKey;
3687 StackPtr->Parameters.Write.Length = Length;
3688 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3689
3690 /* Check if this is buffered I/O */
3691 if (DeviceObject->Flags & DO_BUFFERED_IO)
3692 {
3693 /* Check if we have a buffer length */
3694 if (Length)
3695 {
3696 /* Enter SEH */
3697 _SEH2_TRY
3698 {
3699 /* Allocate a buffer */
3700 Irp->AssociatedIrp.SystemBuffer =
3701 ExAllocatePoolWithTag(NonPagedPool,
3702 Length,
3703 TAG_SYSB);
3704
3705 /* Copy the data into it */
3706 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3707 }
3708 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3709 {
3710 /* Allocating failed, clean up and return the exception code */
3711 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3712 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3713 }
3714 _SEH2_END;
3715
3716 /* Set the flags */
3717 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3718 }
3719 else
3720 {
3721 /* Not writing anything */
3722 Irp->Flags = IRP_BUFFERED_IO;
3723 }
3724 }
3725 else if (DeviceObject->Flags & DO_DIRECT_IO)
3726 {
3727 /* Check if we have a buffer length */
3728 if (Length)
3729 {
3730 _SEH2_TRY
3731 {
3732 /* Allocate an MDL */
3733 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
3734 if (!Mdl)
3735 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
3736 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
3737 }
3738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3739 {
3740 /* Allocating failed, clean up and return the exception code */
3741 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3742 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3743 }
3744 _SEH2_END;
3745 }
3746
3747 /* No allocation flags */
3748 Irp->Flags = 0;
3749 }
3750 else
3751 {
3752 /* No allocation flags, and use the buffer directly */
3753 Irp->Flags = 0;
3754 Irp->UserBuffer = Buffer;
3755 }
3756
3757 /* Now set the deferred read flags */
3758 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
3759 #if 0
3760 /* FIXME: VFAT SUCKS */
3761 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3762 #endif
3763
3764 /* Perform the call */
3765 return IopPerformSynchronousRequest(DeviceObject,
3766 Irp,
3767 FileObject,
3768 TRUE,
3769 PreviousMode,
3770 Synchronous,
3771 IopWriteTransfer);
3772 }
3773
3774 NTSTATUS
3775 NTAPI
3776 NtWriteFileGather(IN HANDLE FileHandle,
3777 IN HANDLE Event OPTIONAL,
3778 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3779 IN PVOID UserApcContext OPTIONAL,
3780 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3781 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3782 IN ULONG BufferLength,
3783 IN PLARGE_INTEGER ByteOffset,
3784 IN PULONG Key OPTIONAL)
3785 {
3786 UNIMPLEMENTED;
3787 return STATUS_NOT_IMPLEMENTED;
3788 }
3789
3790 /*
3791 * @implemented
3792 */
3793 NTSTATUS
3794 NTAPI
3795 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
3796 OUT PIO_STATUS_BLOCK IoStatusBlock,
3797 OUT PVOID FsInformation,
3798 IN ULONG Length,
3799 IN FS_INFORMATION_CLASS FsInformationClass)
3800 {
3801 PFILE_OBJECT FileObject;
3802 PIRP Irp;
3803 PIO_STACK_LOCATION StackPtr;
3804 PDEVICE_OBJECT DeviceObject;
3805 PKEVENT Event = NULL;
3806 BOOLEAN LocalEvent = FALSE;
3807 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3808 NTSTATUS Status;
3809 IO_STATUS_BLOCK KernelIosb;
3810 PAGED_CODE();
3811 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3812
3813 /* Check if we're called from user mode */
3814 if (PreviousMode != KernelMode)
3815 {
3816 /* Validate the information class */
3817 if ((FsInformationClass >= FileFsMaximumInformation) ||
3818 !(IopQueryFsOperationLength[FsInformationClass]))
3819 {
3820 /* Invalid class */
3821 return STATUS_INVALID_INFO_CLASS;
3822 }
3823
3824 /* Validate the length */
3825 if (Length < IopQueryFsOperationLength[FsInformationClass])
3826 {
3827 /* Invalid length */
3828 return STATUS_INFO_LENGTH_MISMATCH;
3829 }
3830
3831 /* Enter SEH for probing */
3832 _SEH2_TRY
3833 {
3834 /* Probe the I/O Status block */
3835 ProbeForWriteIoStatusBlock(IoStatusBlock);
3836
3837 /* Probe the information */
3838 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
3839 }
3840 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3841 {
3842 /* Return the exception code */
3843 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3844 }
3845 _SEH2_END;
3846 }
3847
3848 /* Get File Object */
3849 Status = ObReferenceObjectByHandle(FileHandle,
3850 IopQueryFsOperationAccess
3851 [FsInformationClass],
3852 IoFileObjectType,
3853 PreviousMode,
3854 (PVOID*)&FileObject,
3855 NULL);
3856 if (!NT_SUCCESS(Status)) return Status;
3857
3858 /* Check if we should use Sync IO or not */
3859 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3860 {
3861 /* Lock it */
3862 IopLockFileObject(FileObject);
3863 }
3864 else
3865 {
3866 /* Use local event */
3867 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3868 if (!Event)
3869 {
3870 ObDereferenceObject(FileObject);
3871 return STATUS_INSUFFICIENT_RESOURCES;
3872 }
3873 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3874 LocalEvent = TRUE;
3875 }
3876
3877 /* Get the device object */
3878 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3879
3880 /* Clear File Object event */
3881 KeClearEvent(&FileObject->Event);
3882
3883 /* Allocate the IRP */
3884 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3885 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3886
3887 /* Set up the IRP */
3888 Irp->RequestorMode = PreviousMode;
3889 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3890 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3891 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3892 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3893 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3894 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3895 Irp->UserBuffer = FsInformation;
3896 Irp->AssociatedIrp.SystemBuffer = NULL;
3897 Irp->MdlAddress = NULL;
3898
3899 /* Set up Stack Data */
3900 StackPtr = IoGetNextIrpStackLocation(Irp);
3901 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
3902 StackPtr->FileObject = FileObject;
3903
3904 /* Enter SEH */
3905 _SEH2_TRY
3906 {
3907 /* Allocate a buffer */
3908 Irp->AssociatedIrp.SystemBuffer =
3909 ExAllocatePoolWithTag(NonPagedPool,
3910 Length,
3911 TAG_SYSB);
3912 }
3913 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3914 {
3915 /* Allocating failed, clean up and return the exception code */
3916 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3917 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3918 }
3919 _SEH2_END;
3920
3921 /* Set the flags for this buffered + deferred I/O */
3922 Irp->Flags |= (IRP_BUFFERED_IO |
3923 IRP_DEALLOCATE_BUFFER |
3924 IRP_INPUT_OPERATION |
3925 IRP_DEFER_IO_COMPLETION);
3926
3927 /* Set Parameters */
3928 StackPtr->Parameters.QueryVolume.Length = Length;
3929 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
3930
3931 /* Call the Driver */
3932 Status = IopPerformSynchronousRequest(DeviceObject,
3933 Irp,
3934 FileObject,
3935 TRUE,
3936 PreviousMode,
3937 !LocalEvent,
3938 IopOtherTransfer);
3939
3940 /* Check if this was async I/O */
3941 if (LocalEvent)
3942 {
3943 /* It was, finalize this request */
3944 Status = IopFinalizeAsynchronousIo(Status,
3945 Event,
3946 Irp,
3947 PreviousMode,
3948 &KernelIosb,
3949 IoStatusBlock);
3950 }
3951
3952 /* Return status */
3953 return Status;
3954 }
3955
3956 /*
3957 * @implemented
3958 */
3959 NTSTATUS
3960 NTAPI
3961 NtSetVolumeInformationFile(IN HANDLE FileHandle,
3962 OUT PIO_STATUS_BLOCK IoStatusBlock,
3963 IN PVOID FsInformation,
3964 IN ULONG Length,
3965 IN FS_INFORMATION_CLASS FsInformationClass)
3966 {
3967 PFILE_OBJECT FileObject;
3968 PIRP Irp;
3969 PIO_STACK_LOCATION StackPtr;
3970 PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
3971 PKEVENT Event = NULL;
3972 BOOLEAN LocalEvent = FALSE;
3973 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3974 NTSTATUS Status;
3975 IO_STATUS_BLOCK KernelIosb;
3976 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
3977 PAGED_CODE();
3978 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3979
3980 /* Check if we're called from user mode */
3981 if (PreviousMode != KernelMode)
3982 {
3983 /* Validate the information class */
3984 if ((FsInformationClass >= FileFsMaximumInformation) ||
3985 !(IopSetFsOperationLength[FsInformationClass]))
3986 {
3987 /* Invalid class */
3988 return STATUS_INVALID_INFO_CLASS;
3989 }
3990
3991 /* Validate the length */
3992 if (Length < IopSetFsOperationLength[FsInformationClass])
3993 {
3994 /* Invalid length */
3995 return STATUS_INFO_LENGTH_MISMATCH;
3996 }
3997
3998 /* Enter SEH for probing */
3999 _SEH2_TRY
4000 {
4001 /* Probe the I/O Status block */
4002 ProbeForWriteIoStatusBlock(IoStatusBlock);
4003
4004 /* Probe the information */
4005 ProbeForRead(FsInformation, Length, sizeof(ULONG));
4006 }
4007 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4008 {
4009 /* Return the exception code */
4010 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4011 }
4012 _SEH2_END;
4013 }
4014
4015 /* Get File Object */
4016 Status = ObReferenceObjectByHandle(FileHandle,
4017 IopSetFsOperationAccess
4018 [FsInformationClass],
4019 IoFileObjectType,
4020 PreviousMode,
4021 (PVOID*)&FileObject,
4022 NULL);
4023 if (!NT_SUCCESS(Status)) return Status;
4024
4025 /* Get target device for notification */
4026 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
4027 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
4028
4029 /* Check if we should use Sync IO or not */
4030 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4031 {
4032 /* Lock it */
4033 IopLockFileObject(FileObject);
4034 }
4035 else
4036 {
4037 /* Use local event */
4038 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
4039 if (!Event)
4040 {
4041 ObDereferenceObject(FileObject);
4042 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4043 return STATUS_INSUFFICIENT_RESOURCES;
4044 }
4045 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
4046 LocalEvent = TRUE;
4047 }
4048
4049 /* Get the device object */
4050 DeviceObject = IoGetRelatedDeviceObject(FileObject);
4051
4052 /* Clear File Object event */
4053 KeClearEvent(&FileObject->Event);
4054
4055 /* Allocate the IRP */
4056 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4057 if (!Irp)
4058 {
4059 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4060 return IopCleanupFailedIrp(FileObject, NULL, Event);
4061 }
4062
4063 /* Set up the IRP */
4064 Irp->RequestorMode = PreviousMode;
4065 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4066 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4067 Irp->UserEvent = (LocalEvent) ? Event : NULL;
4068 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4069 Irp->Tail.Overlay.OriginalFileObject = FileObject;
4070 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4071 Irp->UserBuffer = FsInformation;
4072 Irp->AssociatedIrp.SystemBuffer = NULL;
4073 Irp->MdlAddress = NULL;
4074
4075 /* Set up Stack Data */
4076 StackPtr = IoGetNextIrpStackLocation(Irp);
4077 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
4078 StackPtr->FileObject = FileObject;
4079
4080 /* Enter SEH */
4081 _SEH2_TRY
4082 {
4083 /* Allocate a buffer */
4084 Irp->AssociatedIrp.SystemBuffer =
4085 ExAllocatePoolWithTag(NonPagedPool,
4086 Length,
4087 TAG_SYSB);
4088
4089 /* Copy the data into it */
4090 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
4091 }
4092 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4093 {
4094 /* Allocating failed, clean up and return the exception code */
4095 IopCleanupAfterException(FileObject, Irp, NULL, Event);
4096 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
4097 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4098 }
4099 _SEH2_END;
4100
4101 /* Set the flags for this buffered + deferred I/O */
4102 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
4103
4104 /* Set Parameters */
4105 StackPtr->Parameters.SetVolume.Length = Length;
4106 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
4107
4108 /* Call the Driver */
4109 Status = IopPerformSynchronousRequest(DeviceObject,
4110 Irp,
4111 FileObject,
4112 FALSE,
4113 PreviousMode,
4114 !LocalEvent,
4115 IopOtherTransfer);
4116
4117 /* Check if this was async I/O */
4118 if (LocalEvent)
4119 {
4120 /* It was, finalize this request */
4121 Status = IopFinalizeAsynchronousIo(Status,
4122 Event,
4123 Irp,
4124 PreviousMode,
4125 &KernelIosb,
4126 IoStatusBlock);
4127 }
4128
4129 if (TargetDeviceObject && NT_SUCCESS(Status))
4130 {
4131 /* Time to report change */
4132 NotificationStructure.Version = 1;
4133 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
4134 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
4135 NotificationStructure.FileObject = NULL;
4136 NotificationStructure.NameBufferOffset = - 1;
4137 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
4138 }
4139
4140 /* Return status */
4141 return Status;
4142 }
4143
4144 /*
4145 * @unimplemented
4146 */
4147 NTSTATUS
4148 NTAPI
4149 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
4150 {
4151 UNIMPLEMENTED;
4152 return STATUS_NOT_IMPLEMENTED;
4153 }
4154
4155 /*
4156 * @unimplemented
4157 */
4158 NTSTATUS
4159 NTAPI
4160 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
4161 {
4162 UNIMPLEMENTED;
4163 return STATUS_NOT_IMPLEMENTED;
4164 }