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