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