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