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