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