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