[NTOSKRNL]
[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, Event, NULL);
350
351 /* Setup the IRP */
352 Irp->UserIosb = IoStatusBlock;
353 Irp->UserEvent = EventObject;
354 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
355 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
356 Irp->Cancel = FALSE;
357 Irp->CancelRoutine = NULL;
358 Irp->PendingReturned = FALSE;
359 Irp->RequestorMode = PreviousMode;
360 Irp->MdlAddress = NULL;
361 Irp->AssociatedIrp.SystemBuffer = NULL;
362 Irp->Flags = 0;
363 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
364 Irp->Tail.Overlay.OriginalFileObject = FileObject;
365 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
366
367 /* Set stack location settings */
368 StackPtr = IoGetNextIrpStackLocation(Irp);
369 StackPtr->FileObject = FileObject;
370 StackPtr->MajorFunction = IsDevIoCtl ?
371 IRP_MJ_DEVICE_CONTROL :
372 IRP_MJ_FILE_SYSTEM_CONTROL;
373 StackPtr->MinorFunction = 0; /* 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 /* Setup the IRP */
666 Irp->UserIosb = &IoStatusBlock;
667 Irp->UserEvent = &Event;
668 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
669 Irp->RequestorMode = KernelMode;
670 Irp->AssociatedIrp.SystemBuffer = Buffer;
671 Irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO | IRP_OB_QUERY_NAME;
672 Irp->Tail.Overlay.OriginalFileObject = FileObject;
673 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
674
675 Stack = IoGetNextIrpStackLocation(Irp);
676 Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
677 Stack->FileObject = FileObject;
678 Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
679 Stack->Parameters.QueryFile.Length = Length;
680
681
682 /* Queue the IRP */
683 IopQueueIrpToThread(Irp);
684
685 /* Call the driver */
686 Status = IoCallDriver(DeviceObject, Irp);
687 if (Status == STATUS_PENDING)
688 {
689 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
690 Status = IoStatusBlock.Status;
691 }
692
693 *ReturnedLength = IoStatusBlock.Information;
694 return Status;
695 }
696
697 NTSTATUS
698 NTAPI
699 IopGetBasicInformationFile(IN PFILE_OBJECT FileObject,
700 OUT PFILE_BASIC_INFORMATION BasicInfo)
701 {
702 ULONG ReturnedLength;
703 PDEVICE_OBJECT DeviceObject;
704 IO_STATUS_BLOCK IoStatusBlock;
705
706 PAGED_CODE();
707
708 /* Try to do it the fast way if possible */
709 DeviceObject = IoGetRelatedDeviceObject(FileObject);
710 if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
711 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
712 DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
713 ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
714 BasicInfo,
715 &IoStatusBlock,
716 DeviceObject))
717 {
718 return IoStatusBlock.Status;
719 }
720
721 /* In case it failed, fall back to IRP-based method */
722 return IopGetFileInformation(FileObject, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, BasicInfo, &ReturnedLength);
723 }
724
725 NTSTATUS
726 NTAPI
727 IopOpenLinkOrRenameTarget(OUT PHANDLE Handle,
728 IN PIRP Irp,
729 IN PFILE_RENAME_INFORMATION RenameInfo,
730 IN PFILE_OBJECT FileObject)
731 {
732 NTSTATUS Status;
733 HANDLE TargetHandle;
734 UNICODE_STRING FileName;
735 PIO_STACK_LOCATION Stack;
736 PFILE_OBJECT TargetFileObject;
737 IO_STATUS_BLOCK IoStatusBlock;
738 FILE_BASIC_INFORMATION BasicInfo;
739 OBJECT_ATTRIBUTES ObjectAttributes;
740 OBJECT_HANDLE_INFORMATION HandleInformation;
741 ACCESS_MASK DesiredAccess = FILE_WRITE_DATA;
742
743 PAGED_CODE();
744
745 /* First, establish whether our target is a directory */
746 if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
747 {
748 Status = IopGetBasicInformationFile(FileObject, &BasicInfo);
749 if (!NT_SUCCESS(Status))
750 {
751 return Status;
752 }
753
754 if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
755 DesiredAccess = FILE_ADD_SUBDIRECTORY;
756 }
757 }
758
759 /* Setup the string to the target */
760 FileName.Buffer = RenameInfo->FileName;
761 FileName.Length = RenameInfo->FileNameLength;
762 FileName.MaximumLength = RenameInfo->FileNameLength;
763
764 InitializeObjectAttributes(&ObjectAttributes,
765 &FileName,
766 (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE) | OBJ_KERNEL_HANDLE,
767 RenameInfo->RootDirectory,
768 NULL);
769
770 /* And open its parent directory */
771 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
772 {
773 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
774 #if 0
775 /* Commented out - we don't support FO extension yet
776 * FIXME: Corrected last arg when it's supported
777 */
778 Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
779 DesiredAccess | SYNCHRONIZE,
780 &ObjectAttributes,
781 &IoStatusBlock,
782 NULL,
783 0,
784 FILE_SHARE_READ | FILE_SHARE_WRITE,
785 FILE_OPEN,
786 FILE_OPEN_FOR_BACKUP_INTENT,
787 NULL,
788 0,
789 CreateFileTypeNone,
790 NULL,
791 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
792 FileObject->DeviceObject);
793 #else
794 ASSERT(FALSE);
795 UNIMPLEMENTED;
796 return STATUS_NOT_IMPLEMENTED;
797 #endif
798 }
799 else
800 {
801 Status = IoCreateFile(&TargetHandle,
802 DesiredAccess | SYNCHRONIZE,
803 &ObjectAttributes,
804 &IoStatusBlock,
805 NULL,
806 0,
807 FILE_SHARE_READ | FILE_SHARE_WRITE,
808 FILE_OPEN,
809 FILE_OPEN_FOR_BACKUP_INTENT,
810 NULL,
811 0,
812 CreateFileTypeNone,
813 NULL,
814 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING);
815 }
816
817 if (!NT_SUCCESS(Status))
818 {
819 return Status;
820 }
821
822 /* Once open, continue only if:
823 * Target exists and we're allowed to overwrite it
824 */
825 Stack = IoGetNextIrpStackLocation(Irp);
826 if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
827 !RenameInfo->ReplaceIfExists &&
828 IoStatusBlock.Information == FILE_EXISTS)
829 {
830 ObCloseHandle(TargetHandle, KernelMode);
831 return STATUS_OBJECT_NAME_COLLISION;
832 }
833
834 /* Now, we'll get the associated device of the target, to check for same device location
835 * So, get the FO first
836 */
837 Status = ObReferenceObjectByHandle(TargetHandle,
838 FILE_WRITE_DATA,
839 IoFileObjectType,
840 KernelMode,
841 (PVOID *)&TargetFileObject,
842 &HandleInformation);
843 if (!NT_SUCCESS(Status))
844 {
845 ObCloseHandle(TargetHandle, KernelMode);
846 return Status;
847 }
848
849 /* We can dereference, we have the handle */
850 ObDereferenceObject(TargetFileObject);
851 /* If we're not on the same device, error out **/
852 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
853 {
854 ObCloseHandle(TargetHandle, KernelMode);
855 return STATUS_NOT_SAME_DEVICE;
856 }
857
858 /* Return parent directory file object and handle */
859 Stack->Parameters.SetFile.FileObject = TargetFileObject;
860 *Handle = TargetHandle;
861
862 return STATUS_SUCCESS;
863 }
864
865 /* PUBLIC FUNCTIONS **********************************************************/
866
867 /*
868 * @implemented
869 */
870 NTSTATUS
871 NTAPI
872 IoSynchronousPageWrite(IN PFILE_OBJECT FileObject,
873 IN PMDL Mdl,
874 IN PLARGE_INTEGER Offset,
875 IN PKEVENT Event,
876 IN PIO_STATUS_BLOCK StatusBlock)
877 {
878 PIRP Irp;
879 PIO_STACK_LOCATION StackPtr;
880 PDEVICE_OBJECT DeviceObject;
881 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
882 FileObject, Mdl, Offset);
883
884 /* Get the Device Object */
885 DeviceObject = IoGetRelatedDeviceObject(FileObject);
886
887 /* Allocate IRP */
888 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
889 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
890
891 /* Get the Stack */
892 StackPtr = IoGetNextIrpStackLocation(Irp);
893
894 /* Create the IRP Settings */
895 Irp->MdlAddress = Mdl;
896 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
897 Irp->UserIosb = StatusBlock;
898 Irp->UserEvent = Event;
899 Irp->RequestorMode = KernelMode;
900 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
901 Irp->Tail.Overlay.OriginalFileObject = FileObject;
902 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
903
904 /* Set the Stack Settings */
905 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
906 StackPtr->Parameters.Write.ByteOffset = *Offset;
907 StackPtr->MajorFunction = IRP_MJ_WRITE;
908 StackPtr->FileObject = FileObject;
909
910 /* Call the Driver */
911 return IoCallDriver(DeviceObject, Irp);
912 }
913
914 /*
915 * @implemented
916 */
917 NTSTATUS
918 NTAPI
919 IoPageRead(IN PFILE_OBJECT FileObject,
920 IN PMDL Mdl,
921 IN PLARGE_INTEGER Offset,
922 IN PKEVENT Event,
923 IN PIO_STATUS_BLOCK StatusBlock)
924 {
925 PIRP Irp;
926 PIO_STACK_LOCATION StackPtr;
927 PDEVICE_OBJECT DeviceObject;
928 IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
929 FileObject, Mdl, Offset);
930
931 /* Get the Device Object */
932 DeviceObject = IoGetRelatedDeviceObject(FileObject);
933
934 /* Allocate IRP */
935 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
936 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
937
938 /* Get the Stack */
939 StackPtr = IoGetNextIrpStackLocation(Irp);
940
941 /* Create the IRP Settings */
942 Irp->MdlAddress = Mdl;
943 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
944 Irp->UserIosb = StatusBlock;
945 Irp->UserEvent = Event;
946 Irp->RequestorMode = KernelMode;
947 Irp->Flags = IRP_PAGING_IO |
948 IRP_NOCACHE |
949 IRP_SYNCHRONOUS_PAGING_IO |
950 IRP_INPUT_OPERATION;
951 Irp->Tail.Overlay.OriginalFileObject = FileObject;
952 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
953
954 /* Set the Stack Settings */
955 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
956 StackPtr->Parameters.Read.ByteOffset = *Offset;
957 StackPtr->MajorFunction = IRP_MJ_READ;
958 StackPtr->FileObject = FileObject;
959
960 /* Call the Driver */
961 return IoCallDriver(DeviceObject, Irp);
962 }
963
964 /*
965 * @implemented
966 */
967 NTSTATUS
968 NTAPI
969 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
970 IN FILE_INFORMATION_CLASS FileInformationClass,
971 IN ULONG Length,
972 OUT PVOID FileInformation,
973 OUT PULONG ReturnedLength)
974 {
975 /* Call the shared routine */
976 return IopQueryDeviceInformation(FileObject,
977 FileInformationClass,
978 Length,
979 FileInformation,
980 ReturnedLength,
981 TRUE);
982 }
983
984 /*
985 * @implemented
986 */
987 NTSTATUS
988 NTAPI
989 IoQueryVolumeInformation(IN PFILE_OBJECT FileObject,
990 IN FS_INFORMATION_CLASS FsInformationClass,
991 IN ULONG Length,
992 OUT PVOID FsInformation,
993 OUT PULONG ReturnedLength)
994 {
995 /* Call the shared routine */
996 return IopQueryDeviceInformation(FileObject,
997 FsInformationClass,
998 Length,
999 FsInformation,
1000 ReturnedLength,
1001 FALSE);
1002 }
1003
1004 /*
1005 * @implemented
1006 */
1007 NTSTATUS
1008 NTAPI
1009 IoSetInformation(IN PFILE_OBJECT FileObject,
1010 IN FILE_INFORMATION_CLASS FileInformationClass,
1011 IN ULONG Length,
1012 IN PVOID FileInformation)
1013 {
1014 IO_STATUS_BLOCK IoStatusBlock;
1015 PIRP Irp;
1016 PDEVICE_OBJECT DeviceObject;
1017 PIO_STACK_LOCATION StackPtr;
1018 BOOLEAN LocalEvent = FALSE;
1019 KEVENT Event;
1020 NTSTATUS Status;
1021 PAGED_CODE();
1022 IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx \n",
1023 FileObject, FileInformationClass, Length);
1024
1025 /* Reference the object */
1026 ObReferenceObject(FileObject);
1027
1028 /* Check if this is a file that was opened for Synch I/O */
1029 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1030 {
1031 /* Lock it */
1032 IopLockFileObject(FileObject);
1033
1034 /* Use File Object event */
1035 KeClearEvent(&FileObject->Event);
1036 }
1037 else
1038 {
1039 /* Use local event */
1040 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1041 LocalEvent = TRUE;
1042 }
1043
1044 /* Get the Device Object */
1045 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1046
1047 /* Allocate the IRP */
1048 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1049 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1050
1051 /* Set the IRP */
1052 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1053 Irp->RequestorMode = KernelMode;
1054 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1055 Irp->UserIosb = &IoStatusBlock;
1056 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1057 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1058 Irp->Flags |= IRP_BUFFERED_IO;
1059 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1060 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1061
1062 /* Set the Stack Data */
1063 StackPtr = IoGetNextIrpStackLocation(Irp);
1064 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
1065 StackPtr->FileObject = FileObject;
1066
1067 /* Set Parameters */
1068 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1069 StackPtr->Parameters.SetFile.Length = Length;
1070
1071 /* Queue the IRP */
1072 IopQueueIrpToThread(Irp);
1073
1074 /* Call the Driver */
1075 Status = IoCallDriver(DeviceObject, Irp);
1076
1077 /* Check if this was synch I/O */
1078 if (!LocalEvent)
1079 {
1080 /* Check if the requet is pending */
1081 if (Status == STATUS_PENDING)
1082 {
1083 /* Wait on the file object */
1084 Status = KeWaitForSingleObject(&FileObject->Event,
1085 Executive,
1086 KernelMode,
1087 (FileObject->Flags &
1088 FO_ALERTABLE_IO) != 0,
1089 NULL);
1090 if (Status == STATUS_ALERTED)
1091 {
1092 /* Abort the operation */
1093 IopAbortInterruptedIrp(&FileObject->Event, Irp);
1094 }
1095
1096 /* Get the final status */
1097 Status = FileObject->FinalStatus;
1098 }
1099
1100 /* Release the file lock */
1101 IopUnlockFileObject(FileObject);
1102 }
1103 else if (Status == STATUS_PENDING)
1104 {
1105 /* Wait on the local event and get the final status */
1106 KeWaitForSingleObject(&Event,
1107 Executive,
1108 KernelMode,
1109 FALSE,
1110 NULL);
1111 Status = IoStatusBlock.Status;
1112 }
1113
1114 /* Return the status */
1115 return Status;
1116 }
1117
1118 /* NATIVE SERVICES ***********************************************************/
1119
1120 /*
1121 * @implemented
1122 */
1123 NTSTATUS
1124 NTAPI
1125 NtDeviceIoControlFile(IN HANDLE DeviceHandle,
1126 IN HANDLE Event OPTIONAL,
1127 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1128 IN PVOID UserApcContext OPTIONAL,
1129 OUT PIO_STATUS_BLOCK IoStatusBlock,
1130 IN ULONG IoControlCode,
1131 IN PVOID InputBuffer,
1132 IN ULONG InputBufferLength OPTIONAL,
1133 OUT PVOID OutputBuffer,
1134 IN ULONG OutputBufferLength OPTIONAL)
1135 {
1136 /* Call the Generic Function */
1137 return IopDeviceFsIoControl(DeviceHandle,
1138 Event,
1139 UserApcRoutine,
1140 UserApcContext,
1141 IoStatusBlock,
1142 IoControlCode,
1143 InputBuffer,
1144 InputBufferLength,
1145 OutputBuffer,
1146 OutputBufferLength,
1147 TRUE);
1148 }
1149
1150 /*
1151 * @implemented
1152 */
1153 NTSTATUS
1154 NTAPI
1155 NtFsControlFile(IN HANDLE DeviceHandle,
1156 IN HANDLE Event OPTIONAL,
1157 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1158 IN PVOID UserApcContext OPTIONAL,
1159 OUT PIO_STATUS_BLOCK IoStatusBlock,
1160 IN ULONG IoControlCode,
1161 IN PVOID InputBuffer,
1162 IN ULONG InputBufferLength OPTIONAL,
1163 OUT PVOID OutputBuffer,
1164 IN ULONG OutputBufferLength OPTIONAL)
1165 {
1166 /* Call the Generic Function */
1167 return IopDeviceFsIoControl(DeviceHandle,
1168 Event,
1169 UserApcRoutine,
1170 UserApcContext,
1171 IoStatusBlock,
1172 IoControlCode,
1173 InputBuffer,
1174 InputBufferLength,
1175 OutputBuffer,
1176 OutputBufferLength,
1177 FALSE);
1178 }
1179
1180 NTSTATUS
1181 NTAPI
1182 NtFlushBuffersFile(IN HANDLE FileHandle,
1183 OUT PIO_STATUS_BLOCK IoStatusBlock)
1184 {
1185 PFILE_OBJECT FileObject;
1186 PIRP Irp;
1187 PIO_STACK_LOCATION StackPtr;
1188 NTSTATUS Status;
1189 PDEVICE_OBJECT DeviceObject;
1190 PKEVENT Event = NULL;
1191 BOOLEAN LocalEvent = FALSE;
1192 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1193 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1194 IO_STATUS_BLOCK KernelIosb;
1195 PAGED_CODE();
1196 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1197
1198 if (PreviousMode != KernelMode)
1199 {
1200 /* Protect probes */
1201 _SEH2_TRY
1202 {
1203 /* Probe the I/O Status block */
1204 ProbeForWriteIoStatusBlock(IoStatusBlock);
1205 }
1206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1207 {
1208 /* Return the exception code */
1209 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1210 }
1211 _SEH2_END;
1212 }
1213
1214 /* Get the File Object */
1215 Status = ObReferenceObjectByHandle(FileHandle,
1216 0,
1217 IoFileObjectType,
1218 PreviousMode,
1219 (PVOID*)&FileObject,
1220 &ObjectHandleInfo);
1221 if (!NT_SUCCESS(Status)) return Status;
1222
1223 /*
1224 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1225 * granted. However, if this is a named pipe, make sure we don't ask for
1226 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1227 * access right!
1228 */
1229 if (!(ObjectHandleInfo.GrantedAccess &
1230 ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1231 FILE_WRITE_DATA)))
1232 {
1233 /* We failed */
1234 ObDereferenceObject(FileObject);
1235 return STATUS_ACCESS_DENIED;
1236 }
1237
1238 /* Check if we should use Sync IO or not */
1239 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1240 {
1241 /* Lock it */
1242 IopLockFileObject(FileObject);
1243 }
1244 else
1245 {
1246 /* Use local event */
1247 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1248 if (!Event)
1249 {
1250 /* We failed */
1251 ObDereferenceObject(FileObject);
1252 return STATUS_INSUFFICIENT_RESOURCES;
1253 }
1254 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1255 LocalEvent = TRUE;
1256 }
1257
1258 /* Get the Device Object */
1259 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1260
1261 /* Clear the event */
1262 KeClearEvent(&FileObject->Event);
1263
1264 /* Allocate the IRP */
1265 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1266 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1267
1268 /* Set up the IRP */
1269 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1270 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1271 Irp->UserEvent = (LocalEvent) ? Event : NULL;
1272 Irp->RequestorMode = PreviousMode;
1273 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1274 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1275 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1276
1277 /* Set up Stack Data */
1278 StackPtr = IoGetNextIrpStackLocation(Irp);
1279 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1280 StackPtr->FileObject = FileObject;
1281
1282 /* Call the Driver */
1283 Status = IopPerformSynchronousRequest(DeviceObject,
1284 Irp,
1285 FileObject,
1286 FALSE,
1287 PreviousMode,
1288 !LocalEvent,
1289 IopOtherTransfer);
1290
1291 /* Check if this was async I/O */
1292 if (LocalEvent)
1293 {
1294 /* It was, finalize this request */
1295 Status = IopFinalizeAsynchronousIo(Status,
1296 Event,
1297 Irp,
1298 PreviousMode,
1299 &KernelIosb,
1300 IoStatusBlock);
1301 }
1302
1303 /* Return the Status */
1304 return Status;
1305 }
1306
1307 /*
1308 * @implemented
1309 */
1310 NTSTATUS
1311 NTAPI
1312 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1313 IN HANDLE EventHandle OPTIONAL,
1314 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1315 IN PVOID ApcContext OPTIONAL,
1316 OUT PIO_STATUS_BLOCK IoStatusBlock,
1317 OUT PVOID Buffer,
1318 IN ULONG BufferSize,
1319 IN ULONG CompletionFilter,
1320 IN BOOLEAN WatchTree)
1321 {
1322 PIRP Irp;
1323 PKEVENT Event = NULL;
1324 PDEVICE_OBJECT DeviceObject;
1325 PFILE_OBJECT FileObject;
1326 PIO_STACK_LOCATION IoStack;
1327 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1328 NTSTATUS Status;
1329 BOOLEAN LockedForSync = FALSE;
1330 PAGED_CODE();
1331 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1332
1333 /* Check if we're called from user mode */
1334 if (PreviousMode != KernelMode)
1335 {
1336 /* Enter SEH for probing */
1337 _SEH2_TRY
1338 {
1339 /* Probe the I/O STatus block */
1340 ProbeForWriteIoStatusBlock(IoStatusBlock);
1341
1342 /* Probe the buffer */
1343 if (BufferSize) ProbeForWrite(Buffer, BufferSize, sizeof(ULONG));
1344 }
1345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1346 {
1347 /* Return the exception code */
1348 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1349 }
1350 _SEH2_END;
1351
1352 /* Check if CompletionFilter is valid */
1353 if (!CompletionFilter || (CompletionFilter & ~FILE_NOTIFY_VALID_MASK))
1354 {
1355 return STATUS_INVALID_PARAMETER;
1356 }
1357 }
1358
1359 /* Get File Object */
1360 Status = ObReferenceObjectByHandle(FileHandle,
1361 FILE_LIST_DIRECTORY,
1362 IoFileObjectType,
1363 PreviousMode,
1364 (PVOID*)&FileObject,
1365 NULL);
1366 if (!NT_SUCCESS(Status)) return Status;
1367
1368 /* Check if we have an event handle */
1369 if (EventHandle)
1370 {
1371 /* Reference it */
1372 Status = ObReferenceObjectByHandle(EventHandle,
1373 EVENT_MODIFY_STATE,
1374 ExEventObjectType,
1375 PreviousMode,
1376 (PVOID *)&Event,
1377 NULL);
1378 if (Status != STATUS_SUCCESS)
1379 {
1380 ObDereferenceObject(FileObject);
1381 return Status;
1382 }
1383 KeClearEvent(Event);
1384 }
1385
1386 /* Check if we should use Sync IO or not */
1387 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1388 {
1389 /* Lock it */
1390 IopLockFileObject(FileObject);
1391 LockedForSync = TRUE;
1392 }
1393
1394 /* Clear File Object event */
1395 KeClearEvent(&FileObject->Event);
1396
1397 /* Get the device object */
1398 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1399
1400 /* Allocate the IRP */
1401 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1402 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1403
1404 /* Set up the IRP */
1405 Irp->RequestorMode = PreviousMode;
1406 Irp->UserIosb = IoStatusBlock;
1407 Irp->UserEvent = Event;
1408 Irp->UserBuffer = Buffer;
1409 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1410 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1411 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1412 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1413
1414 /* Set up Stack Data */
1415 IoStack = IoGetNextIrpStackLocation(Irp);
1416 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1417 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
1418 IoStack->FileObject = FileObject;
1419
1420 /* Set parameters */
1421 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1422 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1423 if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1424
1425 /* Perform the call */
1426 return IopPerformSynchronousRequest(DeviceObject,
1427 Irp,
1428 FileObject,
1429 FALSE,
1430 PreviousMode,
1431 LockedForSync,
1432 IopOtherTransfer);
1433 }
1434
1435 /*
1436 * @implemented
1437 */
1438 NTSTATUS
1439 NTAPI
1440 NtLockFile(IN HANDLE FileHandle,
1441 IN HANDLE EventHandle OPTIONAL,
1442 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1443 IN PVOID ApcContext OPTIONAL,
1444 OUT PIO_STATUS_BLOCK IoStatusBlock,
1445 IN PLARGE_INTEGER ByteOffset,
1446 IN PLARGE_INTEGER Length,
1447 IN ULONG Key,
1448 IN BOOLEAN FailImmediately,
1449 IN BOOLEAN ExclusiveLock)
1450 {
1451 PFILE_OBJECT FileObject;
1452 PLARGE_INTEGER LocalLength = NULL;
1453 PIRP Irp;
1454 PIO_STACK_LOCATION StackPtr;
1455 PDEVICE_OBJECT DeviceObject;
1456 PKEVENT Event = NULL;
1457 BOOLEAN LockedForSync = FALSE;
1458 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1459 LARGE_INTEGER CapturedByteOffset, CapturedLength;
1460 NTSTATUS Status;
1461 OBJECT_HANDLE_INFORMATION HandleInformation;
1462 PAGED_CODE();
1463 CapturedByteOffset.QuadPart = 0;
1464 CapturedLength.QuadPart = 0;
1465 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1466
1467 /* Get File Object */
1468 Status = ObReferenceObjectByHandle(FileHandle,
1469 0,
1470 IoFileObjectType,
1471 PreviousMode,
1472 (PVOID*)&FileObject,
1473 &HandleInformation);
1474 if (!NT_SUCCESS(Status)) return Status;
1475
1476 /* Check if we're called from user mode */
1477 if (PreviousMode != KernelMode)
1478 {
1479 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1480 if (!(HandleInformation.GrantedAccess &
1481 (FILE_WRITE_DATA | FILE_READ_DATA)))
1482 {
1483 ObDereferenceObject(FileObject);
1484 return STATUS_ACCESS_DENIED;
1485 }
1486
1487 /* Enter SEH for probing */
1488 _SEH2_TRY
1489 {
1490 /* Probe the I/O STatus block */
1491 ProbeForWriteIoStatusBlock(IoStatusBlock);
1492
1493 /* Probe and capture the large integers */
1494 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1495 CapturedLength = ProbeForReadLargeInteger(Length);
1496 }
1497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1498 {
1499 /* Dereference the object and return exception code */
1500 ObDereferenceObject(FileObject);
1501 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1502 }
1503 _SEH2_END;
1504 }
1505 else
1506 {
1507 /* Otherwise, capture them directly */
1508 CapturedByteOffset = *ByteOffset;
1509 CapturedLength = *Length;
1510 }
1511
1512 /* Check if we have an event handle */
1513 if (EventHandle)
1514 {
1515 /* Reference it */
1516 Status = ObReferenceObjectByHandle(EventHandle,
1517 EVENT_MODIFY_STATE,
1518 ExEventObjectType,
1519 PreviousMode,
1520 (PVOID *)&Event,
1521 NULL);
1522 if (Status != STATUS_SUCCESS) return Status;
1523 KeClearEvent(Event);
1524 }
1525
1526 /* Get the device object */
1527 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1528
1529 /* Check if we should use Sync IO or not */
1530 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1531 {
1532 /* Lock it */
1533 IopLockFileObject(FileObject);
1534 LockedForSync = TRUE;
1535 }
1536
1537 /* Clear File Object event */
1538 KeClearEvent(&FileObject->Event);
1539 FileObject->LockOperation = TRUE;
1540
1541 /* Allocate the IRP */
1542 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1543 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1544
1545 /* Set up the IRP */
1546 Irp->RequestorMode = PreviousMode;
1547 Irp->UserIosb = IoStatusBlock;
1548 Irp->UserEvent = Event;
1549 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1550 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1551 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1552 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1553
1554 /* Set up Stack Data */
1555 StackPtr = IoGetNextIrpStackLocation(Irp);
1556 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1557 StackPtr->MinorFunction = IRP_MN_LOCK;
1558 StackPtr->FileObject = FileObject;
1559
1560 /* Allocate local buffer */
1561 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1562 sizeof(LARGE_INTEGER),
1563 TAG_LOCK);
1564 if (!LocalLength)
1565 {
1566 /* Allocating failed, clean up and return failure */
1567 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1568 return STATUS_INSUFFICIENT_RESOURCES;
1569 }
1570
1571 /* Set the length */
1572 *LocalLength = CapturedLength;
1573 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1574 StackPtr->Parameters.LockControl.Length = LocalLength;
1575
1576 /* Set Parameters */
1577 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1578 StackPtr->Parameters.LockControl.Key = Key;
1579
1580 /* Set Flags */
1581 if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1582 if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1583
1584 /* Perform the call */
1585 return IopPerformSynchronousRequest(DeviceObject,
1586 Irp,
1587 FileObject,
1588 FALSE,
1589 PreviousMode,
1590 LockedForSync,
1591 IopOtherTransfer);
1592 }
1593
1594 /*
1595 * @implemented
1596 */
1597 NTSTATUS
1598 NTAPI
1599 NtQueryDirectoryFile(IN HANDLE FileHandle,
1600 IN HANDLE EventHandle OPTIONAL,
1601 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1602 IN PVOID ApcContext OPTIONAL,
1603 OUT PIO_STATUS_BLOCK IoStatusBlock,
1604 OUT PVOID FileInformation,
1605 IN ULONG Length,
1606 IN FILE_INFORMATION_CLASS FileInformationClass,
1607 IN BOOLEAN ReturnSingleEntry,
1608 IN PUNICODE_STRING FileName OPTIONAL,
1609 IN BOOLEAN RestartScan)
1610 {
1611 PIRP Irp;
1612 PDEVICE_OBJECT DeviceObject;
1613 PFILE_OBJECT FileObject;
1614 PIO_STACK_LOCATION StackPtr;
1615 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1616 NTSTATUS Status;
1617 BOOLEAN LockedForSynch = FALSE;
1618 PKEVENT Event = NULL;
1619 volatile PVOID AuxBuffer = NULL;
1620 PMDL Mdl;
1621 UNICODE_STRING CapturedFileName;
1622 PUNICODE_STRING SearchPattern;
1623 PAGED_CODE();
1624 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1625
1626 /* Check if we came from user mode */
1627 if (PreviousMode != KernelMode)
1628 {
1629 /* Enter SEH for probing */
1630 _SEH2_TRY
1631 {
1632 /* Probe the I/O Status Block */
1633 ProbeForWriteIoStatusBlock(IoStatusBlock);
1634
1635 /* Probe the file information */
1636 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1637
1638 /* Check if we have a file name */
1639 if (FileName)
1640 {
1641 /* Capture it */
1642 CapturedFileName = ProbeForReadUnicodeString(FileName);
1643 if (CapturedFileName.Length)
1644 {
1645 /* Probe its buffer */
1646 ProbeForRead(CapturedFileName.Buffer,
1647 CapturedFileName.Length,
1648 1);
1649 }
1650
1651 /* Allocate the auxiliary buffer */
1652 AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
1653 CapturedFileName.Length +
1654 sizeof(UNICODE_STRING),
1655 TAG_SYSB);
1656 RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
1657 sizeof(UNICODE_STRING)),
1658 CapturedFileName.Buffer,
1659 CapturedFileName.Length);
1660
1661 /* Setup the search pattern */
1662 SearchPattern = (PUNICODE_STRING)AuxBuffer;
1663 SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
1664 sizeof(UNICODE_STRING));
1665 SearchPattern->Length = CapturedFileName.Length;
1666 SearchPattern->MaximumLength = CapturedFileName.Length;
1667 }
1668 }
1669 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1670 {
1671 /* Free buffer and return the exception code */
1672 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1673 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1674 }
1675 _SEH2_END;
1676 }
1677
1678 /* Get File Object */
1679 Status = ObReferenceObjectByHandle(FileHandle,
1680 FILE_LIST_DIRECTORY,
1681 IoFileObjectType,
1682 PreviousMode,
1683 (PVOID *)&FileObject,
1684 NULL);
1685 if (!NT_SUCCESS(Status))
1686 {
1687 /* Fail */
1688 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1689 return Status;
1690 }
1691
1692 /* Check if we have an even handle */
1693 if (EventHandle)
1694 {
1695 /* Get its pointer */
1696 Status = ObReferenceObjectByHandle(EventHandle,
1697 EVENT_MODIFY_STATE,
1698 ExEventObjectType,
1699 PreviousMode,
1700 (PVOID *)&Event,
1701 NULL);
1702 if (!NT_SUCCESS(Status))
1703 {
1704 /* Fail */
1705 ObDereferenceObject(FileObject);
1706 return Status;
1707 }
1708
1709 /* Clear it */
1710 KeClearEvent(Event);
1711 }
1712
1713 /* Check if this is a file that was opened for Synch I/O */
1714 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1715 {
1716 /* Lock it */
1717 IopLockFileObject(FileObject);
1718
1719 /* Remember to unlock later */
1720 LockedForSynch = TRUE;
1721 }
1722
1723 /* Get the device object */
1724 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1725
1726 /* Clear the File Object's event */
1727 KeClearEvent(&FileObject->Event);
1728
1729 /* Allocate the IRP */
1730 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1731 if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
1732
1733 /* Set up the IRP */
1734 Irp->RequestorMode = PreviousMode;
1735 Irp->UserIosb = IoStatusBlock;
1736 Irp->UserEvent = Event;
1737 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1738 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1739 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1740 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1741 Irp->MdlAddress = NULL;
1742 Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
1743 Irp->AssociatedIrp.SystemBuffer = NULL;
1744
1745 /* Check if this is buffered I/O */
1746 if (DeviceObject->Flags & DO_BUFFERED_IO)
1747 {
1748 /* Allocate a buffer */
1749 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
1750 Length,
1751 TAG_SYSB);
1752 if (!Irp->AssociatedIrp.SystemBuffer)
1753 {
1754 /* Allocating failed, clean up and return the exception code */
1755 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1756 if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
1757
1758 /* Return the exception code */
1759 return STATUS_INSUFFICIENT_RESOURCES;
1760 }
1761
1762 /* Set the buffer and flags */
1763 Irp->UserBuffer = FileInformation;
1764 Irp->Flags = (IRP_BUFFERED_IO |
1765 IRP_DEALLOCATE_BUFFER |
1766 IRP_INPUT_OPERATION);
1767 }
1768 else if (DeviceObject->Flags & DO_DIRECT_IO)
1769 {
1770 _SEH2_TRY
1771 {
1772 /* Allocate an MDL */
1773 Mdl = IoAllocateMdl(FileInformation, Length, FALSE, TRUE, Irp);
1774 if (!Mdl) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
1775 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
1776 }
1777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1778 {
1779 /* Allocating failed, clean up and return the exception code */
1780 IopCleanupAfterException(FileObject, Irp, Event, NULL);
1781 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1782 }
1783 _SEH2_END;
1784 }
1785 else
1786 {
1787 /* No allocation flags, and use the buffer directly */
1788 Irp->UserBuffer = FileInformation;
1789 }
1790
1791 /* Set up Stack Data */
1792 StackPtr = IoGetNextIrpStackLocation(Irp);
1793 StackPtr->FileObject = FileObject;
1794 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1795 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
1796
1797 /* Set Parameters */
1798 StackPtr->Parameters.QueryDirectory.FileInformationClass =
1799 FileInformationClass;
1800 StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
1801 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
1802 StackPtr->Parameters.QueryDirectory.Length = Length;
1803 StackPtr->Flags = 0;
1804 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
1805 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
1806
1807 /* Set deferred I/O */
1808 Irp->Flags |= IRP_DEFER_IO_COMPLETION;
1809
1810 /* Perform the call */
1811 return IopPerformSynchronousRequest(DeviceObject,
1812 Irp,
1813 FileObject,
1814 TRUE,
1815 PreviousMode,
1816 LockedForSynch,
1817 IopOtherTransfer);
1818 }
1819
1820 /*
1821 * @unimplemented
1822 */
1823 NTSTATUS
1824 NTAPI
1825 NtQueryEaFile(IN HANDLE FileHandle,
1826 OUT PIO_STATUS_BLOCK IoStatusBlock,
1827 OUT PVOID Buffer,
1828 IN ULONG Length,
1829 IN BOOLEAN ReturnSingleEntry,
1830 IN PVOID EaList OPTIONAL,
1831 IN ULONG EaListLength,
1832 IN PULONG EaIndex OPTIONAL,
1833 IN BOOLEAN RestartScan)
1834 {
1835 UNIMPLEMENTED;
1836 return STATUS_NOT_IMPLEMENTED;
1837 }
1838
1839 /*
1840 * @implemented
1841 */
1842 NTSTATUS
1843 NTAPI
1844 NtQueryInformationFile(IN HANDLE FileHandle,
1845 OUT PIO_STATUS_BLOCK IoStatusBlock,
1846 IN PVOID FileInformation,
1847 IN ULONG Length,
1848 IN FILE_INFORMATION_CLASS FileInformationClass)
1849 {
1850 OBJECT_HANDLE_INFORMATION HandleInformation;
1851 PFILE_OBJECT FileObject;
1852 NTSTATUS Status;
1853 PIRP Irp;
1854 PDEVICE_OBJECT DeviceObject;
1855 PIO_STACK_LOCATION StackPtr;
1856 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1857 PKEVENT Event = NULL;
1858 BOOLEAN LocalEvent = FALSE;
1859 PKNORMAL_ROUTINE NormalRoutine;
1860 PVOID NormalContext;
1861 KIRQL OldIrql;
1862 IO_STATUS_BLOCK KernelIosb;
1863 PAGED_CODE();
1864 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1865
1866 /* Check if we're called from user mode */
1867 if (PreviousMode != KernelMode)
1868 {
1869 /* Validate the information class */
1870 if ((FileInformationClass >= FileMaximumInformation) ||
1871 !(IopQueryOperationLength[FileInformationClass]))
1872 {
1873 /* Invalid class */
1874 return STATUS_INVALID_INFO_CLASS;
1875 }
1876
1877 /* Validate the length */
1878 if (Length < IopQueryOperationLength[FileInformationClass])
1879 {
1880 /* Invalid length */
1881 return STATUS_INFO_LENGTH_MISMATCH;
1882 }
1883
1884 /* Enter SEH for probing */
1885 _SEH2_TRY
1886 {
1887 /* Probe the I/O Status block */
1888 ProbeForWriteIoStatusBlock(IoStatusBlock);
1889
1890 /* Probe the information */
1891 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1892 }
1893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1894 {
1895 /* Return the exception code */
1896 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1897 }
1898 _SEH2_END;
1899 }
1900 else
1901 {
1902 /* Validate the information class */
1903 if ((FileInformationClass >= FileMaximumInformation) ||
1904 !(IopQueryOperationLength[FileInformationClass]))
1905 {
1906 /* Invalid class */
1907 return STATUS_INVALID_INFO_CLASS;
1908 }
1909
1910 /* Validate the length */
1911 if (Length < IopQueryOperationLength[FileInformationClass])
1912 {
1913 /* Invalid length */
1914 return STATUS_INFO_LENGTH_MISMATCH;
1915 }
1916 }
1917
1918 /* Reference the Handle */
1919 Status = ObReferenceObjectByHandle(FileHandle,
1920 IopQueryOperationAccess
1921 [FileInformationClass],
1922 IoFileObjectType,
1923 PreviousMode,
1924 (PVOID *)&FileObject,
1925 &HandleInformation);
1926 if (!NT_SUCCESS(Status)) return Status;
1927
1928 /* Check if this is a direct open or not */
1929 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1930 {
1931 /* Get the device object */
1932 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1933 }
1934 else
1935 {
1936 /* Get the device object */
1937 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1938 }
1939
1940 /* Check if this is a file that was opened for Synch I/O */
1941 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1942 {
1943 /* Lock it */
1944 IopLockFileObject(FileObject);
1945
1946 /* Check if the caller just wants the position */
1947 if (FileInformationClass == FilePositionInformation)
1948 {
1949 /* Protect write in SEH */
1950 _SEH2_TRY
1951 {
1952 /* Write the offset */
1953 ((PFILE_POSITION_INFORMATION)FileInformation)->
1954 CurrentByteOffset = FileObject->CurrentByteOffset;
1955
1956 /* Fill out the I/O Status Block */
1957 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
1958 Status = IoStatusBlock->Status = STATUS_SUCCESS;
1959 }
1960 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1961 {
1962 /* Get the exception code */
1963 Status = _SEH2_GetExceptionCode();
1964 }
1965 _SEH2_END;
1966
1967 /* Release the file lock, dereference the file and return */
1968 IopUnlockFileObject(FileObject);
1969 ObDereferenceObject(FileObject);
1970 return Status;
1971 }
1972 }
1973 else
1974 {
1975 /* Use local event */
1976 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
1977 if (!Event)
1978 {
1979 ObDereferenceObject(FileObject);
1980 return STATUS_INSUFFICIENT_RESOURCES;
1981 }
1982 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1983 LocalEvent = TRUE;
1984 }
1985
1986 /* Clear the File Object event */
1987 KeClearEvent(&FileObject->Event);
1988
1989 /* Allocate the IRP */
1990 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1991 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1992
1993 /* Set the IRP */
1994 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1995 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1996 Irp->RequestorMode = PreviousMode;
1997 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1998 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1999 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2000 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2001 Irp->AssociatedIrp.SystemBuffer = NULL;
2002 Irp->MdlAddress = NULL;
2003 Irp->UserBuffer = FileInformation;
2004
2005 /* Set the Stack Data */
2006 StackPtr = IoGetNextIrpStackLocation(Irp);
2007 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2008 StackPtr->FileObject = FileObject;
2009
2010 /* Enter SEH */
2011 _SEH2_TRY
2012 {
2013 /* Allocate a buffer */
2014 Irp->AssociatedIrp.SystemBuffer =
2015 ExAllocatePoolWithTag(NonPagedPool,
2016 Length,
2017 TAG_SYSB);
2018 }
2019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2020 {
2021 /* Allocating failed, clean up and return the exception code */
2022 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2023 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2024 }
2025 _SEH2_END;
2026
2027 /* Set the flags */
2028 Irp->Flags |= (IRP_BUFFERED_IO |
2029 IRP_DEALLOCATE_BUFFER |
2030 IRP_INPUT_OPERATION |
2031 IRP_DEFER_IO_COMPLETION);
2032
2033 /* Set the Parameters */
2034 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2035 StackPtr->Parameters.QueryFile.Length = Length;
2036
2037 /* Queue the IRP */
2038 IopQueueIrpToThread(Irp);
2039
2040 /* Update operation counts */
2041 IopUpdateOperationCount(IopOtherTransfer);
2042
2043 /* Call the Driver */
2044 Status = IoCallDriver(DeviceObject, Irp);
2045 if (Status == STATUS_PENDING)
2046 {
2047 /* Check if this was async I/O */
2048 if (LocalEvent)
2049 {
2050 /* Then to a non-alertable wait */
2051 Status = KeWaitForSingleObject(Event,
2052 Executive,
2053 PreviousMode,
2054 FALSE,
2055 NULL);
2056 if (Status == STATUS_USER_APC)
2057 {
2058 /* Abort the request */
2059 IopAbortInterruptedIrp(Event, Irp);
2060 }
2061
2062 /* Set the final status */
2063 Status = KernelIosb.Status;
2064
2065 /* Enter SEH to write the IOSB back */
2066 _SEH2_TRY
2067 {
2068 /* Write it back to the caller */
2069 *IoStatusBlock = KernelIosb;
2070 }
2071 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2072 {
2073 /* Get the exception code */
2074 Status = _SEH2_GetExceptionCode();
2075 }
2076 _SEH2_END;
2077
2078 /* Free the event */
2079 ExFreePoolWithTag(Event, TAG_IO);
2080 }
2081 else
2082 {
2083 /* Wait for the IRP */
2084 Status = KeWaitForSingleObject(&FileObject->Event,
2085 Executive,
2086 PreviousMode,
2087 (FileObject->Flags &
2088 FO_ALERTABLE_IO) != 0,
2089 NULL);
2090 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2091 {
2092 /* Abort the request */
2093 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2094 }
2095
2096 /* Set the final status */
2097 Status = FileObject->FinalStatus;
2098
2099 /* Release the file lock */
2100 IopUnlockFileObject(FileObject);
2101 }
2102 }
2103 else
2104 {
2105 /* Free the event if we had one */
2106 if (LocalEvent)
2107 {
2108 /* Clear it in the IRP for completion */
2109 Irp->UserEvent = NULL;
2110 ExFreePoolWithTag(Event, TAG_IO);
2111 }
2112
2113 /* Set the caller IOSB */
2114 Irp->UserIosb = IoStatusBlock;
2115
2116 /* The IRP wasn't completed, complete it ourselves */
2117 KeRaiseIrql(APC_LEVEL, &OldIrql);
2118 IopCompleteRequest(&Irp->Tail.Apc,
2119 &NormalRoutine,
2120 &NormalContext,
2121 (PVOID*)&FileObject,
2122 &NormalContext);
2123 KeLowerIrql(OldIrql);
2124
2125 /* Release the file object if we had locked it*/
2126 if (!LocalEvent) IopUnlockFileObject(FileObject);
2127 }
2128
2129 /* Return the Status */
2130 return Status;
2131 }
2132
2133 /*
2134 * @unimplemented
2135 */
2136 NTSTATUS
2137 NTAPI
2138 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2139 OUT PIO_STATUS_BLOCK IoStatusBlock,
2140 OUT PVOID Buffer,
2141 IN ULONG Length,
2142 IN BOOLEAN ReturnSingleEntry,
2143 IN PVOID SidList OPTIONAL,
2144 IN ULONG SidListLength,
2145 IN PSID StartSid OPTIONAL,
2146 IN BOOLEAN RestartScan)
2147 {
2148 UNIMPLEMENTED;
2149 return STATUS_NOT_IMPLEMENTED;
2150 }
2151
2152 /*
2153 * @implemented
2154 */
2155 NTSTATUS
2156 NTAPI
2157 NtReadFile(IN HANDLE FileHandle,
2158 IN HANDLE Event OPTIONAL,
2159 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2160 IN PVOID ApcContext OPTIONAL,
2161 OUT PIO_STATUS_BLOCK IoStatusBlock,
2162 OUT PVOID Buffer,
2163 IN ULONG Length,
2164 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2165 IN PULONG Key OPTIONAL)
2166 {
2167 NTSTATUS Status;
2168 PFILE_OBJECT FileObject;
2169 PIRP Irp;
2170 PDEVICE_OBJECT DeviceObject;
2171 PIO_STACK_LOCATION StackPtr;
2172 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2173 PKEVENT EventObject = NULL;
2174 LARGE_INTEGER CapturedByteOffset;
2175 ULONG CapturedKey = 0;
2176 BOOLEAN Synchronous = FALSE;
2177 PMDL Mdl;
2178 PAGED_CODE();
2179 CapturedByteOffset.QuadPart = 0;
2180 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2181
2182 /* Validate User-Mode Buffers */
2183 if (PreviousMode != KernelMode)
2184 {
2185 _SEH2_TRY
2186 {
2187 /* Probe the status block */
2188 ProbeForWriteIoStatusBlock(IoStatusBlock);
2189
2190 /* Probe the read buffer */
2191 ProbeForWrite(Buffer, Length, 1);
2192
2193 /* Check if we got a byte offset */
2194 if (ByteOffset)
2195 {
2196 /* Capture and probe it */
2197 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2198 }
2199
2200 /* Capture and probe the key */
2201 if (Key) CapturedKey = ProbeForReadUlong(Key);
2202 }
2203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2204 {
2205 /* Return the exception code */
2206 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2207 }
2208 _SEH2_END;
2209 }
2210 else
2211 {
2212 /* Kernel mode: capture directly */
2213 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2214 if (Key) CapturedKey = *Key;
2215 }
2216
2217 /* Get File Object */
2218 Status = ObReferenceObjectByHandle(FileHandle,
2219 FILE_READ_DATA,
2220 IoFileObjectType,
2221 PreviousMode,
2222 (PVOID*)&FileObject,
2223 NULL);
2224 if (!NT_SUCCESS(Status)) return Status;
2225
2226 /* Check for event */
2227 if (Event)
2228 {
2229 /* Reference it */
2230 Status = ObReferenceObjectByHandle(Event,
2231 EVENT_MODIFY_STATE,
2232 ExEventObjectType,
2233 PreviousMode,
2234 (PVOID*)&EventObject,
2235 NULL);
2236 if (!NT_SUCCESS(Status))
2237 {
2238 /* Fail */
2239 ObDereferenceObject(FileObject);
2240 return Status;
2241 }
2242
2243 /* Otherwise reset the event */
2244 KeClearEvent(EventObject);
2245 }
2246
2247 /* Check if we should use Sync IO or not */
2248 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2249 {
2250 /* Lock the file object */
2251 IopLockFileObject(FileObject);
2252
2253 /* Check if we don't have a byte offset avilable */
2254 if (!(ByteOffset) ||
2255 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2256 (CapturedByteOffset.u.HighPart == -1)))
2257 {
2258 /* Use the Current Byte Offset instead */
2259 CapturedByteOffset = FileObject->CurrentByteOffset;
2260 }
2261
2262 /* Remember we are sync */
2263 Synchronous = TRUE;
2264 }
2265 else if (!(ByteOffset) &&
2266 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2267 {
2268 /* Otherwise, this was async I/O without a byte offset, so fail */
2269 if (EventObject) ObDereferenceObject(EventObject);
2270 ObDereferenceObject(FileObject);
2271 return STATUS_INVALID_PARAMETER;
2272 }
2273
2274 /* Get the device object */
2275 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2276
2277 /* Clear the File Object's event */
2278 KeClearEvent(&FileObject->Event);
2279
2280 /* Allocate the IRP */
2281 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2282 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
2283
2284 /* Set the IRP */
2285 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2286 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2287 Irp->RequestorMode = PreviousMode;
2288 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2289 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2290 Irp->UserIosb = IoStatusBlock;
2291 Irp->UserEvent = EventObject;
2292 Irp->PendingReturned = FALSE;
2293 Irp->Cancel = FALSE;
2294 Irp->CancelRoutine = NULL;
2295 Irp->AssociatedIrp.SystemBuffer = NULL;
2296 Irp->MdlAddress = NULL;
2297
2298 /* Set the Stack Data */
2299 StackPtr = IoGetNextIrpStackLocation(Irp);
2300 StackPtr->MajorFunction = IRP_MJ_READ;
2301 StackPtr->FileObject = FileObject;
2302 StackPtr->Parameters.Read.Key = CapturedKey;
2303 StackPtr->Parameters.Read.Length = Length;
2304 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2305
2306 /* Check if this is buffered I/O */
2307 if (DeviceObject->Flags & DO_BUFFERED_IO)
2308 {
2309 /* Check if we have a buffer length */
2310 if (Length)
2311 {
2312 /* Enter SEH */
2313 _SEH2_TRY
2314 {
2315 /* Allocate a buffer */
2316 Irp->AssociatedIrp.SystemBuffer =
2317 ExAllocatePoolWithTag(NonPagedPool,
2318 Length,
2319 TAG_SYSB);
2320 }
2321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2322 {
2323 /* Allocating failed, clean up and return the exception code */
2324 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2325 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2326 }
2327 _SEH2_END;
2328
2329 /* Set the buffer and flags */
2330 Irp->UserBuffer = Buffer;
2331 Irp->Flags = (IRP_BUFFERED_IO |
2332 IRP_DEALLOCATE_BUFFER |
2333 IRP_INPUT_OPERATION);
2334 }
2335 else
2336 {
2337 /* Not reading anything */
2338 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2339 }
2340 }
2341 else if (DeviceObject->Flags & DO_DIRECT_IO)
2342 {
2343 /* Check if we have a buffer length */
2344 if (Length)
2345 {
2346 _SEH2_TRY
2347 {
2348 /* Allocate an MDL */
2349 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2350 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2351 }
2352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2353 {
2354 /* Allocating failed, clean up and return the exception code */
2355 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2356 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2357 }
2358 _SEH2_END;
2359
2360 }
2361
2362 /* No allocation flags */
2363 Irp->Flags = 0;
2364 }
2365 else
2366 {
2367 /* No allocation flags, and use the buffer directly */
2368 Irp->Flags = 0;
2369 Irp->UserBuffer = Buffer;
2370 }
2371
2372 /* Now set the deferred read flags */
2373 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2374 #if 0
2375 /* FIXME: VFAT SUCKS */
2376 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2377 #endif
2378
2379 /* Perform the call */
2380 return IopPerformSynchronousRequest(DeviceObject,
2381 Irp,
2382 FileObject,
2383 TRUE,
2384 PreviousMode,
2385 Synchronous,
2386 IopReadTransfer);
2387 }
2388
2389 /*
2390 * @unimplemented
2391 */
2392 NTSTATUS
2393 NTAPI
2394 NtReadFileScatter(IN HANDLE FileHandle,
2395 IN HANDLE Event OPTIONAL,
2396 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2397 IN PVOID UserApcContext OPTIONAL,
2398 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2399 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2400 IN ULONG BufferLength,
2401 IN PLARGE_INTEGER ByteOffset,
2402 IN PULONG Key OPTIONAL)
2403 {
2404 UNIMPLEMENTED;
2405 return STATUS_NOT_IMPLEMENTED;
2406 }
2407
2408 /*
2409 * @unimplemented
2410 */
2411 NTSTATUS
2412 NTAPI
2413 NtSetEaFile(IN HANDLE FileHandle,
2414 IN PIO_STATUS_BLOCK IoStatusBlock,
2415 IN PVOID EaBuffer,
2416 IN ULONG EaBufferSize)
2417 {
2418 UNIMPLEMENTED;
2419 return STATUS_NOT_IMPLEMENTED;
2420 }
2421
2422 /*
2423 * @implemented
2424 */
2425 NTSTATUS
2426 NTAPI
2427 NtSetInformationFile(IN HANDLE FileHandle,
2428 OUT PIO_STATUS_BLOCK IoStatusBlock,
2429 IN PVOID FileInformation,
2430 IN ULONG Length,
2431 IN FILE_INFORMATION_CLASS FileInformationClass)
2432 {
2433 PFILE_OBJECT FileObject;
2434 NTSTATUS Status;
2435 PIRP Irp;
2436 PDEVICE_OBJECT DeviceObject;
2437 PIO_STACK_LOCATION StackPtr;
2438 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2439 PKEVENT Event = NULL;
2440 BOOLEAN LocalEvent = FALSE;
2441 PKNORMAL_ROUTINE NormalRoutine;
2442 PVOID NormalContext;
2443 KIRQL OldIrql;
2444 IO_STATUS_BLOCK KernelIosb;
2445 PVOID Queue;
2446 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2447 PIO_COMPLETION_CONTEXT Context;
2448 PFILE_RENAME_INFORMATION RenameInfo;
2449 HANDLE TargetHandle = NULL;
2450 PAGED_CODE();
2451 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2452
2453 /* Check if we're called from user mode */
2454 if (PreviousMode != KernelMode)
2455 {
2456 /* Validate the information class */
2457 if ((FileInformationClass >= FileMaximumInformation) ||
2458 !(IopSetOperationLength[FileInformationClass]))
2459 {
2460 /* Invalid class */
2461 return STATUS_INVALID_INFO_CLASS;
2462 }
2463
2464 /* Validate the length */
2465 if (Length < IopSetOperationLength[FileInformationClass])
2466 {
2467 /* Invalid length */
2468 return STATUS_INFO_LENGTH_MISMATCH;
2469 }
2470
2471 /* Enter SEH for probing */
2472 _SEH2_TRY
2473 {
2474 /* Probe the I/O Status block */
2475 ProbeForWriteIoStatusBlock(IoStatusBlock);
2476
2477 /* Probe the information */
2478 ProbeForRead(FileInformation,
2479 Length,
2480 (Length == sizeof(BOOLEAN)) ?
2481 sizeof(BOOLEAN) : sizeof(ULONG));
2482 }
2483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2484 {
2485 /* Return the exception code */
2486 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2487 }
2488 _SEH2_END;
2489 }
2490 else
2491 {
2492 /* Validate the information class */
2493 if ((FileInformationClass >= FileMaximumInformation) ||
2494 !(IopSetOperationLength[FileInformationClass]))
2495 {
2496 /* Invalid class */
2497 return STATUS_INVALID_INFO_CLASS;
2498 }
2499
2500 /* Validate the length */
2501 if (Length < IopSetOperationLength[FileInformationClass])
2502 {
2503 /* Invalid length */
2504 return STATUS_INFO_LENGTH_MISMATCH;
2505 }
2506 }
2507
2508 /* Reference the Handle */
2509 Status = ObReferenceObjectByHandle(FileHandle,
2510 IopSetOperationAccess
2511 [FileInformationClass],
2512 IoFileObjectType,
2513 PreviousMode,
2514 (PVOID *)&FileObject,
2515 NULL);
2516 if (!NT_SUCCESS(Status)) return Status;
2517
2518 /* Check if this is a direct open or not */
2519 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2520 {
2521 /* Get the device object */
2522 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2523 }
2524 else
2525 {
2526 /* Get the device object */
2527 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2528 }
2529
2530 /* Check if this is a file that was opened for Synch I/O */
2531 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2532 {
2533 /* Lock it */
2534 IopLockFileObject(FileObject);
2535
2536 /* Check if the caller just wants the position */
2537 if (FileInformationClass == FilePositionInformation)
2538 {
2539 /* Protect write in SEH */
2540 _SEH2_TRY
2541 {
2542 /* Write the offset */
2543 FileObject->CurrentByteOffset =
2544 ((PFILE_POSITION_INFORMATION)FileInformation)->
2545 CurrentByteOffset;
2546
2547 /* Fill out the I/O Status Block */
2548 IoStatusBlock->Information = 0;
2549 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2550 }
2551 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2552 {
2553 /* Get the exception code */
2554 Status = _SEH2_GetExceptionCode();
2555 }
2556 _SEH2_END;
2557
2558 /* Update transfer count */
2559 IopUpdateTransferCount(IopOtherTransfer, Length);
2560
2561 /* Release the file lock, dereference the file and return */
2562 IopUnlockFileObject(FileObject);
2563 ObDereferenceObject(FileObject);
2564 return Status;
2565 }
2566 }
2567 else
2568 {
2569 /* Use local event */
2570 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2571 if (!Event)
2572 {
2573 ObDereferenceObject(FileObject);
2574 return STATUS_INSUFFICIENT_RESOURCES;
2575 }
2576
2577 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2578 LocalEvent = TRUE;
2579 }
2580
2581 /* Clear the File Object event */
2582 KeClearEvent(&FileObject->Event);
2583
2584 /* Allocate the IRP */
2585 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2586 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2587
2588 /* Set the IRP */
2589 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2590 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2591 Irp->RequestorMode = PreviousMode;
2592 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2593 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2594 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2595 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2596 Irp->AssociatedIrp.SystemBuffer = NULL;
2597 Irp->MdlAddress = NULL;
2598 Irp->UserBuffer = FileInformation;
2599
2600 /* Set the Stack Data */
2601 StackPtr = IoGetNextIrpStackLocation(Irp);
2602 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
2603 StackPtr->FileObject = FileObject;
2604
2605 /* Enter SEH */
2606 _SEH2_TRY
2607 {
2608 /* Allocate a buffer */
2609 Irp->AssociatedIrp.SystemBuffer =
2610 ExAllocatePoolWithTag(NonPagedPool,
2611 Length,
2612 TAG_SYSB);
2613
2614 /* Copy the data into it */
2615 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2616 FileInformation,
2617 Length);
2618 }
2619 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2620 {
2621 /* Allocating failed, clean up and return the exception code */
2622 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2623 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2624 }
2625 _SEH2_END;
2626
2627 /* Set the flags */
2628 Irp->Flags |= (IRP_BUFFERED_IO |
2629 IRP_DEALLOCATE_BUFFER |
2630 IRP_DEFER_IO_COMPLETION);
2631
2632 /* Set the Parameters */
2633 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
2634 StackPtr->Parameters.SetFile.Length = Length;
2635
2636 /* Queue the IRP */
2637 IopQueueIrpToThread(Irp);
2638
2639 /* Update operation counts */
2640 IopUpdateOperationCount(IopOtherTransfer);
2641
2642 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
2643 /* Handle IO Completion Port quickly */
2644 if (FileInformationClass == FileCompletionInformation)
2645 {
2646 /* Check if the file object already has a completion port */
2647 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
2648 (FileObject->CompletionContext))
2649 {
2650 /* Fail */
2651 Status = STATUS_INVALID_PARAMETER;
2652 }
2653 else
2654 {
2655 /* Reference the Port */
2656 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
2657 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
2658 IO_COMPLETION_MODIFY_STATE,
2659 IoCompletionType,
2660 PreviousMode,
2661 (PVOID*)&Queue,
2662 NULL);
2663 if (NT_SUCCESS(Status))
2664 {
2665 /* Allocate the Context */
2666 Context = ExAllocatePoolWithTag(PagedPool,
2667 sizeof(IO_COMPLETION_CONTEXT),
2668 IOC_TAG);
2669 if (Context)
2670 {
2671 /* Set the Data */
2672 Context->Key = CompletionInfo->Key;
2673 Context->Port = Queue;
2674 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
2675 CompletionContext,
2676 Context,
2677 NULL))
2678 {
2679 /*
2680 * Someone else set the completion port in the
2681 * meanwhile, so dereference the port and fail.
2682 */
2683 ExFreePoolWithTag(Context, IOC_TAG);
2684 ObDereferenceObject(Queue);
2685 Status = STATUS_INVALID_PARAMETER;
2686 }
2687 }
2688 else
2689 {
2690 /* Dereference the Port now */
2691 ObDereferenceObject(Queue);
2692 Status = STATUS_INSUFFICIENT_RESOURCES;
2693 }
2694 }
2695 }
2696
2697 /* Set the IRP Status */
2698 Irp->IoStatus.Status = Status;
2699 Irp->IoStatus.Information = 0;
2700 }
2701 else if (FileInformationClass == FileRenameInformation ||
2702 FileInformationClass == FileLinkInformation ||
2703 FileInformationClass == FileMoveClusterInformation)
2704 {
2705 /* Get associated information */
2706 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
2707
2708 /* Only rename if:
2709 * -> We have a name
2710 * -> In unicode
2711 * -> sizes are valid
2712 */
2713 if (RenameInfo->FileNameLength != 0 &&
2714 !(RenameInfo->FileNameLength & 1) &&
2715 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
2716 {
2717 /* Properly set information received */
2718 if (FileInformationClass == FileMoveClusterInformation)
2719 {
2720 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
2721 }
2722 else
2723 {
2724 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
2725 }
2726
2727 /* If we got fully path OR relative target, attempt a parent directory open */
2728 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
2729 {
2730 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
2731 if (!NT_SUCCESS(Status))
2732 {
2733 Irp->IoStatus.Status = Status;
2734 }
2735 else
2736 {
2737 /* Call the Driver */
2738 Status = IoCallDriver(DeviceObject, Irp);
2739 }
2740 }
2741 else
2742 {
2743 /* Call the Driver */
2744 Status = IoCallDriver(DeviceObject, Irp);
2745 }
2746 }
2747 else
2748 {
2749 Status = STATUS_INVALID_PARAMETER;
2750 Irp->IoStatus.Status = Status;
2751 }
2752 }
2753 else
2754 {
2755 /* Call the Driver */
2756 Status = IoCallDriver(DeviceObject, Irp);
2757 }
2758
2759 /* Check if we're waiting for the IRP to complete */
2760 if (Status == STATUS_PENDING)
2761 {
2762 /* Check if this was async I/O */
2763 if (LocalEvent)
2764 {
2765 /* Then to a non-alertable wait */
2766 Status = KeWaitForSingleObject(Event,
2767 Executive,
2768 PreviousMode,
2769 FALSE,
2770 NULL);
2771 if (Status == STATUS_USER_APC)
2772 {
2773 /* Abort the request */
2774 IopAbortInterruptedIrp(Event, Irp);
2775 }
2776
2777 /* Set the final status */
2778 Status = KernelIosb.Status;
2779
2780 /* Enter SEH to write the IOSB back */
2781 _SEH2_TRY
2782 {
2783 /* Write it back to the caller */
2784 *IoStatusBlock = KernelIosb;
2785 }
2786 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2787 {
2788 /* Get the exception code */
2789 Status = _SEH2_GetExceptionCode();
2790 }
2791 _SEH2_END;
2792
2793 /* Free the event */
2794 ExFreePoolWithTag(Event, TAG_IO);
2795 }
2796 else
2797 {
2798 /* Wait for the IRP */
2799 Status = KeWaitForSingleObject(&FileObject->Event,
2800 Executive,
2801 PreviousMode,
2802 (FileObject->Flags &
2803 FO_ALERTABLE_IO) != 0,
2804 NULL);
2805 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2806 {
2807 /* Abort the request */
2808 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2809 }
2810
2811 /* Set the final status */
2812 Status = FileObject->FinalStatus;
2813
2814 /* Release the file lock */
2815 IopUnlockFileObject(FileObject);
2816 }
2817 }
2818 else
2819 {
2820 /* Free the event if we had one */
2821 if (LocalEvent)
2822 {
2823 /* Clear it in the IRP for completion */
2824 Irp->UserEvent = NULL;
2825 ExFreePoolWithTag(Event, TAG_IO);
2826 }
2827
2828 /* Set the caller IOSB */
2829 Irp->UserIosb = IoStatusBlock;
2830
2831 /* The IRP wasn't completed, complete it ourselves */
2832 KeRaiseIrql(APC_LEVEL, &OldIrql);
2833 IopCompleteRequest(&Irp->Tail.Apc,
2834 &NormalRoutine,
2835 &NormalContext,
2836 (PVOID*)&FileObject,
2837 &NormalContext);
2838 KeLowerIrql(OldIrql);
2839
2840 /* Release the file object if we had locked it*/
2841 if (!LocalEvent) IopUnlockFileObject(FileObject);
2842 }
2843
2844 if (TargetHandle != NULL)
2845 {
2846 ObCloseHandle(TargetHandle, KernelMode);
2847 }
2848
2849 /* Return the Status */
2850 return Status;
2851 }
2852
2853 /*
2854 * @unimplemented
2855 */
2856 NTSTATUS
2857 NTAPI
2858 NtSetQuotaInformationFile(IN HANDLE FileHandle,
2859 OUT PIO_STATUS_BLOCK IoStatusBlock,
2860 IN PVOID Buffer,
2861 IN ULONG BufferLength)
2862 {
2863 UNIMPLEMENTED;
2864 return STATUS_NOT_IMPLEMENTED;
2865 }
2866
2867 /*
2868 * @implemented
2869 */
2870 NTSTATUS
2871 NTAPI
2872 NtUnlockFile(IN HANDLE FileHandle,
2873 OUT PIO_STATUS_BLOCK IoStatusBlock,
2874 IN PLARGE_INTEGER ByteOffset,
2875 IN PLARGE_INTEGER Length,
2876 IN ULONG Key OPTIONAL)
2877 {
2878 PFILE_OBJECT FileObject;
2879 PLARGE_INTEGER LocalLength = NULL;
2880 PIRP Irp;
2881 PIO_STACK_LOCATION StackPtr;
2882 PDEVICE_OBJECT DeviceObject;
2883 PKEVENT Event = NULL;
2884 BOOLEAN LocalEvent = FALSE;
2885 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2886 LARGE_INTEGER CapturedByteOffset, CapturedLength;
2887 NTSTATUS Status;
2888 OBJECT_HANDLE_INFORMATION HandleInformation;
2889 IO_STATUS_BLOCK KernelIosb;
2890 PAGED_CODE();
2891 CapturedByteOffset.QuadPart = 0;
2892 CapturedLength.QuadPart = 0;
2893 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2894
2895 /* Get File Object */
2896 Status = ObReferenceObjectByHandle(FileHandle,
2897 0,
2898 IoFileObjectType,
2899 PreviousMode,
2900 (PVOID*)&FileObject,
2901 &HandleInformation);
2902 if (!NT_SUCCESS(Status)) return Status;
2903
2904 /* Check if we're called from user mode */
2905 if (PreviousMode != KernelMode)
2906 {
2907 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
2908 if (!(HandleInformation.GrantedAccess &
2909 (FILE_WRITE_DATA | FILE_READ_DATA)))
2910 {
2911 ObDereferenceObject(FileObject);
2912 return STATUS_ACCESS_DENIED;
2913 }
2914
2915 /* Enter SEH for probing */
2916 _SEH2_TRY
2917 {
2918 /* Probe the I/O Status block */
2919 ProbeForWriteIoStatusBlock(IoStatusBlock);
2920
2921 /* Probe and capture the large integers */
2922 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2923 CapturedLength = ProbeForReadLargeInteger(Length);
2924 }
2925 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2926 {
2927 /* Dereference the object and return exception code */
2928 ObDereferenceObject(FileObject);
2929 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2930 }
2931 _SEH2_END;
2932 }
2933 else
2934 {
2935 /* Otherwise, capture them directly */
2936 CapturedByteOffset = *ByteOffset;
2937 CapturedLength = *Length;
2938 }
2939
2940 /* Check if this is a direct open or not */
2941 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2942 {
2943 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2944 }
2945 else
2946 {
2947 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2948 }
2949
2950 /* Check if we should use Sync IO or not */
2951 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2952 {
2953 /* Lock it */
2954 IopLockFileObject(FileObject);
2955 }
2956 else
2957 {
2958 /* Use local event */
2959 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2960 if (!Event)
2961 {
2962 ObDereferenceObject(FileObject);
2963 return STATUS_INSUFFICIENT_RESOURCES;
2964 }
2965 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2966 LocalEvent = TRUE;
2967 }
2968
2969 /* Clear File Object event */
2970 KeClearEvent(&FileObject->Event);
2971
2972 /* Allocate the IRP */
2973 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2974 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2975
2976 /* Set up the IRP */
2977 Irp->RequestorMode = PreviousMode;
2978 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2979 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2980 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2981 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2982 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2983 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2984
2985 /* Set up Stack Data */
2986 StackPtr = IoGetNextIrpStackLocation(Irp);
2987 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2988 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
2989 StackPtr->FileObject = FileObject;
2990
2991 /* Enter SEH */
2992 _SEH2_TRY
2993 {
2994 /* Allocate a buffer */
2995 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
2996 sizeof(LARGE_INTEGER),
2997 TAG_LOCK);
2998
2999 /* Set the length */
3000 *LocalLength = CapturedLength;
3001 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3002 StackPtr->Parameters.LockControl.Length = LocalLength;
3003 }
3004 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3005 {
3006 /* Allocating failed, clean up and return the exception code */
3007 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3008 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3009
3010 /* Return the exception code */
3011 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3012 }
3013 _SEH2_END;
3014
3015 /* Set Parameters */
3016 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3017 StackPtr->Parameters.LockControl.Key = Key;
3018
3019 /* Call the Driver */
3020 Status = IopPerformSynchronousRequest(DeviceObject,
3021 Irp,
3022 FileObject,
3023 FALSE,
3024 PreviousMode,
3025 !LocalEvent,
3026 IopOtherTransfer);
3027
3028 /* Check if this was async I/O */
3029 if (LocalEvent)
3030 {
3031 /* It was, finalize this request */
3032 Status = IopFinalizeAsynchronousIo(Status,
3033 Event,
3034 Irp,
3035 PreviousMode,
3036 &KernelIosb,
3037 IoStatusBlock);
3038 }
3039
3040 /* Return status */
3041 return Status;
3042 }
3043
3044 /*
3045 * @implemented
3046 */
3047 NTSTATUS
3048 NTAPI
3049 NtWriteFile(IN HANDLE FileHandle,
3050 IN HANDLE Event OPTIONAL,
3051 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3052 IN PVOID ApcContext OPTIONAL,
3053 OUT PIO_STATUS_BLOCK IoStatusBlock,
3054 IN PVOID Buffer,
3055 IN ULONG Length,
3056 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3057 IN PULONG Key OPTIONAL)
3058 {
3059 NTSTATUS Status;
3060 PFILE_OBJECT FileObject;
3061 PIRP Irp;
3062 PDEVICE_OBJECT DeviceObject;
3063 PIO_STACK_LOCATION StackPtr;
3064 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3065 PKEVENT EventObject = NULL;
3066 LARGE_INTEGER CapturedByteOffset;
3067 ULONG CapturedKey = 0;
3068 BOOLEAN Synchronous = FALSE;
3069 PMDL Mdl;
3070 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3071 PAGED_CODE();
3072 CapturedByteOffset.QuadPart = 0;
3073 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3074
3075 /* Get File Object */
3076 Status = ObReferenceObjectByHandle(FileHandle,
3077 0,
3078 IoFileObjectType,
3079 PreviousMode,
3080 (PVOID*)&FileObject,
3081 &ObjectHandleInfo);
3082 if (!NT_SUCCESS(Status)) return Status;
3083
3084 /* Validate User-Mode Buffers */
3085 if (PreviousMode != KernelMode)
3086 {
3087 _SEH2_TRY
3088 {
3089 /*
3090 * Check if the handle has either FILE_WRITE_DATA or
3091 * FILE_APPEND_DATA granted. However, if this is a named pipe,
3092 * make sure we don't ask for FILE_APPEND_DATA as it interferes
3093 * with the FILE_CREATE_PIPE_INSTANCE access right!
3094 */
3095 if (!(ObjectHandleInfo.GrantedAccess &
3096 ((!(FileObject->Flags & FO_NAMED_PIPE) ?
3097 FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
3098 {
3099 /* We failed */
3100 ObDereferenceObject(FileObject);
3101 _SEH2_YIELD(return STATUS_ACCESS_DENIED);
3102 }
3103
3104 /* Probe the status block */
3105 ProbeForWriteIoStatusBlock(IoStatusBlock);
3106
3107 /* Probe the read buffer */
3108 ProbeForRead(Buffer, Length, 1);
3109
3110 /* Check if we got a byte offset */
3111 if (ByteOffset)
3112 {
3113 /* Capture and probe it */
3114 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3115 }
3116
3117 /* Capture and probe the key */
3118 if (Key) CapturedKey = ProbeForReadUlong(Key);
3119 }
3120 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3121 {
3122 /* Return the exception code */
3123 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3124 }
3125 _SEH2_END;
3126 }
3127 else
3128 {
3129 /* Kernel mode: capture directly */
3130 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3131 if (Key) CapturedKey = *Key;
3132 }
3133
3134 /* Check if this is an append operation */
3135 if ((ObjectHandleInfo.GrantedAccess &
3136 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3137 {
3138 /* Give the drivers something to understand */
3139 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3140 CapturedByteOffset.u.HighPart = -1;
3141 }
3142
3143 /* Check for event */
3144 if (Event)
3145 {
3146 /* Reference it */
3147 Status = ObReferenceObjectByHandle(Event,
3148 EVENT_MODIFY_STATE,
3149 ExEventObjectType,
3150 PreviousMode,
3151 (PVOID*)&EventObject,
3152 NULL);
3153 if (!NT_SUCCESS(Status))
3154 {
3155 /* Fail */
3156 ObDereferenceObject(FileObject);
3157 return Status;
3158 }
3159
3160 /* Otherwise reset the event */
3161 KeClearEvent(EventObject);
3162 }
3163
3164 /* Check if we should use Sync IO or not */
3165 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3166 {
3167 /* Lock the file object */
3168 IopLockFileObject(FileObject);
3169
3170 /* Check if we don't have a byte offset avilable */
3171 if (!(ByteOffset) ||
3172 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3173 (CapturedByteOffset.u.HighPart == -1)))
3174 {
3175 /* Use the Current Byte Offset instead */
3176 CapturedByteOffset = FileObject->CurrentByteOffset;
3177 }
3178
3179 /* Remember we are sync */
3180 Synchronous = TRUE;
3181 }
3182 else if (!(ByteOffset) &&
3183 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3184 {
3185 /* Otherwise, this was async I/O without a byte offset, so fail */
3186 if (EventObject) ObDereferenceObject(EventObject);
3187 ObDereferenceObject(FileObject);
3188 return STATUS_INVALID_PARAMETER;
3189 }
3190
3191 /* Get the device object */
3192 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3193
3194 /* Clear the File Object's event */
3195 KeClearEvent(&FileObject->Event);
3196
3197 /* Allocate the IRP */
3198 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3199 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
3200
3201 /* Set the IRP */
3202 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3203 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3204 Irp->RequestorMode = PreviousMode;
3205 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3206 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3207 Irp->UserIosb = IoStatusBlock;
3208 Irp->UserEvent = EventObject;
3209 Irp->PendingReturned = FALSE;
3210 Irp->Cancel = FALSE;
3211 Irp->CancelRoutine = NULL;
3212 Irp->AssociatedIrp.SystemBuffer = NULL;
3213 Irp->MdlAddress = NULL;
3214
3215 /* Set the Stack Data */
3216 StackPtr = IoGetNextIrpStackLocation(Irp);
3217 StackPtr->MajorFunction = IRP_MJ_WRITE;
3218 StackPtr->FileObject = FileObject;
3219 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3220 SL_WRITE_THROUGH : 0;
3221 StackPtr->Parameters.Write.Key = CapturedKey;
3222 StackPtr->Parameters.Write.Length = Length;
3223 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3224
3225 /* Check if this is buffered I/O */
3226 if (DeviceObject->Flags & DO_BUFFERED_IO)
3227 {
3228 /* Check if we have a buffer length */
3229 if (Length)
3230 {
3231 /* Enter SEH */
3232 _SEH2_TRY
3233 {
3234 /* Allocate a buffer */
3235 Irp->AssociatedIrp.SystemBuffer =
3236 ExAllocatePoolWithTag(NonPagedPool,
3237 Length,
3238 TAG_SYSB);
3239
3240 /* Copy the data into it */
3241 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3242 }
3243 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3244 {
3245 /* Allocating failed, clean up and return the exception code */
3246 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3247 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3248 }
3249 _SEH2_END;
3250
3251 /* Set the flags */
3252 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3253 }
3254 else
3255 {
3256 /* Not writing anything */
3257 Irp->Flags = IRP_BUFFERED_IO;
3258 }
3259 }
3260 else if (DeviceObject->Flags & DO_DIRECT_IO)
3261 {
3262 /* Check if we have a buffer length */
3263 if (Length)
3264 {
3265 _SEH2_TRY
3266 {
3267 /* Allocate an MDL */
3268 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
3269 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
3270 }
3271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3272 {
3273 /* Allocating failed, clean up and return the exception code */
3274 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3275 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3276 }
3277 _SEH2_END;
3278 }
3279
3280 /* No allocation flags */
3281 Irp->Flags = 0;
3282 }
3283 else
3284 {
3285 /* No allocation flags, and use the buffer directly */
3286 Irp->Flags = 0;
3287 Irp->UserBuffer = Buffer;
3288 }
3289
3290 /* Now set the deferred read flags */
3291 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
3292 #if 0
3293 /* FIXME: VFAT SUCKS */
3294 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3295 #endif
3296
3297 /* Perform the call */
3298 return IopPerformSynchronousRequest(DeviceObject,
3299 Irp,
3300 FileObject,
3301 TRUE,
3302 PreviousMode,
3303 Synchronous,
3304 IopWriteTransfer);
3305 }
3306
3307 NTSTATUS
3308 NTAPI
3309 NtWriteFileGather(IN HANDLE FileHandle,
3310 IN HANDLE Event OPTIONAL,
3311 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3312 IN PVOID UserApcContext OPTIONAL,
3313 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3314 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3315 IN ULONG BufferLength,
3316 IN PLARGE_INTEGER ByteOffset,
3317 IN PULONG Key OPTIONAL)
3318 {
3319 UNIMPLEMENTED;
3320 return STATUS_NOT_IMPLEMENTED;
3321 }
3322
3323 /*
3324 * @implemented
3325 */
3326 NTSTATUS
3327 NTAPI
3328 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
3329 OUT PIO_STATUS_BLOCK IoStatusBlock,
3330 OUT PVOID FsInformation,
3331 IN ULONG Length,
3332 IN FS_INFORMATION_CLASS FsInformationClass)
3333 {
3334 PFILE_OBJECT FileObject;
3335 PIRP Irp;
3336 PIO_STACK_LOCATION StackPtr;
3337 PDEVICE_OBJECT DeviceObject;
3338 PKEVENT Event = NULL;
3339 BOOLEAN LocalEvent = FALSE;
3340 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3341 NTSTATUS Status;
3342 IO_STATUS_BLOCK KernelIosb;
3343 PAGED_CODE();
3344 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3345
3346 /* Check if we're called from user mode */
3347 if (PreviousMode != KernelMode)
3348 {
3349 /* Validate the information class */
3350 if ((FsInformationClass >= FileFsMaximumInformation) ||
3351 !(IopQueryFsOperationLength[FsInformationClass]))
3352 {
3353 /* Invalid class */
3354 return STATUS_INVALID_INFO_CLASS;
3355 }
3356
3357 /* Validate the length */
3358 if (Length < IopQueryFsOperationLength[FsInformationClass])
3359 {
3360 /* Invalid length */
3361 return STATUS_INFO_LENGTH_MISMATCH;
3362 }
3363
3364 /* Enter SEH for probing */
3365 _SEH2_TRY
3366 {
3367 /* Probe the I/O Status block */
3368 ProbeForWriteIoStatusBlock(IoStatusBlock);
3369
3370 /* Probe the information */
3371 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
3372 }
3373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3374 {
3375 /* Return the exception code */
3376 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3377 }
3378 _SEH2_END;
3379 }
3380
3381 /* Get File Object */
3382 Status = ObReferenceObjectByHandle(FileHandle,
3383 IopQueryFsOperationAccess
3384 [FsInformationClass],
3385 IoFileObjectType,
3386 PreviousMode,
3387 (PVOID*)&FileObject,
3388 NULL);
3389 if (!NT_SUCCESS(Status)) return Status;
3390
3391 /* Check if we should use Sync IO or not */
3392 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3393 {
3394 /* Lock it */
3395 IopLockFileObject(FileObject);
3396 }
3397 else
3398 {
3399 /* Use local event */
3400 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3401 if (!Event)
3402 {
3403 ObDereferenceObject(FileObject);
3404 return STATUS_INSUFFICIENT_RESOURCES;
3405 }
3406 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3407 LocalEvent = TRUE;
3408 }
3409
3410 /* Get the device object */
3411 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3412
3413 /* Clear File Object event */
3414 KeClearEvent(&FileObject->Event);
3415
3416 /* Allocate the IRP */
3417 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3418 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3419
3420 /* Set up the IRP */
3421 Irp->RequestorMode = PreviousMode;
3422 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3423 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3424 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3425 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3426 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3427 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3428 Irp->UserBuffer = FsInformation;
3429 Irp->AssociatedIrp.SystemBuffer = NULL;
3430 Irp->MdlAddress = NULL;
3431
3432 /* Set up Stack Data */
3433 StackPtr = IoGetNextIrpStackLocation(Irp);
3434 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
3435 StackPtr->FileObject = FileObject;
3436
3437 /* Enter SEH */
3438 _SEH2_TRY
3439 {
3440 /* Allocate a buffer */
3441 Irp->AssociatedIrp.SystemBuffer =
3442 ExAllocatePoolWithTag(NonPagedPool,
3443 Length,
3444 TAG_SYSB);
3445 }
3446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3447 {
3448 /* Allocating failed, clean up and return the exception code */
3449 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3450 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3451 }
3452 _SEH2_END;
3453
3454 /* Set the flags for this buffered + deferred I/O */
3455 Irp->Flags |= (IRP_BUFFERED_IO |
3456 IRP_DEALLOCATE_BUFFER |
3457 IRP_INPUT_OPERATION |
3458 IRP_DEFER_IO_COMPLETION);
3459
3460 /* Set Parameters */
3461 StackPtr->Parameters.QueryVolume.Length = Length;
3462 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
3463
3464 /* Call the Driver */
3465 Status = IopPerformSynchronousRequest(DeviceObject,
3466 Irp,
3467 FileObject,
3468 TRUE,
3469 PreviousMode,
3470 !LocalEvent,
3471 IopOtherTransfer);
3472
3473 /* Check if this was async I/O */
3474 if (LocalEvent)
3475 {
3476 /* It was, finalize this request */
3477 Status = IopFinalizeAsynchronousIo(Status,
3478 Event,
3479 Irp,
3480 PreviousMode,
3481 &KernelIosb,
3482 IoStatusBlock);
3483 }
3484
3485 /* Return status */
3486 return Status;
3487 }
3488
3489 /*
3490 * @implemented
3491 */
3492 NTSTATUS
3493 NTAPI
3494 NtSetVolumeInformationFile(IN HANDLE FileHandle,
3495 OUT PIO_STATUS_BLOCK IoStatusBlock,
3496 IN PVOID FsInformation,
3497 IN ULONG Length,
3498 IN FS_INFORMATION_CLASS FsInformationClass)
3499 {
3500 PFILE_OBJECT FileObject;
3501 PIRP Irp;
3502 PIO_STACK_LOCATION StackPtr;
3503 PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
3504 PKEVENT Event = NULL;
3505 BOOLEAN LocalEvent = FALSE;
3506 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3507 NTSTATUS Status;
3508 IO_STATUS_BLOCK KernelIosb;
3509 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
3510 PAGED_CODE();
3511 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3512
3513 /* Check if we're called from user mode */
3514 if (PreviousMode != KernelMode)
3515 {
3516 /* Validate the information class */
3517 if ((FsInformationClass >= FileFsMaximumInformation) ||
3518 !(IopSetFsOperationLength[FsInformationClass]))
3519 {
3520 /* Invalid class */
3521 return STATUS_INVALID_INFO_CLASS;
3522 }
3523
3524 /* Validate the length */
3525 if (Length < IopSetFsOperationLength[FsInformationClass])
3526 {
3527 /* Invalid length */
3528 return STATUS_INFO_LENGTH_MISMATCH;
3529 }
3530
3531 /* Enter SEH for probing */
3532 _SEH2_TRY
3533 {
3534 /* Probe the I/O Status block */
3535 ProbeForWriteIoStatusBlock(IoStatusBlock);
3536
3537 /* Probe the information */
3538 ProbeForRead(FsInformation, Length, sizeof(ULONG));
3539 }
3540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3541 {
3542 /* Return the exception code */
3543 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3544 }
3545 _SEH2_END;
3546 }
3547
3548 /* Get File Object */
3549 Status = ObReferenceObjectByHandle(FileHandle,
3550 IopSetFsOperationAccess
3551 [FsInformationClass],
3552 IoFileObjectType,
3553 PreviousMode,
3554 (PVOID*)&FileObject,
3555 NULL);
3556 if (!NT_SUCCESS(Status)) return Status;
3557
3558 /* Get target device for notification */
3559 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
3560 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
3561
3562 /* Check if we should use Sync IO or not */
3563 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3564 {
3565 /* Lock it */
3566 IopLockFileObject(FileObject);
3567 }
3568 else
3569 {
3570 /* Use local event */
3571 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3572 if (!Event)
3573 {
3574 ObDereferenceObject(FileObject);
3575 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3576 return STATUS_INSUFFICIENT_RESOURCES;
3577 }
3578 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3579 LocalEvent = TRUE;
3580 }
3581
3582 /* Get the device object */
3583 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3584
3585 /* Clear File Object event */
3586 KeClearEvent(&FileObject->Event);
3587
3588 /* Allocate the IRP */
3589 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3590 if (!Irp)
3591 {
3592 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3593 return IopCleanupFailedIrp(FileObject, NULL, Event);
3594 }
3595
3596 /* Set up the IRP */
3597 Irp->RequestorMode = PreviousMode;
3598 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3599 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3600 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3601 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3602 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3603 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3604 Irp->UserBuffer = FsInformation;
3605 Irp->AssociatedIrp.SystemBuffer = NULL;
3606 Irp->MdlAddress = NULL;
3607
3608 /* Set up Stack Data */
3609 StackPtr = IoGetNextIrpStackLocation(Irp);
3610 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
3611 StackPtr->FileObject = FileObject;
3612
3613 /* Enter SEH */
3614 _SEH2_TRY
3615 {
3616 /* Allocate a buffer */
3617 Irp->AssociatedIrp.SystemBuffer =
3618 ExAllocatePoolWithTag(NonPagedPool,
3619 Length,
3620 TAG_SYSB);
3621
3622 /* Copy the data into it */
3623 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
3624 }
3625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3626 {
3627 /* Allocating failed, clean up and return the exception code */
3628 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3629 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3630 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3631 }
3632 _SEH2_END;
3633
3634 /* Set the flags for this buffered + deferred I/O */
3635 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3636
3637 /* Set Parameters */
3638 StackPtr->Parameters.SetVolume.Length = Length;
3639 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
3640
3641 /* Call the Driver */
3642 Status = IopPerformSynchronousRequest(DeviceObject,
3643 Irp,
3644 FileObject,
3645 FALSE,
3646 PreviousMode,
3647 !LocalEvent,
3648 IopOtherTransfer);
3649
3650 /* Check if this was async I/O */
3651 if (LocalEvent)
3652 {
3653 /* It was, finalize this request */
3654 Status = IopFinalizeAsynchronousIo(Status,
3655 Event,
3656 Irp,
3657 PreviousMode,
3658 &KernelIosb,
3659 IoStatusBlock);
3660 }
3661
3662 if (TargetDeviceObject && NT_SUCCESS(Status))
3663 {
3664 /* Time to report change */
3665 NotificationStructure.Version = 1;
3666 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
3667 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
3668 NotificationStructure.FileObject = NULL;
3669 NotificationStructure.NameBufferOffset = - 1;
3670 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
3671 }
3672
3673 /* Return status */
3674 return Status;
3675 }
3676
3677 /*
3678 * @unimplemented
3679 */
3680 NTSTATUS
3681 NTAPI
3682 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
3683 {
3684 UNIMPLEMENTED;
3685 return STATUS_NOT_IMPLEMENTED;
3686 }
3687
3688 /*
3689 * @unimplemented
3690 */
3691 NTSTATUS
3692 NTAPI
3693 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
3694 {
3695 UNIMPLEMENTED;
3696 return STATUS_NOT_IMPLEMENTED;
3697 }