[NTOSKRNL] Add the CcDataFlushes and CcDataPages counters
[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 /* Is the write originating from Cc? */
1043 if (FileObject->SectionObjectPointer != NULL &&
1044 FileObject->SectionObjectPointer->SharedCacheMap != NULL)
1045 {
1046 ++CcDataFlushes;
1047 CcDataPages += BYTES_TO_PAGES(MmGetMdlByteCount(Mdl));
1048 }
1049
1050 /* Get the Device Object */
1051 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1052
1053 /* Allocate IRP */
1054 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1055 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1056
1057 /* Get the Stack */
1058 StackPtr = IoGetNextIrpStackLocation(Irp);
1059
1060 /* Create the IRP Settings */
1061 Irp->MdlAddress = Mdl;
1062 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1063 Irp->UserIosb = StatusBlock;
1064 Irp->UserEvent = Event;
1065 Irp->RequestorMode = KernelMode;
1066 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
1067 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1068 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1069
1070 /* Set the Stack Settings */
1071 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
1072 StackPtr->Parameters.Write.ByteOffset = *Offset;
1073 StackPtr->MajorFunction = IRP_MJ_WRITE;
1074 StackPtr->FileObject = FileObject;
1075
1076 /* Call the Driver */
1077 return IoCallDriver(DeviceObject, Irp);
1078 }
1079
1080 /*
1081 * @implemented
1082 */
1083 NTSTATUS
1084 NTAPI
1085 IoPageRead(IN PFILE_OBJECT FileObject,
1086 IN PMDL Mdl,
1087 IN PLARGE_INTEGER Offset,
1088 IN PKEVENT Event,
1089 IN PIO_STATUS_BLOCK StatusBlock)
1090 {
1091 PIRP Irp;
1092 PIO_STACK_LOCATION StackPtr;
1093 PDEVICE_OBJECT DeviceObject;
1094 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
1095 FileObject, Mdl, Offset);
1096
1097 /* Get the Device Object */
1098 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1099
1100 /* Allocate IRP */
1101 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1102 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1103
1104 /* Get the Stack */
1105 StackPtr = IoGetNextIrpStackLocation(Irp);
1106
1107 /* Create the IRP Settings */
1108 Irp->MdlAddress = Mdl;
1109 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1110 Irp->UserIosb = StatusBlock;
1111 Irp->UserEvent = Event;
1112 Irp->RequestorMode = KernelMode;
1113 Irp->Flags = IRP_PAGING_IO |
1114 IRP_NOCACHE |
1115 IRP_SYNCHRONOUS_PAGING_IO |
1116 IRP_INPUT_OPERATION;
1117 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1118 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1119
1120 /* Set the Stack Settings */
1121 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
1122 StackPtr->Parameters.Read.ByteOffset = *Offset;
1123 StackPtr->MajorFunction = IRP_MJ_READ;
1124 StackPtr->FileObject = FileObject;
1125
1126 /* Call the Driver */
1127 return IoCallDriver(DeviceObject, Irp);
1128 }
1129
1130 /*
1131 * @implemented
1132 */
1133 NTSTATUS
1134 NTAPI
1135 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
1136 IN FILE_INFORMATION_CLASS FileInformationClass,
1137 IN ULONG Length,
1138 OUT PVOID FileInformation,
1139 OUT PULONG ReturnedLength)
1140 {
1141 /* Call the shared routine */
1142 return IopQueryDeviceInformation(FileObject,
1143 FileInformationClass,
1144 Length,
1145 FileInformation,
1146 ReturnedLength,
1147 TRUE);
1148 }
1149
1150 /*
1151 * @implemented
1152 */
1153 NTSTATUS
1154 NTAPI
1155 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
1156 IN FS_INFORMATION_CLASS FsInformationClass,
1157 IN ULONG Length,
1158 OUT PVOID FsInformation,
1159 OUT PULONG ReturnedLength)
1160 {
1161 /* Call the shared routine */
1162 return IopQueryDeviceInformation(FileObject,
1163 FsInformationClass,
1164 Length,
1165 FsInformation,
1166 ReturnedLength,
1167 FALSE);
1168 }
1169
1170 /*
1171 * @implemented
1172 */
1173 NTSTATUS
1174 NTAPI
1175 IoSetInformation(IN PFILE_OBJECT FileObject,
1176 IN FILE_INFORMATION_CLASS FileInformationClass,
1177 IN ULONG Length,
1178 IN PVOID FileInformation)
1179 {
1180 IO_STATUS_BLOCK IoStatusBlock;
1181 PIRP Irp;
1182 PDEVICE_OBJECT DeviceObject;
1183 PIO_STACK_LOCATION StackPtr;
1184 BOOLEAN LocalEvent = FALSE;
1185 KEVENT Event;
1186 NTSTATUS Status;
1187 PAGED_CODE();
1188 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n",
1189 FileObject, FileInformationClass, Length);
1190
1191 /* Reference the object */
1192 ObReferenceObject(FileObject);
1193
1194 /* Check if this is a file that was opened for Synch I/O */
1195 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1196 {
1197 /* Lock it */
1198 IopLockFileObject(FileObject);
1199
1200 /* Use File Object event */
1201 KeClearEvent(&FileObject->Event);
1202 }
1203 else
1204 {
1205 /* Use local event */
1206 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1207 LocalEvent = TRUE;
1208 }
1209
1210 /* Get the Device Object */
1211 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1212
1213 /* Allocate the IRP */
1214 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1215 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1216
1217 /* Set the IRP */
1218 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1219 Irp->RequestorMode = KernelMode;
1220 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1221 Irp->UserIosb = &IoStatusBlock;
1222 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1223 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1224 Irp->Flags |= IRP_BUFFERED_IO;
1225 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1226 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1227
1228 /* Set the Stack Data */
1229 StackPtr = IoGetNextIrpStackLocation(Irp);
1230 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
1231 StackPtr->FileObject = FileObject;
1232
1233 /* Set Parameters */
1234 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1235 StackPtr->Parameters.SetFile.Length = Length;
1236
1237 /* Queue the IRP */
1238 IopQueueIrpToThread(Irp);
1239
1240 /* Call the Driver */
1241 Status = IoCallDriver(DeviceObject, Irp);
1242
1243 /* Check if this was synch I/O */
1244 if (!LocalEvent)
1245 {
1246 /* Check if the request is pending */
1247 if (Status == STATUS_PENDING)
1248 {
1249 /* Wait on the file object */
1250 Status = KeWaitForSingleObject(&FileObject->Event,
1251 Executive,
1252 KernelMode,
1253 (FileObject->Flags &
1254 FO_ALERTABLE_IO) != 0,
1255 NULL);
1256 if (Status == STATUS_ALERTED)
1257 {
1258 /* Abort the operation */
1259 IopAbortInterruptedIrp(&FileObject->Event, Irp);
1260 }
1261
1262 /* Get the final status */
1263 Status = FileObject->FinalStatus;
1264 }
1265
1266 /* Release the file lock */
1267 IopUnlockFileObject(FileObject);
1268 }
1269 else if (Status == STATUS_PENDING)
1270 {
1271 /* Wait on the local event and get the final status */
1272 KeWaitForSingleObject(&Event,
1273 Executive,
1274 KernelMode,
1275 FALSE,
1276 NULL);
1277 Status = IoStatusBlock.Status;
1278 }
1279
1280 /* Return the status */
1281 return Status;
1282 }
1283
1284 /* NATIVE SERVICES ***********************************************************/
1285
1286 /*
1287 * @implemented
1288 */
1289 NTSTATUS
1290 NTAPI
1291 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
1292 IN HANDLE Event OPTIONAL,
1293 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1294 IN PVOID UserApcContext OPTIONAL,
1295 OUT PIO_STATUS_BLOCK IoStatusBlock,
1296 IN ULONG IoControlCode,
1297 IN PVOID InputBuffer,
1298 IN ULONG InputBufferLength OPTIONAL,
1299 OUT PVOID OutputBuffer,
1300 IN ULONG OutputBufferLength OPTIONAL)
1301 {
1302 /* Call the Generic Function */
1303 return IopDeviceFsIoControl(DeviceHandle,
1304 Event,
1305 UserApcRoutine,
1306 UserApcContext,
1307 IoStatusBlock,
1308 IoControlCode,
1309 InputBuffer,
1310 InputBufferLength,
1311 OutputBuffer,
1312 OutputBufferLength,
1313 TRUE);
1314 }
1315
1316 /*
1317 * @implemented
1318 */
1319 NTSTATUS
1320 NTAPI
1321 NtFsControlFile(IN HANDLE DeviceHandle,
1322 IN HANDLE Event OPTIONAL,
1323 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1324 IN PVOID UserApcContext OPTIONAL,
1325 OUT PIO_STATUS_BLOCK IoStatusBlock,
1326 IN ULONG IoControlCode,
1327 IN PVOID InputBuffer,
1328 IN ULONG InputBufferLength OPTIONAL,
1329 OUT PVOID OutputBuffer,
1330 IN ULONG OutputBufferLength OPTIONAL)
1331 {
1332 /* Call the Generic Function */
1333 return IopDeviceFsIoControl(DeviceHandle,
1334 Event,
1335 UserApcRoutine,
1336 UserApcContext,
1337 IoStatusBlock,
1338 IoControlCode,
1339 InputBuffer,
1340 InputBufferLength,
1341 OutputBuffer,
1342 OutputBufferLength,
1343 FALSE);
1344 }
1345
1346 NTSTATUS
1347 NTAPI
1348 NtFlushBuffersFile(IN HANDLE FileHandle,
1349 OUT PIO_STATUS_BLOCK IoStatusBlock)
1350 {
1351 PFILE_OBJECT FileObject;
1352 PIRP Irp;
1353 PIO_STACK_LOCATION StackPtr;
1354 NTSTATUS Status;
1355 PDEVICE_OBJECT DeviceObject;
1356 PKEVENT Event = NULL;
1357 BOOLEAN LocalEvent = FALSE;
1358 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1359 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1360 IO_STATUS_BLOCK KernelIosb;
1361 PAGED_CODE();
1362 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1363
1364 if (PreviousMode != KernelMode)
1365 {
1366 /* Protect probes */
1367 _SEH2_TRY
1368 {
1369 /* Probe the I/O Status block */
1370 ProbeForWriteIoStatusBlock(IoStatusBlock);
1371 }
1372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1373 {
1374 /* Return the exception code */
1375 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1376 }
1377 _SEH2_END;
1378 }
1379
1380 /* Get the File Object */
1381 Status = ObReferenceObjectByHandle(FileHandle,
1382 0,
1383 IoFileObjectType,
1384 PreviousMode,
1385 (PVOID*)&FileObject,
1386 &ObjectHandleInfo);
1387 if (!NT_SUCCESS(Status)) return Status;
1388
1389 /*
1390 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1391 * granted. However, if this is a named pipe, make sure we don't ask for
1392 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1393 * access right!
1394 */
1395 if (!(ObjectHandleInfo.GrantedAccess &
1396 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1397 FILE_WRITE_DATA)))
1398 {
1399 /* We failed */
1400 ObDereferenceObject(FileObject);
1401 return STATUS_ACCESS_DENIED;
1402 }
1403
1404 /* Check if we should use Sync IO or not */
1405 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1406 {
1407 /* Lock it */
1408 IopLockFileObject(FileObject);
1409 }
1410 else
1411 {
1412 /* Use local event */
1413 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1414 if (!Event)
1415 {
1416 /* We failed */
1417 ObDereferenceObject(FileObject);
1418 return STATUS_INSUFFICIENT_RESOURCES;
1419 }
1420 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1421 LocalEvent = TRUE;
1422 }
1423
1424 /* Get the Device Object */
1425 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1426
1427 /* Clear the event */
1428 KeClearEvent(&FileObject->Event);
1429
1430 /* Allocate the IRP */
1431 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1432 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1433
1434 /* Set up the IRP */
1435 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1436 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1437 Irp->UserEvent = (LocalEvent) ? Event : NULL;
1438 Irp->RequestorMode = PreviousMode;
1439 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1440 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1441 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1442
1443 /* Set up Stack Data */
1444 StackPtr = IoGetNextIrpStackLocation(Irp);
1445 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1446 StackPtr->FileObject = FileObject;
1447
1448 /* Call the Driver */
1449 Status = IopPerformSynchronousRequest(DeviceObject,
1450 Irp,
1451 FileObject,
1452 FALSE,
1453 PreviousMode,
1454 !LocalEvent,
1455 IopOtherTransfer);
1456
1457 /* Check if this was async I/O */
1458 if (LocalEvent)
1459 {
1460 /* It was, finalize this request */
1461 Status = IopFinalizeAsynchronousIo(Status,
1462 Event,
1463 Irp,
1464 PreviousMode,
1465 &KernelIosb,
1466 IoStatusBlock);
1467 }
1468
1469 /* Return the Status */
1470 return Status;
1471 }
1472
1473 /*
1474 * @implemented
1475 */
1476 NTSTATUS
1477 NTAPI
1478 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1479 IN HANDLE EventHandle OPTIONAL,
1480 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1481 IN PVOID ApcContext OPTIONAL,
1482 OUT PIO_STATUS_BLOCK IoStatusBlock,
1483 OUT PVOID Buffer,
1484 IN ULONG BufferSize,
1485 IN ULONG CompletionFilter,
1486 IN BOOLEAN WatchTree)
1487 {
1488 PIRP Irp;
1489 PKEVENT Event = NULL;
1490 PDEVICE_OBJECT DeviceObject;
1491 PFILE_OBJECT FileObject;
1492 PIO_STACK_LOCATION IoStack;
1493 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1494 NTSTATUS Status;
1495 BOOLEAN LockedForSync = FALSE;
1496 PAGED_CODE();
1497 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1498
1499 /* Check if we're called from user mode */
1500 if (PreviousMode != KernelMode)
1501 {
1502 /* Enter SEH for probing */
1503 _SEH2_TRY
1504 {
1505 /* Probe the I/O STatus block */
1506 ProbeForWriteIoStatusBlock(IoStatusBlock);
1507
1508 /* Probe the buffer */
1509 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
1510 }
1511 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1512 {
1513 /* Return the exception code */
1514 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1515 }
1516 _SEH2_END;
1517
1518 /* Check if CompletionFilter is valid */
1519 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
1520 {
1521 return STATUS_INVALID_PARAMETER;
1522 }
1523 }
1524
1525 /* Get File Object */
1526 Status = ObReferenceObjectByHandle(FileHandle,
1527 FILE_LIST_DIRECTORY,
1528 IoFileObjectType,
1529 PreviousMode,
1530 (PVOID*)&FileObject,
1531 NULL);
1532 if (!NT_SUCCESS(Status)) return Status;
1533
1534 /* Check if we have an event handle */
1535 if (EventHandle)
1536 {
1537 /* Reference it */
1538 Status = ObReferenceObjectByHandle(EventHandle,
1539 EVENT_MODIFY_STATE,
1540 ExEventObjectType,
1541 PreviousMode,
1542 (PVOID *)&Event,
1543 NULL);
1544 if (Status != STATUS_SUCCESS)
1545 {
1546 ObDereferenceObject(FileObject);
1547 return Status;
1548 }
1549 KeClearEvent(Event);
1550 }
1551
1552 /* Check if we should use Sync IO or not */
1553 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1554 {
1555 /* Lock it */
1556 IopLockFileObject(FileObject);
1557 LockedForSync = TRUE;
1558 }
1559
1560 /* Clear File Object event */
1561 KeClearEvent(&FileObject->Event);
1562
1563 /* Get the device object */
1564 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1565
1566 /* Allocate the IRP */
1567 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1568 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1569
1570 /* Set up the IRP */
1571 Irp->RequestorMode = PreviousMode;
1572 Irp->UserIosb = IoStatusBlock;
1573 Irp->UserEvent = Event;
1574 Irp->UserBuffer = Buffer;
1575 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1576 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1577 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1578 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1579
1580 /* Set up Stack Data */
1581 IoStack = IoGetNextIrpStackLocation(Irp);
1582 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1583 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
1584 IoStack->FileObject = FileObject;
1585
1586 /* Set parameters */
1587 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1588 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1589 if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1590
1591 /* Perform the call */
1592 return IopPerformSynchronousRequest(DeviceObject,
1593 Irp,
1594 FileObject,
1595 FALSE,
1596 PreviousMode,
1597 LockedForSync,
1598 IopOtherTransfer);
1599 }
1600
1601 /*
1602 * @implemented
1603 */
1604 NTSTATUS
1605 NTAPI
1606 NtLockFile(IN HANDLE FileHandle,
1607 IN HANDLE EventHandle OPTIONAL,
1608 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1609 IN PVOID ApcContext OPTIONAL,
1610 OUT PIO_STATUS_BLOCK IoStatusBlock,
1611 IN PLARGE_INTEGER ByteOffset,
1612 IN PLARGE_INTEGER Length,
1613 IN ULONG Key,
1614 IN BOOLEAN FailImmediately,
1615 IN BOOLEAN ExclusiveLock)
1616 {
1617 PFILE_OBJECT FileObject;
1618 PLARGE_INTEGER LocalLength = NULL;
1619 PIRP Irp;
1620 PIO_STACK_LOCATION StackPtr;
1621 PDEVICE_OBJECT DeviceObject;
1622 PKEVENT Event = NULL;
1623 BOOLEAN LockedForSync = FALSE;
1624 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1625 LARGE_INTEGER CapturedByteOffset, CapturedLength;
1626 NTSTATUS Status;
1627 OBJECT_HANDLE_INFORMATION HandleInformation;
1628 PFAST_IO_DISPATCH FastIoDispatch;
1629 PAGED_CODE();
1630 CapturedByteOffset.QuadPart = 0;
1631 CapturedLength.QuadPart = 0;
1632 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1633
1634 /* Get File Object */
1635 Status = ObReferenceObjectByHandle(FileHandle,
1636 0,
1637 IoFileObjectType,
1638 PreviousMode,
1639 (PVOID*)&FileObject,
1640 &HandleInformation);
1641 if (!NT_SUCCESS(Status)) return Status;
1642
1643 /* Check if we're called from user mode */
1644 if (PreviousMode != KernelMode)
1645 {
1646 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1647 if (!(HandleInformation.GrantedAccess &
1648 (FILE_WRITE_DATA | FILE_READ_DATA)))
1649 {
1650 ObDereferenceObject(FileObject);
1651 return STATUS_ACCESS_DENIED;
1652 }
1653
1654 /* Enter SEH for probing */
1655 _SEH2_TRY
1656 {
1657 /* Probe the I/O STatus block */
1658 ProbeForWriteIoStatusBlock(IoStatusBlock);
1659
1660 /* Probe and capture the large integers */
1661 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1662 CapturedLength = ProbeForReadLargeInteger(Length);
1663 }
1664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1665 {
1666 /* Dereference the object and return exception code */
1667 ObDereferenceObject(FileObject);
1668 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1669 }
1670 _SEH2_END;
1671 }
1672 else
1673 {
1674 /* Otherwise, capture them directly */
1675 CapturedByteOffset = *ByteOffset;
1676 CapturedLength = *Length;
1677 }
1678
1679 /* Check if we have an event handle */
1680 if (EventHandle)
1681 {
1682 /* Reference it */
1683 Status = ObReferenceObjectByHandle(EventHandle,
1684 EVENT_MODIFY_STATE,
1685 ExEventObjectType,
1686 PreviousMode,
1687 (PVOID *)&Event,
1688 NULL);
1689 if (Status != STATUS_SUCCESS) return Status;
1690 KeClearEvent(Event);
1691 }
1692
1693 /* Get the device object */
1694 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1695
1696 /* Try to do it the FastIO way if possible */
1697 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
1698 if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
1699 {
1700 IO_STATUS_BLOCK KernelIosb;
1701
1702 if (FastIoDispatch->FastIoLock(FileObject,
1703 &CapturedByteOffset,
1704 &CapturedLength,
1705 PsGetCurrentProcess(),
1706 Key,
1707 FailImmediately,
1708 ExclusiveLock,
1709 &KernelIosb,
1710 DeviceObject))
1711 {
1712 /* Write the IOSB back */
1713 _SEH2_TRY
1714 {
1715 *IoStatusBlock = KernelIosb;
1716 }
1717 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1718 {
1719 KernelIosb.Status = _SEH2_GetExceptionCode();
1720 }
1721 _SEH2_END;
1722
1723 /* If we had an event, signal it */
1724 if (EventHandle)
1725 {
1726 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1727 ObDereferenceObject(Event);
1728 }
1729
1730 /* Set completion if required */
1731 if (FileObject->CompletionContext != NULL && ApcContext != NULL)
1732 {
1733 if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
1734 FileObject->CompletionContext->Key,
1735 ApcContext,
1736 KernelIosb.Status,
1737 KernelIosb.Information,
1738 TRUE)))
1739 {
1740 KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
1741 }
1742 }
1743
1744 FileObject->LockOperation = TRUE;
1745
1746 /* We're done with FastIO! */
1747 ObDereferenceObject(FileObject);
1748 return KernelIosb.Status;
1749 }
1750 }
1751
1752 /* Check if we should use Sync IO or not */
1753 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1754 {
1755 /* Lock it */
1756 IopLockFileObject(FileObject);
1757 LockedForSync = TRUE;
1758 }
1759
1760 /* Clear File Object event */
1761 KeClearEvent(&FileObject->Event);
1762 FileObject->LockOperation = TRUE;
1763
1764 /* Allocate the IRP */
1765 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1766 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1767
1768 /* Set up the IRP */
1769 Irp->RequestorMode = PreviousMode;
1770 Irp->UserIosb = IoStatusBlock;
1771 Irp->UserEvent = Event;
1772 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1773 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1774 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1775 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1776
1777 /* Set up Stack Data */
1778 StackPtr = IoGetNextIrpStackLocation(Irp);
1779 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1780 StackPtr->MinorFunction = IRP_MN_LOCK;
1781 StackPtr->FileObject = FileObject;
1782
1783 /* Allocate local buffer */
1784 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1785 sizeof(LARGE_INTEGER),
1786 TAG_LOCK);
1787 if (!LocalLength)
1788 {
1789 /* Allocating failed, clean up and return failure */
1790 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1791 return STATUS_INSUFFICIENT_RESOURCES;
1792 }
1793
1794 /* Set the length */
1795 *LocalLength = CapturedLength;
1796 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1797 StackPtr->Parameters.LockControl.Length = LocalLength;
1798
1799 /* Set Parameters */
1800 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1801 StackPtr->Parameters.LockControl.Key = Key;
1802
1803 /* Set Flags */
1804 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1805 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1806
1807 /* Perform the call */
1808 return IopPerformSynchronousRequest(DeviceObject,
1809 Irp,
1810 FileObject,
1811 FALSE,
1812 PreviousMode,
1813 LockedForSync,
1814 IopOtherTransfer);
1815 }
1816
1817 /*
1818 * @implemented
1819 */
1820 NTSTATUS
1821 NTAPI
1822 NtQueryDirectoryFile(IN HANDLE FileHandle,
1823 IN HANDLE EventHandle OPTIONAL,
1824 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1825 IN PVOID ApcContext OPTIONAL,
1826 OUT PIO_STATUS_BLOCK IoStatusBlock,
1827 OUT PVOID FileInformation,
1828 IN ULONG Length,
1829 IN FILE_INFORMATION_CLASS FileInformationClass,
1830 IN BOOLEAN ReturnSingleEntry,
1831 IN PUNICODE_STRING FileName OPTIONAL,
1832 IN BOOLEAN RestartScan)
1833 {
1834 PIRP Irp;
1835 PDEVICE_OBJECT DeviceObject;
1836 PFILE_OBJECT FileObject;
1837 PIO_STACK_LOCATION StackPtr;
1838 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1839 NTSTATUS Status;
1840 BOOLEAN LockedForSynch = FALSE;
1841 PKEVENT Event = NULL;
1842 volatile PVOID AuxBuffer = NULL;
1843 PMDL Mdl;
1844 UNICODE_STRING CapturedFileName;
1845 PUNICODE_STRING SearchPattern;
1846 PAGED_CODE();
1847 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1848
1849 /* Check if we came from user mode */
1850 if (PreviousMode != KernelMode)
1851 {
1852 /* Enter SEH for probing */
1853 _SEH2_TRY
1854 {
1855 /* Probe the I/O Status Block */
1856 ProbeForWriteIoStatusBlock(IoStatusBlock);
1857
1858 /* Probe the file information */
1859 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1860
1861 /* Check if we have a file name */
1862 if (FileName)
1863 {
1864 /* Capture it */
1865 CapturedFileName = ProbeForReadUnicodeString(FileName);
1866 if (CapturedFileName.Length)
1867 {
1868 /* Probe its buffer */
1869 ProbeForRead(CapturedFileName.Buffer,
1870 CapturedFileName.Length,
1871 1);
1872 }
1873
1874 /* Allocate the auxiliary buffer */
1875 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
1876 CapturedFileName.Length +
1877 sizeof(UNICODE_STRING),
1878 TAG_SYSB);
1879 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
1880 sizeof(UNICODE_STRING)),
1881 CapturedFileName.Buffer,
1882 CapturedFileName.Length);
1883
1884 /* Setup the search pattern */
1885 SearchPattern = (PUNICODE_STRING)AuxBuffer;
1886 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
1887 sizeof(UNICODE_STRING));
1888 SearchPattern->Length = CapturedFileName.Length;
1889 SearchPattern->MaximumLength = CapturedFileName.Length;
1890 }
1891 }
1892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1893 {
1894 /* Free buffer and return the exception code */
1895 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1896 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1897 }
1898 _SEH2_END;
1899 }
1900
1901 /* Get File Object */
1902 Status = ObReferenceObjectByHandle(FileHandle,
1903 FILE_LIST_DIRECTORY,
1904 IoFileObjectType,
1905 PreviousMode,
1906 (PVOID *)&FileObject,
1907 NULL);
1908 if (!NT_SUCCESS(Status))
1909 {
1910 /* Fail */
1911 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1912 return Status;
1913 }
1914
1915 /* Are there two associated completion routines? */
1916 if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
1917 {
1918 ObDereferenceObject(FileObject);
1919 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1920 return STATUS_INVALID_PARAMETER;
1921 }
1922
1923 /* Check if we have an even handle */
1924 if (EventHandle)
1925 {
1926 /* Get its pointer */
1927 Status = ObReferenceObjectByHandle(EventHandle,
1928 EVENT_MODIFY_STATE,
1929 ExEventObjectType,
1930 PreviousMode,
1931 (PVOID *)&Event,
1932 NULL);
1933 if (!NT_SUCCESS(Status))
1934 {
1935 /* Fail */
1936 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1937 ObDereferenceObject(FileObject);
1938 return Status;
1939 }
1940
1941 /* Clear it */
1942 KeClearEvent(Event);
1943 }
1944
1945 /* Check if this is a file that was opened for Synch I/O */
1946 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1947 {
1948 /* Lock it */
1949 IopLockFileObject(FileObject);
1950
1951 /* Remember to unlock later */
1952 LockedForSynch = TRUE;
1953 }
1954
1955 /* Get the device object */
1956 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1957
1958 /* Clear the File Object's event */
1959 KeClearEvent(&FileObject->Event);
1960
1961 /* Allocate the IRP */
1962 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1963 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
1964
1965 /* Set up the IRP */
1966 Irp->RequestorMode = PreviousMode;
1967 Irp->UserIosb = IoStatusBlock;
1968 Irp->UserEvent = Event;
1969 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1970 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1971 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1972 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1973 Irp->MdlAddress = NULL;
1974 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
1975 Irp->AssociatedIrp.SystemBuffer = NULL;
1976
1977 /* Check if this is buffered I/O */
1978 if (DeviceObject->Flags & DO_BUFFERED_IO)
1979 {
1980 /* Allocate a buffer */
1981 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
1982 Length,
1983 TAG_SYSB);
1984 if (!Irp->AssociatedIrp.SystemBuffer)
1985 {
1986 /* Allocating failed, clean up and return the exception code */
1987 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1988 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1989
1990 /* Return the exception code */
1991 return STATUS_INSUFFICIENT_RESOURCES;
1992 }
1993
1994 /* Set the buffer and flags */
1995 Irp->UserBuffer = FileInformation;
1996 Irp->Flags = (IRP_BUFFERED_IO |
1997 IRP_DEALLOCATE_BUFFER |
1998 IRP_INPUT_OPERATION);
1999 }
2000 else if (DeviceObject->Flags & DO_DIRECT_IO)
2001 {
2002 _SEH2_TRY
2003 {
2004 /* Allocate an MDL */
2005 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
2006 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2007 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2008 }
2009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2010 {
2011 /* Allocating failed, clean up and return the exception code */
2012 IopCleanupAfterException(FileObject, Irp, Event, NULL);
2013 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2014 }
2015 _SEH2_END;
2016 }
2017 else
2018 {
2019 /* No allocation flags, and use the buffer directly */
2020 Irp->UserBuffer = FileInformation;
2021 }
2022
2023 /* Set up Stack Data */
2024 StackPtr = IoGetNextIrpStackLocation(Irp);
2025 StackPtr->FileObject = FileObject;
2026 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2027 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
2028
2029 /* Set Parameters */
2030 StackPtr->Parameters.QueryDirectory.FileInformationClass =
2031 FileInformationClass;
2032 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
2033 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2034 StackPtr->Parameters.QueryDirectory.Length = Length;
2035 StackPtr->Flags = 0;
2036 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2037 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
2038
2039 /* Set deferred I/O */
2040 Irp->Flags |= IRP_DEFER_IO_COMPLETION;
2041
2042 /* Perform the call */
2043 return IopPerformSynchronousRequest(DeviceObject,
2044 Irp,
2045 FileObject,
2046 TRUE,
2047 PreviousMode,
2048 LockedForSynch,
2049 IopOtherTransfer);
2050 }
2051
2052 /*
2053 * @unimplemented
2054 */
2055 NTSTATUS
2056 NTAPI
2057 NtQueryEaFile(IN HANDLE FileHandle,
2058 OUT PIO_STATUS_BLOCK IoStatusBlock,
2059 OUT PVOID Buffer,
2060 IN ULONG Length,
2061 IN BOOLEAN ReturnSingleEntry,
2062 IN PVOID EaList OPTIONAL,
2063 IN ULONG EaListLength,
2064 IN PULONG EaIndex OPTIONAL,
2065 IN BOOLEAN RestartScan)
2066 {
2067 UNIMPLEMENTED;
2068 return STATUS_NOT_IMPLEMENTED;
2069 }
2070
2071 /*
2072 * @implemented
2073 */
2074 NTSTATUS
2075 NTAPI
2076 NtQueryInformationFile(IN HANDLE FileHandle,
2077 OUT PIO_STATUS_BLOCK IoStatusBlock,
2078 IN PVOID FileInformation,
2079 IN ULONG Length,
2080 IN FILE_INFORMATION_CLASS FileInformationClass)
2081 {
2082 OBJECT_HANDLE_INFORMATION HandleInformation;
2083 PFILE_OBJECT FileObject;
2084 NTSTATUS Status;
2085 PIRP Irp;
2086 PDEVICE_OBJECT DeviceObject;
2087 PIO_STACK_LOCATION StackPtr;
2088 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2089 PKEVENT Event = NULL;
2090 BOOLEAN LocalEvent = FALSE;
2091 PKNORMAL_ROUTINE NormalRoutine;
2092 PVOID NormalContext;
2093 KIRQL OldIrql;
2094 IO_STATUS_BLOCK KernelIosb;
2095 BOOLEAN CallDriver = TRUE;
2096 PFILE_ACCESS_INFORMATION AccessBuffer;
2097 PFILE_MODE_INFORMATION ModeBuffer;
2098 PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
2099 PFILE_ALL_INFORMATION AllBuffer;
2100 PFAST_IO_DISPATCH FastIoDispatch;
2101 PAGED_CODE();
2102 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2103
2104 /* Check if we're called from user mode */
2105 if (PreviousMode != KernelMode)
2106 {
2107 /* Validate the information class */
2108 if ((FileInformationClass >= FileMaximumInformation) ||
2109 !(IopQueryOperationLength[FileInformationClass]))
2110 {
2111 /* Invalid class */
2112 return STATUS_INVALID_INFO_CLASS;
2113 }
2114
2115 /* Validate the length */
2116 if (Length < IopQueryOperationLength[FileInformationClass])
2117 {
2118 /* Invalid length */
2119 return STATUS_INFO_LENGTH_MISMATCH;
2120 }
2121
2122 /* Enter SEH for probing */
2123 _SEH2_TRY
2124 {
2125 /* Probe the I/O Status block */
2126 ProbeForWriteIoStatusBlock(IoStatusBlock);
2127
2128 /* Probe the information */
2129 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
2130 }
2131 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2132 {
2133 /* Return the exception code */
2134 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2135 }
2136 _SEH2_END;
2137 }
2138 #if DBG
2139 else
2140 {
2141 /* Validate the information class */
2142 if ((FileInformationClass >= FileMaximumInformation) ||
2143 !(IopQueryOperationLength[FileInformationClass]))
2144 {
2145 /* Invalid class */
2146 return STATUS_INVALID_INFO_CLASS;
2147 }
2148
2149 /* Validate the length */
2150 if (Length < IopQueryOperationLength[FileInformationClass])
2151 {
2152 /* Invalid length */
2153 return STATUS_INFO_LENGTH_MISMATCH;
2154 }
2155 }
2156 #endif
2157
2158 /* Reference the Handle */
2159 Status = ObReferenceObjectByHandle(FileHandle,
2160 IopQueryOperationAccess
2161 [FileInformationClass],
2162 IoFileObjectType,
2163 PreviousMode,
2164 (PVOID *)&FileObject,
2165 &HandleInformation);
2166 if (!NT_SUCCESS(Status)) return Status;
2167
2168 /* Check if this is a direct open or not */
2169 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2170 {
2171 /* Get the device object */
2172 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2173 }
2174 else
2175 {
2176 /* Get the device object */
2177 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2178 }
2179
2180 /* Check if this is a file that was opened for Synch I/O */
2181 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2182 {
2183 /* Lock it */
2184 IopLockFileObject(FileObject);
2185
2186 /* Check if the caller just wants the position */
2187 if (FileInformationClass == FilePositionInformation)
2188 {
2189 /* Protect write in SEH */
2190 _SEH2_TRY
2191 {
2192 /* Write the offset */
2193 ((PFILE_POSITION_INFORMATION)FileInformation)->
2194 CurrentByteOffset = FileObject->CurrentByteOffset;
2195
2196 /* Fill out the I/O Status Block */
2197 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
2198 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2199 }
2200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2201 {
2202 /* Get the exception code */
2203 Status = _SEH2_GetExceptionCode();
2204 }
2205 _SEH2_END;
2206
2207 /* Release the file lock, dereference the file and return */
2208 IopUnlockFileObject(FileObject);
2209 ObDereferenceObject(FileObject);
2210 return Status;
2211 }
2212 }
2213 else
2214 {
2215 /* Use local event */
2216 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2217 if (!Event)
2218 {
2219 ObDereferenceObject(FileObject);
2220 return STATUS_INSUFFICIENT_RESOURCES;
2221 }
2222 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2223 LocalEvent = TRUE;
2224 }
2225
2226 /* Check if FastIO is possible for the two available information classes */
2227 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2228 if (FastIoDispatch != NULL &&
2229 ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
2230 (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
2231 {
2232 BOOLEAN Success = FALSE;
2233
2234 if (FileInformationClass == FileBasicInformation)
2235 {
2236 Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
2237 FileInformation,
2238 &KernelIosb,
2239 DeviceObject);
2240 }
2241 else
2242 {
2243 Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
2244 FileInformation,
2245 &KernelIosb,
2246 DeviceObject);
2247 }
2248
2249 /* If call succeed */
2250 if (Success)
2251 {
2252 /* Write the IOSB back */
2253 _SEH2_TRY
2254 {
2255 *IoStatusBlock = KernelIosb;
2256 }
2257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2258 {
2259 KernelIosb.Status = _SEH2_GetExceptionCode();
2260 }
2261 _SEH2_END;
2262
2263 /* Free the event if we had one */
2264 if (LocalEvent)
2265 {
2266 ExFreePoolWithTag(Event, TAG_IO);
2267 }
2268
2269 /* If FO was locked, unlock it */
2270 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2271 {
2272 IopUnlockFileObject(FileObject);
2273 }
2274
2275 /* We're done with FastIO! */
2276 ObDereferenceObject(FileObject);
2277 return KernelIosb.Status;
2278 }
2279 }
2280
2281 /* Clear the File Object event */
2282 KeClearEvent(&FileObject->Event);
2283
2284 /* Allocate the IRP */
2285 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2286 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2287
2288 /* Set the IRP */
2289 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2290 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2291 Irp->RequestorMode = PreviousMode;
2292 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2293 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2294 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2295 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2296 Irp->AssociatedIrp.SystemBuffer = NULL;
2297 Irp->MdlAddress = NULL;
2298 Irp->UserBuffer = FileInformation;
2299
2300 /* Set the Stack Data */
2301 StackPtr = IoGetNextIrpStackLocation(Irp);
2302 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2303 StackPtr->FileObject = FileObject;
2304
2305 /* Enter SEH */
2306 _SEH2_TRY
2307 {
2308 /* Allocate a buffer */
2309 Irp->AssociatedIrp.SystemBuffer =
2310 ExAllocatePoolWithTag(NonPagedPool,
2311 Length,
2312 TAG_SYSB);
2313 }
2314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2315 {
2316 /* Allocating failed, clean up and return the exception code */
2317 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2319 }
2320 _SEH2_END;
2321
2322 /* Set the flags */
2323 Irp->Flags |= (IRP_BUFFERED_IO |
2324 IRP_DEALLOCATE_BUFFER |
2325 IRP_INPUT_OPERATION |
2326 IRP_DEFER_IO_COMPLETION);
2327
2328 /* Set the Parameters */
2329 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2330 StackPtr->Parameters.QueryFile.Length = Length;
2331
2332 /* Queue the IRP */
2333 IopQueueIrpToThread(Irp);
2334
2335 /* Update operation counts */
2336 IopUpdateOperationCount(IopOtherTransfer);
2337
2338 /* Fill in file information before calling the driver.
2339 See 'File System Internals' page 485.*/
2340 if (FileInformationClass == FileAccessInformation)
2341 {
2342 AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2343 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2344 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2345 CallDriver = FALSE;
2346 }
2347 else if (FileInformationClass == FileModeInformation)
2348 {
2349 ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2350 ModeBuffer->Mode = IopGetFileMode(FileObject);
2351 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2352 CallDriver = FALSE;
2353 }
2354 else if (FileInformationClass == FileAlignmentInformation)
2355 {
2356 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2357 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2358 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2359 CallDriver = FALSE;
2360 }
2361 else if (FileInformationClass == FileAllInformation)
2362 {
2363 AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2364 AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2365 AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
2366 AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2367 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2368 sizeof(FILE_MODE_INFORMATION) +
2369 sizeof(FILE_ALIGNMENT_INFORMATION);
2370 }
2371
2372 /* Call the Driver */
2373 if (CallDriver)
2374 {
2375 Status = IoCallDriver(DeviceObject, Irp);
2376 }
2377 else
2378 {
2379 Status = STATUS_SUCCESS;
2380 Irp->IoStatus.Status = STATUS_SUCCESS;
2381 }
2382
2383 if (Status == STATUS_PENDING)
2384 {
2385 /* Check if this was async I/O */
2386 if (LocalEvent)
2387 {
2388 /* Then to a non-alertable wait */
2389 Status = KeWaitForSingleObject(Event,
2390 Executive,
2391 PreviousMode,
2392 FALSE,
2393 NULL);
2394 if (Status == STATUS_USER_APC)
2395 {
2396 /* Abort the request */
2397 IopAbortInterruptedIrp(Event, Irp);
2398 }
2399
2400 /* Set the final status */
2401 Status = KernelIosb.Status;
2402
2403 /* Enter SEH to write the IOSB back */
2404 _SEH2_TRY
2405 {
2406 /* Write it back to the caller */
2407 *IoStatusBlock = KernelIosb;
2408 }
2409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2410 {
2411 /* Get the exception code */
2412 Status = _SEH2_GetExceptionCode();
2413 }
2414 _SEH2_END;
2415
2416 /* Free the event */
2417 ExFreePoolWithTag(Event, TAG_IO);
2418 }
2419 else
2420 {
2421 /* Wait for the IRP */
2422 Status = KeWaitForSingleObject(&FileObject->Event,
2423 Executive,
2424 PreviousMode,
2425 (FileObject->Flags &
2426 FO_ALERTABLE_IO) != 0,
2427 NULL);
2428 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2429 {
2430 /* Abort the request */
2431 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2432 }
2433
2434 /* Set the final status */
2435 Status = FileObject->FinalStatus;
2436
2437 /* Release the file lock */
2438 IopUnlockFileObject(FileObject);
2439 }
2440 }
2441 else
2442 {
2443 /* Free the event if we had one */
2444 if (LocalEvent)
2445 {
2446 /* Clear it in the IRP for completion */
2447 Irp->UserEvent = NULL;
2448 ExFreePoolWithTag(Event, TAG_IO);
2449 }
2450
2451 /* Set the caller IOSB */
2452 Irp->UserIosb = IoStatusBlock;
2453
2454 /* The IRP wasn't completed, complete it ourselves */
2455 KeRaiseIrql(APC_LEVEL, &OldIrql);
2456 IopCompleteRequest(&Irp->Tail.Apc,
2457 &NormalRoutine,
2458 &NormalContext,
2459 (PVOID*)&FileObject,
2460 &NormalContext);
2461 KeLowerIrql(OldIrql);
2462
2463 /* Release the file object if we had locked it*/
2464 if (!LocalEvent) IopUnlockFileObject(FileObject);
2465 }
2466
2467 /* Return the Status */
2468 return Status;
2469 }
2470
2471 /*
2472 * @unimplemented
2473 */
2474 NTSTATUS
2475 NTAPI
2476 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2477 OUT PIO_STATUS_BLOCK IoStatusBlock,
2478 OUT PVOID Buffer,
2479 IN ULONG Length,
2480 IN BOOLEAN ReturnSingleEntry,
2481 IN PVOID SidList OPTIONAL,
2482 IN ULONG SidListLength,
2483 IN PSID StartSid OPTIONAL,
2484 IN BOOLEAN RestartScan)
2485 {
2486 UNIMPLEMENTED;
2487 return STATUS_NOT_IMPLEMENTED;
2488 }
2489
2490 /*
2491 * @implemented
2492 */
2493 NTSTATUS
2494 NTAPI
2495 NtReadFile(IN HANDLE FileHandle,
2496 IN HANDLE Event OPTIONAL,
2497 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2498 IN PVOID ApcContext OPTIONAL,
2499 OUT PIO_STATUS_BLOCK IoStatusBlock,
2500 OUT PVOID Buffer,
2501 IN ULONG Length,
2502 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2503 IN PULONG Key OPTIONAL)
2504 {
2505 NTSTATUS Status;
2506 PFILE_OBJECT FileObject;
2507 PIRP Irp;
2508 PDEVICE_OBJECT DeviceObject;
2509 PIO_STACK_LOCATION StackPtr;
2510 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2511 PKEVENT EventObject = NULL;
2512 LARGE_INTEGER CapturedByteOffset;
2513 ULONG CapturedKey = 0;
2514 BOOLEAN Synchronous = FALSE;
2515 PMDL Mdl;
2516 PFAST_IO_DISPATCH FastIoDispatch;
2517 IO_STATUS_BLOCK KernelIosb;
2518 BOOLEAN Success;
2519
2520 PAGED_CODE();
2521 CapturedByteOffset.QuadPart = 0;
2522 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2523
2524 /* Validate User-Mode Buffers */
2525 if (PreviousMode != KernelMode)
2526 {
2527 _SEH2_TRY
2528 {
2529 /* Probe the status block */
2530 ProbeForWriteIoStatusBlock(IoStatusBlock);
2531
2532 /* Probe the read buffer */
2533 ProbeForWrite(Buffer, Length, 1);
2534
2535 /* Check if we got a byte offset */
2536 if (ByteOffset)
2537 {
2538 /* Capture and probe it */
2539 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2540 }
2541
2542 /* Capture and probe the key */
2543 if (Key) CapturedKey = ProbeForReadUlong(Key);
2544 }
2545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2546 {
2547 /* Return the exception code */
2548 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2549 }
2550 _SEH2_END;
2551 }
2552 else
2553 {
2554 /* Kernel mode: capture directly */
2555 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2556 if (Key) CapturedKey = *Key;
2557 }
2558
2559 /* Get File Object */
2560 Status = ObReferenceObjectByHandle(FileHandle,
2561 FILE_READ_DATA,
2562 IoFileObjectType,
2563 PreviousMode,
2564 (PVOID*)&FileObject,
2565 NULL);
2566 if (!NT_SUCCESS(Status)) return Status;
2567
2568 /* Check for event */
2569 if (Event)
2570 {
2571 /* Reference it */
2572 Status = ObReferenceObjectByHandle(Event,
2573 EVENT_MODIFY_STATE,
2574 ExEventObjectType,
2575 PreviousMode,
2576 (PVOID*)&EventObject,
2577 NULL);
2578 if (!NT_SUCCESS(Status))
2579 {
2580 /* Fail */
2581 ObDereferenceObject(FileObject);
2582 return Status;
2583 }
2584
2585 /* Otherwise reset the event */
2586 KeClearEvent(EventObject);
2587 }
2588
2589 /* Get the device object */
2590 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2591
2592 /* Check if we should use Sync IO or not */
2593 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2594 {
2595 /* Lock the file object */
2596 IopLockFileObject(FileObject);
2597
2598 /* Check if we don't have a byte offset available */
2599 if (!(ByteOffset) ||
2600 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2601 (CapturedByteOffset.u.HighPart == -1)))
2602 {
2603 /* Use the Current Byte Offset instead */
2604 CapturedByteOffset = FileObject->CurrentByteOffset;
2605 }
2606
2607 /* If the file is cached, try fast I/O */
2608 if (FileObject->PrivateCacheMap)
2609 {
2610 /* Perform fast read */
2611 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2612 ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
2613
2614 Success = FastIoDispatch->FastIoRead(FileObject,
2615 &CapturedByteOffset,
2616 Length,
2617 TRUE,
2618 CapturedKey,
2619 Buffer,
2620 &KernelIosb,
2621 DeviceObject);
2622
2623 /* Only accept the result if we got a straightforward status */
2624 if (Success &&
2625 (KernelIosb.Status == STATUS_SUCCESS ||
2626 KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2627 KernelIosb.Status == STATUS_END_OF_FILE))
2628 {
2629 /* Fast path -- update transfer & operation counts */
2630 IopUpdateOperationCount(IopReadTransfer);
2631 IopUpdateTransferCount(IopReadTransfer,
2632 (ULONG)KernelIosb.Information);
2633
2634 /* Enter SEH to write the IOSB back */
2635 _SEH2_TRY
2636 {
2637 /* Write it back to the caller */
2638 *IoStatusBlock = KernelIosb;
2639 }
2640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2641 {
2642 /* The caller's IOSB was invalid, so fail */
2643 if (EventObject) ObDereferenceObject(EventObject);
2644 IopUnlockFileObject(FileObject);
2645 ObDereferenceObject(FileObject);
2646 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2647 }
2648 _SEH2_END;
2649
2650 /* Signal the completion event */
2651 if (EventObject)
2652 {
2653 KeSetEvent(EventObject, 0, FALSE);
2654 ObDereferenceObject(EventObject);
2655 }
2656
2657 /* Clean up */
2658 IopUnlockFileObject(FileObject);
2659 ObDereferenceObject(FileObject);
2660 return KernelIosb.Status;
2661 }
2662 }
2663
2664 /* Remember we are sync */
2665 Synchronous = TRUE;
2666 }
2667 else if (!(ByteOffset) &&
2668 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2669 {
2670 /* Otherwise, this was async I/O without a byte offset, so fail */
2671 if (EventObject) ObDereferenceObject(EventObject);
2672 ObDereferenceObject(FileObject);
2673 return STATUS_INVALID_PARAMETER;
2674 }
2675
2676 /* Clear the File Object's event */
2677 KeClearEvent(&FileObject->Event);
2678
2679 /* Allocate the IRP */
2680 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2681 if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2682
2683 /* Set the IRP */
2684 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2685 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2686 Irp->RequestorMode = PreviousMode;
2687 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2688 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2689 Irp->UserIosb = IoStatusBlock;
2690 Irp->UserEvent = EventObject;
2691 Irp->PendingReturned = FALSE;
2692 Irp->Cancel = FALSE;
2693 Irp->CancelRoutine = NULL;
2694 Irp->AssociatedIrp.SystemBuffer = NULL;
2695 Irp->MdlAddress = NULL;
2696
2697 /* Set the Stack Data */
2698 StackPtr = IoGetNextIrpStackLocation(Irp);
2699 StackPtr->MajorFunction = IRP_MJ_READ;
2700 StackPtr->FileObject = FileObject;
2701 StackPtr->Parameters.Read.Key = CapturedKey;
2702 StackPtr->Parameters.Read.Length = Length;
2703 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2704
2705 /* Check if this is buffered I/O */
2706 if (DeviceObject->Flags & DO_BUFFERED_IO)
2707 {
2708 /* Check if we have a buffer length */
2709 if (Length)
2710 {
2711 /* Enter SEH */
2712 _SEH2_TRY
2713 {
2714 /* Allocate a buffer */
2715 Irp->AssociatedIrp.SystemBuffer =
2716 ExAllocatePoolWithTag(NonPagedPool,
2717 Length,
2718 TAG_SYSB);
2719 }
2720 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2721 {
2722 /* Allocating failed, clean up and return the exception code */
2723 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2724 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2725 }
2726 _SEH2_END;
2727
2728 /* Set the buffer and flags */
2729 Irp->UserBuffer = Buffer;
2730 Irp->Flags = (IRP_BUFFERED_IO |
2731 IRP_DEALLOCATE_BUFFER |
2732 IRP_INPUT_OPERATION);
2733 }
2734 else
2735 {
2736 /* Not reading anything */
2737 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2738 }
2739 }
2740 else if (DeviceObject->Flags & DO_DIRECT_IO)
2741 {
2742 /* Check if we have a buffer length */
2743 if (Length)
2744 {
2745 _SEH2_TRY
2746 {
2747 /* Allocate an MDL */
2748 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2749 if (!Mdl)
2750 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2751 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2752 }
2753 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2754 {
2755 /* Allocating failed, clean up and return the exception code */
2756 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2757 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2758 }
2759 _SEH2_END;
2760
2761 }
2762
2763 /* No allocation flags */
2764 Irp->Flags = 0;
2765 }
2766 else
2767 {
2768 /* No allocation flags, and use the buffer directly */
2769 Irp->Flags = 0;
2770 Irp->UserBuffer = Buffer;
2771 }
2772
2773 /* Now set the deferred read flags */
2774 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2775 #if 0
2776 /* FIXME: VFAT SUCKS */
2777 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2778 #endif
2779
2780 /* Perform the call */
2781 return IopPerformSynchronousRequest(DeviceObject,
2782 Irp,
2783 FileObject,
2784 TRUE,
2785 PreviousMode,
2786 Synchronous,
2787 IopReadTransfer);
2788 }
2789
2790 /*
2791 * @unimplemented
2792 */
2793 NTSTATUS
2794 NTAPI
2795 NtReadFileScatter(IN HANDLE FileHandle,
2796 IN HANDLE Event OPTIONAL,
2797 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2798 IN PVOID UserApcContext OPTIONAL,
2799 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2800 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2801 IN ULONG BufferLength,
2802 IN PLARGE_INTEGER ByteOffset,
2803 IN PULONG Key OPTIONAL)
2804 {
2805 UNIMPLEMENTED;
2806 return STATUS_NOT_IMPLEMENTED;
2807 }
2808
2809 /*
2810 * @unimplemented
2811 */
2812 NTSTATUS
2813 NTAPI
2814 NtSetEaFile(IN HANDLE FileHandle,
2815 IN PIO_STATUS_BLOCK IoStatusBlock,
2816 IN PVOID EaBuffer,
2817 IN ULONG EaBufferSize)
2818 {
2819 UNIMPLEMENTED;
2820 return STATUS_NOT_IMPLEMENTED;
2821 }
2822
2823 /*
2824 * @implemented
2825 */
2826 NTSTATUS
2827 NTAPI
2828 NtSetInformationFile(IN HANDLE FileHandle,
2829 OUT PIO_STATUS_BLOCK IoStatusBlock,
2830 IN PVOID FileInformation,
2831 IN ULONG Length,
2832 IN FILE_INFORMATION_CLASS FileInformationClass)
2833 {
2834 PFILE_OBJECT FileObject;
2835 NTSTATUS Status;
2836 PIRP Irp;
2837 PDEVICE_OBJECT DeviceObject;
2838 PIO_STACK_LOCATION StackPtr;
2839 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2840 PKEVENT Event = NULL;
2841 BOOLEAN LocalEvent = FALSE;
2842 PKNORMAL_ROUTINE NormalRoutine;
2843 PVOID NormalContext;
2844 KIRQL OldIrql;
2845 IO_STATUS_BLOCK KernelIosb;
2846 PVOID Queue;
2847 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2848 PIO_COMPLETION_CONTEXT Context;
2849 PFILE_RENAME_INFORMATION RenameInfo;
2850 HANDLE TargetHandle = NULL;
2851 PAGED_CODE();
2852 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2853
2854 /* Check if we're called from user mode */
2855 if (PreviousMode != KernelMode)
2856 {
2857 /* Validate the information class */
2858 if ((FileInformationClass >= FileMaximumInformation) ||
2859 !(IopSetOperationLength[FileInformationClass]))
2860 {
2861 /* Invalid class */
2862 return STATUS_INVALID_INFO_CLASS;
2863 }
2864
2865 /* Validate the length */
2866 if (Length < IopSetOperationLength[FileInformationClass])
2867 {
2868 /* Invalid length */
2869 return STATUS_INFO_LENGTH_MISMATCH;
2870 }
2871
2872 /* Enter SEH for probing */
2873 _SEH2_TRY
2874 {
2875 /* Probe the I/O Status block */
2876 ProbeForWriteIoStatusBlock(IoStatusBlock);
2877
2878 /* Probe the information */
2879 ProbeForRead(FileInformation,
2880 Length,
2881 (Length == sizeof(BOOLEAN)) ?
2882 sizeof(BOOLEAN) : sizeof(ULONG));
2883 }
2884 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2885 {
2886 /* Return the exception code */
2887 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2888 }
2889 _SEH2_END;
2890 }
2891 else
2892 {
2893 /* Validate the information class */
2894 if ((FileInformationClass >= FileMaximumInformation) ||
2895 !(IopSetOperationLength[FileInformationClass]))
2896 {
2897 /* Invalid class */
2898 return STATUS_INVALID_INFO_CLASS;
2899 }
2900
2901 /* Validate the length */
2902 if (Length < IopSetOperationLength[FileInformationClass])
2903 {
2904 /* Invalid length */
2905 return STATUS_INFO_LENGTH_MISMATCH;
2906 }
2907 }
2908
2909 /* Reference the Handle */
2910 Status = ObReferenceObjectByHandle(FileHandle,
2911 IopSetOperationAccess
2912 [FileInformationClass],
2913 IoFileObjectType,
2914 PreviousMode,
2915 (PVOID *)&FileObject,
2916 NULL);
2917 if (!NT_SUCCESS(Status)) return Status;
2918
2919 /* Check if this is a direct open or not */
2920 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2921 {
2922 /* Get the device object */
2923 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2924 }
2925 else
2926 {
2927 /* Get the device object */
2928 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2929 }
2930
2931 DPRINT("Will call: %p\n", DeviceObject);
2932 DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
2933
2934 /* Check if this is a file that was opened for Synch I/O */
2935 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2936 {
2937 /* Lock it */
2938 IopLockFileObject(FileObject);
2939
2940 /* Check if the caller just wants the position */
2941 if (FileInformationClass == FilePositionInformation)
2942 {
2943 /* Protect write in SEH */
2944 _SEH2_TRY
2945 {
2946 /* Write the offset */
2947 FileObject->CurrentByteOffset =
2948 ((PFILE_POSITION_INFORMATION)FileInformation)->
2949 CurrentByteOffset;
2950
2951 /* Fill out the I/O Status Block */
2952 IoStatusBlock->Information = 0;
2953 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2954 }
2955 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2956 {
2957 /* Get the exception code */
2958 Status = _SEH2_GetExceptionCode();
2959 }
2960 _SEH2_END;
2961
2962 /* Update transfer count */
2963 IopUpdateTransferCount(IopOtherTransfer, Length);
2964
2965 /* Release the file lock, dereference the file and return */
2966 IopUnlockFileObject(FileObject);
2967 ObDereferenceObject(FileObject);
2968 return Status;
2969 }
2970 }
2971 else
2972 {
2973 /* Use local event */
2974 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2975 if (!Event)
2976 {
2977 ObDereferenceObject(FileObject);
2978 return STATUS_INSUFFICIENT_RESOURCES;
2979 }
2980
2981 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2982 LocalEvent = TRUE;
2983 }
2984
2985 /* Clear the File Object event */
2986 KeClearEvent(&FileObject->Event);
2987
2988 /* Allocate the IRP */
2989 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2990 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2991
2992 /* Set the IRP */
2993 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2994 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2995 Irp->RequestorMode = PreviousMode;
2996 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2997 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2998 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2999 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3000 Irp->AssociatedIrp.SystemBuffer = NULL;
3001 Irp->MdlAddress = NULL;
3002 Irp->UserBuffer = FileInformation;
3003
3004 /* Set the Stack Data */
3005 StackPtr = IoGetNextIrpStackLocation(Irp);
3006 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
3007 StackPtr->FileObject = FileObject;
3008
3009 /* Enter SEH */
3010 _SEH2_TRY
3011 {
3012 /* Allocate a buffer */
3013 Irp->AssociatedIrp.SystemBuffer =
3014 ExAllocatePoolWithTag(NonPagedPool,
3015 Length,
3016 TAG_SYSB);
3017
3018 /* Copy the data into it */
3019 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3020 FileInformation,
3021 Length);
3022 }
3023 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3024 {
3025 /* Allocating failed, clean up and return the exception code */
3026 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3027 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3028 }
3029 _SEH2_END;
3030
3031 /* Set the flags */
3032 Irp->Flags |= (IRP_BUFFERED_IO |
3033 IRP_DEALLOCATE_BUFFER |
3034 IRP_DEFER_IO_COMPLETION);
3035
3036 /* Set the Parameters */
3037 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3038 StackPtr->Parameters.SetFile.Length = Length;
3039
3040 /* Queue the IRP */
3041 IopQueueIrpToThread(Irp);
3042
3043 /* Update operation counts */
3044 IopUpdateOperationCount(IopOtherTransfer);
3045
3046 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3047 /* Handle IO Completion Port quickly */
3048 if (FileInformationClass == FileCompletionInformation)
3049 {
3050 /* Check if the file object already has a completion port */
3051 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3052 (FileObject->CompletionContext))
3053 {
3054 /* Fail */
3055 Status = STATUS_INVALID_PARAMETER;
3056 }
3057 else
3058 {
3059 /* Reference the Port */
3060 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3061 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3062 IO_COMPLETION_MODIFY_STATE,
3063 IoCompletionType,
3064 PreviousMode,
3065 (PVOID*)&Queue,
3066 NULL);
3067 if (NT_SUCCESS(Status))
3068 {
3069 /* Allocate the Context */
3070 Context = ExAllocatePoolWithTag(PagedPool,
3071 sizeof(IO_COMPLETION_CONTEXT),
3072 IOC_TAG);
3073 if (Context)
3074 {
3075 /* Set the Data */
3076 Context->Key = CompletionInfo->Key;
3077 Context->Port = Queue;
3078 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
3079 CompletionContext,
3080 Context,
3081 NULL))
3082 {
3083 /*
3084 * Someone else set the completion port in the
3085 * meanwhile, so dereference the port and fail.
3086 */
3087 ExFreePoolWithTag(Context, IOC_TAG);
3088 ObDereferenceObject(Queue);
3089 Status = STATUS_INVALID_PARAMETER;
3090 }
3091 }
3092 else
3093 {
3094 /* Dereference the Port now */
3095 ObDereferenceObject(Queue);
3096 Status = STATUS_INSUFFICIENT_RESOURCES;
3097 }
3098 }
3099 }
3100
3101 /* Set the IRP Status */
3102 Irp->IoStatus.Status = Status;
3103 Irp->IoStatus.Information = 0;
3104 }
3105 else if (FileInformationClass == FileRenameInformation ||
3106 FileInformationClass == FileLinkInformation ||
3107 FileInformationClass == FileMoveClusterInformation)
3108 {
3109 /* Get associated information */
3110 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3111
3112 /* Only rename if:
3113 * -> We have a name
3114 * -> In unicode
3115 * -> sizes are valid
3116 */
3117 if (RenameInfo->FileNameLength != 0 &&
3118 !(RenameInfo->FileNameLength & 1) &&
3119 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
3120 {
3121 /* Properly set information received */
3122 if (FileInformationClass == FileMoveClusterInformation)
3123 {
3124 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3125 }
3126 else
3127 {
3128 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3129 }
3130
3131 /* If we got fully path OR relative target, attempt a parent directory open */
3132 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3133 {
3134 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
3135 if (!NT_SUCCESS(Status))
3136 {
3137 Irp->IoStatus.Status = Status;
3138 }
3139 else
3140 {
3141 /* Call the Driver */
3142 Status = IoCallDriver(DeviceObject, Irp);
3143 }
3144 }
3145 else
3146 {
3147 /* Call the Driver */
3148 Status = IoCallDriver(DeviceObject, Irp);
3149 }
3150 }
3151 else
3152 {
3153 Status = STATUS_INVALID_PARAMETER;
3154 Irp->IoStatus.Status = Status;
3155 }
3156 }
3157 else
3158 {
3159 /* Call the Driver */
3160 Status = IoCallDriver(DeviceObject, Irp);
3161 }
3162
3163 /* Check if we're waiting for the IRP to complete */
3164 if (Status == STATUS_PENDING)
3165 {
3166 /* Check if this was async I/O */
3167 if (LocalEvent)
3168 {
3169 /* Then to a non-alertable wait */
3170 Status = KeWaitForSingleObject(Event,
3171 Executive,
3172 PreviousMode,
3173 FALSE,
3174 NULL);
3175 if (Status == STATUS_USER_APC)
3176 {
3177 /* Abort the request */
3178 IopAbortInterruptedIrp(Event, Irp);
3179 }
3180
3181 /* Set the final status */
3182 Status = KernelIosb.Status;
3183
3184 /* Enter SEH to write the IOSB back */
3185 _SEH2_TRY
3186 {
3187 /* Write it back to the caller */
3188 *IoStatusBlock = KernelIosb;
3189 }
3190 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3191 {
3192 /* Get the exception code */
3193 Status = _SEH2_GetExceptionCode();
3194 }
3195 _SEH2_END;
3196
3197 /* Free the event */
3198 ExFreePoolWithTag(Event, TAG_IO);
3199 }
3200 else
3201 {
3202 /* Wait for the IRP */
3203 Status = KeWaitForSingleObject(&FileObject->Event,
3204 Executive,
3205 PreviousMode,
3206 (FileObject->Flags &
3207 FO_ALERTABLE_IO) != 0,
3208 NULL);
3209 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3210 {
3211 /* Abort the request */
3212 IopAbortInterruptedIrp(&FileObject->Event, Irp);
3213 }
3214
3215 /* Set the final status */
3216 Status = FileObject->FinalStatus;
3217
3218 /* Release the file lock */
3219 IopUnlockFileObject(FileObject);
3220 }
3221 }
3222 else
3223 {
3224 /* Free the event if we had one */
3225 if (LocalEvent)
3226 {
3227 /* Clear it in the IRP for completion */
3228 Irp->UserEvent = NULL;
3229 ExFreePoolWithTag(Event, TAG_IO);
3230 }
3231
3232 /* Set the caller IOSB */
3233 Irp->UserIosb = IoStatusBlock;
3234
3235 /* The IRP wasn't completed, complete it ourselves */
3236 KeRaiseIrql(APC_LEVEL, &OldIrql);
3237 IopCompleteRequest(&Irp->Tail.Apc,
3238 &NormalRoutine,
3239 &NormalContext,
3240 (PVOID*)&FileObject,
3241 &NormalContext);
3242 KeLowerIrql(OldIrql);
3243
3244 /* Release the file object if we had locked it*/
3245 if (!LocalEvent) IopUnlockFileObject(FileObject);
3246 }
3247
3248 if (TargetHandle != NULL)
3249 {
3250 ObCloseHandle(TargetHandle, KernelMode);
3251 }
3252
3253 /* Return the Status */
3254 return Status;
3255 }
3256
3257 /*
3258 * @unimplemented
3259 */
3260 NTSTATUS
3261 NTAPI
3262 NtSetQuotaInformationFile(IN HANDLE FileHandle,
3263 OUT PIO_STATUS_BLOCK IoStatusBlock,
3264 IN PVOID Buffer,
3265 IN ULONG BufferLength)
3266 {
3267 UNIMPLEMENTED;
3268 return STATUS_NOT_IMPLEMENTED;
3269 }
3270
3271 /*
3272 * @implemented
3273 */
3274 NTSTATUS
3275 NTAPI
3276 NtUnlockFile(IN HANDLE FileHandle,
3277 OUT PIO_STATUS_BLOCK IoStatusBlock,
3278 IN PLARGE_INTEGER ByteOffset,
3279 IN PLARGE_INTEGER Length,
3280 IN ULONG Key OPTIONAL)
3281 {
3282 PFILE_OBJECT FileObject;
3283 PLARGE_INTEGER LocalLength = NULL;
3284 PIRP Irp;
3285 PIO_STACK_LOCATION StackPtr;
3286 PDEVICE_OBJECT DeviceObject;
3287 PKEVENT Event = NULL;
3288 BOOLEAN LocalEvent = FALSE;
3289 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3290 LARGE_INTEGER CapturedByteOffset, CapturedLength;
3291 NTSTATUS Status;
3292 OBJECT_HANDLE_INFORMATION HandleInformation;
3293 IO_STATUS_BLOCK KernelIosb;
3294 PFAST_IO_DISPATCH FastIoDispatch;
3295 PAGED_CODE();
3296 CapturedByteOffset.QuadPart = 0;
3297 CapturedLength.QuadPart = 0;
3298 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3299
3300 /* Get File Object */
3301 Status = ObReferenceObjectByHandle(FileHandle,
3302 0,
3303 IoFileObjectType,
3304 PreviousMode,
3305 (PVOID*)&FileObject,
3306 &HandleInformation);
3307 if (!NT_SUCCESS(Status)) return Status;
3308
3309 /* Check if we're called from user mode */
3310 if (PreviousMode != KernelMode)
3311 {
3312 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3313 if (!(HandleInformation.GrantedAccess &
3314 (FILE_WRITE_DATA | FILE_READ_DATA)))
3315 {
3316 ObDereferenceObject(FileObject);
3317 return STATUS_ACCESS_DENIED;
3318 }
3319
3320 /* Enter SEH for probing */
3321 _SEH2_TRY
3322 {
3323 /* Probe the I/O Status block */
3324 ProbeForWriteIoStatusBlock(IoStatusBlock);
3325
3326 /* Probe and capture the large integers */
3327 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3328 CapturedLength = ProbeForReadLargeInteger(Length);
3329 }
3330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3331 {
3332 /* Dereference the object and return exception code */
3333 ObDereferenceObject(FileObject);
3334 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3335 }
3336 _SEH2_END;
3337 }
3338 else
3339 {
3340 /* Otherwise, capture them directly */
3341 CapturedByteOffset = *ByteOffset;
3342 CapturedLength = *Length;
3343 }
3344
3345 /* Check if this is a direct open or not */
3346 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3347 {
3348 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3349 }
3350 else
3351 {
3352 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3353 }
3354
3355 /* Try to do it the FastIO way if possible */
3356 FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3357 if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
3358 {
3359 if (FastIoDispatch->FastIoUnlockSingle(FileObject,
3360 &CapturedByteOffset,
3361 &CapturedLength,
3362 PsGetCurrentProcess(),
3363 Key,
3364 &KernelIosb,
3365 DeviceObject))
3366 {
3367 /* Write the IOSB back */
3368 _SEH2_TRY
3369 {
3370 *IoStatusBlock = KernelIosb;
3371 }
3372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3373 {
3374 KernelIosb.Status = _SEH2_GetExceptionCode();
3375 }
3376 _SEH2_END;
3377
3378 /* We're done with FastIO! */
3379 ObDereferenceObject(FileObject);
3380 return KernelIosb.Status;
3381 }
3382 }
3383
3384 /* Check if we should use Sync IO or not */
3385 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3386 {
3387 /* Lock it */
3388 IopLockFileObject(FileObject);
3389 }
3390 else
3391 {
3392 /* Use local event */
3393 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3394 if (!Event)
3395 {
3396 ObDereferenceObject(FileObject);
3397 return STATUS_INSUFFICIENT_RESOURCES;
3398 }
3399 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3400 LocalEvent = TRUE;
3401 }
3402
3403 /* Clear File Object event */
3404 KeClearEvent(&FileObject->Event);
3405
3406 /* Allocate the IRP */
3407 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3408 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3409
3410 /* Set up the IRP */
3411 Irp->RequestorMode = PreviousMode;
3412 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3413 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3414 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3415 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3416 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3417 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3418
3419 /* Set up Stack Data */
3420 StackPtr = IoGetNextIrpStackLocation(Irp);
3421 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3422 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3423 StackPtr->FileObject = FileObject;
3424
3425 /* Enter SEH */
3426 _SEH2_TRY
3427 {
3428 /* Allocate a buffer */
3429 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3430 sizeof(LARGE_INTEGER),
3431 TAG_LOCK);
3432
3433 /* Set the length */
3434 *LocalLength = CapturedLength;
3435 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3436 StackPtr->Parameters.LockControl.Length = LocalLength;
3437 }
3438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3439 {
3440 /* Allocating failed, clean up and return the exception code */
3441 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3442 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3443
3444 /* Return the exception code */
3445 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3446 }
3447 _SEH2_END;
3448
3449 /* Set Parameters */
3450 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3451 StackPtr->Parameters.LockControl.Key = Key;
3452
3453 /* Call the Driver */
3454 Status = IopPerformSynchronousRequest(DeviceObject,
3455 Irp,
3456 FileObject,
3457 FALSE,
3458 PreviousMode,
3459 !LocalEvent,
3460 IopOtherTransfer);
3461
3462 /* Check if this was async I/O */
3463 if (LocalEvent)
3464 {
3465 /* It was, finalize this request */
3466 Status = IopFinalizeAsynchronousIo(Status,
3467 Event,
3468 Irp,
3469 PreviousMode,
3470 &KernelIosb,
3471 IoStatusBlock);
3472 }
3473
3474 /* Return status */
3475 return Status;
3476 }
3477
3478 /*
3479 * &#