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