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