ReactOS  0.4.15-dev-3326-ga91f5e8
iofunc.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/io/iomgr/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  * Pierre Schweitzer (pierre@reactos.org)
10  */
11 
12 /* INCLUDES *****************************************************************/
13 
14 #include <ntoskrnl.h>
15 #include <ioevent.h>
16 #define NDEBUG
17 #include <debug.h>
18 #include "internal/io_i.h"
19 
22 
23 /* PRIVATE FUNCTIONS *********************************************************/
24 
25 VOID
26 NTAPI
30  IN PKEVENT LocalEvent OPTIONAL)
31 {
32  PAGED_CODE();
33  IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p\n", Irp, FileObject);
34 
35  if (Irp)
36  {
37  /* Check if we had a buffer */
38  if (Irp->AssociatedIrp.SystemBuffer)
39  {
40  /* Free it */
41  ExFreePool(Irp->AssociatedIrp.SystemBuffer);
42  }
43 
44  /* Free the mdl */
45  if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
46 
47  /* Free the IRP */
48  IoFreeIrp(Irp);
49  }
50 
51  /* Check if we had a file lock */
52  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
53  {
54  /* Release it */
56  }
57 
58  /* Check if we had an event */
60 
61  /* Check if we had a local event */
62  if (LocalEvent) ExFreePool(LocalEvent);
63 
64  /* Derefenrce the FO */
66 }
67 
69 NTAPI
72  IN PIRP Irp,
74  IN PIO_STATUS_BLOCK KernelIosb,
76 {
77  NTSTATUS FinalStatus = SynchStatus;
78  PAGED_CODE();
79  IOTRACE(IO_API_DEBUG, "IRP: %p. Status: %lx\n", Irp, SynchStatus);
80 
81  /* Make sure the IRP was completed, but returned pending */
82  if (FinalStatus == STATUS_PENDING)
83  {
84  /* Wait for the IRP */
85  FinalStatus = KeWaitForSingleObject(Event,
86  Executive,
88  FALSE,
89  NULL);
90  if (FinalStatus == STATUS_USER_APC)
91  {
92  /* Abort the request */
94  }
95 
96  /* Set the final status */
97  FinalStatus = KernelIosb->Status;
98  }
99 
100  /* Wrap potential user-mode write in SEH */
101  _SEH2_TRY
102  {
103  *IoStatusBlock = *KernelIosb;
104  }
106  {
107  /* Get the exception code */
108  FinalStatus = _SEH2_GetExceptionCode();
109  }
110  _SEH2_END;
111 
112  /* Free the event and return status */
113  ExFreePool(Event);
114  return FinalStatus;
115 }
116 
117 NTSTATUS
118 NTAPI
120  IN PIRP Irp,
122  IN BOOLEAN Deferred,
124  IN BOOLEAN SynchIo,
125  IN IOP_TRANSFER_TYPE TransferType)
126 {
128  PKNORMAL_ROUTINE NormalRoutine;
129  PVOID NormalContext = NULL;
130  KIRQL OldIrql;
131  PAGED_CODE();
132  IOTRACE(IO_API_DEBUG, "IRP: %p. DO: %p. FO: %p\n",
134 
135  /* Queue the IRP */
137 
138  /* Update operation counts */
139  IopUpdateOperationCount(TransferType);
140 
141  /* Call the driver */
143 
144  /* Check if we're optimizing this case */
145  if (Deferred)
146  {
147  /* We are! Check if the IRP wasn't completed */
148  if (Status != STATUS_PENDING)
149  {
150  /* Complete it ourselves */
151  ASSERT(!Irp->PendingReturned);
153  IopCompleteRequest(&Irp->Tail.Apc,
154  &NormalRoutine,
155  &NormalContext,
156  (PVOID*)&FileObject,
157  &NormalContext);
159  }
160  }
161 
162  /* Check if this was synch I/O */
163  if (SynchIo)
164  {
165  /* Make sure the IRP was completed, but returned pending */
166  if (Status == STATUS_PENDING)
167  {
168  /* Wait for the IRP */
170  Executive,
171  PreviousMode,
172  (FileObject->Flags &
173  FO_ALERTABLE_IO) != 0,
174  NULL);
175  if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
176  {
177  /* Abort the request */
179  }
180 
181  /* Set the final status */
182  Status = FileObject->FinalStatus;
183  }
184 
185  /* Release the file lock */
187  }
188 
189  /* Return status */
190  return Status;
191 }
192 
193 NTSTATUS
194 NTAPI
197  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
198  IN PVOID UserApcContext OPTIONAL,
205  IN BOOLEAN IsDevIoCtl)
206 {
210  PIRP Irp;
211  PIO_STACK_LOCATION StackPtr;
212  PKEVENT EventObject = NULL;
213  BOOLEAN LockedForSynch = FALSE;
214  ULONG AccessType;
220 
221  PAGED_CODE();
222 
223  IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx\n",
224  DeviceHandle, IoControlCode, IsDevIoCtl);
225 
226  /* Get the access type */
228 
229  /* Check if we came from user mode */
230  if (PreviousMode != KernelMode)
231  {
232  _SEH2_TRY
233  {
234  /* Probe the status block */
236 
237  /* Check if this is buffered I/O */
238  if (AccessType == METHOD_BUFFERED)
239  {
240  /* Check if we have an output buffer */
241  if (OutputBuffer)
242  {
243  /* Probe the output buffer */
246  sizeof(CHAR));
247  }
248  else
249  {
250  /* Make sure the caller can't fake this as we depend on this */
251  OutputBufferLength = 0;
252  }
253  }
254 
255  /* Check if we we have an input buffer I/O */
256  if (AccessType != METHOD_NEITHER)
257  {
258  /* Check if we have an input buffer */
259  if (InputBuffer)
260  {
261  /* Probe the input buffer */
263  }
264  else
265  {
266  /* Make sure the caller can't fake this as we depend on this */
267  InputBufferLength = 0;
268  }
269  }
270  }
272  {
273  /* Return the exception code */
275  }
276  _SEH2_END;
277  }
278 
279  /* Don't check for access rights right now, KernelMode can do anything */
281  0,
283  PreviousMode,
284  (PVOID*)&FileObject,
286  if (!NT_SUCCESS(Status)) return Status;
287 
288  /* Can't use an I/O completion port and an APC in the same time */
289  if ((FileObject->CompletionContext) && (UserApcRoutine))
290  {
291  /* Fail */
294  }
295 
296  /* Check if we from user mode */
297  if (PreviousMode != KernelMode)
298  {
299  /* Get the access mask */
300  DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
301 
302  /* Check if we can open it */
303  if ((DesiredAccess != FILE_ANY_ACCESS) &&
304  (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
305  {
306  /* Dereference the file object and fail */
308  return STATUS_ACCESS_DENIED;
309  }
310  }
311 
312  /* Check for an event */
313  if (Event)
314  {
315  /* Reference it */
319  PreviousMode,
320  (PVOID*)&EventObject,
321  NULL);
322  if (!NT_SUCCESS(Status))
323  {
324  /* Dereference the file object and fail */
326  return Status;
327  }
328 
329  /* Clear it */
330  KeClearEvent(EventObject);
331  }
332 
333  /* Check if this is a file that was opened for Synch I/O */
334  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
335  {
336  /* Lock it */
338  if (Status != STATUS_SUCCESS)
339  {
340  if (EventObject) ObDereferenceObject(EventObject);
342  return Status;
343  }
344 
345  /* Remember to unlock later */
346  LockedForSynch = TRUE;
347  }
348 
349  /* Check if this is a direct open or not */
350  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
351  {
352  /* It's a direct open, get the attached device */
354  }
355  else
356  {
357  /* Otherwise get the related device */
359  }
360 
361  /* If this is a device I/O, try to do it with FastIO path */
362  if (IsDevIoCtl)
363  {
364  PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
365 
366  /* Check whether FSD is FastIO aware and provide an appropriate routine */
368  {
369  IO_STATUS_BLOCK KernelIosb;
370 
371  /* If we have an output buffer coming from usermode */
373  {
374  /* Probe it according to its usage */
375  _SEH2_TRY
376  {
377  if (AccessType == METHOD_IN_DIRECT)
378  {
380  }
381  else if (AccessType == METHOD_OUT_DIRECT)
382  {
384  }
385  }
387  {
388  /* Cleanup after exception and return */
390 
391  /* Return the exception code */
393  }
394  _SEH2_END;
395  }
396 
397  /* If we are dismounting a volume, increase the dismount count */
399  {
400  InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
401  }
402 
403  /* Call the FSD */
405  TRUE,
406  InputBuffer,
408  OutputBuffer,
411  &KernelIosb,
412  DeviceObject))
413  {
414  IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
415 
416  /* Write the IOSB back */
417  _SEH2_TRY
418  {
419  *IoStatusBlock = KernelIosb;
420 
421  }
423  {
424  KernelIosb.Status = _SEH2_GetExceptionCode();
425  }
426  _SEH2_END;
427 
428  /* Backup our complete context in case it exists */
429  if (FileObject->CompletionContext)
430  {
431  CompletionInfo = *(FileObject->CompletionContext);
432  }
433 
434  /* If we had an event, signal it */
435  if (Event)
436  {
437  KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
438  ObDereferenceObject(EventObject);
439  }
440 
441  /* If FO was locked, unlock it */
442  if (LockedForSynch)
443  {
445  }
446 
447  /* Set completion if required */
448  if (CompletionInfo.Port != NULL && UserApcContext != NULL)
449  {
450  if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
451  CompletionInfo.Key,
452  UserApcContext,
453  KernelIosb.Status,
454  KernelIosb.Information,
455  TRUE)))
456  {
458  }
459  }
460 
461  /* We're done with FastIO! */
463  return KernelIosb.Status;
464  }
465  }
466  }
467 
468  /* Clear the event */
469  KeClearEvent(&FileObject->Event);
470 
471  /* Allocate IRP */
472  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
473  if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
474 
475  /* Setup the IRP */
476  Irp->UserIosb = IoStatusBlock;
477  Irp->UserEvent = EventObject;
478  Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
479  Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
480  Irp->Cancel = FALSE;
481  Irp->CancelRoutine = NULL;
482  Irp->PendingReturned = FALSE;
483  Irp->RequestorMode = PreviousMode;
484  Irp->MdlAddress = NULL;
485  Irp->AssociatedIrp.SystemBuffer = NULL;
486  Irp->Flags = 0;
487  Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
488  Irp->Tail.Overlay.OriginalFileObject = FileObject;
489  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
490 
491  /* Set stack location settings */
492  StackPtr = IoGetNextIrpStackLocation(Irp);
493  StackPtr->FileObject = FileObject;
494  StackPtr->MajorFunction = IsDevIoCtl ?
497  StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
498  StackPtr->Control = 0;
499  StackPtr->Flags = 0;
500  StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
501 
502  /* Set the IOCTL Data */
503  StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
504  StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
505  StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
507 
509 
510  /* Handle the Methods */
511  switch (AccessType)
512  {
513  /* Buffered I/O */
514  case METHOD_BUFFERED:
515 
516  /* Enter SEH for allocations */
517  _SEH2_TRY
518  {
519  /* Select the right Buffer Length */
522 
523  /* Make sure there is one */
524  if (BufferLength)
525  {
526  /* Allocate the System Buffer */
527  Irp->AssociatedIrp.SystemBuffer =
529  BufferLength,
530  TAG_SYS_BUF);
531 
532  /* Check if we got a buffer */
533  if (InputBuffer)
534  {
535  /* Copy into the System Buffer */
536  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
537  InputBuffer,
539  }
540 
541  /* Write the flags */
543  if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
544 
545  /* Save the Buffer */
546  Irp->UserBuffer = OutputBuffer;
547  }
548  else
549  {
550  /* Clear the Flags and Buffer */
551  Irp->UserBuffer = NULL;
552  }
553  }
555  {
556  /* Cleanup after exception and return */
559  }
560  _SEH2_END;
561  break;
562 
563  /* Direct I/O */
564  case METHOD_IN_DIRECT:
565  case METHOD_OUT_DIRECT:
566 
567  /* Enter SEH */
568  _SEH2_TRY
569  {
570  /* Check if we got an input buffer */
571  if ((InputBufferLength) && (InputBuffer))
572  {
573  /* Allocate the System Buffer */
574  Irp->AssociatedIrp.SystemBuffer =
577  TAG_SYS_BUF);
578 
579  /* Copy into the System Buffer */
580  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
581  InputBuffer,
583 
584  /* Write the flags */
586  }
587 
588  /* Check if we got an output buffer */
589  if (OutputBufferLength)
590  {
591  /* Allocate the System Buffer */
592  Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
594  FALSE,
595  FALSE,
596  Irp);
597  if (!Irp->MdlAddress)
598  {
599  /* Raise exception we'll catch */
601  }
602 
603  /* Do the probe */
604  MmProbeAndLockPages(Irp->MdlAddress,
605  PreviousMode,
606  (AccessType == METHOD_IN_DIRECT) ?
608  }
609  }
611  {
612  /* Cleanup after exception and return */
615  }
616  _SEH2_END;
617  break;
618 
619  case METHOD_NEITHER:
620 
621  /* Just save the Buffer */
622  Irp->UserBuffer = OutputBuffer;
623  StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
624  }
625 
626  /* Use deferred completion for FS I/O */
627  if (!IsDevIoCtl)
628  {
629  Irp->Flags |= IRP_DEFER_IO_COMPLETION;
630  }
631 
632  /* If we are dismounting a volume, increaase the dismount count */
634  {
635  InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
636  }
637 
638  /* Perform the call */
640  Irp,
641  FileObject,
642  !IsDevIoCtl,
643  PreviousMode,
644  LockedForSynch,
646 }
647 
648 NTSTATUS
649 NTAPI
652  IN ULONG Length,
655  IN BOOLEAN File)
656 {
658  PIRP Irp;
660  PIO_STACK_LOCATION StackPtr;
661  BOOLEAN LocalEvent = FALSE;
662  KEVENT Event;
664  PAGED_CODE();
665  IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx\n",
667 
668  /* Reference the object */
670 
671  /* Check if this is a file that was opened for Synch I/O */
672  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
673  {
674  /* Lock it */
676 
677  /* Use File Object event */
678  KeClearEvent(&FileObject->Event);
679  }
680  else
681  {
682  /* Use local event */
684  LocalEvent = TRUE;
685  }
686 
687  /* Get the Device Object */
689 
690  /* Allocate the IRP */
691  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
692  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
693 
694  /* Set the IRP */
695  Irp->Tail.Overlay.OriginalFileObject = FileObject;
696  Irp->RequestorMode = KernelMode;
697  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
698  Irp->UserIosb = &IoStatusBlock;
699  Irp->UserEvent = (LocalEvent) ? &Event : NULL;
700  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
701  Irp->Flags |= IRP_BUFFERED_IO;
702  Irp->AssociatedIrp.SystemBuffer = Information;
703  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
704 
705  /* Set the Stack Data */
706  StackPtr = IoGetNextIrpStackLocation(Irp);
709  StackPtr->FileObject = FileObject;
710 
711  /* Check which type this is */
712  if (File)
713  {
714  /* Set Parameters */
715  StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
716  StackPtr->Parameters.QueryFile.Length = Length;
717  }
718  else
719  {
720  /* Set Parameters */
721  StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
722  StackPtr->Parameters.QueryVolume.Length = Length;
723  }
724 
725  /* Queue the IRP */
727 
728  /* Call the Driver */
730 
731  /* Check if this was synch I/O */
732  if (!LocalEvent)
733  {
734  /* Check if the request is pending */
735  if (Status == STATUS_PENDING)
736  {
737  /* Wait on the file object */
739  Executive,
740  KernelMode,
741  (FileObject->Flags &
742  FO_ALERTABLE_IO) != 0,
743  NULL);
744  if (Status == STATUS_ALERTED)
745  {
746  /* Abort the operation */
748  }
749 
750  /* Get the final status */
751  Status = FileObject->FinalStatus;
752  }
753 
754  /* Release the file lock */
756  }
757  else if (Status == STATUS_PENDING)
758  {
759  /* Wait on the local event and get the final status */
761  Executive,
762  KernelMode,
763  FALSE,
764  NULL);
766  }
767 
768  /* Return the Length and Status. ReturnedLength is NOT optional */
770  return Status;
771 }
772 
773 NTSTATUS
774 NTAPI
776  IN ULONG Length,
777  IN FILE_INFORMATION_CLASS FileInfoClass,
778  OUT PVOID Buffer,
780 {
781  PIRP Irp;
782  KEVENT Event;
787 
788  PAGED_CODE();
789 
790  /* Allocate an IRP */
793  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
794  if (Irp == NULL)
795  {
798  }
799 
800  /* Init event */
802 
803  /* Setup the IRP */
804  Irp->UserIosb = &IoStatusBlock;
805  Irp->UserEvent = &Event;
806  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
807  Irp->RequestorMode = KernelMode;
808  Irp->AssociatedIrp.SystemBuffer = Buffer;
810  Irp->Tail.Overlay.OriginalFileObject = FileObject;
811  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
812 
814  Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
815  Stack->FileObject = FileObject;
816  Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
817  Stack->Parameters.QueryFile.Length = Length;
818 
819 
820  /* Queue the IRP */
822 
823  /* Call the driver */
825  if (Status == STATUS_PENDING)
826  {
829  }
830 
832  return Status;
833 }
834 
835 NTSTATUS
836 NTAPI
838  OUT PFILE_BASIC_INFORMATION BasicInfo)
839 {
843 
844  PAGED_CODE();
845 
846  /* Try to do it the fast way if possible */
848  if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
849  DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
850  DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
851  ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
852  BasicInfo,
853  &IoStatusBlock,
854  DeviceObject))
855  {
856  return IoStatusBlock.Status;
857  }
858 
859  /* In case it failed, fall back to IRP-based method */
861 }
862 
863 NTSTATUS
864 NTAPI
866  IN PIRP Irp,
867  IN PFILE_RENAME_INFORMATION RenameInfo,
869 {
874  PFILE_OBJECT TargetFileObject;
876  FILE_BASIC_INFORMATION BasicInfo;
880 
881  PAGED_CODE();
882 
883  /* First, establish whether our target is a directory */
884  if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
885  {
887  if (!NT_SUCCESS(Status))
888  {
889  return Status;
890  }
891 
892  if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
894  }
895  }
896 
897  /* Setup the string to the target */
898  FileName.Buffer = RenameInfo->FileName;
899  FileName.Length = RenameInfo->FileNameLength;
900  FileName.MaximumLength = RenameInfo->FileNameLength;
901 
903  &FileName,
905  RenameInfo->RootDirectory,
906  NULL);
907 
908  /* And open its parent directory
909  * Use hint if specified
910  */
912  {
913  PFILE_OBJECT_EXTENSION FileObjectExtension;
914 
916 
917  FileObjectExtension = FileObject->FileObjectExtension;
921  &IoStatusBlock,
922  NULL,
923  0,
925  FILE_OPEN,
927  NULL,
928  0,
930  NULL,
932  FileObjectExtension->TopDeviceObjectHint);
933  }
934  else
935  {
939  &IoStatusBlock,
940  NULL,
941  0,
943  FILE_OPEN,
945  NULL,
946  0,
948  NULL,
950  }
951 
952  if (!NT_SUCCESS(Status))
953  {
954  return Status;
955  }
956 
957  /* Once open, continue only if:
958  * Target exists and we're allowed to overwrite it
959  */
961  if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
962  !RenameInfo->ReplaceIfExists &&
964  {
967  }
968 
969  /* Now, we'll get the associated device of the target, to check for same device location
970  * So, get the FO first
971  */
975  KernelMode,
976  (PVOID *)&TargetFileObject,
978  if (!NT_SUCCESS(Status))
979  {
981  return Status;
982  }
983 
984  /* We can dereference, we have the handle */
985  ObDereferenceObject(TargetFileObject);
986  /* If we're not on the same device, error out **/
988  {
990  return STATUS_NOT_SAME_DEVICE;
991  }
992 
993  /* Return parent directory file object and handle */
994  Stack->Parameters.SetFile.FileObject = TargetFileObject;
995  *Handle = TargetHandle;
996 
997  return STATUS_SUCCESS;
998 }
999 
1000 static
1001 ULONG
1003 {
1004  ULONG Mode = 0;
1005 
1006  if (FileObject->Flags & FO_WRITE_THROUGH)
1008 
1009  if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
1011 
1014 
1015  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1016  {
1017  if (FileObject->Flags & FO_ALERTABLE_IO)
1019  else
1021  }
1022 
1023  if (FileObject->Flags & FO_DELETE_ON_CLOSE)
1025 
1026  return Mode;
1027 }
1028 
1029 static
1030 BOOLEAN
1032 {
1033  KIRQL OldIrql;
1034  PVPB Vpb;
1035  BOOLEAN Mounted;
1036 
1037  /* Assume not mounted */
1038  Mounted = FALSE;
1039 
1040  /* Check whether we have the mount flag */
1042 
1043  Vpb = DeviceObject->Vpb;
1044  if (Vpb != NULL &&
1045  BooleanFlagOn(Vpb->Flags, VPB_MOUNTED))
1046  {
1047  Mounted = TRUE;
1048  }
1049 
1051 
1052  return Mounted;
1053 }
1054 
1055 static
1056 BOOLEAN
1059 {
1060  PDEVICE_OBJECT StackDO;
1061 
1062  /* Browse our whole device stack, trying to find the appropriate driver */
1064  while (StackDO != NULL)
1065  {
1066  /* We've found the driver, return success */
1067  if (StackDO->DriverObject == DriverObject)
1068  {
1069  return TRUE;
1070  }
1071 
1072  /* Move to the next */
1073  StackDO = StackDO->AttachedDevice;
1074  }
1075 
1076  /* We only reach there if driver was not found */
1077  return FALSE;
1078 }
1079 
1080 static
1081 NTSTATUS
1083  IN PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo,
1084  IN ULONG Length)
1085 {
1086  KIRQL OldIrql;
1087  NTSTATUS Status;
1088  UNICODE_STRING DriverName;
1090 
1091  /* Make sure the structure is consistent (ie, driver name fits into the buffer) */
1092  if (Length - FIELD_OFFSET(FILE_FS_DRIVER_PATH_INFORMATION, DriverName) < DriverPathInfo->DriverNameLength)
1093  {
1094  return STATUS_INVALID_PARAMETER;
1095  }
1096 
1097  /* Setup the whole driver name */
1098  DriverName.Length = DriverPathInfo->DriverNameLength;
1099  DriverName.MaximumLength = DriverPathInfo->DriverNameLength;
1100  DriverName.Buffer = &DriverPathInfo->DriverName[0];
1101 
1102  /* Ask Ob for such driver */
1103  Status = ObReferenceObjectByName(&DriverName,
1105  NULL,
1106  0,
1108  KernelMode,
1109  NULL,
1110  (PVOID*)&DriverObject);
1111  /* No such driver, bail out */
1112  if (!NT_SUCCESS(Status))
1113  {
1114  return Status;
1115  }
1116 
1117  /* Lock the devices database, we'll browse it */
1119  /* If we have a VPB, browse the stack from the volume */
1120  if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL)
1121  {
1122  DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->Vpb->DeviceObject, DriverObject);
1123  }
1124  /* Otherwise, do it from the normal device */
1125  else
1126  {
1127  DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->DeviceObject, DriverObject);
1128  }
1130 
1131  /* No longer needed */
1133 
1134  return STATUS_SUCCESS;
1135 }
1136 
1137 /* PUBLIC FUNCTIONS **********************************************************/
1138 
1139 /*
1140  * @implemented
1141  */
1142 NTSTATUS
1143 NTAPI
1145  IN PMDL Mdl,
1147  IN PKEVENT Event,
1148  IN PIO_STATUS_BLOCK StatusBlock)
1149 {
1150  PIRP Irp;
1151  PIO_STACK_LOCATION StackPtr;
1153  IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p\n",
1154  FileObject, Mdl, Offset);
1155 
1156  /* Is the write originating from Cc? */
1157  if (FileObject->SectionObjectPointer != NULL &&
1158  FileObject->SectionObjectPointer->SharedCacheMap != NULL)
1159  {
1160  ++CcDataFlushes;
1162  }
1163 
1164  /* Get the Device Object */
1166 
1167  /* Allocate IRP */
1168  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1169  if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1170 
1171  /* Get the Stack */
1172  StackPtr = IoGetNextIrpStackLocation(Irp);
1173 
1174  /* Create the IRP Settings */
1175  Irp->MdlAddress = Mdl;
1176  Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1177  Irp->UserIosb = StatusBlock;
1178  Irp->UserEvent = Event;
1179  Irp->RequestorMode = KernelMode;
1181  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1182  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1183 
1184  /* Set the Stack Settings */
1185  StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
1186  StackPtr->Parameters.Write.ByteOffset = *Offset;
1187  StackPtr->MajorFunction = IRP_MJ_WRITE;
1188  StackPtr->FileObject = FileObject;
1189 
1190  /* Call the Driver */
1191  return IoCallDriver(DeviceObject, Irp);
1192 }
1193 
1194 /*
1195  * @implemented
1196  */
1197 NTSTATUS
1198 NTAPI
1200  IN PMDL Mdl,
1202  IN PKEVENT Event,
1203  IN PIO_STATUS_BLOCK StatusBlock)
1204 {
1205  PIRP Irp;
1206  PIO_STACK_LOCATION StackPtr;
1208  IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p\n",
1209  FileObject, Mdl, Offset);
1210 
1211  /* Get the Device Object */
1213 
1214  /* Allocate IRP */
1215  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1216  /* If allocation failed, try to see whether we can use
1217  * the reserve IRP
1218  */
1219  if (Irp == NULL)
1220  {
1221  /* We will use it only for paging file */
1223  {
1225  Irp = IopAllocateReserveIrp(DeviceObject->StackSize);
1226  }
1227  else
1228  {
1230  }
1231 
1232  /* If allocation failed (not a paging file or too big stack size)
1233  * Fail for real
1234  */
1235  if (Irp == NULL)
1236  {
1238  }
1239  }
1240 
1241  /* Get the Stack */
1242  StackPtr = IoGetNextIrpStackLocation(Irp);
1243 
1244  /* Create the IRP Settings */
1245  Irp->MdlAddress = Mdl;
1246  Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1247  Irp->UserIosb = StatusBlock;
1248  Irp->UserEvent = Event;
1249  Irp->RequestorMode = KernelMode;
1250  Irp->Flags = IRP_PAGING_IO |
1251  IRP_NOCACHE |
1254  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1255  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1256 
1257  /* Set the Stack Settings */
1258  StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
1259  StackPtr->Parameters.Read.ByteOffset = *Offset;
1260  StackPtr->MajorFunction = IRP_MJ_READ;
1261  StackPtr->FileObject = FileObject;
1262 
1263  /* Call the Driver */
1264  return IoCallDriver(DeviceObject, Irp);
1265 }
1266 
1267 /*
1268  * @implemented
1269  */
1270 NTSTATUS
1271 NTAPI
1274  IN ULONG Length,
1277 {
1278  /* Call the shared routine */
1281  Length,
1284  TRUE);
1285 }
1286 
1287 /*
1288  * @implemented
1289  */
1290 NTSTATUS
1291 NTAPI
1294  IN ULONG Length,
1295  OUT PVOID FsInformation,
1297 {
1298  /* Call the shared routine */
1301  Length,
1302  FsInformation,
1304  FALSE);
1305 }
1306 
1307 /*
1308  * @implemented
1309  */
1310 NTSTATUS
1311 NTAPI
1314  IN ULONG Length,
1316 {
1318  PIRP Irp;
1320  PIO_STACK_LOCATION StackPtr;
1321  BOOLEAN LocalEvent = FALSE;
1322  KEVENT Event;
1323  NTSTATUS Status;
1324  PAGED_CODE();
1325  IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx\n",
1327 
1328  /* Reference the object */
1330 
1331  /* Check if this is a file that was opened for Synch I/O */
1332  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1333  {
1334  /* Lock it */
1336 
1337  /* Use File Object event */
1338  KeClearEvent(&FileObject->Event);
1339  }
1340  else
1341  {
1342  /* Use local event */
1344  LocalEvent = TRUE;
1345  }
1346 
1347  /* Get the Device Object */
1349 
1350  /* Allocate the IRP */
1351  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1352  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1353 
1354  /* Set the IRP */
1355  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1356  Irp->RequestorMode = KernelMode;
1357  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1358  Irp->UserIosb = &IoStatusBlock;
1359  Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1360  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1361  Irp->Flags |= IRP_BUFFERED_IO;
1362  Irp->AssociatedIrp.SystemBuffer = FileInformation;
1363  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1364 
1365  /* Set the Stack Data */
1366  StackPtr = IoGetNextIrpStackLocation(Irp);
1368  StackPtr->FileObject = FileObject;
1369 
1370  /* Set Parameters */
1371  StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1372  StackPtr->Parameters.SetFile.Length = Length;
1373 
1374  /* Queue the IRP */
1376 
1377  /* Call the Driver */
1379 
1380  /* Check if this was synch I/O */
1381  if (!LocalEvent)
1382  {
1383  /* Check if the request is pending */
1384  if (Status == STATUS_PENDING)
1385  {
1386  /* Wait on the file object */
1388  Executive,
1389  KernelMode,
1390  (FileObject->Flags &
1391  FO_ALERTABLE_IO) != 0,
1392  NULL);
1393  if (Status == STATUS_ALERTED)
1394  {
1395  /* Abort the operation */
1397  }
1398 
1399  /* Get the final status */
1400  Status = FileObject->FinalStatus;
1401  }
1402 
1403  /* Release the file lock */
1405  }
1406  else if (Status == STATUS_PENDING)
1407  {
1408  /* Wait on the local event and get the final status */
1410  Executive,
1411  KernelMode,
1412  FALSE,
1413  NULL);
1415  }
1416 
1417  /* Return the status */
1418  return Status;
1419 }
1420 
1421 /* NATIVE SERVICES ***********************************************************/
1422 
1423 /*
1424  * @implemented
1425  */
1426 NTSTATUS
1427 NTAPI
1430  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1431  IN PVOID UserApcContext OPTIONAL,
1438 {
1439  /* Call the Generic Function */
1441  Event,
1442  UserApcRoutine,
1443  UserApcContext,
1444  IoStatusBlock,
1445  IoControlCode,
1446  InputBuffer,
1448  OutputBuffer,
1450  TRUE);
1451 }
1452 
1453 /*
1454  * @implemented
1455  */
1456 NTSTATUS
1457 NTAPI
1460  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1461  IN PVOID UserApcContext OPTIONAL,
1468 {
1469  /* Call the Generic Function */
1471  Event,
1472  UserApcRoutine,
1473  UserApcContext,
1474  IoStatusBlock,
1475  IoControlCode,
1476  InputBuffer,
1478  OutputBuffer,
1480  FALSE);
1481 }
1482 
1483 NTSTATUS
1484 NTAPI
1487 {
1489  PIRP Irp;
1490  PIO_STACK_LOCATION StackPtr;
1491  NTSTATUS Status;
1493  PKEVENT Event = NULL;
1494  BOOLEAN LocalEvent = FALSE;
1495  OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1497  IO_STATUS_BLOCK KernelIosb;
1498  PAGED_CODE();
1499  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1500 
1501  if (PreviousMode != KernelMode)
1502  {
1503  /* Protect probes */
1504  _SEH2_TRY
1505  {
1506  /* Probe the I/O Status block */
1508  }
1510  {
1511  /* Return the exception code */
1513  }
1514  _SEH2_END;
1515  }
1516 
1517  /* Get the File Object */
1519  0,
1521  PreviousMode,
1522  (PVOID*)&FileObject,
1523  &ObjectHandleInfo);
1524  if (!NT_SUCCESS(Status)) return Status;
1525 
1526  /*
1527  * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1528  * granted. However, if this is a named pipe, make sure we don't ask for
1529  * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1530  * access right!
1531  */
1532  if (!(ObjectHandleInfo.GrantedAccess &
1533  ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1534  FILE_WRITE_DATA)))
1535  {
1536  /* We failed */
1538  return STATUS_ACCESS_DENIED;
1539  }
1540 
1541  /* Check if we should use Sync IO or not */
1542  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1543  {
1544  /* Lock it */
1546  if (Status != STATUS_SUCCESS)
1547  {
1549  return Status;
1550  }
1551  }
1552  else
1553  {
1554  /* Use local event */
1556  if (!Event)
1557  {
1558  /* We failed */
1561  }
1563  LocalEvent = TRUE;
1564  }
1565 
1566  /* Get the Device Object */
1568 
1569  /* Clear the event */
1570  KeClearEvent(&FileObject->Event);
1571 
1572  /* Allocate the IRP */
1573  Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1574  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1575 
1576  /* Set up the IRP */
1577  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1578  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1579  Irp->UserEvent = (LocalEvent) ? Event : NULL;
1580  Irp->RequestorMode = PreviousMode;
1581  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1582  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1583  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1584 
1585  /* Set up Stack Data */
1586  StackPtr = IoGetNextIrpStackLocation(Irp);
1587  StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1588  StackPtr->FileObject = FileObject;
1589 
1590  /* Call the Driver */
1592  Irp,
1593  FileObject,
1594  FALSE,
1595  PreviousMode,
1596  !LocalEvent,
1598 
1599  /* Check if this was async I/O */
1600  if (LocalEvent)
1601  {
1602  /* It was, finalize this request */
1604  Event,
1605  Irp,
1606  PreviousMode,
1607  &KernelIosb,
1608  IoStatusBlock);
1609  }
1610 
1611  /* Return the Status */
1612  return Status;
1613 }
1614 
1615 /*
1616  * @implemented
1617  */
1618 NTSTATUS
1619 NTAPI
1625  OUT PVOID Buffer,
1629 {
1630  PIRP Irp;
1631  PKEVENT Event = NULL;
1634  PIO_STACK_LOCATION IoStack;
1636  NTSTATUS Status;
1637  BOOLEAN LockedForSync = FALSE;
1638  PAGED_CODE();
1639  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1640 
1641  /* Check if we're called from user mode */
1642  if (PreviousMode != KernelMode)
1643  {
1644  /* Enter SEH for probing */
1645  _SEH2_TRY
1646  {
1647  /* Probe the I/O STatus block */
1649 
1650  /* Probe the buffer */
1652  }
1654  {
1655  /* Return the exception code */
1657  }
1658  _SEH2_END;
1659 
1660  /* Check if CompletionFilter is valid */
1662  {
1663  return STATUS_INVALID_PARAMETER;
1664  }
1665  }
1666 
1667  /* Get File Object */
1671  PreviousMode,
1672  (PVOID*)&FileObject,
1673  NULL);
1674  if (!NT_SUCCESS(Status)) return Status;
1675 
1676  /* Check if we have an event handle */
1677  if (EventHandle)
1678  {
1679  /* Reference it */
1683  PreviousMode,
1684  (PVOID *)&Event,
1685  NULL);
1686  if (Status != STATUS_SUCCESS)
1687  {
1689  return Status;
1690  }
1692  }
1693 
1694  /* Check if we should use Sync IO or not */
1695  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1696  {
1697  /* Lock it */
1699  if (Status != STATUS_SUCCESS)
1700  {
1703  return Status;
1704  }
1705  LockedForSync = TRUE;
1706  }
1707 
1708  /* Clear File Object event */
1709  KeClearEvent(&FileObject->Event);
1710 
1711  /* Get the device object */
1713 
1714  /* Allocate the IRP */
1715  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1716  if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1717 
1718  /* Set up the IRP */
1719  Irp->RequestorMode = PreviousMode;
1720  Irp->UserIosb = IoStatusBlock;
1721  Irp->UserEvent = Event;
1722  Irp->UserBuffer = Buffer;
1723  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1724  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1725  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1726  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1727 
1728  /* Set up Stack Data */
1729  IoStack = IoGetNextIrpStackLocation(Irp);
1732  IoStack->FileObject = FileObject;
1733 
1734  /* Set parameters */
1735  IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1736  IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1737  if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1738 
1739  /* Perform the call */
1741  Irp,
1742  FileObject,
1743  FALSE,
1744  PreviousMode,
1745  LockedForSync,
1747 }
1748 
1749 /*
1750  * @implemented
1751  */
1752 NTSTATUS
1753 NTAPI
1761  IN ULONG Key,
1764 {
1766  PLARGE_INTEGER LocalLength = NULL;
1767  PIRP Irp;
1768  PIO_STACK_LOCATION StackPtr;
1770  PKEVENT Event = NULL;
1771  BOOLEAN LockedForSync = FALSE;
1773  LARGE_INTEGER CapturedByteOffset, CapturedLength;
1774  NTSTATUS Status;
1777  PAGED_CODE();
1778  CapturedByteOffset.QuadPart = 0;
1779  CapturedLength.QuadPart = 0;
1780  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1781 
1782  /* Get File Object */
1784  0,
1786  PreviousMode,
1787  (PVOID*)&FileObject,
1789  if (!NT_SUCCESS(Status)) return Status;
1790 
1791  /* Check if we're called from user mode */
1792  if (PreviousMode != KernelMode)
1793  {
1794  /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1795  if (!(HandleInformation.GrantedAccess &
1797  {
1799  return STATUS_ACCESS_DENIED;
1800  }
1801 
1802  /* Enter SEH for probing */
1803  _SEH2_TRY
1804  {
1805  /* Probe the I/O STatus block */
1807 
1808  /* Probe and capture the large integers */
1809  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1810  CapturedLength = ProbeForReadLargeInteger(Length);
1811  }
1813  {
1814  /* Dereference the object and return exception code */
1817  }
1818  _SEH2_END;
1819  }
1820  else
1821  {
1822  /* Otherwise, capture them directly */
1823  CapturedByteOffset = *ByteOffset;
1824  CapturedLength = *Length;
1825  }
1826 
1827  /* Check if we have an event handle */
1828  if (EventHandle)
1829  {
1830  /* Reference it */
1834  PreviousMode,
1835  (PVOID *)&Event,
1836  NULL);
1837  if (Status != STATUS_SUCCESS) return Status;
1839  }
1840 
1841  /* Get the device object */
1843 
1844  /* Try to do it the FastIO way if possible */
1845  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
1847  {
1848  IO_STATUS_BLOCK KernelIosb;
1849 
1851  &CapturedByteOffset,
1852  &CapturedLength,
1854  Key,
1856  ExclusiveLock,
1857  &KernelIosb,
1858  DeviceObject))
1859  {
1860  /* Write the IOSB back */
1861  _SEH2_TRY
1862  {
1863  *IoStatusBlock = KernelIosb;
1864  }
1866  {
1867  KernelIosb.Status = _SEH2_GetExceptionCode();
1868  }
1869  _SEH2_END;
1870 
1871  /* If we had an event, signal it */
1872  if (EventHandle)
1873  {
1876  }
1877 
1878  /* Set completion if required */
1879  if (FileObject->CompletionContext != NULL && ApcContext != NULL)
1880  {
1881  if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
1882  FileObject->CompletionContext->Key,
1883  ApcContext,
1884  KernelIosb.Status,
1885  KernelIosb.Information,
1886  TRUE)))
1887  {
1889  }
1890  }
1891 
1892  FileObject->LockOperation = TRUE;
1893 
1894  /* We're done with FastIO! */
1896  return KernelIosb.Status;
1897  }
1898  }
1899 
1900  /* Check if we should use Sync IO or not */
1901  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1902  {
1903  /* Lock it */
1905  if (Status != STATUS_SUCCESS)
1906  {
1909  return Status;
1910  }
1911  LockedForSync = TRUE;
1912  }
1913 
1914  /* Clear File Object event */
1915  KeClearEvent(&FileObject->Event);
1916  FileObject->LockOperation = TRUE;
1917 
1918  /* Allocate the IRP */
1919  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1920  if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1921 
1922  /* Set up the IRP */
1923  Irp->RequestorMode = PreviousMode;
1924  Irp->UserIosb = IoStatusBlock;
1925  Irp->UserEvent = Event;
1926  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1927  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1928  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1929  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1930 
1931  /* Set up Stack Data */
1932  StackPtr = IoGetNextIrpStackLocation(Irp);
1933  StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1934  StackPtr->MinorFunction = IRP_MN_LOCK;
1935  StackPtr->FileObject = FileObject;
1936 
1937  /* Allocate local buffer */
1938  LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1939  sizeof(LARGE_INTEGER),
1940  TAG_LOCK);
1941  if (!LocalLength)
1942  {
1943  /* Allocating failed, clean up and return failure */
1946  }
1947 
1948  /* Set the length */
1949  *LocalLength = CapturedLength;
1950  Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1951  StackPtr->Parameters.LockControl.Length = LocalLength;
1952 
1953  /* Set Parameters */
1954  StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1955  StackPtr->Parameters.LockControl.Key = Key;
1956 
1957  /* Set Flags */
1958  if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1959  if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1960 
1961  /* Perform the call */
1963  Irp,
1964  FileObject,
1965  FALSE,
1966  PreviousMode,
1967  LockedForSync,
1969 }
1970 
1971 /*
1972  * @implemented
1973  */
1974 NTSTATUS
1975 NTAPI
1982  IN ULONG Length,
1987 {
1988  PIRP Irp;
1991  PIO_STACK_LOCATION StackPtr;
1993  NTSTATUS Status;
1994  BOOLEAN LockedForSynch = FALSE;
1995  PKEVENT Event = NULL;
1996  volatile PVOID AuxBuffer = NULL;
1997  PMDL Mdl;
1998  UNICODE_STRING CapturedFileName;
1999  PUNICODE_STRING SearchPattern;
2000  PAGED_CODE();
2001  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2002 
2003  /* Check if we came from user mode */
2004  if (PreviousMode != KernelMode)
2005  {
2006  /* Enter SEH for probing */
2007  _SEH2_TRY
2008  {
2009  /* Probe the I/O Status Block */
2011 
2012  /* Probe the file information */
2014 
2015  /* Check if we have a file name */
2016  if (FileName)
2017  {
2018  /* Capture it */
2019  CapturedFileName = ProbeForReadUnicodeString(FileName);
2020  if (CapturedFileName.Length)
2021  {
2022  /* Probe its buffer */
2023  ProbeForRead(CapturedFileName.Buffer,
2024  CapturedFileName.Length,
2025  1);
2026  }
2027 
2028  /* Allocate the auxiliary buffer */
2029  AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
2030  CapturedFileName.Length +
2031  sizeof(UNICODE_STRING),
2032  TAG_SYSB);
2033  RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
2034  sizeof(UNICODE_STRING)),
2035  CapturedFileName.Buffer,
2036  CapturedFileName.Length);
2037 
2038  /* Setup the search pattern */
2039  SearchPattern = (PUNICODE_STRING)AuxBuffer;
2040  SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
2041  sizeof(UNICODE_STRING));
2042  SearchPattern->Length = CapturedFileName.Length;
2043  SearchPattern->MaximumLength = CapturedFileName.Length;
2044  }
2045  }
2047  {
2048  /* Free buffer and return the exception code */
2049  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2051  }
2052  _SEH2_END;
2053  }
2054 
2055  /* Check input parameters */
2056 
2057  switch (FileInformationClass)
2058  {
2059 #define CHECK_LENGTH(class, struct) \
2060  case class: \
2061  if (Length < sizeof(struct)) \
2062  return STATUS_INFO_LENGTH_MISMATCH; \
2063  break
2070  default:
2071  break;
2072 #undef CHECK_LENGTH
2073  }
2074 
2075  /* Get File Object */
2079  PreviousMode,
2080  (PVOID *)&FileObject,
2081  NULL);
2082  if (!NT_SUCCESS(Status))
2083  {
2084  /* Fail */
2085  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2086  return Status;
2087  }
2088 
2089  /* Are there two associated completion routines? */
2090  if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
2091  {
2093  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2094  return STATUS_INVALID_PARAMETER;
2095  }
2096 
2097  /* Check if we have an even handle */
2098  if (EventHandle)
2099  {
2100  /* Get its pointer */
2104  PreviousMode,
2105  (PVOID *)&Event,
2106  NULL);
2107  if (!NT_SUCCESS(Status))
2108  {
2109  /* Fail */
2110  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2112  return Status;
2113  }
2114 
2115  /* Clear it */
2117  }
2118 
2119  /* Check if this is a file that was opened for Synch I/O */
2120  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2121  {
2122  /* Lock it */
2124  if (Status != STATUS_SUCCESS)
2125  {
2128  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2129  return Status;
2130  }
2131 
2132  /* Remember to unlock later */
2133  LockedForSynch = TRUE;
2134  }
2135 
2136  /* Get the device object */
2138 
2139  /* Clear the File Object's event */
2140  KeClearEvent(&FileObject->Event);
2141 
2142  /* Allocate the IRP */
2143  Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2144  if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
2145 
2146  /* Set up the IRP */
2147  Irp->RequestorMode = PreviousMode;
2148  Irp->UserIosb = IoStatusBlock;
2149  Irp->UserEvent = Event;
2150  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2151  Irp->Tail.Overlay.OriginalFileObject = FileObject;
2152  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2153  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2154  Irp->MdlAddress = NULL;
2155  Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
2156  Irp->AssociatedIrp.SystemBuffer = NULL;
2157 
2158  /* Check if this is buffered I/O */
2159  if (DeviceObject->Flags & DO_BUFFERED_IO)
2160  {
2161  /* Allocate a buffer */
2162  Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2163  Length,
2164  TAG_SYSB);
2165  if (!Irp->AssociatedIrp.SystemBuffer)
2166  {
2167  /* Allocating failed, clean up and return the exception code */
2169  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2170 
2171  /* Return the exception code */
2173  }
2174 
2175  /* Set the buffer and flags */
2176  Irp->UserBuffer = FileInformation;
2177  Irp->Flags = (IRP_BUFFERED_IO |
2180  }
2181  else if (DeviceObject->Flags & DO_DIRECT_IO)
2182  {
2183  _SEH2_TRY
2184  {
2185  /* Allocate an MDL */
2189  }
2191  {
2192  /* Allocating failed, clean up and return the exception code */
2195  }
2196  _SEH2_END;
2197  }
2198  else
2199  {
2200  /* No allocation flags, and use the buffer directly */
2201  Irp->UserBuffer = FileInformation;
2202  }
2203 
2204  /* Set up Stack Data */
2205  StackPtr = IoGetNextIrpStackLocation(Irp);
2206  StackPtr->FileObject = FileObject;
2209 
2210  /* Set Parameters */
2211  StackPtr->Parameters.QueryDirectory.FileInformationClass =
2213  StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
2214  StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2215  StackPtr->Parameters.QueryDirectory.Length = Length;
2216  StackPtr->Flags = 0;
2217  if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2219 
2220  /* Set deferred I/O */
2221  Irp->Flags |= IRP_DEFER_IO_COMPLETION;
2222 
2223  /* Perform the call */
2225  Irp,
2226  FileObject,
2227  TRUE,
2228  PreviousMode,
2229  LockedForSynch,
2231 }
2232 
2233 /*
2234  * @unimplemented
2235  */
2236 NTSTATUS
2237 NTAPI
2240  OUT PVOID Buffer,
2241  IN ULONG Length,
2243  IN PVOID EaList OPTIONAL,
2247 {
2248  UNIMPLEMENTED;
2249  return STATUS_NOT_IMPLEMENTED;
2250 }
2251 
2252 /*
2253  * @implemented
2254  */
2255 NTSTATUS
2256 NTAPI
2260  IN ULONG Length,
2262 {
2265  NTSTATUS Status;
2266  PIRP Irp;
2268  PIO_STACK_LOCATION StackPtr;
2270  PKEVENT Event = NULL;
2271  BOOLEAN LocalEvent = FALSE;
2272  PKNORMAL_ROUTINE NormalRoutine;
2273  PVOID NormalContext;
2274  KIRQL OldIrql;
2275  IO_STATUS_BLOCK KernelIosb;
2276  BOOLEAN CallDriver = TRUE;
2277  PFILE_ACCESS_INFORMATION AccessBuffer;
2278  PFILE_MODE_INFORMATION ModeBuffer;
2279  PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
2280  PFILE_ALL_INFORMATION AllBuffer;
2282  PAGED_CODE();
2283  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2284 
2285  /* Check if we're called from user mode */
2286  if (PreviousMode != KernelMode)
2287  {
2288  /* Validate the information class */
2289  if ((FileInformationClass < 0) ||
2292  {
2293  /* Invalid class */
2295  }
2296 
2297  /* Validate the length */
2299  {
2300  /* Invalid length */
2302  }
2303 
2304  /* Enter SEH for probing */
2305  _SEH2_TRY
2306  {
2307  /* Probe the I/O Status block */
2309 
2310  /* Probe the information */
2312  }
2314  {
2315  /* Return the exception code */
2317  }
2318  _SEH2_END;
2319  }
2320 #if DBG
2321  else
2322  {
2323  /* Validate the information class */
2324  if ((FileInformationClass < 0) ||
2327  {
2328  /* Invalid class */
2330  }
2331 
2332  /* Validate the length */
2334  {
2335  /* Invalid length */
2337  }
2338  }
2339 #endif
2340 
2341  /* Reference the Handle */
2346  PreviousMode,
2347  (PVOID *)&FileObject,
2349  if (!NT_SUCCESS(Status)) return Status;
2350 
2351  /* Check if this is a direct open or not */
2352  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2353  {
2354  /* Get the device object */
2355  DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2356  }
2357  else
2358  {
2359  /* Get the device object */
2361  }
2362 
2363  /* Check if this is a file that was opened for Synch I/O */
2364  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2365  {
2366  /* Lock it */
2368  if (Status != STATUS_SUCCESS)
2369  {
2371  return Status;
2372  }
2373 
2374  /* Check if the caller just wants the position */
2376  {
2377  /* Protect write in SEH */
2378  _SEH2_TRY
2379  {
2380  /* Write the offset */
2382  CurrentByteOffset = FileObject->CurrentByteOffset;
2383 
2384  /* Fill out the I/O Status Block */
2387  }
2389  {
2390  /* Get the exception code */
2392  }
2393  _SEH2_END;
2394 
2395  /* Release the file lock, dereference the file and return */
2398  return Status;
2399  }
2400  }
2401  else
2402  {
2403  /* Use local event */
2405  if (!Event)
2406  {
2409  }
2411  LocalEvent = TRUE;
2412  }
2413 
2414  /* Check if FastIO is possible for the two available information classes */
2415  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2416  if (FastIoDispatch != NULL &&
2419  {
2420  BOOLEAN Success = FALSE;
2421 
2423  {
2426  &KernelIosb,
2427  DeviceObject);
2428  }
2429  else
2430  {
2433  &KernelIosb,
2434  DeviceObject);
2435  }
2436 
2437  /* If call succeed */
2438  if (Success)
2439  {
2440  /* Write the IOSB back */
2441  _SEH2_TRY
2442  {
2443  *IoStatusBlock = KernelIosb;
2444  }
2446  {
2447  KernelIosb.Status = _SEH2_GetExceptionCode();
2448  }
2449  _SEH2_END;
2450 
2451  /* Free the event if we had one */
2452  if (LocalEvent)
2453  {
2455  }
2456 
2457  /* If FO was locked, unlock it */
2458  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2459  {
2461  }
2462 
2463  /* We're done with FastIO! */
2465  return KernelIosb.Status;
2466  }
2467  }
2468 
2469  /* Clear the File Object event */
2470  KeClearEvent(&FileObject->Event);
2471 
2472  /* Allocate the IRP */
2473  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2474  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2475 
2476  /* Set the IRP */
2477  Irp->Tail.Overlay.OriginalFileObject = FileObject;
2478  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2479  Irp->RequestorMode = PreviousMode;
2480  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2481  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2482  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2483  Irp->UserEvent = (LocalEvent) ? Event : NULL;
2484  Irp->AssociatedIrp.SystemBuffer = NULL;
2485  Irp->MdlAddress = NULL;
2486  Irp->UserBuffer = FileInformation;
2487 
2488  /* Set the Stack Data */
2489  StackPtr = IoGetNextIrpStackLocation(Irp);
2491  StackPtr->FileObject = FileObject;
2492 
2493  /* Enter SEH */
2494  _SEH2_TRY
2495  {
2496  /* Allocate a buffer */
2497  Irp->AssociatedIrp.SystemBuffer =
2499  Length,
2500  TAG_SYSB);
2501  }
2503  {
2504  /* Allocating failed, clean up and return the exception code */
2507  }
2508  _SEH2_END;
2509 
2510  /* Set the flags */
2511  Irp->Flags |= (IRP_BUFFERED_IO |
2515 
2516  /* Set the Parameters */
2517  StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2518  StackPtr->Parameters.QueryFile.Length = Length;
2519 
2520  /* Queue the IRP */
2522 
2523  /* Update operation counts */
2525 
2526  /* Fill in file information before calling the driver.
2527  See 'File System Internals' page 485.*/
2529  {
2530  AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2531  AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2532  Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2533  CallDriver = FALSE;
2534  }
2536  {
2537  ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2538  ModeBuffer->Mode = IopGetFileMode(FileObject);
2539  Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2540  CallDriver = FALSE;
2541  }
2543  {
2544  AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2545  AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2546  Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2547  CallDriver = FALSE;
2548  }
2550  {
2551  AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2552  AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2554  AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2555  Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2556  sizeof(FILE_MODE_INFORMATION) +
2558  }
2559 
2560  /* Call the Driver */
2561  if (CallDriver)
2562  {
2564  }
2565  else
2566  {
2568  Irp->IoStatus.Status = STATUS_SUCCESS;
2569  }
2570 
2571  if (Status == STATUS_PENDING)
2572  {
2573  /* Check if this was async I/O */
2574  if (LocalEvent)
2575  {
2576  /* Then to a non-alertable wait */
2578  Executive,
2579  PreviousMode,
2580  FALSE,
2581  NULL);
2582  if (Status == STATUS_USER_APC)
2583  {
2584  /* Abort the request */
2586  }
2587 
2588  /* Set the final status */
2589  Status = KernelIosb.Status;
2590 
2591  /* Enter SEH to write the IOSB back */
2592  _SEH2_TRY
2593  {
2594  /* Write it back to the caller */
2595  *IoStatusBlock = KernelIosb;
2596  }
2598  {
2599  /* Get the exception code */
2601  }
2602  _SEH2_END;
2603 
2604  /* Free the event */
2606  }
2607  else
2608  {
2609  /* Wait for the IRP */
2611  Executive,
2612  PreviousMode,
2613  (FileObject->Flags &
2614  FO_ALERTABLE_IO) != 0,
2615  NULL);
2616  if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2617  {
2618  /* Abort the request */
2620  }
2621 
2622  /* Set the final status */
2623  Status = FileObject->FinalStatus;
2624 
2625  /* Release the file lock */
2627  }
2628  }
2629  else
2630  {
2631  /* Free the event if we had one */
2632  if (LocalEvent)
2633  {
2634  /* Clear it in the IRP for completion */
2635  Irp->UserEvent = NULL;
2637  }
2638 
2639  /* Set the caller IOSB */
2640  Irp->UserIosb = IoStatusBlock;
2641 
2642  /* The IRP wasn't completed, complete it ourselves */
2644  IopCompleteRequest(&Irp->Tail.Apc,
2645  &NormalRoutine,
2646  &NormalContext,
2647  (PVOID*)&FileObject,
2648  &NormalContext);
2650 
2651  /* Release the file object if we had locked it*/
2652  if (!LocalEvent) IopUnlockFileObject(FileObject);
2653  }
2654 
2655  /* Return the Status */
2656  return Status;
2657 }
2658 
2659 /*
2660  * @unimplemented
2661  */
2662 NTSTATUS
2663 NTAPI
2666  OUT PVOID Buffer,
2667  IN ULONG Length,
2669  IN PVOID SidList OPTIONAL,
2673 {
2674  UNIMPLEMENTED;
2675  return STATUS_NOT_IMPLEMENTED;
2676 }
2677 
2678 /*
2679  * @implemented
2680  */
2681 NTSTATUS
2682 NTAPI
2688  OUT PVOID Buffer,
2689  IN ULONG Length,
2692 {
2693  NTSTATUS Status;
2695  PIRP Irp;
2697  PIO_STACK_LOCATION StackPtr;
2699  PKEVENT EventObject = NULL;
2700  LARGE_INTEGER CapturedByteOffset;
2701  ULONG CapturedKey = 0;
2702  BOOLEAN Synchronous = FALSE;
2703  PMDL Mdl;
2705  IO_STATUS_BLOCK KernelIosb;
2706  BOOLEAN Success;
2707 
2708  PAGED_CODE();
2709  CapturedByteOffset.QuadPart = 0;
2710  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2711 
2712  /* Get File Object */
2716  PreviousMode,
2717  (PVOID*)&FileObject,
2718  NULL);
2719  if (!NT_SUCCESS(Status)) return Status;
2720 
2721  /* Get the device object */
2723 
2724  /* Validate User-Mode Buffers */
2725  if (PreviousMode != KernelMode)
2726  {
2727  _SEH2_TRY
2728  {
2729  /* Probe the status block */
2731 
2732  /* Probe the read buffer */
2734 
2735  /* Check if we got a byte offset */
2736  if (ByteOffset)
2737  {
2738  /* Capture and probe it */
2739  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2740  }
2741 
2742  /* Perform additional checks for non-cached file access */
2744  {
2745  /* Fail if Length is not sector size aligned
2746  * Perform a quick check for 2^ sector sizes
2747  * If it fails, try a more standard way
2748  */
2749  if ((DeviceObject->SectorSize != 0) &&
2750  ((DeviceObject->SectorSize - 1) & Length) != 0)
2751  {
2752  if (Length % DeviceObject->SectorSize != 0)
2753  {
2754  /* Release the file object and and fail */
2756  return STATUS_INVALID_PARAMETER;
2757  }
2758  }
2759 
2760  /* Fail if buffer doesn't match alignment requirements */
2761  if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
2762  {
2763  /* Release the file object and and fail */
2765  return STATUS_INVALID_PARAMETER;
2766  }
2767 
2768  if (ByteOffset)
2769  {
2770  /* Fail if ByteOffset is not sector size aligned */
2771  if ((DeviceObject->SectorSize != 0) &&
2772  (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
2773  {
2774  /* Release the file object and and fail */
2776  return STATUS_INVALID_PARAMETER;
2777  }
2778  }
2779  }
2780 
2781  /* Capture and probe the key */
2782  if (Key) CapturedKey = ProbeForReadUlong(Key);
2783  }
2785  {
2786  /* Release the file object and return the exception code */
2789  }
2790  _SEH2_END;
2791  }
2792  else
2793  {
2794  /* Kernel mode: capture directly */
2795  if (ByteOffset) CapturedByteOffset = *ByteOffset;
2796  if (Key) CapturedKey = *Key;
2797  }
2798 
2799  /* Check for invalid offset */
2800  if ((CapturedByteOffset.QuadPart < 0) && (CapturedByteOffset.QuadPart != -2))
2801  {
2802  /* -2 is FILE_USE_FILE_POINTER_POSITION */
2804  return STATUS_INVALID_PARAMETER;
2805  }
2806 
2807  /* Check for event */
2808  if (Event)
2809  {
2810  /* Reference it */
2814  PreviousMode,
2815  (PVOID*)&EventObject,
2816  NULL);
2817  if (!NT_SUCCESS(Status))
2818  {
2819  /* Fail */
2821  return Status;
2822  }
2823 
2824  /* Otherwise reset the event */
2825  KeClearEvent(EventObject);
2826  }
2827 
2828  /* Check if we should use Sync IO or not */
2829  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2830  {
2831  /* Lock the file object */
2833  if (Status != STATUS_SUCCESS)
2834  {
2835  if (EventObject) ObDereferenceObject(EventObject);
2837  return Status;
2838  }
2839 
2840  /* Check if we don't have a byte offset available */
2841  if (!(ByteOffset) ||
2842  ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2843  (CapturedByteOffset.u.HighPart == -1)))
2844  {
2845  /* Use the Current Byte Offset instead */
2846  CapturedByteOffset = FileObject->CurrentByteOffset;
2847  }
2848 
2849  /* If the file is cached, try fast I/O */
2850  if (FileObject->PrivateCacheMap)
2851  {
2852  /* Perform fast read */
2853  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2855 
2857  &CapturedByteOffset,
2858  Length,
2859  TRUE,
2860  CapturedKey,
2861  Buffer,
2862  &KernelIosb,
2863  DeviceObject);
2864 
2865  /* Only accept the result if we got a straightforward status */
2866  if (Success &&
2867  (KernelIosb.Status == STATUS_SUCCESS ||
2868  KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2869  KernelIosb.Status == STATUS_END_OF_FILE))
2870  {
2871  /* Fast path -- update transfer & operation counts */
2874  (ULONG)KernelIosb.Information);
2875 
2876  /* Enter SEH to write the IOSB back */
2877  _SEH2_TRY
2878  {
2879  /* Write it back to the caller */
2880  *IoStatusBlock = KernelIosb;
2881  }
2883  {
2884  /* The caller's IOSB was invalid, so fail */
2885  if (EventObject) ObDereferenceObject(EventObject);
2889  }
2890  _SEH2_END;
2891 
2892  /* Signal the completion event */
2893  if (EventObject)
2894  {
2895  KeSetEvent(EventObject, 0, FALSE);
2896  ObDereferenceObject(EventObject);
2897  }
2898 
2899  /* Clean up */
2902  return KernelIosb.Status;
2903  }
2904  }
2905 
2906  /* Remember we are sync */
2907  Synchronous = TRUE;
2908  }
2909  else if (!(ByteOffset) &&
2910  !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2911  {
2912  /* Otherwise, this was async I/O without a byte offset, so fail */
2913  if (EventObject) ObDereferenceObject(EventObject);
2915  return STATUS_INVALID_PARAMETER;
2916  }
2917 
2918  /* Clear the File Object's event */
2919  KeClearEvent(&FileObject->Event);
2920 
2921  /* Allocate the IRP */
2922  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2923  if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2924 
2925  /* Set the IRP */
2926  Irp->Tail.Overlay.OriginalFileObject = FileObject;
2927  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2928  Irp->RequestorMode = PreviousMode;
2929  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2930  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2931  Irp->UserIosb = IoStatusBlock;
2932  Irp->UserEvent = EventObject;
2933  Irp->PendingReturned = FALSE;
2934  Irp->Cancel = FALSE;
2935  Irp->CancelRoutine = NULL;
2936  Irp->AssociatedIrp.SystemBuffer = NULL;
2937  Irp->MdlAddress = NULL;
2938 
2939  /* Set the Stack Data */
2940  StackPtr = IoGetNextIrpStackLocation(Irp);
2941  StackPtr->MajorFunction = IRP_MJ_READ;
2942  StackPtr->FileObject = FileObject;
2943  StackPtr->Parameters.Read.Key = CapturedKey;
2944  StackPtr->Parameters.Read.Length = Length;
2945  StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2946 
2947  /* Check if this is buffered I/O */
2948  if (DeviceObject->Flags & DO_BUFFERED_IO)
2949  {
2950  /* Check if we have a buffer length */
2951  if (Length)
2952  {
2953  /* Enter SEH */
2954  _SEH2_TRY
2955  {
2956  /* Allocate a buffer */
2957  Irp->AssociatedIrp.SystemBuffer =
2959  Length,
2960  TAG_SYSB);
2961  }
2963  {
2964  /* Allocating failed, clean up and return the exception code */
2965  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2967  }
2968  _SEH2_END;
2969 
2970  /* Set the buffer and flags */
2971  Irp->UserBuffer = Buffer;
2972  Irp->Flags = (IRP_BUFFERED_IO |
2975  }
2976  else
2977  {
2978  /* Not reading anything */
2980  }
2981  }
2982  else if (DeviceObject->Flags & DO_DIRECT_IO)
2983  {
2984  /* Check if we have a buffer length */
2985  if (Length)
2986  {
2987  _SEH2_TRY
2988  {
2989  /* Allocate an MDL */
2991  if (!Mdl)
2994  }
2996  {
2997  /* Allocating failed, clean up and return the exception code */
2998  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3000  }
3001  _SEH2_END;
3002 
3003  }
3004 
3005  /* No allocation flags */
3006  Irp->Flags = 0;
3007  }
3008  else
3009  {
3010  /* No allocation flags, and use the buffer directly */
3011  Irp->Flags = 0;
3012  Irp->UserBuffer = Buffer;
3013  }
3014 
3015  /* Now set the deferred read flags */
3017 
3018  if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3019 
3020  /* Perform the call */
3022  Irp,
3023  FileObject,
3024  TRUE,
3025  PreviousMode,
3026  Synchronous,
3027  IopReadTransfer);
3028 }
3029 
3030 /*
3031  * @unimplemented
3032  */
3033 NTSTATUS
3034 NTAPI
3037  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3038  IN PVOID UserApcContext OPTIONAL,
3039  OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3040  IN FILE_SEGMENT_ELEMENT BufferDescription [],
3044 {
3045  UNIMPLEMENTED;
3046  return STATUS_NOT_IMPLEMENTED;
3047 }
3048 
3049 /*
3050  * @unimplemented
3051  */
3052 NTSTATUS
3053 NTAPI
3056  IN PVOID EaBuffer,
3057  IN ULONG EaBufferSize)
3058 {
3059  UNIMPLEMENTED;
3060  return STATUS_NOT_IMPLEMENTED;
3061 }
3062 
3063 /*
3064  * @implemented
3065  */
3066 NTSTATUS
3067 NTAPI
3071  IN ULONG Length,
3073 {
3075  NTSTATUS Status;
3076  PIRP Irp;
3078  PIO_STACK_LOCATION StackPtr;
3080  PKEVENT Event = NULL;
3081  BOOLEAN LocalEvent = FALSE;
3082  PKNORMAL_ROUTINE NormalRoutine;
3083  PVOID NormalContext;
3084  KIRQL OldIrql;
3085  IO_STATUS_BLOCK KernelIosb;
3086  PVOID Queue;
3089  PFILE_RENAME_INFORMATION RenameInfo;
3091  PAGED_CODE();
3092  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3093 
3094  /* Check if we're called from user mode */
3095  if (PreviousMode != KernelMode)
3096  {
3097  /* Validate the information class */
3098  if ((FileInformationClass < 0) ||
3101  {
3102  /* Invalid class */
3104  }
3105 
3106  /* Validate the length */
3108  {
3109  /* Invalid length */
3111  }
3112 
3113  /* Enter SEH for probing */
3114  _SEH2_TRY
3115  {
3116  /* Probe the I/O Status block */
3118 
3119  /* Probe the information */
3121  Length,
3122  (Length == sizeof(BOOLEAN)) ?
3123  sizeof(BOOLEAN) : sizeof(ULONG));
3124  }
3126  {
3127  /* Return the exception code */
3129  }
3130  _SEH2_END;
3131  }
3132  else
3133  {
3134  /* Validate the information class */
3135  if ((FileInformationClass < 0) ||
3138  {
3139  /* Invalid class */
3141  }
3142 
3143  /* Validate the length */
3145  {
3146  /* Invalid length */
3148  }
3149  }
3150 
3151  /* Reference the Handle */
3156  PreviousMode,
3157  (PVOID *)&FileObject,
3158  NULL);
3159  if (!NT_SUCCESS(Status)) return Status;
3160 
3161  /* Check if this is a direct open or not */
3162  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3163  {
3164  /* Get the device object */
3165  DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3166  }
3167  else
3168  {
3169  /* Get the device object */
3171  }
3172 
3173  DPRINT("Will call: %p\n", DeviceObject);
3174  DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
3175 
3176  /* Check if this is a file that was opened for Synch I/O */
3177  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3178  {
3179  /* Lock it */
3181  if (Status != STATUS_SUCCESS)
3182  {
3184  return Status;
3185  }
3186 
3187  /* Check if the caller just wants the position */
3189  {
3190  /* Protect write in SEH */
3191  _SEH2_TRY
3192  {
3193  /* Write the offset */
3194  FileObject->CurrentByteOffset =
3196  CurrentByteOffset;
3197 
3198  /* Fill out the I/O Status Block */
3201  }
3203  {
3204  /* Get the exception code */
3206  }
3207  _SEH2_END;
3208 
3209  /* Update transfer count */
3211 
3212  /* Release the file lock, dereference the file and return */
3215  return Status;
3216  }
3217  }
3218  else
3219  {
3220  /* Use local event */
3222  if (!Event)
3223  {
3226  }
3227 
3229  LocalEvent = TRUE;
3230  }
3231 
3232  /* Clear the File Object event */
3233  KeClearEvent(&FileObject->Event);
3234 
3235  /* Allocate the IRP */
3236  Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
3237  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3238 
3239  /* Set the IRP */
3240  Irp->Tail.Overlay.OriginalFileObject = FileObject;
3241  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3242  Irp->RequestorMode = PreviousMode;
3243  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3244  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3245  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3246  Irp->UserEvent = (LocalEvent) ? Event : NULL;
3247  Irp->AssociatedIrp.SystemBuffer = NULL;
3248  Irp->MdlAddress = NULL;
3249  Irp->UserBuffer = FileInformation;
3250 
3251  /* Set the Stack Data */
3252  StackPtr = IoGetNextIrpStackLocation(Irp);
3254  StackPtr->FileObject = FileObject;
3255 
3256  /* Enter SEH */
3257  _SEH2_TRY
3258  {
3259  /* Allocate a buffer */
3260  Irp->AssociatedIrp.SystemBuffer =
3262  Length,
3263  TAG_SYSB);
3264 
3265  /* Copy the data into it */
3266  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3268  Length);
3269  }
3271  {
3272  /* Allocating failed, clean up and return the exception code */
3275  }
3276  _SEH2_END;
3277 
3278  /* Set the flags */
3279  Irp->Flags |= (IRP_BUFFERED_IO |
3282 
3283  /* Set the Parameters */
3284  StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3285  StackPtr->Parameters.SetFile.Length = Length;
3286 
3287  /* Queue the IRP */
3289 
3290  /* Update operation counts */
3292 
3293  /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3294  /* Handle IO Completion Port quickly */
3296  {
3297  /* Check if the file object already has a completion port */
3298  if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3299  (FileObject->CompletionContext))
3300  {
3301  /* Fail */
3303  }
3304  else
3305  {
3306  /* Reference the Port */
3307  CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3308  Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3311  PreviousMode,
3312  (PVOID*)&Queue,
3313  NULL);
3314  if (NT_SUCCESS(Status))
3315  {
3316  /* Allocate the Context */
3318  sizeof(IO_COMPLETION_CONTEXT),
3319  IOC_TAG);
3320  if (Context)
3321  {
3322  /* Set the Data */
3323  Context->Key = CompletionInfo->Key;
3324  Context->Port = Queue;
3327  Context,
3328  NULL))
3329  {
3330  /*
3331  * Someone else set the completion port in the
3332  * meanwhile, so dereference the port and fail.
3333  */
3337  }
3338  }
3339  else
3340  {
3341  /* Dereference the Port now */
3344  }
3345  }
3346  }
3347 
3348  /* Set the IRP Status */
3349  Irp->IoStatus.Status = Status;
3350  Irp->IoStatus.Information = 0;
3351  }
3355  {
3356  /* Get associated information */
3357  RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3358 
3359  /* Only rename if:
3360  * -> We have a name
3361  * -> In unicode
3362  * -> sizes are valid
3363  */
3364  if (RenameInfo->FileNameLength != 0 &&
3365  !(RenameInfo->FileNameLength & 1) &&
3367  {
3368  /* Properly set information received */
3370  {
3371  StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3372  }
3373  else
3374  {
3375  StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3376  }
3377 
3378  /* If we got fully path OR relative target, attempt a parent directory open */
3379  if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3380  {
3382  if (!NT_SUCCESS(Status))
3383  {
3384  Irp->IoStatus.Status = Status;
3385  }
3386  else
3387  {
3388  /* Call the Driver */
3390  }
3391  }
3392  else
3393  {
3394  /* Call the Driver */
3396  }
3397  }
3398  else
3399  {
3401  Irp->IoStatus.Status = Status;
3402  }
3403  }
3404  else
3405  {
3406  /* Call the Driver */
3408  }
3409 
3410  /* Check if we're waiting for the IRP to complete */
3411  if (Status == STATUS_PENDING)
3412  {
3413  /* Check if this was async I/O */
3414  if (LocalEvent)
3415  {
3416  /* Then to a non-alertable wait */
3418  Executive,
3419  PreviousMode,
3420  FALSE,
3421  NULL);
3422  if (Status == STATUS_USER_APC)
3423  {
3424  /* Abort the request */
3426  }
3427 
3428  /* Set the final status */
3429  Status = KernelIosb.Status;
3430 
3431  /* Enter SEH to write the IOSB back */
3432  _SEH2_TRY
3433  {
3434  /* Write it back to the caller */
3435  *IoStatusBlock = KernelIosb;
3436  }
3438  {
3439  /* Get the exception code */
3441  }
3442  _SEH2_END;
3443 
3444  /* Free the event */
3446  }
3447  else
3448  {
3449  /* Wait for the IRP */
3451  Executive,
3452  PreviousMode,
3453  (FileObject->Flags &
3454  FO_ALERTABLE_IO) != 0,
3455  NULL);
3456  if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3457  {
3458  /* Abort the request */
3460  }
3461 
3462  /* Set the final status */
3463  Status = FileObject->FinalStatus;
3464 
3465  /* Release the file lock */
3467  }
3468  }
3469  else
3470  {
3471  /* Free the event if we had one */
3472  if (LocalEvent)
3473  {
3474  /* Clear it in the IRP for completion */
3475  Irp->UserEvent = NULL;
3477  }
3478 
3479  /* Set the caller IOSB */
3480  Irp->UserIosb = IoStatusBlock;
3481 
3482  /* The IRP wasn't completed, complete it ourselves */
3484  IopCompleteRequest(&Irp->Tail.Apc,
3485  &NormalRoutine,
3486  &NormalContext,
3487  (PVOID*)&FileObject,
3488  &NormalContext);
3490 
3491  /* Release the file object if we had locked it*/
3492  if (!LocalEvent) IopUnlockFileObject(FileObject);
3493  }
3494 
3495  if (TargetHandle != NULL)
3496  {
3498  }
3499 
3500  /* Return the Status */
3501  return Status;
3502 }
3503 
3504 /*
3505  * @unimplemented
3506  */
3507 NTSTATUS
3508 NTAPI
3511  IN PVOID Buffer,
3513 {
3514  UNIMPLEMENTED;
3515  return STATUS_NOT_IMPLEMENTED;
3516 }
3517 
3518 /*
3519  * @implemented
3520  */
3521 NTSTATUS
3522 NTAPI
3527  IN ULONG Key OPTIONAL)
3528 {
3530  PLARGE_INTEGER LocalLength = NULL;
3531  PIRP Irp;
3532  PIO_STACK_LOCATION StackPtr;
3534  PKEVENT Event = NULL;
3535  BOOLEAN LocalEvent = FALSE;
3537  LARGE_INTEGER CapturedByteOffset, CapturedLength;
3538  NTSTATUS Status;
3540  IO_STATUS_BLOCK KernelIosb;
3542  PAGED_CODE();
3543  CapturedByteOffset.QuadPart = 0;
3544  CapturedLength.QuadPart = 0;
3545  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3546 
3547  /* Get File Object */
3549  0,
3551  PreviousMode,
3552  (PVOID*)&FileObject,
3554  if (!NT_SUCCESS(Status)) return Status;
3555 
3556  /* Check if we're called from user mode */
3557  if (PreviousMode != KernelMode)
3558  {
3559  /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3560  if (!(HandleInformation.GrantedAccess &
3562  {
3564  return STATUS_ACCESS_DENIED;
3565  }
3566 
3567  /* Enter SEH for probing */
3568  _SEH2_TRY
3569  {
3570  /* Probe the I/O Status block */
3572 
3573  /* Probe and capture the large integers */
3574  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3575  CapturedLength = ProbeForReadLargeInteger(Length);
3576  }
3578  {
3579  /* Dereference the object and return exception code */
3582  }
3583  _SEH2_END;
3584  }
3585  else
3586  {
3587  /* Otherwise, capture them directly */
3588  CapturedByteOffset = *ByteOffset;
3589  CapturedLength = *Length;
3590  }
3591 
3592  /* Check if this is a direct open or not */
3593  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3594  {
3595  DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3596  }
3597  else
3598  {
3600  }
3601 
3602  /* Try to do it the FastIO way if possible */
3603  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3605  {
3607  &CapturedByteOffset,
3608  &CapturedLength,
3610  Key,
3611  &KernelIosb,
3612  DeviceObject))
3613  {
3614  /* Write the IOSB back */
3615  _SEH2_TRY
3616  {
3617  *IoStatusBlock = KernelIosb;
3618  }
3620  {
3621  KernelIosb.Status = _SEH2_GetExceptionCode();
3622  }
3623  _SEH2_END;
3624 
3625  /* We're done with FastIO! */
3627  return KernelIosb.Status;
3628  }
3629  }
3630 
3631  /* Check if we should use Sync IO or not */
3632  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3633  {
3634  /* Lock it */
3636  if (Status != STATUS_SUCCESS)
3637  {
3639  return Status;
3640  }
3641  }
3642  else
3643  {
3644  /* Use local event */
3646  if (!Event)
3647  {
3650  }
3652  LocalEvent = TRUE;
3653  }
3654 
3655  /* Clear File Object event */
3656  KeClearEvent(&FileObject->Event);
3657 
3658  /* Allocate the IRP */
3659  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3660  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3661 
3662  /* Set up the IRP */
3663  Irp->RequestorMode = PreviousMode;
3664  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3665  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3666  Irp->UserEvent = (LocalEvent) ? Event : NULL;
3667  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3668  Irp->Tail.Overlay.OriginalFileObject = FileObject;
3669  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3670 
3671  /* Set up Stack Data */
3672  StackPtr = IoGetNextIrpStackLocation(Irp);
3673  StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3674  StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3675  StackPtr->FileObject = FileObject;
3676 
3677  /* Enter SEH */
3678  _SEH2_TRY
3679  {
3680  /* Allocate a buffer */
3681  LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3682  sizeof(LARGE_INTEGER),
3683  TAG_LOCK);
3684 
3685  /* Set the length */
3686  *LocalLength = CapturedLength;
3687  Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3688  StackPtr->Parameters.LockControl.Length = LocalLength;
3689  }
3691  {
3692  /* Allocating failed, clean up and return the exception code */
3694  if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3695 
3696  /* Return the exception code */
3698  }
3699  _SEH2_END;
3700 
3701  /* Set Parameters */
3702  StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3703  StackPtr->Parameters.LockControl.Key = Key;
3704 
3705  /* Call the Driver */
3707  Irp,
3708  FileObject,
3709  FALSE,
3710  PreviousMode,
3711  !LocalEvent,
3713 
3714  /* Check if this was async I/O */
3715  if (LocalEvent)
3716  {
3717  /* It was, finalize this request */
3719  Event,
3720  Irp,
3721  PreviousMode,
3722  &KernelIosb,
3723  IoStatusBlock);
3724  }
3725 
3726  /* Return status */
3727  return Status;
3728 }
3729 
3730 /*
3731  * @implemented
3732  */
3733 NTSTATUS
3734 NTAPI
3740  IN PVOID Buffer,
3741  IN ULONG Length,
3744 {
3745  NTSTATUS Status;
3747  PIRP Irp;
3749  PIO_STACK_LOCATION StackPtr;
3751  PKEVENT EventObject = NULL;
3752  LARGE_INTEGER CapturedByteOffset;
3753  ULONG CapturedKey = 0;
3754  BOOLEAN Synchronous = FALSE;
3755  PMDL Mdl;
3756  OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3758  IO_STATUS_BLOCK KernelIosb;
3759  BOOLEAN Success;
3760 
3761  PAGED_CODE();
3762  CapturedByteOffset.QuadPart = 0;
3763  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3764 
3765  /* Get File Object for write */
3767  PreviousMode,
3768  &FileObject,
3769  &ObjectHandleInfo);
3770  if (!NT_SUCCESS(Status)) return Status;
3771 
3772  /* Get the device object */
3774 
3775  /* Validate User-Mode Buffers */
3776  if (PreviousMode != KernelMode)
3777  {
3778  _SEH2_TRY
3779  {
3780  /* Probe the status block */
3782 
3783  /* Probe the read buffer */
3784  ProbeForRead(Buffer, Length, 1);
3785 
3786  /* Check if we got a byte offset */
3787  if (ByteOffset)
3788  {
3789  /* Capture and probe it */
3790  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3791  }
3792 
3793  /* Perform additional checks for non-cached file access */
3795  {
3796  /* Fail if Length is not sector size aligned
3797  * Perform a quick check for 2^ sector sizes
3798  * If it fails, try a more standard way
3799  */
3800  if ((DeviceObject->SectorSize != 0) &&
3801  ((DeviceObject->SectorSize - 1) & Length) != 0)
3802  {
3803  if (Length % DeviceObject->SectorSize != 0)
3804  {
3805  /* Release the file object and and fail */
3807  return STATUS_INVALID_PARAMETER;
3808  }
3809  }
3810 
3811  /* Fail if buffer doesn't match alignment requirements */
3812  if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
3813  {
3814  /* Release the file object and and fail */
3816  return STATUS_INVALID_PARAMETER;
3817  }
3818 
3819  if (ByteOffset)
3820  {
3821  /* Fail if ByteOffset is not sector size aligned */
3822  if ((DeviceObject->SectorSize != 0) &&
3823  (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
3824  {
3825  /* Only if that's not specific values for synchronous IO */
3826  if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) &&
3827  (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION ||
3829  {
3830  /* Release the file object and and fail */
3832  return STATUS_INVALID_PARAMETER;
3833  }
3834  }
3835  }
3836  }
3837 
3838  /* Capture and probe the key */
3839  if (Key) CapturedKey = ProbeForReadUlong(Key);
3840  }
3842  {
3843  /* Release the file object and return the exception code */
3846  }
3847  _SEH2_END;
3848  }
3849  else
3850  {
3851  /* Kernel mode: capture directly */
3852  if (ByteOffset) CapturedByteOffset = *ByteOffset;
3853  if (Key) CapturedKey = *Key;
3854  }
3855 
3856  /* Check for invalid offset */
3857  if (CapturedByteOffset.QuadPart < -2)
3858  {
3859  /* -1 is FILE_WRITE_TO_END_OF_FILE */
3860  /* -2 is FILE_USE_FILE_POINTER_POSITION */
3862  return STATUS_INVALID_PARAMETER;
3863  }
3864 
3865  /* Check if this is an append operation */
3866  if ((ObjectHandleInfo.GrantedAccess &
3868  {
3869  /* Give the drivers something to understand */
3870  CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3871  CapturedByteOffset.u.HighPart = -1;
3872  }
3873 
3874  /* Check for event */
3875  if (Event)
3876  {
3877  /* Reference it */
3881  PreviousMode,
3882  (PVOID*)&EventObject,
3883  NULL);
3884  if (!NT_SUCCESS(Status))
3885  {
3886  /* Fail */
3888  return Status;
3889  }
3890 
3891  /* Otherwise reset the event */
3892  KeClearEvent(EventObject);
3893  }
3894 
3895  /* Check if we should use Sync IO or not */
3896  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3897  {
3898  /* Lock the file object */
3900  if (Status != STATUS_SUCCESS)
3901  {
3902  if (EventObject) ObDereferenceObject(EventObject);
3904  return Status;
3905  }
3906 
3907  /* Check if we don't have a byte offset available */
3908  if (!(ByteOffset) ||
3909  ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3910  (CapturedByteOffset.u.HighPart == -1)))
3911  {
3912  /* Use the Current Byte Offset instead */
3913  CapturedByteOffset = FileObject->CurrentByteOffset;
3914  }
3915 
3916  /* If the file is cached, try fast I/O */
3917  if (FileObject->PrivateCacheMap)
3918  {
3919  /* Perform fast write */
3920  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3922 
3924  &CapturedByteOffset,
3925  Length,
3926  TRUE,
3927  CapturedKey,
3928  Buffer,
3929  &KernelIosb,
3930  DeviceObject);
3931 
3932  /* Only accept the result if it was successful */
3933  if (Success &&
3934  KernelIosb.Status == STATUS_SUCCESS)
3935  {
3936  /* Fast path -- update transfer & operation counts */
3939  (ULONG)KernelIosb.Information);
3940 
3941  /* Enter SEH to write the IOSB back */
3942  _SEH2_TRY
3943  {
3944  /* Write it back to the caller */
3945  *IoStatusBlock = KernelIosb;
3946  }
3948  {
3949  /* The caller's IOSB was invalid, so fail */
3950  if (EventObject) ObDereferenceObject(EventObject);
3954  }
3955  _SEH2_END;
3956 
3957  /* Signal the completion event */
3958  if (EventObject)
3959  {
3960  KeSetEvent(EventObject, 0, FALSE);
3961  ObDereferenceObject(EventObject);
3962  }
3963 
3964  /* Clean up */
3967  return KernelIosb.Status;
3968  }
3969  }
3970 
3971  /* Remember we are sync */
3972  Synchronous = TRUE;
3973  }
3974  else if (!(ByteOffset) &&
3975  !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
3976  {
3977  /* Otherwise, this was async I/O without a byte offset, so fail */
3978  if (EventObject) ObDereferenceObject(EventObject);
3980  return STATUS_INVALID_PARAMETER;
3981  }
3982 
3983  /* Clear the File Object's event */
3984  KeClearEvent(&FileObject->Event);
3985 
3986  /* Allocate the IRP */
3987  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3988  if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
3989 
3990  /* Set the IRP */
3991  Irp->Tail.Overlay.OriginalFileObject = FileObject;
3992  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3993  Irp->RequestorMode = PreviousMode;
3994  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3995  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3996  Irp->UserIosb = IoStatusBlock;
3997  Irp->UserEvent = EventObject;
3998  Irp->PendingReturned = FALSE;
3999  Irp->Cancel = FALSE;
4000  Irp->CancelRoutine = NULL;
4001  Irp->AssociatedIrp.SystemBuffer = NULL;
4002  Irp->MdlAddress = NULL;
4003 
4004  /* Set the Stack Data */
4005  StackPtr = IoGetNextIrpStackLocation(Irp);
4006  StackPtr->MajorFunction = IRP_MJ_WRITE;
4007  StackPtr->FileObject = FileObject;
4008  StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
4009  SL_WRITE_THROUGH : 0;
4010  StackPtr->Parameters.Write.Key = CapturedKey;
4011  StackPtr->Parameters.Write.Length = Length;
4012  StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
4013 
4014  /* Check if this is buffered I/O */
4015  if (DeviceObject->Flags & DO_BUFFERED_IO)
4016  {
4017  /* Check if we have a buffer length */
4018  if (Length)
4019  {
4020  /* Enter SEH */
4021  _SEH2_TRY
4022  {
4023  /* Allocate a buffer */
4024  Irp->AssociatedIrp.SystemBuffer =
4026  Length,
4027  TAG_SYSB);
4028 
4029  /* Copy the data into it */
4030  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
4031  }
4033  {
4034  /* Allocating failed, clean up and return the exception code */
4035  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4037  }
4038  _SEH2_END;
4039 
4040  /* Set the flags */
4042  }
4043  else
4044  {
4045  /* Not writing anything */
4046  Irp->Flags = IRP_BUFFERED_IO;
4047  }
4048  }
4049  else if (DeviceObject->Flags & DO_DIRECT_IO)
4050  {
4051  /* Check if we have a buffer length */
4052  if (Length)
4053  {
4054  _SEH2_TRY
4055  {
4056  /* Allocate an MDL */
4058  if (!Mdl)
4061  }
4063  {
4064  /* Allocating failed, clean up and return the exception code */
4065  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4067  }
4068  _SEH2_END;
4069  }
4070 
4071  /* No allocation flags */
4072  Irp->Flags = 0;
4073  }
4074  else
4075  {
4076  /* No allocation flags, and use the buffer directly */
4077  Irp->Flags = 0;
4078  Irp->UserBuffer = Buffer;
4079  }
4080 
4081  /* Now set the deferred read flags */
4083 
4084  if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
4085 
4086  /* Perform the call */
4088  Irp,
4089  FileObject,
4090  TRUE,
4091  PreviousMode,
4092  Synchronous,
4094 }
4095 
4096 NTSTATUS
4097 NTAPI
4100  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
4101  IN PVOID UserApcContext OPTIONAL,
4102  OUT PIO_STATUS_BLOCK UserIoStatusBlock,
4103  IN FILE_SEGMENT_ELEMENT BufferDescription [],
4107 {
4108  UNIMPLEMENTED;
4109  return STATUS_NOT_IMPLEMENTED;
4110 }
4111 
4112 /*
4113  * @implemented
4114  */
4115 NTSTATUS
4116 NTAPI
4119  OUT PVOID FsInformation,
4120  IN ULONG Length,
4122 {
4124  PIRP Irp;
4125  PIO_STACK_LOCATION StackPtr;
4127  PKEVENT Event = NULL;
4128  BOOLEAN LocalEvent = FALSE;
4130  NTSTATUS Status;
4131  IO_STATUS_BLOCK KernelIosb;
4132  PAGED_CODE();
4133  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4134 
4135  /* Check if we're called from user mode */
4136  if (PreviousMode != KernelMode)
4137  {
4138  /* Validate the information class */
4139  if ((FsInformationClass < 0) ||
4142  {
4143  /* Invalid class */
4145  }
4146 
4147  /* Validate the length */
4149  {
4150  /* Invalid length */
4152  }
4153 
4154  /* Enter SEH for probing */
4155  _SEH2_TRY
4156  {
4157  /* Probe the I/O Status block */
4159 
4160  /* Probe the information */
4161  ProbeForWrite(FsInformation, Length, sizeof(ULONG));
4162  }
4164  {
4165  /* Return the exception code */
4167  }
4168  _SEH2_END;
4169  }
4170 
4171  /* Get File Object */
4176  PreviousMode,
4177  (PVOID*)&FileObject,
4178  NULL);
4179  if (!NT_SUCCESS(Status)) return Status;
4180 
4181  /* Only allow direct device open for FileFsDeviceInformation */
4184  {
4187  }
4188 
4189  /* Check if we should use Sync IO or not */
4190  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4191  {
4192  /* Lock it */
4194  if (Status != STATUS_SUCCESS)
4195  {
4197  return Status;
4198  }
4199  }
4200 
4201  /*
4202  * Quick path for FileFsDeviceInformation - the kernel has enough
4203  * info to reply instead of the driver, excepted for network file systems
4204  */
4207  {
4208  PFILE_FS_DEVICE_INFORMATION FsDeviceInfo = FsInformation;
4209  DeviceObject = FileObject->DeviceObject;
4210 
4211  _SEH2_TRY
4212  {
4213  FsDeviceInfo->DeviceType = DeviceObject->DeviceType;
4214 
4215  /* Complete characteristcs with mount status if relevant */
4216  FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
4218  {
4220  }
4221 
4224  }
4226  {
4227  /* Check if we had a file lock */
4229  {
4230  /* Release it */
4232  }
4233 
4234  /* Dereference the FO */
4236 
4238  }
4239  _SEH2_END;
4240 
4241  /* Check if we had a file lock */
4243  {
4244  /* Release it */
4246  }
4247 
4248  /* Dereference the FO */
4250 
4251  return STATUS_SUCCESS;
4252  }
4253  /* This is to be handled by the kernel, not by FSD */
4255  {
4256  PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo;
4257 
4258  _SEH2_TRY
4259  {
4260  /* Allocate our local structure */
4262 
4263  /* And copy back caller data */
4264  RtlCopyMemory(DriverPathInfo, FsInformation, Length);
4265 
4266  /* Is the driver in the IO path? */
4268  /* We failed, don't continue execution */
4269  if (!NT_SUCCESS(Status))
4270  {
4272  }
4273 
4274  /* We succeed, copy back info */
4275  ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath;
4276 
4277  /* We're done */
4280  }
4282  {
4284  }
4285  _SEH2_END;
4286 
4287  /* Don't leak */
4288  if (DriverPathInfo != NULL)
4289  {
4290  ExFreePoolWithTag(DriverPathInfo, TAG_IO);
4291  }
4292 
4293  /* Check if we had a file lock */
4295  {
4296  /* Release it */
4298  }
4299 
4300  /* Dereference the FO */
4302 
4303  return Status;
4304  }
4305 
4307  {
4308  /* Use local event */
4310  if (!Event)
4311  {
4314  }
4316  LocalEvent = TRUE;
4317  }
4318 
4319  /* Get the device object */
4321 
4322  /* Clear File Object event */
4323  KeClearEvent(&FileObject->Event);
4324 
4325  /* Allocate the IRP */
4326  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4327  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
4328 
4329  /* Set up the IRP */
4330  Irp->RequestorMode = PreviousMode;
4331  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4332  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4333  Irp->UserEvent = (LocalEvent) ? Event : NULL;
4334  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4335  Irp->Tail.Overlay.OriginalFileObject = FileObject;
4336  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4337  Irp->UserBuffer = FsInformation;
4338  Irp->AssociatedIrp.SystemBuffer = NULL;
4339  Irp->MdlAddress = NULL;
4340 
4341  /* Set up Stack Data */
4342  StackPtr = IoGetNextIrpStackLocation(Irp);
4344  StackPtr->FileObject = FileObject;
4345 
4346  /* Enter SEH */
4347  _SEH2_TRY
4348  {
4349  /* Allocate a buffer */
4350  Irp->AssociatedIrp.SystemBuffer =
4352  Length,
4353  TAG_SYSB);
4354  }
4356  {
4357  /* Allocating failed, clean up and return the exception code */
4360  }
4361  _SEH2_END;
4362 
4363  /* Set the flags for this buffered + deferred I/O */
4364  Irp->Flags |= (IRP_BUFFERED_IO |
4368 
4369  /* Set Parameters */
4370  StackPtr->Parameters.QueryVolume.Length = Length;
4371  StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
4372 
4373  /* Call the Driver */
4375  Irp,
4376  FileObject,
4377  TRUE,
4378  PreviousMode,
4379  !LocalEvent,
4381 
4382  /* Check if this was async I/O */
4383  if (LocalEvent)
4384  {
4385  /* It was, finalize this request */
4387  Event,
4388  Irp,
4389  PreviousMode,
4390  &KernelIosb,
4391  IoStatusBlock);
4392  }
4393 
4394  /* Return status */
4395  return Status;
4396 }
4397 
4398 /*
4399  * @implemented
4400  */
4401 NTSTATUS
4402 NTAPI
4405  IN PVOID FsInformation,
4406  IN ULONG Length,
4408 {
4410  PIRP Irp;
4411  PIO_STACK_LOCATION StackPtr;
4413  PKEVENT Event = NULL;
4414  BOOLEAN LocalEvent = FALSE;
4416  NTSTATUS Status;
4417  IO_STATUS_BLOCK KernelIosb;
4419  PAGED_CODE();
4420  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4421 
4422  /* Check if we're called from user mode */
4423  if (PreviousMode != KernelMode)
4424  {
4425  /* Validate the information class */
4426  if ((FsInformationClass < 0) ||
4429  {
4430  /* Invalid class */
4432  }
4433 
4434  /* Validate the length */
4436  {
4437  /* Invalid length */
4439  }
4440 
4441  /* Enter SEH for probing */
4442  _SEH2_TRY
4443  {
4444  /* Probe the I/O Status block */
4446 
4447  /* Probe the information */
4448  ProbeForRead(FsInformation, Length, sizeof(ULONG));
4449  }
4451  {
4452  /* Return the exception code */
4454  }
4455  _SEH2_END;
4456  }
4457 
4458  /* Get File Object */
4463  PreviousMode,
4464  (PVOID*)&FileObject,
4465  NULL);
4466  if (!NT_SUCCESS(Status)) return Status;
4467 
4468  /* Get target device for notification */
4471 
4472  /* Check if we should use Sync IO or not */
4473  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4474  {
4475  /* Lock it */
4477  if (Status != STATUS_SUCCESS)
4478  {
4481  return Status;
4482  }
4483  }
4484  else
4485  {
4486  /* Use local event */
4488  if (!Event)
4489  {
4493  }
4495  LocalEvent = TRUE;
4496  }
4497 
4498  /* Get the device object */
4500 
4501  /* Clear File Object event */
4502  KeClearEvent(&FileObject->Event);
4503 
4504  /* Allocate the IRP */
4505  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4506  if (!Irp)
4507  {
4510  }
4511 
4512  /* Set up the IRP */
4513  Irp->RequestorMode = PreviousMode;
4514  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4515  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4516  Irp->UserEvent = (LocalEvent) ? Event : NULL;
4517  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4518  Irp->Tail.Overlay.OriginalFileObject = FileObject;
4519  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4520  Irp->UserBuffer = FsInformation;
4521  Irp->AssociatedIrp.SystemBuffer = NULL;
4522  Irp->MdlAddress = NULL;
4523 
4524  /* Set up Stack Data */
4525  StackPtr = IoGetNextIrpStackLocation(Irp);
4527  StackPtr->FileObject = FileObject;
4528 
4529  /* Enter SEH */
4530  _SEH2_TRY
4531  {
4532  /* Allocate a buffer */
4533  Irp->AssociatedIrp.SystemBuffer =
4535  Length,
4536  TAG_SYSB);
4537 
4538  /* Copy the data into it */
4539  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
4540  }
4542  {
4543  /* Allocating failed, clean up and return the exception code */
4547  }
4548  _SEH2_END;
4549 
4550  /* Set the flags for this buffered + deferred I/O */
4552 
4553  /* Set Parameters */
4554  StackPtr->Parameters.SetVolume.Length = Length;
4555  StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
4556 
4557  /* Call the Driver */
4559  Irp,
4560  FileObject,
4561  FALSE,
4562  PreviousMode,
4563  !LocalEvent,
4565 
4566  /* Check if this was async I/O */
4567  if (LocalEvent)
4568  {
4569  /* It was, finalize this request */
4571  Event,
4572  Irp,
4573  PreviousMode,
4574  &KernelIosb,
4575  IoStatusBlock);
4576  }
4577 
4579  {
4580  /* Time to report change */
4581  NotificationStructure.Version = 1;
4583  NotificationStructure.Event = GUID_IO_VOLUME_NAME_CHANGE;
4584  NotificationStructure.FileObject = NULL;
4585  NotificationStructure.NameBufferOffset = - 1;
4587  }
4588 
4589  /* Return status */
4590  return Status;
4591 }
4592 
4593 /*
4594  * @unimplemented
4595  */
4596 NTSTATUS
4597 NTAPI
4599 {