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