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