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