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