[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / iofunc.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iofunc.c
5 * PURPOSE: Generic I/O Functions that build IRPs for various operations
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 * Filip Navara (navaraf@reactos.org)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #include <ioevent.h>
15 #define NDEBUG
16 #include <debug.h>
17 #include "internal/io_i.h"
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 VOID
22 NTAPI
23 IopCleanupAfterException(IN PFILE_OBJECT FileObject,
24 IN PIRP Irp,
25 IN PKEVENT Event OPTIONAL,
26 IN PKEVENT LocalEvent OPTIONAL)
27 {
28 PAGED_CODE();
29 IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
30
31 /* Check if we had a buffer */
32 if (Irp->AssociatedIrp.SystemBuffer)
33 {
34 /* Free it */
35 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
36 }
37
38 /* Free the mdl */
39 if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
40
41 /* Free the IRP */
42 IoFreeIrp(Irp);
43
44 /* Check if we had a file lock */
45 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
46 {
47 /* Release it */
48 IopUnlockFileObject(FileObject);
49 }
50
51 /* Check if we had an event */
52 if (Event) ObDereferenceObject(Event);
53
54 /* Check if we had a local event */
55 if (LocalEvent) ExFreePool(LocalEvent);
56
57 /* Derefenrce the FO */
58 ObDereferenceObject(FileObject);
59 }
60
61 NTSTATUS
62 NTAPI
63 IopFinalizeAsynchronousIo(IN NTSTATUS SynchStatus,
64 IN PKEVENT Event,
65 IN PIRP Irp,
66 IN KPROCESSOR_MODE PreviousMode,
67 IN PIO_STATUS_BLOCK KernelIosb,
68 OUT PIO_STATUS_BLOCK IoStatusBlock)
69 {
70 NTSTATUS FinalStatus = SynchStatus;
71 PAGED_CODE();
72 IOTRACE(IO_API_DEBUG, "IRP: %p. Status: %lx \n", Irp, SynchStatus);
73
74 /* Make sure the IRP was completed, but returned pending */
75 if (FinalStatus == STATUS_PENDING)
76 {
77 /* Wait for the IRP */
78 FinalStatus = KeWaitForSingleObject(Event,
79 Executive,
80 PreviousMode,
81 FALSE,
82 NULL);
83 if (FinalStatus == STATUS_USER_APC)
84 {
85 /* Abort the request */
86 IopAbortInterruptedIrp(Event, Irp);
87 }
88
89 /* Set the final status */
90 FinalStatus = KernelIosb->Status;
91 }
92
93 /* Wrap potential user-mode write in SEH */
94 _SEH2_TRY
95 {
96 *IoStatusBlock = *KernelIosb;
97 }
98 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
99 {
100 /* Get the exception code */
101 FinalStatus = _SEH2_GetExceptionCode();
102 }
103 _SEH2_END;
104
105 /* Free the event and return status */
106 ExFreePool(Event);
107 return FinalStatus;
108 }
109
110 NTSTATUS
111 NTAPI
112 IopPerformSynchronousRequest(IN PDEVICE_OBJECT DeviceObject,
113 IN PIRP Irp,
114 IN PFILE_OBJECT FileObject,
115 IN BOOLEAN Deferred,
116 IN KPROCESSOR_MODE PreviousMode,
117 IN BOOLEAN SynchIo,
118 IN IOP_TRANSFER_TYPE TransferType)
119 {
120 NTSTATUS Status;
121 PKNORMAL_ROUTINE NormalRoutine;
122 PVOID NormalContext = NULL;
123 KIRQL OldIrql;
124 PAGED_CODE();
125 IOTRACE(IO_API_DEBUG, "IRP: %p. DO: %p. FO: %p \n",
126 Irp, DeviceObject, FileObject);
127
128 /* Queue the IRP */
129 IopQueueIrpToThread(Irp);
130
131 /* Update operation counts */
132 IopUpdateOperationCount(TransferType);
133
134 /* Call the driver */
135 Status = IoCallDriver(DeviceObject, Irp);
136
137 /* Check if we're optimizing this case */
138 if (Deferred)
139 {
140 /* We are! Check if the IRP wasn't completed */
141 if (Status != STATUS_PENDING)
142 {
143 /* Complete it ourselves */
144 ASSERT(!Irp->PendingReturned);
145 KeRaiseIrql(APC_LEVEL, &OldIrql);
146 IopCompleteRequest(&Irp->Tail.Apc,
147 &NormalRoutine,
148 &NormalContext,
149 (PVOID*)&FileObject,
150 &NormalContext);
151 KeLowerIrql(OldIrql);
152 }
153 }
154
155 /* Check if this was synch I/O */
156 if (SynchIo)
157 {
158 /* Make sure the IRP was completed, but returned pending */
159 if (Status == STATUS_PENDING)
160 {
161 /* Wait for the IRP */
162 Status = KeWaitForSingleObject(&FileObject->Event,
163 Executive,
164 PreviousMode,
165 (FileObject->Flags &
166 FO_ALERTABLE_IO) != 0,
167 NULL);
168 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
169 {
170 /* Abort the request */
171 IopAbortInterruptedIrp(&FileObject->Event, Irp);
172 }
173
174 /* Set the final status */
175 Status = FileObject->FinalStatus;
176 }
177
178 /* Release the file lock */
179 IopUnlockFileObject(FileObject);
180 }
181
182 /* Return status */
183 return Status;
184 }
185
186 NTSTATUS
187 NTAPI
188 IopDeviceFsIoControl(IN HANDLE DeviceHandle,
189 IN HANDLE Event OPTIONAL,
190 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
191 IN PVOID UserApcContext OPTIONAL,
192 OUT PIO_STATUS_BLOCK IoStatusBlock,
193 IN ULONG IoControlCode,
194 IN PVOID InputBuffer,
195 IN ULONG InputBufferLength OPTIONAL,
196 OUT PVOID OutputBuffer,
197 IN ULONG OutputBufferLength OPTIONAL,
198 IN BOOLEAN IsDevIoCtl)
199 {
200 NTSTATUS Status;
201 PFILE_OBJECT FileObject;
202 PDEVICE_OBJECT DeviceObject;
203 PIRP Irp;
204 PIO_STACK_LOCATION StackPtr;
205 PKEVENT EventObject = NULL;
206 BOOLEAN LockedForSynch = FALSE;
207 ULONG AccessType;
208 OBJECT_HANDLE_INFORMATION HandleInformation;
209 ACCESS_MASK DesiredAccess;
210 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
211 ULONG BufferLength;
212 IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
213 DeviceHandle, IoControlCode, IsDevIoCtl);
214
215 /* Get the access type */
216 AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
217
218 /* Check if we came from user mode */
219 if (PreviousMode != KernelMode)
220 {
221 _SEH2_TRY
222 {
223 /* Probe the status block */
224 ProbeForWriteIoStatusBlock(IoStatusBlock);
225
226 /* Check if this is buffered I/O */
227 if (AccessType == METHOD_BUFFERED)
228 {
229 /* Check if we have an output buffer */
230 if (OutputBuffer)
231 {
232 /* Probe the output buffer */
233 ProbeForWrite(OutputBuffer,
234 OutputBufferLength,
235 sizeof(CHAR));
236 }
237 else
238 {
239 /* Make sure the caller can't fake this as we depend on this */
240 OutputBufferLength = 0;
241 }
242 }
243
244 /* Check if we we have an input buffer I/O */
245 if (AccessType != METHOD_NEITHER)
246 {
247 /* Check if we have an input buffer */
248 if (InputBuffer)
249 {
250 /* Probe the input buffer */
251 ProbeForRead(InputBuffer, InputBufferLength, sizeof(CHAR));
252 }
253 else
254 {
255 /* Make sure the caller can't fake this as we depend on this */
256 InputBufferLength = 0;
257 }
258 }
259 }
260 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
261 {
262 /* Return the exception code */
263 _SEH2_YIELD(return _SEH2_GetExceptionCode());
264 }
265 _SEH2_END;
266 }
267
268 /* Don't check for access rights right now, KernelMode can do anything */
269 Status = ObReferenceObjectByHandle(DeviceHandle,
270 0,
271 IoFileObjectType,
272 PreviousMode,
273 (PVOID*)&FileObject,
274 &HandleInformation);
275 if (!NT_SUCCESS(Status)) return Status;
276
277 /* Can't use an I/O completion port and an APC in the same time */
278 if ((FileObject->CompletionContext) && (UserApcRoutine))
279 {
280 /* Fail */
281 ObDereferenceObject(FileObject);
282 return STATUS_INVALID_PARAMETER;
283 }
284
285 /* Check if we from user mode */
286 if (PreviousMode != KernelMode)
287 {
288 /* Get the access mask */
289 DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
290
291 /* Check if we can open it */
292 if ((DesiredAccess != FILE_ANY_ACCESS) &&
293 (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
294 {
295 /* Dereference the file object and fail */
296 ObDereferenceObject(FileObject);
297 return STATUS_ACCESS_DENIED;
298 }
299 }
300
301 /* Check for an event */
302 if (Event)
303 {
304 /* Reference it */
305 Status = ObReferenceObjectByHandle(Event,
306 EVENT_MODIFY_STATE,
307 ExEventObjectType,
308 PreviousMode,
309 (PVOID*)&EventObject,
310 NULL);
311 if (!NT_SUCCESS(Status))
312 {
313 /* Dereference the file object and fail */
314 ObDereferenceObject(FileObject);
315 return Status;
316 }
317
318 /* Clear it */
319 KeClearEvent(EventObject);
320 }
321
322 /* Check if this is a file that was opened for Synch I/O */
323 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
324 {
325 /* Lock it */
326 IopLockFileObject(FileObject);
327
328 /* Remember to unlock later */
329 LockedForSynch = TRUE;
330 }
331
332 /* Check if this is a direct open or not */
333 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
334 {
335 /* It's a direct open, get the attached device */
336 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
337 }
338 else
339 {
340 /* Otherwise get the related device */
341 DeviceObject = IoGetRelatedDeviceObject(FileObject);
342 }
343
344 /* Clear the event */
345 KeClearEvent(&FileObject->Event);
346
347 /* Allocate IRP */
348 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
349 if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
350
351 /* Setup the IRP */
352 Irp->UserIosb = IoStatusBlock;
353 Irp->UserEvent = EventObject;
354 Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
355 Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
356 Irp->Cancel = FALSE;
357 Irp->CancelRoutine = NULL;
358 Irp->PendingReturned = FALSE;
359 Irp->RequestorMode = PreviousMode;
360 Irp->MdlAddress = NULL;
361 Irp->AssociatedIrp.SystemBuffer = NULL;
362 Irp->Flags = 0;
363 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
364 Irp->Tail.Overlay.OriginalFileObject = FileObject;
365 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
366
367 /* Set stack location settings */
368 StackPtr = IoGetNextIrpStackLocation(Irp);
369 StackPtr->FileObject = FileObject;
370 StackPtr->MajorFunction = IsDevIoCtl ?
371 IRP_MJ_DEVICE_CONTROL :
372 IRP_MJ_FILE_SYSTEM_CONTROL;
373 StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
374 StackPtr->Control = 0;
375 StackPtr->Flags = 0;
376 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
377
378 /* Set the IOCTL Data */
379 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
380 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
381 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
382 OutputBufferLength;
383
384 /* Handle the Methods */
385 switch (AccessType)
386 {
387 /* Buffered I/O */
388 case METHOD_BUFFERED:
389
390 /* Enter SEH for allocations */
391 _SEH2_TRY
392 {
393 /* Select the right Buffer Length */
394 BufferLength = (InputBufferLength > OutputBufferLength) ?
395 InputBufferLength : OutputBufferLength;
396
397 /* Make sure there is one */
398 if (BufferLength)
399 {
400 /* Allocate the System Buffer */
401 Irp->AssociatedIrp.SystemBuffer =
402 ExAllocatePoolWithTag(NonPagedPool,
403 BufferLength,
404 TAG_SYS_BUF);
405
406 /* Check if we got a buffer */
407 if (InputBuffer)
408 {
409 /* Copy into the System Buffer */
410 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
411 InputBuffer,
412 InputBufferLength);
413 }
414
415 /* Write the flags */
416 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
417 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
418
419 /* Save the Buffer */
420 Irp->UserBuffer = OutputBuffer;
421 }
422 else
423 {
424 /* Clear the Flags and Buffer */
425 Irp->UserBuffer = NULL;
426 }
427 }
428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
429 {
430 /* Cleanup after exception and return */
431 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
432 _SEH2_YIELD(return _SEH2_GetExceptionCode());
433 }
434 _SEH2_END;
435 break;
436
437 /* Direct I/O */
438 case METHOD_IN_DIRECT:
439 case METHOD_OUT_DIRECT:
440
441 /* Enter SEH */
442 _SEH2_TRY
443 {
444 /* Check if we got an input buffer */
445 if ((InputBufferLength) && (InputBuffer))
446 {
447 /* Allocate the System Buffer */
448 Irp->AssociatedIrp.SystemBuffer =
449 ExAllocatePoolWithTag(NonPagedPool,
450 InputBufferLength,
451 TAG_SYS_BUF);
452
453 /* Copy into the System Buffer */
454 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
455 InputBuffer,
456 InputBufferLength);
457
458 /* Write the flags */
459 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
460 }
461
462 /* Check if we got an output buffer */
463 if (OutputBuffer)
464 {
465 /* Allocate the System Buffer */
466 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
467 OutputBufferLength,
468 FALSE,
469 FALSE,
470 Irp);
471 if (!Irp->MdlAddress)
472 {
473 /* Raise exception we'll catch */
474 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
475 }
476
477 /* Do the probe */
478 MmProbeAndLockPages(Irp->MdlAddress,
479 PreviousMode,
480 (AccessType == METHOD_IN_DIRECT) ?
481 IoReadAccess : IoWriteAccess);
482 }
483 }
484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
485 {
486 /* Cleanup after exception and return */
487 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
488 _SEH2_YIELD(return _SEH2_GetExceptionCode());
489 }
490 _SEH2_END;
491 break;
492
493 case METHOD_NEITHER:
494
495 /* Just save the Buffer */
496 Irp->UserBuffer = OutputBuffer;
497 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
498 }
499
500 /* Use deferred completion for FS I/O */
501 Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
502
503 /* Perform the call */
504 return IopPerformSynchronousRequest(DeviceObject,
505 Irp,
506 FileObject,
507 !IsDevIoCtl,
508 PreviousMode,
509 LockedForSynch,
510 IopOtherTransfer);
511 }
512
513 NTSTATUS
514 NTAPI
515 IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
516 IN ULONG InformationClass,
517 IN ULONG Length,
518 OUT PVOID Information,
519 OUT PULONG ReturnedLength,
520 IN BOOLEAN File)
521 {
522 IO_STATUS_BLOCK IoStatusBlock;
523 PIRP Irp;
524 PDEVICE_OBJECT DeviceObject;
525 PIO_STACK_LOCATION StackPtr;
526 BOOLEAN LocalEvent = FALSE;
527 KEVENT Event;
528 NTSTATUS Status;
529 PAGED_CODE();
530 IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
531 FileObject, InformationClass, File);
532
533 /* Reference the object */
534 ObReferenceObject(FileObject);
535
536 /* Check if this is a file that was opened for Synch I/O */
537 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
538 {
539 /* Lock it */
540 IopLockFileObject(FileObject);
541
542 /* Use File Object event */
543 KeClearEvent(&FileObject->Event);
544 }
545 else
546 {
547 /* Use local event */
548 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
549 LocalEvent = TRUE;
550 }
551
552 /* Get the Device Object */
553 DeviceObject = IoGetRelatedDeviceObject(FileObject);
554
555 /* Allocate the IRP */
556 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
557 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
558
559 /* Set the IRP */
560 Irp->Tail.Overlay.OriginalFileObject = FileObject;
561 Irp->RequestorMode = KernelMode;
562 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
563 Irp->UserIosb = &IoStatusBlock;
564 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
565 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
566 Irp->Flags |= IRP_BUFFERED_IO;
567 Irp->AssociatedIrp.SystemBuffer = Information;
568 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
569
570 /* Set the Stack Data */
571 StackPtr = IoGetNextIrpStackLocation(Irp);
572 StackPtr->MajorFunction = File ? IRP_MJ_QUERY_INFORMATION:
573 IRP_MJ_QUERY_VOLUME_INFORMATION;
574 StackPtr->FileObject = FileObject;
575
576 /* Check which type this is */
577 if (File)
578 {
579 /* Set Parameters */
580 StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
581 StackPtr->Parameters.QueryFile.Length = Length;
582 }
583 else
584 {
585 /* Set Parameters */
586 StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
587 StackPtr->Parameters.QueryVolume.Length = Length;
588 }
589
590 /* Queue the IRP */
591 IopQueueIrpToThread(Irp);
592
593 /* Call the Driver */
594 Status = IoCallDriver(DeviceObject, Irp);
595
596 /* Check if this was synch I/O */
597 if (!LocalEvent)
598 {
599 /* Check if the requet is pending */
600 if (Status == STATUS_PENDING)
601 {
602 /* Wait on the file object */
603 Status = KeWaitForSingleObject(&FileObject->Event,
604 Executive,
605 KernelMode,
606 (FileObject->Flags &
607 FO_ALERTABLE_IO) != 0,
608 NULL);
609 if (Status == STATUS_ALERTED)
610 {
611 /* Abort the operation */
612 IopAbortInterruptedIrp(&FileObject->Event, Irp);
613 }
614
615 /* Get the final status */
616 Status = FileObject->FinalStatus;
617 }
618
619 /* Release the file lock */
620 IopUnlockFileObject(FileObject);
621 }
622 else if (Status == STATUS_PENDING)
623 {
624 /* Wait on the local event and get the final status */
625 KeWaitForSingleObject(&Event,
626 Executive,
627 KernelMode,
628 FALSE,
629 NULL);
630 Status = IoStatusBlock.Status;
631 }
632
633 /* Return the Length and Status. ReturnedLength is NOT optional */
634 *ReturnedLength = (ULONG)IoStatusBlock.Information;
635 return Status;
636 }
637
638 NTSTATUS
639 NTAPI
640 IopGetFileInformation(IN PFILE_OBJECT FileObject,
641 IN ULONG Length,
642 IN FILE_INFORMATION_CLASS FileInfoClass,
643 OUT PVOID Buffer,
644 OUT PULONG ReturnedLength)
645 {
646 PIRP Irp;
647 KEVENT Event;
648 NTSTATUS Status;
649 PIO_STACK_LOCATION Stack;
650 PDEVICE_OBJECT DeviceObject;
651 IO_STATUS_BLOCK IoStatusBlock;
652
653 PAGED_CODE();
654
655 /* Allocate an IRP */
656 ObReferenceObject(FileObject);
657 DeviceObject = IoGetRelatedDeviceObject(FileObject);
658 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
659 if (Irp == NULL)
660 {
661 ObDereferenceObject(FileObject);
662 return STATUS_INSUFFICIENT_RESOURCES;
663 }
664
665 /* 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 PAGED_CODE();
1900 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1901
1902 /* Check if we're called from user mode */
1903 if (PreviousMode != KernelMode)
1904 {
1905 /* Validate the information class */
1906 if ((FileInformationClass >= FileMaximumInformation) ||
1907 !(IopQueryOperationLength[FileInformationClass]))
1908 {
1909 /* Invalid class */
1910 return STATUS_INVALID_INFO_CLASS;
1911 }
1912
1913 /* Validate the length */
1914 if (Length < IopQueryOperationLength[FileInformationClass])
1915 {
1916 /* Invalid length */
1917 return STATUS_INFO_LENGTH_MISMATCH;
1918 }
1919
1920 /* Enter SEH for probing */
1921 _SEH2_TRY
1922 {
1923 /* Probe the I/O Status block */
1924 ProbeForWriteIoStatusBlock(IoStatusBlock);
1925
1926 /* Probe the information */
1927 ProbeForWrite(FileInformation, Length, sizeof(ULONG));
1928 }
1929 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1930 {
1931 /* Return the exception code */
1932 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1933 }
1934 _SEH2_END;
1935 }
1936 else
1937 {
1938 /* Validate the information class */
1939 if ((FileInformationClass >= FileMaximumInformation) ||
1940 !(IopQueryOperationLength[FileInformationClass]))
1941 {
1942 /* Invalid class */
1943 return STATUS_INVALID_INFO_CLASS;
1944 }
1945
1946 /* Validate the length */
1947 if (Length < IopQueryOperationLength[FileInformationClass])
1948 {
1949 /* Invalid length */
1950 return STATUS_INFO_LENGTH_MISMATCH;
1951 }
1952 }
1953
1954 /* Reference the Handle */
1955 Status = ObReferenceObjectByHandle(FileHandle,
1956 IopQueryOperationAccess
1957 [FileInformationClass],
1958 IoFileObjectType,
1959 PreviousMode,
1960 (PVOID *)&FileObject,
1961 &HandleInformation);
1962 if (!NT_SUCCESS(Status)) return Status;
1963
1964 /* Check if this is a direct open or not */
1965 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1966 {
1967 /* Get the device object */
1968 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1969 }
1970 else
1971 {
1972 /* Get the device object */
1973 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1974 }
1975
1976 /* Check if this is a file that was opened for Synch I/O */
1977 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1978 {
1979 /* Lock it */
1980 IopLockFileObject(FileObject);
1981
1982 /* Check if the caller just wants the position */
1983 if (FileInformationClass == FilePositionInformation)
1984 {
1985 /* Protect write in SEH */
1986 _SEH2_TRY
1987 {
1988 /* Write the offset */
1989 ((PFILE_POSITION_INFORMATION)FileInformation)->
1990 CurrentByteOffset = FileObject->CurrentByteOffset;
1991
1992 /* Fill out the I/O Status Block */
1993 IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION);
1994 Status = IoStatusBlock->Status = STATUS_SUCCESS;
1995 }
1996 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1997 {
1998 /* Get the exception code */
1999 Status = _SEH2_GetExceptionCode();
2000 }
2001 _SEH2_END;
2002
2003 /* Release the file lock, dereference the file and return */
2004 IopUnlockFileObject(FileObject);
2005 ObDereferenceObject(FileObject);
2006 return Status;
2007 }
2008 }
2009 else
2010 {
2011 /* Use local event */
2012 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2013 if (!Event)
2014 {
2015 ObDereferenceObject(FileObject);
2016 return STATUS_INSUFFICIENT_RESOURCES;
2017 }
2018 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2019 LocalEvent = TRUE;
2020 }
2021
2022 /* Clear the File Object event */
2023 KeClearEvent(&FileObject->Event);
2024
2025 /* Allocate the IRP */
2026 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2027 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2028
2029 /* Set the IRP */
2030 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2031 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2032 Irp->RequestorMode = PreviousMode;
2033 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2034 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2035 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2036 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2037 Irp->AssociatedIrp.SystemBuffer = NULL;
2038 Irp->MdlAddress = NULL;
2039 Irp->UserBuffer = FileInformation;
2040
2041 /* Set the Stack Data */
2042 StackPtr = IoGetNextIrpStackLocation(Irp);
2043 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2044 StackPtr->FileObject = FileObject;
2045
2046 /* Enter SEH */
2047 _SEH2_TRY
2048 {
2049 /* Allocate a buffer */
2050 Irp->AssociatedIrp.SystemBuffer =
2051 ExAllocatePoolWithTag(NonPagedPool,
2052 Length,
2053 TAG_SYSB);
2054 }
2055 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2056 {
2057 /* Allocating failed, clean up and return the exception code */
2058 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2059 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2060 }
2061 _SEH2_END;
2062
2063 /* Set the flags */
2064 Irp->Flags |= (IRP_BUFFERED_IO |
2065 IRP_DEALLOCATE_BUFFER |
2066 IRP_INPUT_OPERATION |
2067 IRP_DEFER_IO_COMPLETION);
2068
2069 /* Set the Parameters */
2070 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2071 StackPtr->Parameters.QueryFile.Length = Length;
2072
2073 /* Queue the IRP */
2074 IopQueueIrpToThread(Irp);
2075
2076 /* Update operation counts */
2077 IopUpdateOperationCount(IopOtherTransfer);
2078
2079 /* Fill in file information before calling the driver.
2080 See 'File System Internals' page 485.*/
2081 if (FileInformationClass == FileAccessInformation)
2082 {
2083 AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2084 AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2085 Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2086 CallDriver = FALSE;
2087 }
2088 else if (FileInformationClass == FileModeInformation)
2089 {
2090 ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2091 ModeBuffer->Mode = IopGetFileMode(FileObject);
2092 Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2093 CallDriver = FALSE;
2094 }
2095 else if (FileInformationClass == FileAlignmentInformation)
2096 {
2097 AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2098 AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2099 Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2100 CallDriver = FALSE;
2101 }
2102
2103 /* Call the Driver */
2104 if (CallDriver)
2105 {
2106 Status = IoCallDriver(DeviceObject, Irp);
2107 }
2108 else
2109 {
2110 Status = STATUS_SUCCESS;
2111 Irp->IoStatus.Status = STATUS_SUCCESS;
2112 }
2113
2114 if (Status == STATUS_PENDING)
2115 {
2116 /* Check if this was async I/O */
2117 if (LocalEvent)
2118 {
2119 /* Then to a non-alertable wait */
2120 Status = KeWaitForSingleObject(Event,
2121 Executive,
2122 PreviousMode,
2123 FALSE,
2124 NULL);
2125 if (Status == STATUS_USER_APC)
2126 {
2127 /* Abort the request */
2128 IopAbortInterruptedIrp(Event, Irp);
2129 }
2130
2131 /* Set the final status */
2132 Status = KernelIosb.Status;
2133
2134 /* Enter SEH to write the IOSB back */
2135 _SEH2_TRY
2136 {
2137 /* Write it back to the caller */
2138 *IoStatusBlock = KernelIosb;
2139 }
2140 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2141 {
2142 /* Get the exception code */
2143 Status = _SEH2_GetExceptionCode();
2144 }
2145 _SEH2_END;
2146
2147 /* Free the event */
2148 ExFreePoolWithTag(Event, TAG_IO);
2149 }
2150 else
2151 {
2152 /* Wait for the IRP */
2153 Status = KeWaitForSingleObject(&FileObject->Event,
2154 Executive,
2155 PreviousMode,
2156 (FileObject->Flags &
2157 FO_ALERTABLE_IO) != 0,
2158 NULL);
2159 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2160 {
2161 /* Abort the request */
2162 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2163 }
2164
2165 /* Set the final status */
2166 Status = FileObject->FinalStatus;
2167
2168 /* Release the file lock */
2169 IopUnlockFileObject(FileObject);
2170 }
2171 }
2172 else
2173 {
2174 /* Free the event if we had one */
2175 if (LocalEvent)
2176 {
2177 /* Clear it in the IRP for completion */
2178 Irp->UserEvent = NULL;
2179 ExFreePoolWithTag(Event, TAG_IO);
2180 }
2181
2182 /* Set the caller IOSB */
2183 Irp->UserIosb = IoStatusBlock;
2184
2185 /* The IRP wasn't completed, complete it ourselves */
2186 KeRaiseIrql(APC_LEVEL, &OldIrql);
2187 IopCompleteRequest(&Irp->Tail.Apc,
2188 &NormalRoutine,
2189 &NormalContext,
2190 (PVOID*)&FileObject,
2191 &NormalContext);
2192 KeLowerIrql(OldIrql);
2193
2194 /* Release the file object if we had locked it*/
2195 if (!LocalEvent) IopUnlockFileObject(FileObject);
2196 }
2197
2198 /* Return the Status */
2199 return Status;
2200 }
2201
2202 /*
2203 * @unimplemented
2204 */
2205 NTSTATUS
2206 NTAPI
2207 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2208 OUT PIO_STATUS_BLOCK IoStatusBlock,
2209 OUT PVOID Buffer,
2210 IN ULONG Length,
2211 IN BOOLEAN ReturnSingleEntry,
2212 IN PVOID SidList OPTIONAL,
2213 IN ULONG SidListLength,
2214 IN PSID StartSid OPTIONAL,
2215 IN BOOLEAN RestartScan)
2216 {
2217 UNIMPLEMENTED;
2218 return STATUS_NOT_IMPLEMENTED;
2219 }
2220
2221 /*
2222 * @implemented
2223 */
2224 NTSTATUS
2225 NTAPI
2226 NtReadFile(IN HANDLE FileHandle,
2227 IN HANDLE Event OPTIONAL,
2228 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2229 IN PVOID ApcContext OPTIONAL,
2230 OUT PIO_STATUS_BLOCK IoStatusBlock,
2231 OUT PVOID Buffer,
2232 IN ULONG Length,
2233 IN PLARGE_INTEGER ByteOffset OPTIONAL,
2234 IN PULONG Key OPTIONAL)
2235 {
2236 NTSTATUS Status;
2237 PFILE_OBJECT FileObject;
2238 PIRP Irp;
2239 PDEVICE_OBJECT DeviceObject;
2240 PIO_STACK_LOCATION StackPtr;
2241 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2242 PKEVENT EventObject = NULL;
2243 LARGE_INTEGER CapturedByteOffset;
2244 ULONG CapturedKey = 0;
2245 BOOLEAN Synchronous = FALSE;
2246 PMDL Mdl;
2247 PAGED_CODE();
2248 CapturedByteOffset.QuadPart = 0;
2249 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2250
2251 /* Validate User-Mode Buffers */
2252 if (PreviousMode != KernelMode)
2253 {
2254 _SEH2_TRY
2255 {
2256 /* Probe the status block */
2257 ProbeForWriteIoStatusBlock(IoStatusBlock);
2258
2259 /* Probe the read buffer */
2260 ProbeForWrite(Buffer, Length, 1);
2261
2262 /* Check if we got a byte offset */
2263 if (ByteOffset)
2264 {
2265 /* Capture and probe it */
2266 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2267 }
2268
2269 /* Capture and probe the key */
2270 if (Key) CapturedKey = ProbeForReadUlong(Key);
2271 }
2272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2273 {
2274 /* Return the exception code */
2275 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2276 }
2277 _SEH2_END;
2278 }
2279 else
2280 {
2281 /* Kernel mode: capture directly */
2282 if (ByteOffset) CapturedByteOffset = *ByteOffset;
2283 if (Key) CapturedKey = *Key;
2284 }
2285
2286 /* Get File Object */
2287 Status = ObReferenceObjectByHandle(FileHandle,
2288 FILE_READ_DATA,
2289 IoFileObjectType,
2290 PreviousMode,
2291 (PVOID*)&FileObject,
2292 NULL);
2293 if (!NT_SUCCESS(Status)) return Status;
2294
2295 /* Check for event */
2296 if (Event)
2297 {
2298 /* Reference it */
2299 Status = ObReferenceObjectByHandle(Event,
2300 EVENT_MODIFY_STATE,
2301 ExEventObjectType,
2302 PreviousMode,
2303 (PVOID*)&EventObject,
2304 NULL);
2305 if (!NT_SUCCESS(Status))
2306 {
2307 /* Fail */
2308 ObDereferenceObject(FileObject);
2309 return Status;
2310 }
2311
2312 /* Otherwise reset the event */
2313 KeClearEvent(EventObject);
2314 }
2315
2316 /* Check if we should use Sync IO or not */
2317 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2318 {
2319 /* Lock the file object */
2320 IopLockFileObject(FileObject);
2321
2322 /* Check if we don't have a byte offset avilable */
2323 if (!(ByteOffset) ||
2324 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2325 (CapturedByteOffset.u.HighPart == -1)))
2326 {
2327 /* Use the Current Byte Offset instead */
2328 CapturedByteOffset = FileObject->CurrentByteOffset;
2329 }
2330
2331 /* Remember we are sync */
2332 Synchronous = TRUE;
2333 }
2334 else if (!(ByteOffset) &&
2335 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2336 {
2337 /* Otherwise, this was async I/O without a byte offset, so fail */
2338 if (EventObject) ObDereferenceObject(EventObject);
2339 ObDereferenceObject(FileObject);
2340 return STATUS_INVALID_PARAMETER;
2341 }
2342
2343 /* Get the device object */
2344 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2345
2346 /* Clear the File Object's event */
2347 KeClearEvent(&FileObject->Event);
2348
2349 /* Allocate the IRP */
2350 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2351 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
2352
2353 /* Set the IRP */
2354 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2355 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2356 Irp->RequestorMode = PreviousMode;
2357 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2358 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2359 Irp->UserIosb = IoStatusBlock;
2360 Irp->UserEvent = EventObject;
2361 Irp->PendingReturned = FALSE;
2362 Irp->Cancel = FALSE;
2363 Irp->CancelRoutine = NULL;
2364 Irp->AssociatedIrp.SystemBuffer = NULL;
2365 Irp->MdlAddress = NULL;
2366
2367 /* Set the Stack Data */
2368 StackPtr = IoGetNextIrpStackLocation(Irp);
2369 StackPtr->MajorFunction = IRP_MJ_READ;
2370 StackPtr->FileObject = FileObject;
2371 StackPtr->Parameters.Read.Key = CapturedKey;
2372 StackPtr->Parameters.Read.Length = Length;
2373 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2374
2375 /* Check if this is buffered I/O */
2376 if (DeviceObject->Flags & DO_BUFFERED_IO)
2377 {
2378 /* Check if we have a buffer length */
2379 if (Length)
2380 {
2381 /* Enter SEH */
2382 _SEH2_TRY
2383 {
2384 /* Allocate a buffer */
2385 Irp->AssociatedIrp.SystemBuffer =
2386 ExAllocatePoolWithTag(NonPagedPool,
2387 Length,
2388 TAG_SYSB);
2389 }
2390 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2391 {
2392 /* Allocating failed, clean up and return the exception code */
2393 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2394 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2395 }
2396 _SEH2_END;
2397
2398 /* Set the buffer and flags */
2399 Irp->UserBuffer = Buffer;
2400 Irp->Flags = (IRP_BUFFERED_IO |
2401 IRP_DEALLOCATE_BUFFER |
2402 IRP_INPUT_OPERATION);
2403 }
2404 else
2405 {
2406 /* Not reading anything */
2407 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
2408 }
2409 }
2410 else if (DeviceObject->Flags & DO_DIRECT_IO)
2411 {
2412 /* Check if we have a buffer length */
2413 if (Length)
2414 {
2415 _SEH2_TRY
2416 {
2417 /* Allocate an MDL */
2418 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
2419 if (!Mdl)
2420 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
2421 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
2422 }
2423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2424 {
2425 /* Allocating failed, clean up and return the exception code */
2426 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2427 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2428 }
2429 _SEH2_END;
2430
2431 }
2432
2433 /* No allocation flags */
2434 Irp->Flags = 0;
2435 }
2436 else
2437 {
2438 /* No allocation flags, and use the buffer directly */
2439 Irp->Flags = 0;
2440 Irp->UserBuffer = Buffer;
2441 }
2442
2443 /* Now set the deferred read flags */
2444 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);
2445 #if 0
2446 /* FIXME: VFAT SUCKS */
2447 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2448 #endif
2449
2450 /* Perform the call */
2451 return IopPerformSynchronousRequest(DeviceObject,
2452 Irp,
2453 FileObject,
2454 TRUE,
2455 PreviousMode,
2456 Synchronous,
2457 IopReadTransfer);
2458 }
2459
2460 /*
2461 * @unimplemented
2462 */
2463 NTSTATUS
2464 NTAPI
2465 NtReadFileScatter(IN HANDLE FileHandle,
2466 IN HANDLE Event OPTIONAL,
2467 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2468 IN PVOID UserApcContext OPTIONAL,
2469 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2470 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2471 IN ULONG BufferLength,
2472 IN PLARGE_INTEGER ByteOffset,
2473 IN PULONG Key OPTIONAL)
2474 {
2475 UNIMPLEMENTED;
2476 return STATUS_NOT_IMPLEMENTED;
2477 }
2478
2479 /*
2480 * @unimplemented
2481 */
2482 NTSTATUS
2483 NTAPI
2484 NtSetEaFile(IN HANDLE FileHandle,
2485 IN PIO_STATUS_BLOCK IoStatusBlock,
2486 IN PVOID EaBuffer,
2487 IN ULONG EaBufferSize)
2488 {
2489 UNIMPLEMENTED;
2490 return STATUS_NOT_IMPLEMENTED;
2491 }
2492
2493 /*
2494 * @implemented
2495 */
2496 NTSTATUS
2497 NTAPI
2498 NtSetInformationFile(IN HANDLE FileHandle,
2499 OUT PIO_STATUS_BLOCK IoStatusBlock,
2500 IN PVOID FileInformation,
2501 IN ULONG Length,
2502 IN FILE_INFORMATION_CLASS FileInformationClass)
2503 {
2504 PFILE_OBJECT FileObject;
2505 NTSTATUS Status;
2506 PIRP Irp;
2507 PDEVICE_OBJECT DeviceObject;
2508 PIO_STACK_LOCATION StackPtr;
2509 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2510 PKEVENT Event = NULL;
2511 BOOLEAN LocalEvent = FALSE;
2512 PKNORMAL_ROUTINE NormalRoutine;
2513 PVOID NormalContext;
2514 KIRQL OldIrql;
2515 IO_STATUS_BLOCK KernelIosb;
2516 PVOID Queue;
2517 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2518 PIO_COMPLETION_CONTEXT Context;
2519 PFILE_RENAME_INFORMATION RenameInfo;
2520 HANDLE TargetHandle = NULL;
2521 PAGED_CODE();
2522 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2523
2524 /* Check if we're called from user mode */
2525 if (PreviousMode != KernelMode)
2526 {
2527 /* Validate the information class */
2528 if ((FileInformationClass >= FileMaximumInformation) ||
2529 !(IopSetOperationLength[FileInformationClass]))
2530 {
2531 /* Invalid class */
2532 return STATUS_INVALID_INFO_CLASS;
2533 }
2534
2535 /* Validate the length */
2536 if (Length < IopSetOperationLength[FileInformationClass])
2537 {
2538 /* Invalid length */
2539 return STATUS_INFO_LENGTH_MISMATCH;
2540 }
2541
2542 /* Enter SEH for probing */
2543 _SEH2_TRY
2544 {
2545 /* Probe the I/O Status block */
2546 ProbeForWriteIoStatusBlock(IoStatusBlock);
2547
2548 /* Probe the information */
2549 ProbeForRead(FileInformation,
2550 Length,
2551 (Length == sizeof(BOOLEAN)) ?
2552 sizeof(BOOLEAN) : sizeof(ULONG));
2553 }
2554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2555 {
2556 /* Return the exception code */
2557 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2558 }
2559 _SEH2_END;
2560 }
2561 else
2562 {
2563 /* Validate the information class */
2564 if ((FileInformationClass >= FileMaximumInformation) ||
2565 !(IopSetOperationLength[FileInformationClass]))
2566 {
2567 /* Invalid class */
2568 return STATUS_INVALID_INFO_CLASS;
2569 }
2570
2571 /* Validate the length */
2572 if (Length < IopSetOperationLength[FileInformationClass])
2573 {
2574 /* Invalid length */
2575 return STATUS_INFO_LENGTH_MISMATCH;
2576 }
2577 }
2578
2579 /* Reference the Handle */
2580 Status = ObReferenceObjectByHandle(FileHandle,
2581 IopSetOperationAccess
2582 [FileInformationClass],
2583 IoFileObjectType,
2584 PreviousMode,
2585 (PVOID *)&FileObject,
2586 NULL);
2587 if (!NT_SUCCESS(Status)) return Status;
2588
2589 /* Check if this is a direct open or not */
2590 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2591 {
2592 /* Get the device object */
2593 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2594 }
2595 else
2596 {
2597 /* Get the device object */
2598 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2599 }
2600
2601 /* Check if this is a file that was opened for Synch I/O */
2602 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2603 {
2604 /* Lock it */
2605 IopLockFileObject(FileObject);
2606
2607 /* Check if the caller just wants the position */
2608 if (FileInformationClass == FilePositionInformation)
2609 {
2610 /* Protect write in SEH */
2611 _SEH2_TRY
2612 {
2613 /* Write the offset */
2614 FileObject->CurrentByteOffset =
2615 ((PFILE_POSITION_INFORMATION)FileInformation)->
2616 CurrentByteOffset;
2617
2618 /* Fill out the I/O Status Block */
2619 IoStatusBlock->Information = 0;
2620 Status = IoStatusBlock->Status = STATUS_SUCCESS;
2621 }
2622 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2623 {
2624 /* Get the exception code */
2625 Status = _SEH2_GetExceptionCode();
2626 }
2627 _SEH2_END;
2628
2629 /* Update transfer count */
2630 IopUpdateTransferCount(IopOtherTransfer, Length);
2631
2632 /* Release the file lock, dereference the file and return */
2633 IopUnlockFileObject(FileObject);
2634 ObDereferenceObject(FileObject);
2635 return Status;
2636 }
2637 }
2638 else
2639 {
2640 /* Use local event */
2641 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
2642 if (!Event)
2643 {
2644 ObDereferenceObject(FileObject);
2645 return STATUS_INSUFFICIENT_RESOURCES;
2646 }
2647
2648 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
2649 LocalEvent = TRUE;
2650 }
2651
2652 /* Clear the File Object event */
2653 KeClearEvent(&FileObject->Event);
2654
2655 /* Allocate the IRP */
2656 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2657 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2658
2659 /* Set the IRP */
2660 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2661 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2662 Irp->RequestorMode = PreviousMode;
2663 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2664 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2665 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2666 Irp->UserEvent = (LocalEvent) ? Event : NULL;
2667 Irp->AssociatedIrp.SystemBuffer = NULL;
2668 Irp->MdlAddress = NULL;
2669 Irp->UserBuffer = FileInformation;
2670
2671 /* Set the Stack Data */
2672 StackPtr = IoGetNextIrpStackLocation(Irp);
2673 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
2674 StackPtr->FileObject = FileObject;
2675
2676 /* Enter SEH */
2677 _SEH2_TRY
2678 {
2679 /* Allocate a buffer */
2680 Irp->AssociatedIrp.SystemBuffer =
2681 ExAllocatePoolWithTag(NonPagedPool,
2682 Length,
2683 TAG_SYSB);
2684
2685 /* Copy the data into it */
2686 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2687 FileInformation,
2688 Length);
2689 }
2690 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2691 {
2692 /* Allocating failed, clean up and return the exception code */
2693 IopCleanupAfterException(FileObject, Irp, NULL, Event);
2694 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2695 }
2696 _SEH2_END;
2697
2698 /* Set the flags */
2699 Irp->Flags |= (IRP_BUFFERED_IO |
2700 IRP_DEALLOCATE_BUFFER |
2701 IRP_DEFER_IO_COMPLETION);
2702
2703 /* Set the Parameters */
2704 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
2705 StackPtr->Parameters.SetFile.Length = Length;
2706
2707 /* Queue the IRP */
2708 IopQueueIrpToThread(Irp);
2709
2710 /* Update operation counts */
2711 IopUpdateOperationCount(IopOtherTransfer);
2712
2713 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
2714 /* Handle IO Completion Port quickly */
2715 if (FileInformationClass == FileCompletionInformation)
2716 {
2717 /* Check if the file object already has a completion port */
2718 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
2719 (FileObject->CompletionContext))
2720 {
2721 /* Fail */
2722 Status = STATUS_INVALID_PARAMETER;
2723 }
2724 else
2725 {
2726 /* Reference the Port */
2727 CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
2728 Status = ObReferenceObjectByHandle(CompletionInfo->Port,
2729 IO_COMPLETION_MODIFY_STATE,
2730 IoCompletionType,
2731 PreviousMode,
2732 (PVOID*)&Queue,
2733 NULL);
2734 if (NT_SUCCESS(Status))
2735 {
2736 /* Allocate the Context */
2737 Context = ExAllocatePoolWithTag(PagedPool,
2738 sizeof(IO_COMPLETION_CONTEXT),
2739 IOC_TAG);
2740 if (Context)
2741 {
2742 /* Set the Data */
2743 Context->Key = CompletionInfo->Key;
2744 Context->Port = Queue;
2745 if (InterlockedCompareExchangePointer((PVOID*)&FileObject->
2746 CompletionContext,
2747 Context,
2748 NULL))
2749 {
2750 /*
2751 * Someone else set the completion port in the
2752 * meanwhile, so dereference the port and fail.
2753 */
2754 ExFreePoolWithTag(Context, IOC_TAG);
2755 ObDereferenceObject(Queue);
2756 Status = STATUS_INVALID_PARAMETER;
2757 }
2758 }
2759 else
2760 {
2761 /* Dereference the Port now */
2762 ObDereferenceObject(Queue);
2763 Status = STATUS_INSUFFICIENT_RESOURCES;
2764 }
2765 }
2766 }
2767
2768 /* Set the IRP Status */
2769 Irp->IoStatus.Status = Status;
2770 Irp->IoStatus.Information = 0;
2771 }
2772 else if (FileInformationClass == FileRenameInformation ||
2773 FileInformationClass == FileLinkInformation ||
2774 FileInformationClass == FileMoveClusterInformation)
2775 {
2776 /* Get associated information */
2777 RenameInfo = Irp->AssociatedIrp.SystemBuffer;
2778
2779 /* Only rename if:
2780 * -> We have a name
2781 * -> In unicode
2782 * -> sizes are valid
2783 */
2784 if (RenameInfo->FileNameLength != 0 &&
2785 !(RenameInfo->FileNameLength & 1) &&
2786 (Length - FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) >= RenameInfo->FileNameLength))
2787 {
2788 /* Properly set information received */
2789 if (FileInformationClass == FileMoveClusterInformation)
2790 {
2791 StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
2792 }
2793 else
2794 {
2795 StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
2796 }
2797
2798 /* If we got fully path OR relative target, attempt a parent directory open */
2799 if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
2800 {
2801 Status = IopOpenLinkOrRenameTarget(&TargetHandle, Irp, RenameInfo, FileObject);
2802 if (!NT_SUCCESS(Status))
2803 {
2804 Irp->IoStatus.Status = Status;
2805 }
2806 else
2807 {
2808 /* Call the Driver */
2809 Status = IoCallDriver(DeviceObject, Irp);
2810 }
2811 }
2812 else
2813 {
2814 /* Call the Driver */
2815 Status = IoCallDriver(DeviceObject, Irp);
2816 }
2817 }
2818 else
2819 {
2820 Status = STATUS_INVALID_PARAMETER;
2821 Irp->IoStatus.Status = Status;
2822 }
2823 }
2824 else
2825 {
2826 /* Call the Driver */
2827 Status = IoCallDriver(DeviceObject, Irp);
2828 }
2829
2830 /* Check if we're waiting for the IRP to complete */
2831 if (Status == STATUS_PENDING)
2832 {
2833 /* Check if this was async I/O */
2834 if (LocalEvent)
2835 {
2836 /* Then to a non-alertable wait */
2837 Status = KeWaitForSingleObject(Event,
2838 Executive,
2839 PreviousMode,
2840 FALSE,
2841 NULL);
2842 if (Status == STATUS_USER_APC)
2843 {
2844 /* Abort the request */
2845 IopAbortInterruptedIrp(Event, Irp);
2846 }
2847
2848 /* Set the final status */
2849 Status = KernelIosb.Status;
2850
2851 /* Enter SEH to write the IOSB back */
2852 _SEH2_TRY
2853 {
2854 /* Write it back to the caller */
2855 *IoStatusBlock = KernelIosb;
2856 }
2857 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2858 {
2859 /* Get the exception code */
2860 Status = _SEH2_GetExceptionCode();
2861 }
2862 _SEH2_END;
2863
2864 /* Free the event */
2865 ExFreePoolWithTag(Event, TAG_IO);
2866 }
2867 else
2868 {
2869 /* Wait for the IRP */
2870 Status = KeWaitForSingleObject(&FileObject->Event,
2871 Executive,
2872 PreviousMode,
2873 (FileObject->Flags &
2874 FO_ALERTABLE_IO) != 0,
2875 NULL);
2876 if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2877 {
2878 /* Abort the request */
2879 IopAbortInterruptedIrp(&FileObject->Event, Irp);
2880 }
2881
2882 /* Set the final status */
2883 Status = FileObject->FinalStatus;
2884
2885 /* Release the file lock */
2886 IopUnlockFileObject(FileObject);
2887 }
2888 }
2889 else
2890 {
2891 /* Free the event if we had one */
2892 if (LocalEvent)
2893 {
2894 /* Clear it in the IRP for completion */
2895 Irp->UserEvent = NULL;
2896 ExFreePoolWithTag(Event, TAG_IO);
2897 }
2898
2899 /* Set the caller IOSB */
2900 Irp->UserIosb = IoStatusBlock;
2901
2902 /* The IRP wasn't completed, complete it ourselves */
2903 KeRaiseIrql(APC_LEVEL, &OldIrql);
2904 IopCompleteRequest(&Irp->Tail.Apc,
2905 &NormalRoutine,
2906 &NormalContext,
2907 (PVOID*)&FileObject,
2908 &NormalContext);
2909 KeLowerIrql(OldIrql);
2910
2911 /* Release the file object if we had locked it*/
2912 if (!LocalEvent) IopUnlockFileObject(FileObject);
2913 }
2914
2915 if (TargetHandle != NULL)
2916 {
2917 ObCloseHandle(TargetHandle, KernelMode);
2918 }
2919
2920 /* Return the Status */
2921 return Status;
2922 }
2923
2924 /*
2925 * @unimplemented
2926 */
2927 NTSTATUS
2928 NTAPI
2929 NtSetQuotaInformationFile(IN HANDLE FileHandle,
2930 OUT PIO_STATUS_BLOCK IoStatusBlock,
2931 IN PVOID Buffer,
2932 IN ULONG BufferLength)
2933 {
2934 UNIMPLEMENTED;
2935 return STATUS_NOT_IMPLEMENTED;
2936 }
2937
2938 /*
2939 * @implemented
2940 */
2941 NTSTATUS
2942 NTAPI
2943 NtUnlockFile(IN HANDLE FileHandle,
2944 OUT PIO_STATUS_BLOCK IoStatusBlock,
2945 IN PLARGE_INTEGER ByteOffset,
2946 IN PLARGE_INTEGER Length,
2947 IN ULONG Key OPTIONAL)
2948 {
2949 PFILE_OBJECT FileObject;
2950 PLARGE_INTEGER LocalLength = NULL;
2951 PIRP Irp;
2952 PIO_STACK_LOCATION StackPtr;
2953 PDEVICE_OBJECT DeviceObject;
2954 PKEVENT Event = NULL;
2955 BOOLEAN LocalEvent = FALSE;
2956 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2957 LARGE_INTEGER CapturedByteOffset, CapturedLength;
2958 NTSTATUS Status;
2959 OBJECT_HANDLE_INFORMATION HandleInformation;
2960 IO_STATUS_BLOCK KernelIosb;
2961 PAGED_CODE();
2962 CapturedByteOffset.QuadPart = 0;
2963 CapturedLength.QuadPart = 0;
2964 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2965
2966 /* Get File Object */
2967 Status = ObReferenceObjectByHandle(FileHandle,
2968 0,
2969 IoFileObjectType,
2970 PreviousMode,
2971 (PVOID*)&FileObject,
2972 &HandleInformation);
2973 if (!NT_SUCCESS(Status)) return Status;
2974
2975 /* Check if we're called from user mode */
2976 if (PreviousMode != KernelMode)
2977 {
2978 /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
2979 if (!(HandleInformation.GrantedAccess &
2980 (FILE_WRITE_DATA | FILE_READ_DATA)))
2981 {
2982 ObDereferenceObject(FileObject);
2983 return STATUS_ACCESS_DENIED;
2984 }
2985
2986 /* Enter SEH for probing */
2987 _SEH2_TRY
2988 {
2989 /* Probe the I/O Status block */
2990 ProbeForWriteIoStatusBlock(IoStatusBlock);
2991
2992 /* Probe and capture the large integers */
2993 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2994 CapturedLength = ProbeForReadLargeInteger(Length);
2995 }
2996 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2997 {
2998 /* Dereference the object and return exception code */
2999 ObDereferenceObject(FileObject);
3000 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3001 }
3002 _SEH2_END;
3003 }
3004 else
3005 {
3006 /* Otherwise, capture them directly */
3007 CapturedByteOffset = *ByteOffset;
3008 CapturedLength = *Length;
3009 }
3010
3011 /* Check if this is a direct open or not */
3012 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3013 {
3014 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3015 }
3016 else
3017 {
3018 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3019 }
3020
3021 /* Check if we should use Sync IO or not */
3022 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3023 {
3024 /* Lock it */
3025 IopLockFileObject(FileObject);
3026 }
3027 else
3028 {
3029 /* Use local event */
3030 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3031 if (!Event)
3032 {
3033 ObDereferenceObject(FileObject);
3034 return STATUS_INSUFFICIENT_RESOURCES;
3035 }
3036 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3037 LocalEvent = TRUE;
3038 }
3039
3040 /* Clear File Object event */
3041 KeClearEvent(&FileObject->Event);
3042
3043 /* Allocate the IRP */
3044 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3045 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3046
3047 /* Set up the IRP */
3048 Irp->RequestorMode = PreviousMode;
3049 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3050 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3051 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3052 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3053 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3054 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3055
3056 /* Set up Stack Data */
3057 StackPtr = IoGetNextIrpStackLocation(Irp);
3058 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3059 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3060 StackPtr->FileObject = FileObject;
3061
3062 /* Enter SEH */
3063 _SEH2_TRY
3064 {
3065 /* Allocate a buffer */
3066 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3067 sizeof(LARGE_INTEGER),
3068 TAG_LOCK);
3069
3070 /* Set the length */
3071 *LocalLength = CapturedLength;
3072 Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3073 StackPtr->Parameters.LockControl.Length = LocalLength;
3074 }
3075 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3076 {
3077 /* Allocating failed, clean up and return the exception code */
3078 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3079 if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3080
3081 /* Return the exception code */
3082 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3083 }
3084 _SEH2_END;
3085
3086 /* Set Parameters */
3087 StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3088 StackPtr->Parameters.LockControl.Key = Key;
3089
3090 /* Call the Driver */
3091 Status = IopPerformSynchronousRequest(DeviceObject,
3092 Irp,
3093 FileObject,
3094 FALSE,
3095 PreviousMode,
3096 !LocalEvent,
3097 IopOtherTransfer);
3098
3099 /* Check if this was async I/O */
3100 if (LocalEvent)
3101 {
3102 /* It was, finalize this request */
3103 Status = IopFinalizeAsynchronousIo(Status,
3104 Event,
3105 Irp,
3106 PreviousMode,
3107 &KernelIosb,
3108 IoStatusBlock);
3109 }
3110
3111 /* Return status */
3112 return Status;
3113 }
3114
3115 /*
3116 * @implemented
3117 */
3118 NTSTATUS
3119 NTAPI
3120 NtWriteFile(IN HANDLE FileHandle,
3121 IN HANDLE Event OPTIONAL,
3122 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
3123 IN PVOID ApcContext OPTIONAL,
3124 OUT PIO_STATUS_BLOCK IoStatusBlock,
3125 IN PVOID Buffer,
3126 IN ULONG Length,
3127 IN PLARGE_INTEGER ByteOffset OPTIONAL,
3128 IN PULONG Key OPTIONAL)
3129 {
3130 NTSTATUS Status;
3131 PFILE_OBJECT FileObject;
3132 PIRP Irp;
3133 PDEVICE_OBJECT DeviceObject;
3134 PIO_STACK_LOCATION StackPtr;
3135 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3136 PKEVENT EventObject = NULL;
3137 LARGE_INTEGER CapturedByteOffset;
3138 ULONG CapturedKey = 0;
3139 BOOLEAN Synchronous = FALSE;
3140 PMDL Mdl;
3141 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3142 PAGED_CODE();
3143 CapturedByteOffset.QuadPart = 0;
3144 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3145
3146 /* Get File Object */
3147 Status = ObReferenceObjectByHandle(FileHandle,
3148 0,
3149 IoFileObjectType,
3150 PreviousMode,
3151 (PVOID*)&FileObject,
3152 &ObjectHandleInfo);
3153 if (!NT_SUCCESS(Status)) return Status;
3154
3155 /* Validate User-Mode Buffers */
3156 if (PreviousMode != KernelMode)
3157 {
3158 _SEH2_TRY
3159 {
3160 /*
3161 * Check if the handle has either FILE_WRITE_DATA or
3162 * FILE_APPEND_DATA granted. However, if this is a named pipe,
3163 * make sure we don't ask for FILE_APPEND_DATA as it interferes
3164 * with the FILE_CREATE_PIPE_INSTANCE access right!
3165 */
3166 if (!(ObjectHandleInfo.GrantedAccess &
3167 ((!(FileObject->Flags & FO_NAMED_PIPE) ?
3168 FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))
3169 {
3170 /* We failed */
3171 ObDereferenceObject(FileObject);
3172 _SEH2_YIELD(return STATUS_ACCESS_DENIED);
3173 }
3174
3175 /* Probe the status block */
3176 ProbeForWriteIoStatusBlock(IoStatusBlock);
3177
3178 /* Probe the read buffer */
3179 ProbeForRead(Buffer, Length, 1);
3180
3181 /* Check if we got a byte offset */
3182 if (ByteOffset)
3183 {
3184 /* Capture and probe it */
3185 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3186 }
3187
3188 /* Capture and probe the key */
3189 if (Key) CapturedKey = ProbeForReadUlong(Key);
3190 }
3191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3192 {
3193 /* Return the exception code */
3194 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3195 }
3196 _SEH2_END;
3197 }
3198 else
3199 {
3200 /* Kernel mode: capture directly */
3201 if (ByteOffset) CapturedByteOffset = *ByteOffset;
3202 if (Key) CapturedKey = *Key;
3203 }
3204
3205 /* Check if this is an append operation */
3206 if ((ObjectHandleInfo.GrantedAccess &
3207 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)
3208 {
3209 /* Give the drivers something to understand */
3210 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3211 CapturedByteOffset.u.HighPart = -1;
3212 }
3213
3214 /* Check for event */
3215 if (Event)
3216 {
3217 /* Reference it */
3218 Status = ObReferenceObjectByHandle(Event,
3219 EVENT_MODIFY_STATE,
3220 ExEventObjectType,
3221 PreviousMode,
3222 (PVOID*)&EventObject,
3223 NULL);
3224 if (!NT_SUCCESS(Status))
3225 {
3226 /* Fail */
3227 ObDereferenceObject(FileObject);
3228 return Status;
3229 }
3230
3231 /* Otherwise reset the event */
3232 KeClearEvent(EventObject);
3233 }
3234
3235 /* Check if we should use Sync IO or not */
3236 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3237 {
3238 /* Lock the file object */
3239 IopLockFileObject(FileObject);
3240
3241 /* Check if we don't have a byte offset avilable */
3242 if (!(ByteOffset) ||
3243 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3244 (CapturedByteOffset.u.HighPart == -1)))
3245 {
3246 /* Use the Current Byte Offset instead */
3247 CapturedByteOffset = FileObject->CurrentByteOffset;
3248 }
3249
3250 /* Remember we are sync */
3251 Synchronous = TRUE;
3252 }
3253 else if (!(ByteOffset) &&
3254 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3255 {
3256 /* Otherwise, this was async I/O without a byte offset, so fail */
3257 if (EventObject) ObDereferenceObject(EventObject);
3258 ObDereferenceObject(FileObject);
3259 return STATUS_INVALID_PARAMETER;
3260 }
3261
3262 /* Get the device object */
3263 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3264
3265 /* Clear the File Object's event */
3266 KeClearEvent(&FileObject->Event);
3267
3268 /* Allocate the IRP */
3269 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3270 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
3271
3272 /* Set the IRP */
3273 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3274 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3275 Irp->RequestorMode = PreviousMode;
3276 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3277 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3278 Irp->UserIosb = IoStatusBlock;
3279 Irp->UserEvent = EventObject;
3280 Irp->PendingReturned = FALSE;
3281 Irp->Cancel = FALSE;
3282 Irp->CancelRoutine = NULL;
3283 Irp->AssociatedIrp.SystemBuffer = NULL;
3284 Irp->MdlAddress = NULL;
3285
3286 /* Set the Stack Data */
3287 StackPtr = IoGetNextIrpStackLocation(Irp);
3288 StackPtr->MajorFunction = IRP_MJ_WRITE;
3289 StackPtr->FileObject = FileObject;
3290 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
3291 SL_WRITE_THROUGH : 0;
3292 StackPtr->Parameters.Write.Key = CapturedKey;
3293 StackPtr->Parameters.Write.Length = Length;
3294 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
3295
3296 /* Check if this is buffered I/O */
3297 if (DeviceObject->Flags & DO_BUFFERED_IO)
3298 {
3299 /* Check if we have a buffer length */
3300 if (Length)
3301 {
3302 /* Enter SEH */
3303 _SEH2_TRY
3304 {
3305 /* Allocate a buffer */
3306 Irp->AssociatedIrp.SystemBuffer =
3307 ExAllocatePoolWithTag(NonPagedPool,
3308 Length,
3309 TAG_SYSB);
3310
3311 /* Copy the data into it */
3312 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
3313 }
3314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3315 {
3316 /* Allocating failed, clean up and return the exception code */
3317 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3319 }
3320 _SEH2_END;
3321
3322 /* Set the flags */
3323 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3324 }
3325 else
3326 {
3327 /* Not writing anything */
3328 Irp->Flags = IRP_BUFFERED_IO;
3329 }
3330 }
3331 else if (DeviceObject->Flags & DO_DIRECT_IO)
3332 {
3333 /* Check if we have a buffer length */
3334 if (Length)
3335 {
3336 _SEH2_TRY
3337 {
3338 /* Allocate an MDL */
3339 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
3340 if (!Mdl)
3341 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
3342 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
3343 }
3344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3345 {
3346 /* Allocating failed, clean up and return the exception code */
3347 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3348 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3349 }
3350 _SEH2_END;
3351 }
3352
3353 /* No allocation flags */
3354 Irp->Flags = 0;
3355 }
3356 else
3357 {
3358 /* No allocation flags, and use the buffer directly */
3359 Irp->Flags = 0;
3360 Irp->UserBuffer = Buffer;
3361 }
3362
3363 /* Now set the deferred read flags */
3364 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);
3365 #if 0
3366 /* FIXME: VFAT SUCKS */
3367 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3368 #endif
3369
3370 /* Perform the call */
3371 return IopPerformSynchronousRequest(DeviceObject,
3372 Irp,
3373 FileObject,
3374 TRUE,
3375 PreviousMode,
3376 Synchronous,
3377 IopWriteTransfer);
3378 }
3379
3380 NTSTATUS
3381 NTAPI
3382 NtWriteFileGather(IN HANDLE FileHandle,
3383 IN HANDLE Event OPTIONAL,
3384 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3385 IN PVOID UserApcContext OPTIONAL,
3386 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3387 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3388 IN ULONG BufferLength,
3389 IN PLARGE_INTEGER ByteOffset,
3390 IN PULONG Key OPTIONAL)
3391 {
3392 UNIMPLEMENTED;
3393 return STATUS_NOT_IMPLEMENTED;
3394 }
3395
3396 /*
3397 * @implemented
3398 */
3399 NTSTATUS
3400 NTAPI
3401 NtQueryVolumeInformationFile(IN HANDLE FileHandle,
3402 OUT PIO_STATUS_BLOCK IoStatusBlock,
3403 OUT PVOID FsInformation,
3404 IN ULONG Length,
3405 IN FS_INFORMATION_CLASS FsInformationClass)
3406 {
3407 PFILE_OBJECT FileObject;
3408 PIRP Irp;
3409 PIO_STACK_LOCATION StackPtr;
3410 PDEVICE_OBJECT DeviceObject;
3411 PKEVENT Event = NULL;
3412 BOOLEAN LocalEvent = FALSE;
3413 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3414 NTSTATUS Status;
3415 IO_STATUS_BLOCK KernelIosb;
3416 PAGED_CODE();
3417 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3418
3419 /* Check if we're called from user mode */
3420 if (PreviousMode != KernelMode)
3421 {
3422 /* Validate the information class */
3423 if ((FsInformationClass >= FileFsMaximumInformation) ||
3424 !(IopQueryFsOperationLength[FsInformationClass]))
3425 {
3426 /* Invalid class */
3427 return STATUS_INVALID_INFO_CLASS;
3428 }
3429
3430 /* Validate the length */
3431 if (Length < IopQueryFsOperationLength[FsInformationClass])
3432 {
3433 /* Invalid length */
3434 return STATUS_INFO_LENGTH_MISMATCH;
3435 }
3436
3437 /* Enter SEH for probing */
3438 _SEH2_TRY
3439 {
3440 /* Probe the I/O Status block */
3441 ProbeForWriteIoStatusBlock(IoStatusBlock);
3442
3443 /* Probe the information */
3444 ProbeForWrite(FsInformation, Length, sizeof(ULONG));
3445 }
3446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3447 {
3448 /* Return the exception code */
3449 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3450 }
3451 _SEH2_END;
3452 }
3453
3454 /* Get File Object */
3455 Status = ObReferenceObjectByHandle(FileHandle,
3456 IopQueryFsOperationAccess
3457 [FsInformationClass],
3458 IoFileObjectType,
3459 PreviousMode,
3460 (PVOID*)&FileObject,
3461 NULL);
3462 if (!NT_SUCCESS(Status)) return Status;
3463
3464 /* Check if we should use Sync IO or not */
3465 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3466 {
3467 /* Lock it */
3468 IopLockFileObject(FileObject);
3469 }
3470 else
3471 {
3472 /* Use local event */
3473 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3474 if (!Event)
3475 {
3476 ObDereferenceObject(FileObject);
3477 return STATUS_INSUFFICIENT_RESOURCES;
3478 }
3479 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3480 LocalEvent = TRUE;
3481 }
3482
3483 /* Get the device object */
3484 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3485
3486 /* Clear File Object event */
3487 KeClearEvent(&FileObject->Event);
3488
3489 /* Allocate the IRP */
3490 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3491 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3492
3493 /* Set up the IRP */
3494 Irp->RequestorMode = PreviousMode;
3495 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3496 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3497 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3498 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3499 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3500 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3501 Irp->UserBuffer = FsInformation;
3502 Irp->AssociatedIrp.SystemBuffer = NULL;
3503 Irp->MdlAddress = NULL;
3504
3505 /* Set up Stack Data */
3506 StackPtr = IoGetNextIrpStackLocation(Irp);
3507 StackPtr->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
3508 StackPtr->FileObject = FileObject;
3509
3510 /* Enter SEH */
3511 _SEH2_TRY
3512 {
3513 /* Allocate a buffer */
3514 Irp->AssociatedIrp.SystemBuffer =
3515 ExAllocatePoolWithTag(NonPagedPool,
3516 Length,
3517 TAG_SYSB);
3518 }
3519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3520 {
3521 /* Allocating failed, clean up and return the exception code */
3522 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3523 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3524 }
3525 _SEH2_END;
3526
3527 /* Set the flags for this buffered + deferred I/O */
3528 Irp->Flags |= (IRP_BUFFERED_IO |
3529 IRP_DEALLOCATE_BUFFER |
3530 IRP_INPUT_OPERATION |
3531 IRP_DEFER_IO_COMPLETION);
3532
3533 /* Set Parameters */
3534 StackPtr->Parameters.QueryVolume.Length = Length;
3535 StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
3536
3537 /* Call the Driver */
3538 Status = IopPerformSynchronousRequest(DeviceObject,
3539 Irp,
3540 FileObject,
3541 TRUE,
3542 PreviousMode,
3543 !LocalEvent,
3544 IopOtherTransfer);
3545
3546 /* Check if this was async I/O */
3547 if (LocalEvent)
3548 {
3549 /* It was, finalize this request */
3550 Status = IopFinalizeAsynchronousIo(Status,
3551 Event,
3552 Irp,
3553 PreviousMode,
3554 &KernelIosb,
3555 IoStatusBlock);
3556 }
3557
3558 /* Return status */
3559 return Status;
3560 }
3561
3562 /*
3563 * @implemented
3564 */
3565 NTSTATUS
3566 NTAPI
3567 NtSetVolumeInformationFile(IN HANDLE FileHandle,
3568 OUT PIO_STATUS_BLOCK IoStatusBlock,
3569 IN PVOID FsInformation,
3570 IN ULONG Length,
3571 IN FS_INFORMATION_CLASS FsInformationClass)
3572 {
3573 PFILE_OBJECT FileObject;
3574 PIRP Irp;
3575 PIO_STACK_LOCATION StackPtr;
3576 PDEVICE_OBJECT DeviceObject, TargetDeviceObject;
3577 PKEVENT Event = NULL;
3578 BOOLEAN LocalEvent = FALSE;
3579 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3580 NTSTATUS Status;
3581 IO_STATUS_BLOCK KernelIosb;
3582 TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure;
3583 PAGED_CODE();
3584 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3585
3586 /* Check if we're called from user mode */
3587 if (PreviousMode != KernelMode)
3588 {
3589 /* Validate the information class */
3590 if ((FsInformationClass >= FileFsMaximumInformation) ||
3591 !(IopSetFsOperationLength[FsInformationClass]))
3592 {
3593 /* Invalid class */
3594 return STATUS_INVALID_INFO_CLASS;
3595 }
3596
3597 /* Validate the length */
3598 if (Length < IopSetFsOperationLength[FsInformationClass])
3599 {
3600 /* Invalid length */
3601 return STATUS_INFO_LENGTH_MISMATCH;
3602 }
3603
3604 /* Enter SEH for probing */
3605 _SEH2_TRY
3606 {
3607 /* Probe the I/O Status block */
3608 ProbeForWriteIoStatusBlock(IoStatusBlock);
3609
3610 /* Probe the information */
3611 ProbeForRead(FsInformation, Length, sizeof(ULONG));
3612 }
3613 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3614 {
3615 /* Return the exception code */
3616 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3617 }
3618 _SEH2_END;
3619 }
3620
3621 /* Get File Object */
3622 Status = ObReferenceObjectByHandle(FileHandle,
3623 IopSetFsOperationAccess
3624 [FsInformationClass],
3625 IoFileObjectType,
3626 PreviousMode,
3627 (PVOID*)&FileObject,
3628 NULL);
3629 if (!NT_SUCCESS(Status)) return Status;
3630
3631 /* Get target device for notification */
3632 Status = IoGetRelatedTargetDevice(FileObject, &TargetDeviceObject);
3633 if (!NT_SUCCESS(Status)) TargetDeviceObject = NULL;
3634
3635 /* Check if we should use Sync IO or not */
3636 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3637 {
3638 /* Lock it */
3639 IopLockFileObject(FileObject);
3640 }
3641 else
3642 {
3643 /* Use local event */
3644 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO);
3645 if (!Event)
3646 {
3647 ObDereferenceObject(FileObject);
3648 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3649 return STATUS_INSUFFICIENT_RESOURCES;
3650 }
3651 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
3652 LocalEvent = TRUE;
3653 }
3654
3655 /* Get the device object */
3656 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3657
3658 /* Clear File Object event */
3659 KeClearEvent(&FileObject->Event);
3660
3661 /* Allocate the IRP */
3662 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3663 if (!Irp)
3664 {
3665 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3666 return IopCleanupFailedIrp(FileObject, NULL, Event);
3667 }
3668
3669 /* Set up the IRP */
3670 Irp->RequestorMode = PreviousMode;
3671 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3672 Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3673 Irp->UserEvent = (LocalEvent) ? Event : NULL;
3674 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3675 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3676 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3677 Irp->UserBuffer = FsInformation;
3678 Irp->AssociatedIrp.SystemBuffer = NULL;
3679 Irp->MdlAddress = NULL;
3680
3681 /* Set up Stack Data */
3682 StackPtr = IoGetNextIrpStackLocation(Irp);
3683 StackPtr->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
3684 StackPtr->FileObject = FileObject;
3685
3686 /* Enter SEH */
3687 _SEH2_TRY
3688 {
3689 /* Allocate a buffer */
3690 Irp->AssociatedIrp.SystemBuffer =
3691 ExAllocatePoolWithTag(NonPagedPool,
3692 Length,
3693 TAG_SYSB);
3694
3695 /* Copy the data into it */
3696 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
3697 }
3698 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3699 {
3700 /* Allocating failed, clean up and return the exception code */
3701 IopCleanupAfterException(FileObject, Irp, NULL, Event);
3702 if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
3703 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3704 }
3705 _SEH2_END;
3706
3707 /* Set the flags for this buffered + deferred I/O */
3708 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
3709
3710 /* Set Parameters */
3711 StackPtr->Parameters.SetVolume.Length = Length;
3712 StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
3713
3714 /* Call the Driver */
3715 Status = IopPerformSynchronousRequest(DeviceObject,
3716 Irp,
3717 FileObject,
3718 FALSE,
3719 PreviousMode,
3720 !LocalEvent,
3721 IopOtherTransfer);
3722
3723 /* Check if this was async I/O */
3724 if (LocalEvent)
3725 {
3726 /* It was, finalize this request */
3727 Status = IopFinalizeAsynchronousIo(Status,
3728 Event,
3729 Irp,
3730 PreviousMode,
3731 &KernelIosb,
3732 IoStatusBlock);
3733 }
3734
3735 if (TargetDeviceObject && NT_SUCCESS(Status))
3736 {
3737 /* Time to report change */
3738 NotificationStructure.Version = 1;
3739 NotificationStructure.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
3740 NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
3741 NotificationStructure.FileObject = NULL;
3742 NotificationStructure.NameBufferOffset = - 1;
3743 Status = IoReportTargetDeviceChange(TargetDeviceObject, &NotificationStructure);
3744 }
3745
3746 /* Return status */
3747 return Status;
3748 }
3749
3750 /*
3751 * @unimplemented
3752 */
3753 NTSTATUS
3754 NTAPI
3755 NtCancelDeviceWakeupRequest(IN HANDLE DeviceHandle)
3756 {
3757 UNIMPLEMENTED;
3758 return STATUS_NOT_IMPLEMENTED;
3759 }
3760
3761 /*
3762 * @unimplemented
3763 */
3764 NTSTATUS
3765 NTAPI
3766 NtRequestDeviceWakeup(IN HANDLE DeviceHandle)
3767 {
3768 UNIMPLEMENTED;
3769 return STATUS_NOT_IMPLEMENTED;
3770 }