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