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