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