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