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