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