ReactOS  0.4.15-dev-4863-gba0d16f
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  NormalRoutine = NULL;
152  NormalContext = NULL;
153  ASSERT(!Irp->PendingReturned);
155  IopCompleteRequest(&Irp->Tail.Apc,
156  &NormalRoutine,
157  &NormalContext,
158  (PVOID*)&FileObject,
159  &NormalContext);
161  }
162  }
163 
164  /* Check if this was synch I/O */
165  if (SynchIo)
166  {
167  /* Make sure the IRP was completed, but returned pending */
168  if (Status == STATUS_PENDING)
169  {
170  /* Wait for the IRP */
172  Executive,
173  PreviousMode,
174  (FileObject->Flags &
175  FO_ALERTABLE_IO) != 0,
176  NULL);
177  if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
178  {
179  /* Abort the request */
181  }
182 
183  /* Set the final status */
184  Status = FileObject->FinalStatus;
185  }
186 
187  /* Release the file lock */
189  }
190 
191  /* Return status */
192  return Status;
193 }
194 
195 NTSTATUS
196 NTAPI
199  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
200  IN PVOID UserApcContext OPTIONAL,
207  IN BOOLEAN IsDevIoCtl)
208 {
212  PIRP Irp;
213  PIO_STACK_LOCATION StackPtr;
214  PKEVENT EventObject = NULL;
215  BOOLEAN LockedForSynch = FALSE;
216  ULONG AccessType;
222 
223  PAGED_CODE();
224 
225  IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx\n",
226  DeviceHandle, IoControlCode, IsDevIoCtl);
227 
228  /* Get the access type */
230 
231  /* Check if we came from user mode */
232  if (PreviousMode != KernelMode)
233  {
234  _SEH2_TRY
235  {
236  /* Probe the status block */
238 
239  /* Check if this is buffered I/O */
240  if (AccessType == METHOD_BUFFERED)
241  {
242  /* Check if we have an output buffer */
243  if (OutputBuffer)
244  {
245  /* Probe the output buffer */
248  sizeof(CHAR));
249  }
250  else
251  {
252  /* Make sure the caller can't fake this as we depend on this */
253  OutputBufferLength = 0;
254  }
255  }
256 
257  /* Check if we we have an input buffer I/O */
258  if (AccessType != METHOD_NEITHER)
259  {
260  /* Check if we have an input buffer */
261  if (InputBuffer)
262  {
263  /* Probe the input buffer */
265  }
266  else
267  {
268  /* Make sure the caller can't fake this as we depend on this */
269  InputBufferLength = 0;
270  }
271  }
272  }
274  {
275  /* Return the exception code */
277  }
278  _SEH2_END;
279  }
280 
281  /* Don't check for access rights right now, KernelMode can do anything */
283  0,
285  PreviousMode,
286  (PVOID*)&FileObject,
288  if (!NT_SUCCESS(Status)) return Status;
289 
290  /* Can't use an I/O completion port and an APC at the same time */
291  if ((FileObject->CompletionContext) && (UserApcRoutine))
292  {
293  /* Fail */
296  }
297 
298  /* Check if we from user mode */
299  if (PreviousMode != KernelMode)
300  {
301  /* Get the access mask */
302  DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3);
303 
304  /* Check if we can open it */
305  if ((DesiredAccess != FILE_ANY_ACCESS) &&
306  (HandleInformation.GrantedAccess & DesiredAccess) != DesiredAccess)
307  {
308  /* Dereference the file object and fail */
310  return STATUS_ACCESS_DENIED;
311  }
312  }
313 
314  /* Check for an event */
315  if (Event)
316  {
317  /* Reference it */
321  PreviousMode,
322  (PVOID*)&EventObject,
323  NULL);
324  if (!NT_SUCCESS(Status))
325  {
326  /* Dereference the file object and fail */
328  return Status;
329  }
330 
331  /* Clear it */
332  KeClearEvent(EventObject);
333  }
334 
335  /* Check if this is a file that was opened for Synch I/O */
336  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
337  {
338  /* Lock it */
340  if (Status != STATUS_SUCCESS)
341  {
342  if (EventObject) ObDereferenceObject(EventObject);
344  return Status;
345  }
346 
347  /* Remember to unlock later */
348  LockedForSynch = TRUE;
349  }
350 
351  /* Check if this is a direct open or not */
352  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
353  {
354  /* It's a direct open, get the attached device */
356  }
357  else
358  {
359  /* Otherwise get the related device */
361  }
362 
363  /* If this is a device I/O, try to do it with FastIO path */
364  if (IsDevIoCtl)
365  {
366  PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
367 
368  /* Check whether FSD is FastIO aware and provide an appropriate routine */
370  {
371  IO_STATUS_BLOCK KernelIosb;
372 
373  /* If we have an output buffer coming from usermode */
375  {
376  /* Probe it according to its usage */
377  _SEH2_TRY
378  {
379  if (AccessType == METHOD_IN_DIRECT)
380  {
382  }
383  else if (AccessType == METHOD_OUT_DIRECT)
384  {
386  }
387  }
389  {
390  /* Cleanup after exception and return */
392 
393  /* Return the exception code */
395  }
396  _SEH2_END;
397  }
398 
399  /* If we are dismounting a volume, increase the dismount count */
401  {
402  InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
403  }
404 
405  /* Call the FSD */
407  TRUE,
408  InputBuffer,
410  OutputBuffer,
413  &KernelIosb,
414  DeviceObject))
415  {
416  IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
417 
418  /* Write the IOSB back */
419  _SEH2_TRY
420  {
421  *IoStatusBlock = KernelIosb;
422 
423  }
425  {
426  KernelIosb.Status = _SEH2_GetExceptionCode();
427  }
428  _SEH2_END;
429 
430  /* Backup our complete context in case it exists */
431  if (FileObject->CompletionContext)
432  {
433  CompletionInfo = *(FileObject->CompletionContext);
434  }
435 
436  /* If we had an event, signal it */
437  if (Event)
438  {
439  KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
440  ObDereferenceObject(EventObject);
441  }
442 
443  /* If FO was locked, unlock it */
444  if (LockedForSynch)
445  {
447  }
448 
449  /* Set completion if required */
450  if (CompletionInfo.Port != NULL && UserApcContext != NULL)
451  {
452  if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
453  CompletionInfo.Key,
454  UserApcContext,
455  KernelIosb.Status,
456  KernelIosb.Information,
457  TRUE)))
458  {
460  }
461  }
462 
463  /* We're done with FastIO! */
465  return KernelIosb.Status;
466  }
467  }
468  }
469 
470  /* Clear the event */
471  KeClearEvent(&FileObject->Event);
472 
473  /* Allocate IRP */
474  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
475  if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
476 
477  /* Setup the IRP */
478  Irp->UserIosb = IoStatusBlock;
479  Irp->UserEvent = EventObject;
480  Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine;
481  Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext;
482  Irp->Cancel = FALSE;
483  Irp->CancelRoutine = NULL;
484  Irp->PendingReturned = FALSE;
485  Irp->RequestorMode = PreviousMode;
486  Irp->MdlAddress = NULL;
487  Irp->AssociatedIrp.SystemBuffer = NULL;
488  Irp->Flags = 0;
489  Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
490  Irp->Tail.Overlay.OriginalFileObject = FileObject;
491  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
492 
493  /* Set stack location settings */
494  StackPtr = IoGetNextIrpStackLocation(Irp);
495  StackPtr->FileObject = FileObject;
496  StackPtr->MajorFunction = IsDevIoCtl ?
499  StackPtr->MinorFunction = 0; /* Minor function 0 is IRP_MN_USER_FS_REQUEST */
500  StackPtr->Control = 0;
501  StackPtr->Flags = 0;
502  StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
503 
504  /* Set the IOCTL Data */
505  StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
506  StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
507  StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
509 
511 
512  /* Handle the Methods */
513  switch (AccessType)
514  {
515  /* Buffered I/O */
516  case METHOD_BUFFERED:
517 
518  /* Enter SEH for allocations */
519  _SEH2_TRY
520  {
521  /* Select the right Buffer Length */
524 
525  /* Make sure there is one */
526  if (BufferLength)
527  {
528  /* Allocate the System Buffer */
529  Irp->AssociatedIrp.SystemBuffer =
531  BufferLength,
532  TAG_SYS_BUF);
533 
534  /* Check if we got a buffer */
535  if (InputBuffer)
536  {
537  /* Copy into the System Buffer */
538  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
539  InputBuffer,
541  }
542 
543  /* Write the flags */
545  if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
546 
547  /* Save the Buffer */
548  Irp->UserBuffer = OutputBuffer;
549  }
550  else
551  {
552  /* Clear the Flags and Buffer */
553  Irp->UserBuffer = NULL;
554  }
555  }
557  {
558  /* Cleanup after exception and return */
561  }
562  _SEH2_END;
563  break;
564 
565  /* Direct I/O */
566  case METHOD_IN_DIRECT:
567  case METHOD_OUT_DIRECT:
568 
569  /* Enter SEH */
570  _SEH2_TRY
571  {
572  /* Check if we got an input buffer */
573  if ((InputBufferLength) && (InputBuffer))
574  {
575  /* Allocate the System Buffer */
576  Irp->AssociatedIrp.SystemBuffer =
579  TAG_SYS_BUF);
580 
581  /* Copy into the System Buffer */
582  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
583  InputBuffer,
585 
586  /* Write the flags */
588  }
589 
590  /* Check if we got an output buffer */
591  if (OutputBufferLength)
592  {
593  /* Allocate the System Buffer */
594  Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
596  FALSE,
597  FALSE,
598  Irp);
599  if (!Irp->MdlAddress)
600  {
601  /* Raise exception we'll catch */
603  }
604 
605  /* Do the probe */
606  MmProbeAndLockPages(Irp->MdlAddress,
607  PreviousMode,
608  (AccessType == METHOD_IN_DIRECT) ?
610  }
611  }
613  {
614  /* Cleanup after exception and return */
617  }
618  _SEH2_END;
619  break;
620 
621  case METHOD_NEITHER:
622 
623  /* Just save the Buffer */
624  Irp->UserBuffer = OutputBuffer;
625  StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
626  }
627 
628  /* Use deferred completion for FS I/O */
629  if (!IsDevIoCtl)
630  {
631  Irp->Flags |= IRP_DEFER_IO_COMPLETION;
632  }
633 
634  /* If we are dismounting a volume, increaase the dismount count */
636  {
637  InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
638  }
639 
640  /* Perform the call */
642  Irp,
643  FileObject,
644  !IsDevIoCtl,
645  PreviousMode,
646  LockedForSynch,
648 }
649 
650 NTSTATUS
651 NTAPI
654  IN ULONG Length,
657  IN BOOLEAN File)
658 {
660  PIRP Irp;
662  PIO_STACK_LOCATION StackPtr;
663  BOOLEAN LocalEvent = FALSE;
664  KEVENT Event;
666  PAGED_CODE();
667  IOTRACE(IO_API_DEBUG, "Handle: %p. CTL: %lx. Type: %lx\n",
669 
670  /* Reference the object */
672 
673  /* Check if this is a file that was opened for Synch I/O */
674  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
675  {
676  /* Lock it */
678 
679  /* Use File Object event */
680  KeClearEvent(&FileObject->Event);
681  }
682  else
683  {
684  /* Use local event */
686  LocalEvent = TRUE;
687  }
688 
689  /* Get the Device Object */
691 
692  /* Allocate the IRP */
693  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
694  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
695 
696  /* Set the IRP */
697  Irp->Tail.Overlay.OriginalFileObject = FileObject;
698  Irp->RequestorMode = KernelMode;
699  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
700  Irp->UserIosb = &IoStatusBlock;
701  Irp->UserEvent = (LocalEvent) ? &Event : NULL;
702  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
703  Irp->Flags |= IRP_BUFFERED_IO;
704  Irp->AssociatedIrp.SystemBuffer = Information;
705  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
706 
707  /* Set the Stack Data */
708  StackPtr = IoGetNextIrpStackLocation(Irp);
711  StackPtr->FileObject = FileObject;
712 
713  /* Check which type this is */
714  if (File)
715  {
716  /* Set Parameters */
717  StackPtr->Parameters.QueryFile.FileInformationClass = InformationClass;
718  StackPtr->Parameters.QueryFile.Length = Length;
719  }
720  else
721  {
722  /* Set Parameters */
723  StackPtr->Parameters.QueryVolume.FsInformationClass = InformationClass;
724  StackPtr->Parameters.QueryVolume.Length = Length;
725  }
726 
727  /* Queue the IRP */
729 
730  /* Call the Driver */
732 
733  /* Check if this was synch I/O */
734  if (!LocalEvent)
735  {
736  /* Check if the request is pending */
737  if (Status == STATUS_PENDING)
738  {
739  /* Wait on the file object */
741  Executive,
742  KernelMode,
743  (FileObject->Flags &
744  FO_ALERTABLE_IO) != 0,
745  NULL);
746  if (Status == STATUS_ALERTED)
747  {
748  /* Abort the operation */
750  }
751 
752  /* Get the final status */
753  Status = FileObject->FinalStatus;
754  }
755 
756  /* Release the file lock */
758  }
759  else if (Status == STATUS_PENDING)
760  {
761  /* Wait on the local event and get the final status */
763  Executive,
764  KernelMode,
765  FALSE,
766  NULL);
768  }
769 
770  /* Return the Length and Status. ReturnedLength is NOT optional */
772  return Status;
773 }
774 
775 NTSTATUS
776 NTAPI
778  IN ULONG Length,
779  IN FILE_INFORMATION_CLASS FileInfoClass,
780  OUT PVOID Buffer,
782 {
783  PIRP Irp;
784  KEVENT Event;
789 
790  PAGED_CODE();
791 
792  /* Allocate an IRP */
795  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
796  if (Irp == NULL)
797  {
800  }
801 
802  /* Init event */
804 
805  /* Setup the IRP */
806  Irp->UserIosb = &IoStatusBlock;
807  Irp->UserEvent = &Event;
808  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
809  Irp->RequestorMode = KernelMode;
810  Irp->AssociatedIrp.SystemBuffer = Buffer;
812  Irp->Tail.Overlay.OriginalFileObject = FileObject;
813  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
814 
816  Stack->MajorFunction = IRP_MJ_QUERY_INFORMATION;
817  Stack->FileObject = FileObject;
818  Stack->Parameters.QueryFile.FileInformationClass = FileInfoClass;
819  Stack->Parameters.QueryFile.Length = Length;
820 
821 
822  /* Queue the IRP */
824 
825  /* Call the driver */
827  if (Status == STATUS_PENDING)
828  {
831  }
832 
834  return Status;
835 }
836 
837 NTSTATUS
838 NTAPI
840  OUT PFILE_BASIC_INFORMATION BasicInfo)
841 {
845 
846  PAGED_CODE();
847 
848  /* Try to do it the fast way if possible */
850  if (DeviceObject->DriverObject->FastIoDispatch != NULL &&
851  DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo != NULL &&
852  DeviceObject->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(FileObject,
853  ((FileObject->Flags & FO_SYNCHRONOUS_IO) != 0),
854  BasicInfo,
855  &IoStatusBlock,
856  DeviceObject))
857  {
858  return IoStatusBlock.Status;
859  }
860 
861  /* In case it failed, fall back to IRP-based method */
863 }
864 
865 NTSTATUS
866 NTAPI
868  IN PIRP Irp,
869  IN PFILE_RENAME_INFORMATION RenameInfo,
871 {
876  PFILE_OBJECT TargetFileObject;
878  FILE_BASIC_INFORMATION BasicInfo;
882 
883  PAGED_CODE();
884 
885  /* First, establish whether our target is a directory */
886  if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
887  {
889  if (!NT_SUCCESS(Status))
890  {
891  return Status;
892  }
893 
894  if (BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
896  }
897  }
898 
899  /* Setup the string to the target */
900  FileName.Buffer = RenameInfo->FileName;
901  FileName.Length = RenameInfo->FileNameLength;
902  FileName.MaximumLength = RenameInfo->FileNameLength;
903 
905  &FileName,
907  RenameInfo->RootDirectory,
908  NULL);
909 
910  /* And open its parent directory
911  * Use hint if specified
912  */
914  {
915  PFILE_OBJECT_EXTENSION FileObjectExtension;
916 
918 
919  FileObjectExtension = FileObject->FileObjectExtension;
923  &IoStatusBlock,
924  NULL,
925  0,
927  FILE_OPEN,
929  NULL,
930  0,
932  NULL,
934  FileObjectExtension->TopDeviceObjectHint);
935  }
936  else
937  {
941  &IoStatusBlock,
942  NULL,
943  0,
945  FILE_OPEN,
947  NULL,
948  0,
950  NULL,
952  }
953 
954  if (!NT_SUCCESS(Status))
955  {
956  return Status;
957  }
958 
959  /* Once open, continue only if:
960  * Target exists and we're allowed to overwrite it
961  */
963  if (Stack->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
964  !RenameInfo->ReplaceIfExists &&
966  {
969  }
970 
971  /* Now, we'll get the associated device of the target, to check for same device location
972  * So, get the FO first
973  */
977  KernelMode,
978  (PVOID *)&TargetFileObject,
980  if (!NT_SUCCESS(Status))
981  {
983  return Status;
984  }
985 
986  /* We can dereference, we have the handle */
987  ObDereferenceObject(TargetFileObject);
988  /* If we're not on the same device, error out **/
990  {
992  return STATUS_NOT_SAME_DEVICE;
993  }
994 
995  /* Return parent directory file object and handle */
996  Stack->Parameters.SetFile.FileObject = TargetFileObject;
997  *Handle = TargetHandle;
998 
999  return STATUS_SUCCESS;
1000 }
1001 
1002 static
1003 ULONG
1005 {
1006  ULONG Mode = 0;
1007 
1008  if (FileObject->Flags & FO_WRITE_THROUGH)
1010 
1011  if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
1013 
1016 
1017  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1018  {
1019  if (FileObject->Flags & FO_ALERTABLE_IO)
1021  else
1023  }
1024 
1025  if (FileObject->Flags & FO_DELETE_ON_CLOSE)
1027 
1028  return Mode;
1029 }
1030 
1031 static
1032 BOOLEAN
1034 {
1035  KIRQL OldIrql;
1036  PVPB Vpb;
1037  BOOLEAN Mounted;
1038 
1039  /* Assume not mounted */
1040  Mounted = FALSE;
1041 
1042  /* Check whether we have the mount flag */
1044 
1045  Vpb = DeviceObject->Vpb;
1046  if (Vpb != NULL &&
1047  BooleanFlagOn(Vpb->Flags, VPB_MOUNTED))
1048  {
1049  Mounted = TRUE;
1050  }
1051 
1053 
1054  return Mounted;
1055 }
1056 
1057 static
1058 BOOLEAN
1061 {
1062  PDEVICE_OBJECT StackDO;
1063 
1064  /* Browse our whole device stack, trying to find the appropriate driver */
1066  while (StackDO != NULL)
1067  {
1068  /* We've found the driver, return success */
1069  if (StackDO->DriverObject == DriverObject)
1070  {
1071  return TRUE;
1072  }
1073 
1074  /* Move to the next */
1075  StackDO = StackDO->AttachedDevice;
1076  }
1077 
1078  /* We only reach there if driver was not found */
1079  return FALSE;
1080 }
1081 
1082 static
1083 NTSTATUS
1085  IN PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo,
1086  IN ULONG Length)
1087 {
1088  KIRQL OldIrql;
1089  NTSTATUS Status;
1090  UNICODE_STRING DriverName;
1092 
1093  /* Make sure the structure is consistent (ie, driver name fits into the buffer) */
1094  if (Length - FIELD_OFFSET(FILE_FS_DRIVER_PATH_INFORMATION, DriverName) < DriverPathInfo->DriverNameLength)
1095  {
1096  return STATUS_INVALID_PARAMETER;
1097  }
1098 
1099  /* Setup the whole driver name */
1100  DriverName.Length = DriverPathInfo->DriverNameLength;
1101  DriverName.MaximumLength = DriverPathInfo->DriverNameLength;
1102  DriverName.Buffer = &DriverPathInfo->DriverName[0];
1103 
1104  /* Ask Ob for such driver */
1105  Status = ObReferenceObjectByName(&DriverName,
1107  NULL,
1108  0,
1110  KernelMode,
1111  NULL,
1112  (PVOID*)&DriverObject);
1113  /* No such driver, bail out */
1114  if (!NT_SUCCESS(Status))
1115  {
1116  return Status;
1117  }
1118 
1119  /* Lock the devices database, we'll browse it */
1121  /* If we have a VPB, browse the stack from the volume */
1122  if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL)
1123  {
1124  DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->Vpb->DeviceObject, DriverObject);
1125  }
1126  /* Otherwise, do it from the normal device */
1127  else
1128  {
1129  DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->DeviceObject, DriverObject);
1130  }
1132 
1133  /* No longer needed */
1135 
1136  return STATUS_SUCCESS;
1137 }
1138 
1139 /* PUBLIC FUNCTIONS **********************************************************/
1140 
1141 /*
1142  * @implemented
1143  */
1144 NTSTATUS
1145 NTAPI
1147  IN PMDL Mdl,
1149  IN PKEVENT Event,
1150  IN PIO_STATUS_BLOCK StatusBlock)
1151 {
1152  PIRP Irp;
1153  PIO_STACK_LOCATION StackPtr;
1155  IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p\n",
1156  FileObject, Mdl, Offset);
1157 
1158  /* Is the write originating from Cc? */
1159  if (FileObject->SectionObjectPointer != NULL &&
1160  FileObject->SectionObjectPointer->SharedCacheMap != NULL)
1161  {
1162  ++CcDataFlushes;
1164  }
1165 
1166  /* Get the Device Object */
1168 
1169  /* Allocate IRP */
1170  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1171  if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1172 
1173  /* Get the Stack */
1174  StackPtr = IoGetNextIrpStackLocation(Irp);
1175 
1176  /* Create the IRP Settings */
1177  Irp->MdlAddress = Mdl;
1178  Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1179  Irp->UserIosb = StatusBlock;
1180  Irp->UserEvent = Event;
1181  Irp->RequestorMode = KernelMode;
1183  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1184  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1185 
1186  /* Set the Stack Settings */
1187  StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
1188  StackPtr->Parameters.Write.ByteOffset = *Offset;
1189  StackPtr->MajorFunction = IRP_MJ_WRITE;
1190  StackPtr->FileObject = FileObject;
1191 
1192  /* Call the Driver */
1193  return IoCallDriver(DeviceObject, Irp);
1194 }
1195 
1196 /*
1197  * @implemented
1198  */
1199 NTSTATUS
1200 NTAPI
1202  IN PMDL Mdl,
1204  IN PKEVENT Event,
1205  IN PIO_STATUS_BLOCK StatusBlock)
1206 {
1207  PIRP Irp;
1208  PIO_STACK_LOCATION StackPtr;
1210  IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p\n",
1211  FileObject, Mdl, Offset);
1212 
1213  /* Get the Device Object */
1215 
1216  /* Allocate IRP */
1217  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1218  /* If allocation failed, try to see whether we can use
1219  * the reserve IRP
1220  */
1221  if (Irp == NULL)
1222  {
1223  /* We will use it only for paging file */
1225  {
1227  Irp = IopAllocateReserveIrp(DeviceObject->StackSize);
1228  }
1229  else
1230  {
1232  }
1233 
1234  /* If allocation failed (not a paging file or too big stack size)
1235  * Fail for real
1236  */
1237  if (Irp == NULL)
1238  {
1240  }
1241  }
1242 
1243  /* Get the Stack */
1244  StackPtr = IoGetNextIrpStackLocation(Irp);
1245 
1246  /* Create the IRP Settings */
1247  Irp->MdlAddress = Mdl;
1248  Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1249  Irp->UserIosb = StatusBlock;
1250  Irp->UserEvent = Event;
1251  Irp->RequestorMode = KernelMode;
1252  Irp->Flags = IRP_PAGING_IO |
1253  IRP_NOCACHE |
1256  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1257  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1258 
1259  /* Set the Stack Settings */
1260  StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
1261  StackPtr->Parameters.Read.ByteOffset = *Offset;
1262  StackPtr->MajorFunction = IRP_MJ_READ;
1263  StackPtr->FileObject = FileObject;
1264 
1265  /* Call the Driver */
1266  return IoCallDriver(DeviceObject, Irp);
1267 }
1268 
1269 /*
1270  * @implemented
1271  */
1272 NTSTATUS
1273 NTAPI
1276  IN ULONG Length,
1279 {
1280  /* Call the shared routine */
1283  Length,
1286  TRUE);
1287 }
1288 
1289 /*
1290  * @implemented
1291  */
1292 NTSTATUS
1293 NTAPI
1296  IN ULONG Length,
1297  OUT PVOID FsInformation,
1299 {
1300  /* Call the shared routine */
1303  Length,
1304  FsInformation,
1306  FALSE);
1307 }
1308 
1309 /*
1310  * @implemented
1311  */
1312 NTSTATUS
1313 NTAPI
1316  IN ULONG Length,
1318 {
1320  PIRP Irp;
1322  PIO_STACK_LOCATION StackPtr;
1323  BOOLEAN LocalEvent = FALSE;
1324  KEVENT Event;
1325  NTSTATUS Status;
1326  PAGED_CODE();
1327  IOTRACE(IO_API_DEBUG, "FileObject: %p. Class: %lx. Length: %lx\n",
1329 
1330  /* Reference the object */
1332 
1333  /* Check if this is a file that was opened for Synch I/O */
1334  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1335  {
1336  /* Lock it */
1338 
1339  /* Use File Object event */
1340  KeClearEvent(&FileObject->Event);
1341  }
1342  else
1343  {
1344  /* Use local event */
1346  LocalEvent = TRUE;
1347  }
1348 
1349  /* Get the Device Object */
1351 
1352  /* Allocate the IRP */
1353  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1354  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1355 
1356  /* Set the IRP */
1357  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1358  Irp->RequestorMode = KernelMode;
1359  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1360  Irp->UserIosb = &IoStatusBlock;
1361  Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1362  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1363  Irp->Flags |= IRP_BUFFERED_IO;
1364  Irp->AssociatedIrp.SystemBuffer = FileInformation;
1365  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1366 
1367  /* Set the Stack Data */
1368  StackPtr = IoGetNextIrpStackLocation(Irp);
1370  StackPtr->FileObject = FileObject;
1371 
1372  /* Set Parameters */
1373  StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
1374  StackPtr->Parameters.SetFile.Length = Length;
1375 
1376  /* Queue the IRP */
1378 
1379  /* Call the Driver */
1381 
1382  /* Check if this was synch I/O */
1383  if (!LocalEvent)
1384  {
1385  /* Check if the request is pending */
1386  if (Status == STATUS_PENDING)
1387  {
1388  /* Wait on the file object */
1390  Executive,
1391  KernelMode,
1392  (FileObject->Flags &
1393  FO_ALERTABLE_IO) != 0,
1394  NULL);
1395  if (Status == STATUS_ALERTED)
1396  {
1397  /* Abort the operation */
1399  }
1400 
1401  /* Get the final status */
1402  Status = FileObject->FinalStatus;
1403  }
1404 
1405  /* Release the file lock */
1407  }
1408  else if (Status == STATUS_PENDING)
1409  {
1410  /* Wait on the local event and get the final status */
1412  Executive,
1413  KernelMode,
1414  FALSE,
1415  NULL);
1417  }
1418 
1419  /* Return the status */
1420  return Status;
1421 }
1422 
1423 /* NATIVE SERVICES ***********************************************************/
1424 
1425 /*
1426  * @implemented
1427  */
1428 NTSTATUS
1429 NTAPI
1432  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1433  IN PVOID UserApcContext OPTIONAL,
1440 {
1441  /* Call the Generic Function */
1443  Event,
1444  UserApcRoutine,
1445  UserApcContext,
1446  IoStatusBlock,
1447  IoControlCode,
1448  InputBuffer,
1450  OutputBuffer,
1452  TRUE);
1453 }
1454 
1455 /*
1456  * @implemented
1457  */
1458 NTSTATUS
1459 NTAPI
1462  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
1463  IN PVOID UserApcContext OPTIONAL,
1470 {
1471  /* Call the Generic Function */
1473  Event,
1474  UserApcRoutine,
1475  UserApcContext,
1476  IoStatusBlock,
1477  IoControlCode,
1478  InputBuffer,
1480  OutputBuffer,
1482  FALSE);
1483 }
1484 
1485 NTSTATUS
1486 NTAPI
1489 {
1491  PIRP Irp;
1492  PIO_STACK_LOCATION StackPtr;
1493  NTSTATUS Status;
1495  PKEVENT Event = NULL;
1496  BOOLEAN LocalEvent = FALSE;
1497  OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
1499  IO_STATUS_BLOCK KernelIosb;
1500  PAGED_CODE();
1501  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1502 
1503  if (PreviousMode != KernelMode)
1504  {
1505  /* Protect probes */
1506  _SEH2_TRY
1507  {
1508  /* Probe the I/O Status block */
1510  }
1512  {
1513  /* Return the exception code */
1515  }
1516  _SEH2_END;
1517  }
1518 
1519  /* Get the File Object */
1521  0,
1523  PreviousMode,
1524  (PVOID*)&FileObject,
1525  &ObjectHandleInfo);
1526  if (!NT_SUCCESS(Status)) return Status;
1527 
1528  /*
1529  * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
1530  * granted. However, if this is a named pipe, make sure we don't ask for
1531  * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
1532  * access right!
1533  */
1534  if (!(ObjectHandleInfo.GrantedAccess &
1535  ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) |
1536  FILE_WRITE_DATA)))
1537  {
1538  /* We failed */
1540  return STATUS_ACCESS_DENIED;
1541  }
1542 
1543  /* Check if we should use Sync IO or not */
1544  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1545  {
1546  /* Lock it */
1548  if (Status != STATUS_SUCCESS)
1549  {
1551  return Status;
1552  }
1553  }
1554  else
1555  {
1556  /* Use local event */
1558  if (!Event)
1559  {
1560  /* We failed */
1563  }
1565  LocalEvent = TRUE;
1566  }
1567 
1568  /* Get the Device Object */
1570 
1571  /* Clear the event */
1572  KeClearEvent(&FileObject->Event);
1573 
1574  /* Allocate the IRP */
1575  Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1576  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
1577 
1578  /* Set up the IRP */
1579  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1580  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
1581  Irp->UserEvent = (LocalEvent) ? Event : NULL;
1582  Irp->RequestorMode = PreviousMode;
1583  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1584  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1585  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1586 
1587  /* Set up Stack Data */
1588  StackPtr = IoGetNextIrpStackLocation(Irp);
1589  StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1590  StackPtr->FileObject = FileObject;
1591 
1592  /* Call the Driver */
1594  Irp,
1595  FileObject,
1596  FALSE,
1597  PreviousMode,
1598  !LocalEvent,
1600 
1601  /* Check if this was async I/O */
1602  if (LocalEvent)
1603  {
1604  /* It was, finalize this request */
1606  Event,
1607  Irp,
1608  PreviousMode,
1609  &KernelIosb,
1610  IoStatusBlock);
1611  }
1612 
1613  /* Return the Status */
1614  return Status;
1615 }
1616 
1617 /*
1618  * @implemented
1619  */
1620 NTSTATUS
1621 NTAPI
1627  OUT PVOID Buffer,
1631 {
1632  PIRP Irp;
1633  PKEVENT Event = NULL;
1636  PIO_STACK_LOCATION IoStack;
1638  NTSTATUS Status;
1639  BOOLEAN LockedForSync = FALSE;
1640  PAGED_CODE();
1641  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1642 
1643  /* Check if we're called from user mode */
1644  if (PreviousMode != KernelMode)
1645  {
1646  /* Enter SEH for probing */
1647  _SEH2_TRY
1648  {
1649  /* Probe the I/O STatus block */
1651 
1652  /* Probe the buffer */
1654  }
1656  {
1657  /* Return the exception code */
1659  }
1660  _SEH2_END;
1661 
1662  /* Check if CompletionFilter is valid */
1664  {
1665  return STATUS_INVALID_PARAMETER;
1666  }
1667  }
1668 
1669  /* Get File Object */
1673  PreviousMode,
1674  (PVOID*)&FileObject,
1675  NULL);
1676  if (!NT_SUCCESS(Status)) return Status;
1677 
1678  /* Can't use an I/O completion port and an APC at the same time */
1679  if ((FileObject->CompletionContext) && (ApcRoutine))
1680  {
1681  /* Fail */
1683  return STATUS_INVALID_PARAMETER;
1684  }
1685 
1686  /* Check if we have an event handle */
1687  if (EventHandle)
1688  {
1689  /* Reference it */
1693  PreviousMode,
1694  (PVOID *)&Event,
1695  NULL);
1696  if (Status != STATUS_SUCCESS)
1697  {
1699  return Status;
1700  }
1702  }
1703 
1704  /* Check if we should use Sync IO or not */
1705  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1706  {
1707  /* Lock it */
1709  if (Status != STATUS_SUCCESS)
1710  {
1713  return Status;
1714  }
1715  LockedForSync = TRUE;
1716  }
1717 
1718  /* Clear File Object event */
1719  KeClearEvent(&FileObject->Event);
1720 
1721  /* Get the device object */
1723 
1724  /* Allocate the IRP */
1725  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1726  if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1727 
1728  /* Set up the IRP */
1729  Irp->RequestorMode = PreviousMode;
1730  Irp->UserIosb = IoStatusBlock;
1731  Irp->UserEvent = Event;
1732  Irp->UserBuffer = Buffer;
1733  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1734  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1735  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1736  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1737 
1738  /* Set up Stack Data */
1739  IoStack = IoGetNextIrpStackLocation(Irp);
1742  IoStack->FileObject = FileObject;
1743 
1744  /* Set parameters */
1745  IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1746  IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1747  if (WatchTree) IoStack->Flags = SL_WATCH_TREE;
1748 
1749  /* Perform the call */
1751  Irp,
1752  FileObject,
1753  FALSE,
1754  PreviousMode,
1755  LockedForSync,
1757 }
1758 
1759 /*
1760  * @implemented
1761  */
1762 NTSTATUS
1763 NTAPI
1771  IN ULONG Key,
1774 {
1776  PLARGE_INTEGER LocalLength = NULL;
1777  PIRP Irp;
1778  PIO_STACK_LOCATION StackPtr;
1780  PKEVENT Event = NULL;
1781  BOOLEAN LockedForSync = FALSE;
1783  LARGE_INTEGER CapturedByteOffset, CapturedLength;
1784  NTSTATUS Status;
1787  PAGED_CODE();
1788  CapturedByteOffset.QuadPart = 0;
1789  CapturedLength.QuadPart = 0;
1790  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
1791 
1792  /* Get File Object */
1794  0,
1796  PreviousMode,
1797  (PVOID*)&FileObject,
1799  if (!NT_SUCCESS(Status)) return Status;
1800 
1801  /* Check if we're called from user mode */
1802  if (PreviousMode != KernelMode)
1803  {
1804  /* Can't use an I/O completion port and an APC at the same time */
1805  if ((FileObject->CompletionContext) && (ApcRoutine))
1806  {
1807  /* Fail */
1809  return STATUS_INVALID_PARAMETER;
1810  }
1811 
1812  /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
1813  if (!(HandleInformation.GrantedAccess &
1815  {
1817  return STATUS_ACCESS_DENIED;
1818  }
1819 
1820  /* Enter SEH for probing */
1821  _SEH2_TRY
1822  {
1823  /* Probe the I/O STatus block */
1825 
1826  /* Probe and capture the large integers */
1827  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
1828  CapturedLength = ProbeForReadLargeInteger(Length);
1829  }
1831  {
1832  /* Dereference the object and return exception code */
1835  }
1836  _SEH2_END;
1837  }
1838  else
1839  {
1840  /* Otherwise, capture them directly */
1841  CapturedByteOffset = *ByteOffset;
1842  CapturedLength = *Length;
1843  }
1844 
1845  /* Check if we have an event handle */
1846  if (EventHandle)
1847  {
1848  /* Reference it */
1852  PreviousMode,
1853  (PVOID *)&Event,
1854  NULL);
1855  if (Status != STATUS_SUCCESS) return Status;
1857  }
1858 
1859  /* Get the device object */
1861 
1862  /* Try to do it the FastIO way if possible */
1863  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
1865  {
1866  IO_STATUS_BLOCK KernelIosb;
1867 
1869  &CapturedByteOffset,
1870  &CapturedLength,
1872  Key,
1874  ExclusiveLock,
1875  &KernelIosb,
1876  DeviceObject))
1877  {
1878  /* Write the IOSB back */
1879  _SEH2_TRY
1880  {
1881  *IoStatusBlock = KernelIosb;
1882  }
1884  {
1885  KernelIosb.Status = _SEH2_GetExceptionCode();
1886  }
1887  _SEH2_END;
1888 
1889  /* If we had an event, signal it */
1890  if (EventHandle)
1891  {
1894  }
1895 
1896  /* Set completion if required */
1897  if (FileObject->CompletionContext != NULL && ApcContext != NULL)
1898  {
1899  if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
1900  FileObject->CompletionContext->Key,
1901  ApcContext,
1902  KernelIosb.Status,
1903  KernelIosb.Information,
1904  TRUE)))
1905  {
1907  }
1908  }
1909 
1910  FileObject->LockOperation = TRUE;
1911 
1912  /* We're done with FastIO! */
1914  return KernelIosb.Status;
1915  }
1916  }
1917 
1918  /* Check if we should use Sync IO or not */
1919  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1920  {
1921  /* Lock it */
1923  if (Status != STATUS_SUCCESS)
1924  {
1927  return Status;
1928  }
1929  LockedForSync = TRUE;
1930  }
1931 
1932  /* Clear File Object event */
1933  KeClearEvent(&FileObject->Event);
1934  FileObject->LockOperation = TRUE;
1935 
1936  /* Allocate the IRP */
1937  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1938  if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
1939 
1940  /* Set up the IRP */
1941  Irp->RequestorMode = PreviousMode;
1942  Irp->UserIosb = IoStatusBlock;
1943  Irp->UserEvent = Event;
1944  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1945  Irp->Tail.Overlay.OriginalFileObject = FileObject;
1946  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1947  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1948 
1949  /* Set up Stack Data */
1950  StackPtr = IoGetNextIrpStackLocation(Irp);
1951  StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1952  StackPtr->MinorFunction = IRP_MN_LOCK;
1953  StackPtr->FileObject = FileObject;
1954 
1955  /* Allocate local buffer */
1956  LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1957  sizeof(LARGE_INTEGER),
1958  TAG_LOCK);
1959  if (!LocalLength)
1960  {
1961  /* Allocating failed, clean up and return failure */
1964  }
1965 
1966  /* Set the length */
1967  *LocalLength = CapturedLength;
1968  Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
1969  StackPtr->Parameters.LockControl.Length = LocalLength;
1970 
1971  /* Set Parameters */
1972  StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
1973  StackPtr->Parameters.LockControl.Key = Key;
1974 
1975  /* Set Flags */
1976  if (FailImmediately) StackPtr->Flags = SL_FAIL_IMMEDIATELY;
1977  if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1978 
1979  /* Perform the call */
1981  Irp,
1982  FileObject,
1983  FALSE,
1984  PreviousMode,
1985  LockedForSync,
1987 }
1988 
1989 /*
1990  * @implemented
1991  */
1992 NTSTATUS
1993 NTAPI
2000  IN ULONG Length,
2005 {
2006  PIRP Irp;
2009  PIO_STACK_LOCATION StackPtr;
2011  NTSTATUS Status;
2012  BOOLEAN LockedForSynch = FALSE;
2013  PKEVENT Event = NULL;
2014  volatile PVOID AuxBuffer = NULL;
2015  PMDL Mdl;
2016  UNICODE_STRING CapturedFileName;
2017  PUNICODE_STRING SearchPattern;
2018  PAGED_CODE();
2019  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2020 
2021  /* Check if we came from user mode */
2022  if (PreviousMode != KernelMode)
2023  {
2024  /* Enter SEH for probing */
2025  _SEH2_TRY
2026  {
2027  /* Probe the I/O Status Block */
2029 
2030  /* Probe the file information */
2032 
2033  /* Check if we have a file name */
2034  if (FileName)
2035  {
2036  /* Capture it */
2037  CapturedFileName = ProbeForReadUnicodeString(FileName);
2038  if (CapturedFileName.Length)
2039  {
2040  /* Probe its buffer */
2041  ProbeForRead(CapturedFileName.Buffer,
2042  CapturedFileName.Length,
2043  1);
2044  }
2045 
2046  /* Allocate the auxiliary buffer */
2047  AuxBuffer = ExAllocatePoolWithTag(NonPagedPool,
2048  CapturedFileName.Length +
2049  sizeof(UNICODE_STRING),
2050  TAG_SYSB);
2051  RtlCopyMemory((PVOID)((ULONG_PTR)AuxBuffer +
2052  sizeof(UNICODE_STRING)),
2053  CapturedFileName.Buffer,
2054  CapturedFileName.Length);
2055 
2056  /* Setup the search pattern */
2057  SearchPattern = (PUNICODE_STRING)AuxBuffer;
2058  SearchPattern->Buffer = (PWCHAR)((ULONG_PTR)AuxBuffer +
2059  sizeof(UNICODE_STRING));
2060  SearchPattern->Length = CapturedFileName.Length;
2061  SearchPattern->MaximumLength = CapturedFileName.Length;
2062  }
2063  }
2065  {
2066  /* Free buffer and return the exception code */
2067  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2069  }
2070  _SEH2_END;
2071  }
2072 
2073  /* Check input parameters */
2074 
2075  switch (FileInformationClass)
2076  {
2077 #define CHECK_LENGTH(class, struct) \
2078  case class: \
2079  if (Length < sizeof(struct)) \
2080  return STATUS_INFO_LENGTH_MISMATCH; \
2081  break
2088  default:
2089  break;
2090 #undef CHECK_LENGTH
2091  }
2092 
2093  /* Get File Object */
2097  PreviousMode,
2098  (PVOID *)&FileObject,
2099  NULL);
2100  if (!NT_SUCCESS(Status))
2101  {
2102  /* Fail */
2103  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2104  return Status;
2105  }
2106 
2107  /* Are there two associated completion routines? */
2108  if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
2109  {
2111  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2112  return STATUS_INVALID_PARAMETER;
2113  }
2114 
2115  /* Check if we have an even handle */
2116  if (EventHandle)
2117  {
2118  /* Get its pointer */
2122  PreviousMode,
2123  (PVOID *)&Event,
2124  NULL);
2125  if (!NT_SUCCESS(Status))
2126  {
2127  /* Fail */
2128  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2130  return Status;
2131  }
2132 
2133  /* Clear it */
2135  }
2136 
2137  /* Check if this is a file that was opened for Synch I/O */
2138  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2139  {
2140  /* Lock it */
2142  if (Status != STATUS_SUCCESS)
2143  {
2146  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2147  return Status;
2148  }
2149 
2150  /* Remember to unlock later */
2151  LockedForSynch = TRUE;
2152  }
2153 
2154  /* Get the device object */
2156 
2157  /* Clear the File Object's event */
2158  KeClearEvent(&FileObject->Event);
2159 
2160  /* Allocate the IRP */
2161  Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
2162  if (!Irp) return IopCleanupFailedIrp(FileObject, EventHandle, AuxBuffer);
2163 
2164  /* Set up the IRP */
2165  Irp->RequestorMode = PreviousMode;
2166  Irp->UserIosb = IoStatusBlock;
2167  Irp->UserEvent = Event;
2168  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2169  Irp->Tail.Overlay.OriginalFileObject = FileObject;
2170  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2171  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2172  Irp->MdlAddress = NULL;
2173  Irp->Tail.Overlay.AuxiliaryBuffer = AuxBuffer;
2174  Irp->AssociatedIrp.SystemBuffer = NULL;
2175 
2176  /* Check if this is buffered I/O */
2177  if (DeviceObject->Flags & DO_BUFFERED_IO)
2178  {
2179  /* Allocate a buffer */
2180  Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2181  Length,
2182  TAG_SYSB);
2183  if (!Irp->AssociatedIrp.SystemBuffer)
2184  {
2185  /* Allocating failed, clean up and return the exception code */
2187  if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
2188 
2189  /* Return the exception code */
2191  }
2192 
2193  /* Set the buffer and flags */
2194  Irp->UserBuffer = FileInformation;
2195  Irp->Flags = (IRP_BUFFERED_IO |
2198  }
2199  else if (DeviceObject->Flags & DO_DIRECT_IO)
2200  {
2201  _SEH2_TRY
2202  {
2203  /* Allocate an MDL */
2207  }
2209  {
2210  /* Allocating failed, clean up and return the exception code */
2213  }
2214  _SEH2_END;
2215  }
2216  else
2217  {
2218  /* No allocation flags, and use the buffer directly */
2219  Irp->UserBuffer = FileInformation;
2220  }
2221 
2222  /* Set up Stack Data */
2223  StackPtr = IoGetNextIrpStackLocation(Irp);
2224  StackPtr->FileObject = FileObject;
2227 
2228  /* Set Parameters */
2229  StackPtr->Parameters.QueryDirectory.FileInformationClass =
2231  StackPtr->Parameters.QueryDirectory.FileName = AuxBuffer;
2232  StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2233  StackPtr->Parameters.QueryDirectory.Length = Length;
2234  StackPtr->Flags = 0;
2235  if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2237 
2238  /* Set deferred I/O */
2239  Irp->Flags |= IRP_DEFER_IO_COMPLETION;
2240 
2241  /* Perform the call */
2243  Irp,
2244  FileObject,
2245  TRUE,
2246  PreviousMode,
2247  LockedForSynch,
2249 }
2250 
2251 /*
2252  * @unimplemented
2253  */
2254 NTSTATUS
2255 NTAPI
2258  OUT PVOID Buffer,
2259  IN ULONG Length,
2261  IN PVOID EaList OPTIONAL,
2265 {
2266  UNIMPLEMENTED;
2267  return STATUS_NOT_IMPLEMENTED;
2268 }
2269 
2270 /*
2271  * @implemented
2272  */
2273 NTSTATUS
2274 NTAPI
2278  IN ULONG Length,
2280 {
2283  NTSTATUS Status;
2284  PIRP Irp;
2286  PIO_STACK_LOCATION StackPtr;
2288  PKEVENT Event = NULL;
2289  BOOLEAN LocalEvent = FALSE;
2290  PKNORMAL_ROUTINE NormalRoutine;
2291  PVOID NormalContext;
2292  KIRQL OldIrql;
2293  IO_STATUS_BLOCK KernelIosb;
2294  BOOLEAN CallDriver = TRUE;
2295  PFILE_ACCESS_INFORMATION AccessBuffer;
2296  PFILE_MODE_INFORMATION ModeBuffer;
2297  PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
2298  PFILE_ALL_INFORMATION AllBuffer;
2300  PAGED_CODE();
2301  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2302 
2303  /* Check if we're called from user mode */
2304  if (PreviousMode != KernelMode)
2305  {
2306  /* Validate the information class */
2307  if ((FileInformationClass < 0) ||
2310  {
2311  /* Invalid class */
2313  }
2314 
2315  /* Validate the length */
2317  {
2318  /* Invalid length */
2320  }
2321 
2322  /* Enter SEH for probing */
2323  _SEH2_TRY
2324  {
2325  /* Probe the I/O Status block */
2327 
2328  /* Probe the information */
2330  }
2332  {
2333  /* Return the exception code */
2335  }
2336  _SEH2_END;
2337  }
2338 #if DBG
2339  else
2340  {
2341  /* Validate the information class */
2342  if ((FileInformationClass < 0) ||
2345  {
2346  /* Invalid class */
2348  }
2349 
2350  /* Validate the length */
2352  {
2353  /* Invalid length */
2355  }
2356  }
2357 #endif
2358 
2359  /* Reference the Handle */
2364  PreviousMode,
2365  (PVOID *)&FileObject,
2367  if (!NT_SUCCESS(Status)) return Status;
2368 
2369  /* Check if this is a direct open or not */
2370  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2371  {
2372  /* Get the device object */
2373  DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2374  }
2375  else
2376  {
2377  /* Get the device object */
2379  }
2380 
2381  /* Check if this is a file that was opened for Synch I/O */
2382  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2383  {
2384  /* Lock it */
2386  if (Status != STATUS_SUCCESS)
2387  {
2389  return Status;
2390  }
2391 
2392  /* Check if the caller just wants the position */
2394  {
2395  /* Protect write in SEH */
2396  _SEH2_TRY
2397  {
2398  /* Write the offset */
2400  CurrentByteOffset = FileObject->CurrentByteOffset;
2401 
2402  /* Fill out the I/O Status Block */
2405  }
2407  {
2408  /* Get the exception code */
2410  }
2411  _SEH2_END;
2412 
2413  /* Release the file lock, dereference the file and return */
2416  return Status;
2417  }
2418  }
2419  else
2420  {
2421  /* Use local event */
2423  if (!Event)
2424  {
2427  }
2429  LocalEvent = TRUE;
2430  }
2431 
2432  /* Check if FastIO is possible for the two available information classes */
2433  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2434  if (FastIoDispatch != NULL &&
2437  {
2438  BOOLEAN Success = FALSE;
2439 
2441  {
2444  &KernelIosb,
2445  DeviceObject);
2446  }
2447  else
2448  {
2451  &KernelIosb,
2452  DeviceObject);
2453  }
2454 
2455  /* If call succeed */
2456  if (Success)
2457  {
2458  /* Write the IOSB back */
2459  _SEH2_TRY
2460  {
2461  *IoStatusBlock = KernelIosb;
2462  }
2464  {
2465  KernelIosb.Status = _SEH2_GetExceptionCode();
2466  }
2467  _SEH2_END;
2468 
2469  /* Free the event if we had one */
2470  if (LocalEvent)
2471  {
2473  }
2474 
2475  /* If FO was locked, unlock it */
2476  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2477  {
2479  }
2480 
2481  /* We're done with FastIO! */
2483  return KernelIosb.Status;
2484  }
2485  }
2486 
2487  /* Clear the File Object event */
2488  KeClearEvent(&FileObject->Event);
2489 
2490  /* Allocate the IRP */
2491  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2492  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
2493 
2494  /* Set the IRP */
2495  Irp->Tail.Overlay.OriginalFileObject = FileObject;
2496  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2497  Irp->RequestorMode = PreviousMode;
2498  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2499  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2500  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
2501  Irp->UserEvent = (LocalEvent) ? Event : NULL;
2502  Irp->AssociatedIrp.SystemBuffer = NULL;
2503  Irp->MdlAddress = NULL;
2504  Irp->UserBuffer = FileInformation;
2505 
2506  /* Set the Stack Data */
2507  StackPtr = IoGetNextIrpStackLocation(Irp);
2509  StackPtr->FileObject = FileObject;
2510 
2511  /* Enter SEH */
2512  _SEH2_TRY
2513  {
2514  /* Allocate a buffer */
2515  Irp->AssociatedIrp.SystemBuffer =
2517  Length,
2518  TAG_SYSB);
2519  }
2521  {
2522  /* Allocating failed, clean up and return the exception code */
2525  }
2526  _SEH2_END;
2527 
2528  /* Set the flags */
2529  Irp->Flags |= (IRP_BUFFERED_IO |
2533 
2534  /* Set the Parameters */
2535  StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2536  StackPtr->Parameters.QueryFile.Length = Length;
2537 
2538  /* Queue the IRP */
2540 
2541  /* Update operation counts */
2543 
2544  /* Fill in file information before calling the driver.
2545  See 'File System Internals' page 485.*/
2547  {
2548  AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
2549  AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
2550  Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
2551  CallDriver = FALSE;
2552  }
2554  {
2555  ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
2556  ModeBuffer->Mode = IopGetFileMode(FileObject);
2557  Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
2558  CallDriver = FALSE;
2559  }
2561  {
2562  AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
2563  AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
2564  Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
2565  CallDriver = FALSE;
2566  }
2568  {
2569  AllBuffer = Irp->AssociatedIrp.SystemBuffer;
2570  AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
2572  AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
2573  Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
2574  sizeof(FILE_MODE_INFORMATION) +
2576  }
2577 
2578  /* Call the Driver */
2579  if (CallDriver)
2580  {
2582  }
2583  else
2584  {
2586  Irp->IoStatus.Status = STATUS_SUCCESS;
2587  }
2588 
2589  if (Status == STATUS_PENDING)
2590  {
2591  /* Check if this was async I/O */
2592  if (LocalEvent)
2593  {
2594  /* Then to a non-alertable wait */
2596  Executive,
2597  PreviousMode,
2598  FALSE,
2599  NULL);
2600  if (Status == STATUS_USER_APC)
2601  {
2602  /* Abort the request */
2604  }
2605 
2606  /* Set the final status */
2607  Status = KernelIosb.Status;
2608 
2609  /* Enter SEH to write the IOSB back */
2610  _SEH2_TRY
2611  {
2612  /* Write it back to the caller */
2613  *IoStatusBlock = KernelIosb;
2614  }
2616  {
2617  /* Get the exception code */
2619  }
2620  _SEH2_END;
2621 
2622  /* Free the event */
2624  }
2625  else
2626  {
2627  /* Wait for the IRP */
2629  Executive,
2630  PreviousMode,
2631  (FileObject->Flags &
2632  FO_ALERTABLE_IO) != 0,
2633  NULL);
2634  if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
2635  {
2636  /* Abort the request */
2638  }
2639 
2640  /* Set the final status */
2641  Status = FileObject->FinalStatus;
2642 
2643  /* Release the file lock */
2645  }
2646  }
2647  else
2648  {
2649  /* Free the event if we had one */
2650  if (LocalEvent)
2651  {
2652  /* Clear it in the IRP for completion */
2653  Irp->UserEvent = NULL;
2655  }
2656 
2657  /* Set the caller IOSB */
2658  Irp->UserIosb = IoStatusBlock;
2659 
2660  /* The IRP wasn't completed, complete it ourselves */
2661  NormalRoutine = NULL;
2662  NormalContext = NULL;
2664  IopCompleteRequest(&Irp->Tail.Apc,
2665  &NormalRoutine,
2666  &NormalContext,
2667  (PVOID*)&FileObject,
2668  &NormalContext);
2670 
2671  /* Release the file object if we had locked it*/
2672  if (!LocalEvent) IopUnlockFileObject(FileObject);
2673  }
2674 
2675  /* Return the Status */
2676  return Status;
2677 }
2678 
2679 /*
2680  * @unimplemented
2681  */
2682 NTSTATUS
2683 NTAPI
2686  OUT PVOID Buffer,
2687  IN ULONG Length,
2689  IN PVOID SidList OPTIONAL,
2693 {
2694  UNIMPLEMENTED;
2695  return STATUS_NOT_IMPLEMENTED;
2696 }
2697 
2698 /*
2699  * @implemented
2700  */
2701 NTSTATUS
2702 NTAPI
2708  OUT PVOID Buffer,
2709  IN ULONG Length,
2712 {
2713  NTSTATUS Status;
2715  PIRP Irp;
2717  PIO_STACK_LOCATION StackPtr;
2719  PKEVENT EventObject = NULL;
2720  LARGE_INTEGER CapturedByteOffset;
2721  ULONG CapturedKey = 0;
2722  BOOLEAN Synchronous = FALSE;
2723  PMDL Mdl;
2725  IO_STATUS_BLOCK KernelIosb;
2726  BOOLEAN Success;
2727 
2728  PAGED_CODE();
2729  CapturedByteOffset.QuadPart = 0;
2730  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2731 
2732  /* Get File Object */
2736  PreviousMode,
2737  (PVOID*)&FileObject,
2738  NULL);
2739  if (!NT_SUCCESS(Status)) return Status;
2740 
2741  /* Get the device object */
2743 
2744  /* Validate User-Mode Buffers */
2745  if (PreviousMode != KernelMode)
2746  {
2747  _SEH2_TRY
2748  {
2749  /* Probe the status block */
2751 
2752  /* Probe the read buffer */
2754 
2755  /* Check if we got a byte offset */
2756  if (ByteOffset)
2757  {
2758  /* Capture and probe it */
2759  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
2760  }
2761 
2762  /* Can't use an I/O completion port and an APC at the same time */
2763  if ((FileObject->CompletionContext) && (ApcRoutine))
2764  {
2765  /* Fail */
2767  return STATUS_INVALID_PARAMETER;
2768  }
2769 
2770  /* Perform additional checks for non-cached file access */
2772  {
2773  /* Fail if Length is not sector size aligned
2774  * Perform a quick check for 2^ sector sizes
2775  * If it fails, try a more standard way
2776  */
2777  if ((DeviceObject->SectorSize != 0) &&
2778  ((DeviceObject->SectorSize - 1) & Length) != 0)
2779  {
2780  if (Length % DeviceObject->SectorSize != 0)
2781  {
2782  /* Release the file object and and fail */
2784  return STATUS_INVALID_PARAMETER;
2785  }
2786  }
2787 
2788  /* Fail if buffer doesn't match alignment requirements */
2789  if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
2790  {
2791  /* Release the file object and and fail */
2793  return STATUS_INVALID_PARAMETER;
2794  }
2795 
2796  if (ByteOffset)
2797  {
2798  /* Fail if ByteOffset is not sector size aligned */
2799  if ((DeviceObject->SectorSize != 0) &&
2800  (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
2801  {
2802  /* Release the file object and and fail */
2804  return STATUS_INVALID_PARAMETER;
2805  }
2806  }
2807  }
2808 
2809  /* Capture and probe the key */
2810  if (Key) CapturedKey = ProbeForReadUlong(Key);
2811  }
2813  {
2814  /* Release the file object and return the exception code */
2817  }
2818  _SEH2_END;
2819  }
2820  else
2821  {
2822  /* Kernel mode: capture directly */
2823  if (ByteOffset) CapturedByteOffset = *ByteOffset;
2824  if (Key) CapturedKey = *Key;
2825  }
2826 
2827  /* Check for invalid offset */
2828  if ((CapturedByteOffset.QuadPart < 0) && (CapturedByteOffset.QuadPart != -2))
2829  {
2830  /* -2 is FILE_USE_FILE_POINTER_POSITION */
2832  return STATUS_INVALID_PARAMETER;
2833  }
2834 
2835  /* Check for event */
2836  if (Event)
2837  {
2838  /* Reference it */
2842  PreviousMode,
2843  (PVOID*)&EventObject,
2844  NULL);
2845  if (!NT_SUCCESS(Status))
2846  {
2847  /* Fail */
2849  return Status;
2850  }
2851 
2852  /* Otherwise reset the event */
2853  KeClearEvent(EventObject);
2854  }
2855 
2856  /* Check if we should use Sync IO or not */
2857  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2858  {
2859  /* Lock the file object */
2861  if (Status != STATUS_SUCCESS)
2862  {
2863  if (EventObject) ObDereferenceObject(EventObject);
2865  return Status;
2866  }
2867 
2868  /* Check if we don't have a byte offset available */
2869  if (!(ByteOffset) ||
2870  ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
2871  (CapturedByteOffset.u.HighPart == -1)))
2872  {
2873  /* Use the Current Byte Offset instead */
2874  CapturedByteOffset = FileObject->CurrentByteOffset;
2875  }
2876 
2877  /* If the file is cached, try fast I/O */
2878  if (FileObject->PrivateCacheMap)
2879  {
2880  /* Perform fast read */
2881  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
2883 
2885  &CapturedByteOffset,
2886  Length,
2887  TRUE,
2888  CapturedKey,
2889  Buffer,
2890  &KernelIosb,
2891  DeviceObject);
2892 
2893  /* Only accept the result if we got a straightforward status */
2894  if (Success &&
2895  (KernelIosb.Status == STATUS_SUCCESS ||
2896  KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
2897  KernelIosb.Status == STATUS_END_OF_FILE))
2898  {
2899  /* Fast path -- update transfer & operation counts */
2902  (ULONG)KernelIosb.Information);
2903 
2904  /* Enter SEH to write the IOSB back */
2905  _SEH2_TRY
2906  {
2907  /* Write it back to the caller */
2908  *IoStatusBlock = KernelIosb;
2909  }
2911  {
2912  /* The caller's IOSB was invalid, so fail */
2913  if (EventObject) ObDereferenceObject(EventObject);
2917  }
2918  _SEH2_END;
2919 
2920  /* Signal the completion event */
2921  if (EventObject)
2922  {
2923  KeSetEvent(EventObject, 0, FALSE);
2924  ObDereferenceObject(EventObject);
2925  }
2926 
2927  /* Clean up */
2930  return KernelIosb.Status;
2931  }
2932  }
2933 
2934  /* Remember we are sync */
2935  Synchronous = TRUE;
2936  }
2937  else if (!(ByteOffset) &&
2938  !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
2939  {
2940  /* Otherwise, this was async I/O without a byte offset, so fail */
2941  if (EventObject) ObDereferenceObject(EventObject);
2943  return STATUS_INVALID_PARAMETER;
2944  }
2945 
2946  /* Clear the File Object's event */
2947  KeClearEvent(&FileObject->Event);
2948 
2949  /* Allocate the IRP */
2950  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2951  if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
2952 
2953  /* Set the IRP */
2954  Irp->Tail.Overlay.OriginalFileObject = FileObject;
2955  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2956  Irp->RequestorMode = PreviousMode;
2957  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2958  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2959  Irp->UserIosb = IoStatusBlock;
2960  Irp->UserEvent = EventObject;
2961  Irp->PendingReturned = FALSE;
2962  Irp->Cancel = FALSE;
2963  Irp->CancelRoutine = NULL;
2964  Irp->AssociatedIrp.SystemBuffer = NULL;
2965  Irp->MdlAddress = NULL;
2966 
2967  /* Set the Stack Data */
2968  StackPtr = IoGetNextIrpStackLocation(Irp);
2969  StackPtr->MajorFunction = IRP_MJ_READ;
2970  StackPtr->FileObject = FileObject;
2971  StackPtr->Parameters.Read.Key = CapturedKey;
2972  StackPtr->Parameters.Read.Length = Length;
2973  StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;
2974 
2975  /* Check if this is buffered I/O */
2976  if (DeviceObject->Flags & DO_BUFFERED_IO)
2977  {
2978  /* Check if we have a buffer length */
2979  if (Length)
2980  {
2981  /* Enter SEH */
2982  _SEH2_TRY
2983  {
2984  /* Allocate a buffer */
2985  Irp->AssociatedIrp.SystemBuffer =
2987  Length,
2988  TAG_SYSB);
2989  }
2991  {
2992  /* Allocating failed, clean up and return the exception code */
2993  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
2995  }
2996  _SEH2_END;
2997 
2998  /* Set the buffer and flags */
2999  Irp->UserBuffer = Buffer;
3000  Irp->Flags = (IRP_BUFFERED_IO |
3003  }
3004  else
3005  {
3006  /* Not reading anything */
3008  }
3009  }
3010  else if (DeviceObject->Flags & DO_DIRECT_IO)
3011  {
3012  /* Check if we have a buffer length */
3013  if (Length)
3014  {
3015  _SEH2_TRY
3016  {
3017  /* Allocate an MDL */
3019  if (!Mdl)
3022  }
3024  {
3025  /* Allocating failed, clean up and return the exception code */
3026  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
3028  }
3029  _SEH2_END;
3030 
3031  }
3032 
3033  /* No allocation flags */
3034  Irp->Flags = 0;
3035  }
3036  else
3037  {
3038  /* No allocation flags, and use the buffer directly */
3039  Irp->Flags = 0;
3040  Irp->UserBuffer = Buffer;
3041  }
3042 
3043  /* Now set the deferred read flags */
3045 
3046  if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3047 
3048  /* Perform the call */
3050  Irp,
3051  FileObject,
3052  TRUE,
3053  PreviousMode,
3054  Synchronous,
3055  IopReadTransfer);
3056 }
3057 
3058 /*
3059  * @unimplemented
3060  */
3061 NTSTATUS
3062 NTAPI
3065  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3066  IN PVOID UserApcContext OPTIONAL,
3067  OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3068  IN FILE_SEGMENT_ELEMENT BufferDescription [],
3072 {
3073  UNIMPLEMENTED;
3074  return STATUS_NOT_IMPLEMENTED;
3075 }
3076 
3077 /*
3078  * @unimplemented
3079  */
3080 NTSTATUS
3081 NTAPI
3084  IN PVOID EaBuffer,
3085  IN ULONG EaBufferSize)
3086 {
3087  UNIMPLEMENTED;
3088  return STATUS_NOT_IMPLEMENTED;
3089 }
3090 
3091 /*
3092  * @implemented
3093  */
3094 NTSTATUS
3095 NTAPI
3099  IN ULONG Length,
3101 {
3103  NTSTATUS Status;
3104  PIRP Irp;
3106  PIO_STACK_LOCATION StackPtr;
3108  PKEVENT Event = NULL;
3109  BOOLEAN LocalEvent = FALSE;
3110  PKNORMAL_ROUTINE NormalRoutine;
3111  PVOID NormalContext;
3112  KIRQL OldIrql;
3113  IO_STATUS_BLOCK KernelIosb;
3114  PVOID Queue;
3117  PFILE_RENAME_INFORMATION RenameInfo;
3119  PAGED_CODE();
3120  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3121 
3122  /* Check if we're called from user mode */
3123  if (PreviousMode != KernelMode)
3124  {
3125  /* Validate the information class */
3126  if ((FileInformationClass < 0) ||
3129  {
3130  /* Invalid class */
3132  }
3133 
3134  /* Validate the length */
3136  {
3137  /* Invalid length */
3139  }
3140 
3141  /* Enter SEH for probing */
3142  _SEH2_TRY
3143  {
3144  /* Probe the I/O Status block */
3146 
3147  /* Probe the information */
3149  Length,
3150  (Length == sizeof(BOOLEAN)) ?
3151  sizeof(BOOLEAN) : sizeof(ULONG));
3152  }
3154  {
3155  /* Return the exception code */
3157  }
3158  _SEH2_END;
3159  }
3160  else
3161  {
3162  /* Validate the information class */
3163  if ((FileInformationClass < 0) ||
3166  {
3167  /* Invalid class */
3169  }
3170 
3171  /* Validate the length */
3173  {
3174  /* Invalid length */
3176  }
3177  }
3178 
3179  /* Reference the Handle */
3184  PreviousMode,
3185  (PVOID *)&FileObject,
3186  NULL);
3187  if (!NT_SUCCESS(Status)) return Status;
3188 
3189  /* Check if this is a direct open or not */
3190  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3191  {
3192  /* Get the device object */
3193  DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3194  }
3195  else
3196  {
3197  /* Get the device object */
3199  }
3200 
3201  DPRINT("Will call: %p\n", DeviceObject);
3202  DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
3203 
3204  /* Check if this is a file that was opened for Synch I/O */
3205  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3206  {
3207  /* Lock it */
3209  if (Status != STATUS_SUCCESS)
3210  {
3212  return Status;
3213  }
3214 
3215  /* Check if the caller just wants the position */
3217  {
3218  /* Protect write in SEH */
3219  _SEH2_TRY
3220  {
3221  /* Write the offset */
3222  FileObject->CurrentByteOffset =
3224  CurrentByteOffset;
3225 
3226  /* Fill out the I/O Status Block */
3229  }
3231  {
3232  /* Get the exception code */
3234  }
3235  _SEH2_END;
3236 
3237  /* Update transfer count */
3239 
3240  /* Release the file lock, dereference the file and return */
3243  return Status;
3244  }
3245  }
3246  else
3247  {
3248  /* Use local event */
3250  if (!Event)
3251  {
3254  }
3255 
3257  LocalEvent = TRUE;
3258  }
3259 
3260  /* Clear the File Object event */
3261  KeClearEvent(&FileObject->Event);
3262 
3263  /* Allocate the IRP */
3264  Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
3265  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3266 
3267  /* Set the IRP */
3268  Irp->Tail.Overlay.OriginalFileObject = FileObject;
3269  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3270  Irp->RequestorMode = PreviousMode;
3271  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3272  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3273  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3274  Irp->UserEvent = (LocalEvent) ? Event : NULL;
3275  Irp->AssociatedIrp.SystemBuffer = NULL;
3276  Irp->MdlAddress = NULL;
3277  Irp->UserBuffer = FileInformation;
3278 
3279  /* Set the Stack Data */
3280  StackPtr = IoGetNextIrpStackLocation(Irp);
3282  StackPtr->FileObject = FileObject;
3283 
3284  /* Enter SEH */
3285  _SEH2_TRY
3286  {
3287  /* Allocate a buffer */
3288  Irp->AssociatedIrp.SystemBuffer =
3290  Length,
3291  TAG_SYSB);
3292 
3293  /* Copy the data into it */
3294  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
3296  Length);
3297  }
3299  {
3300  /* Allocating failed, clean up and return the exception code */
3303  }
3304  _SEH2_END;
3305 
3306  /* Set the flags */
3307  Irp->Flags |= (IRP_BUFFERED_IO |
3310 
3311  /* Set the Parameters */
3312  StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
3313  StackPtr->Parameters.SetFile.Length = Length;
3314 
3315  /* Queue the IRP */
3317 
3318  /* Update operation counts */
3320 
3321  /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
3322  /* Handle IO Completion Port quickly */
3324  {
3325  /* Check if the file object already has a completion port */
3326  if ((FileObject->Flags & FO_SYNCHRONOUS_IO) ||
3327  (FileObject->CompletionContext))
3328  {
3329  /* Fail */
3331  }
3332  else
3333  {
3334  /* Reference the Port */
3335  CompletionInfo = Irp->AssociatedIrp.SystemBuffer;
3336  Status = ObReferenceObjectByHandle(CompletionInfo->Port,
3339  PreviousMode,
3340  (PVOID*)&Queue,
3341  NULL);
3342  if (NT_SUCCESS(Status))
3343  {
3344  /* Allocate the Context */
3346  sizeof(IO_COMPLETION_CONTEXT),
3347  IOC_TAG);
3348  if (Context)
3349  {
3350  /* Set the Data */
3351  Context->Key = CompletionInfo->Key;
3352  Context->Port = Queue;
3355  Context,
3356  NULL))
3357  {
3358  /*
3359  * Someone else set the completion port in the
3360  * meanwhile, so dereference the port and fail.
3361  */
3365  }
3366  }
3367  else
3368  {
3369  /* Dereference the Port now */
3372  }
3373  }
3374  }
3375 
3376  /* Set the IRP Status */
3377  Irp->IoStatus.Status = Status;
3378  Irp->IoStatus.Information = 0;
3379  }
3383  {
3384  /* Get associated information */
3385  RenameInfo = Irp->AssociatedIrp.SystemBuffer;
3386 
3387  /* Only rename if:
3388  * -> We have a name
3389  * -> In unicode
3390  * -> sizes are valid
3391  */
3392  if (RenameInfo->FileNameLength != 0 &&
3393  !(RenameInfo->FileNameLength & 1) &&
3395  {
3396  /* Properly set information received */
3398  {
3399  StackPtr->Parameters.SetFile.ClusterCount = ((PFILE_MOVE_CLUSTER_INFORMATION)RenameInfo)->ClusterCount;
3400  }
3401  else
3402  {
3403  StackPtr->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
3404  }
3405 
3406  /* If we got fully path OR relative target, attempt a parent directory open */
3407  if (RenameInfo->FileName[0] == OBJ_NAME_PATH_SEPARATOR || RenameInfo->RootDirectory)
3408  {
3410  if (!NT_SUCCESS(Status))
3411  {
3412  Irp->IoStatus.Status = Status;
3413  }
3414  else
3415  {
3416  /* Call the Driver */
3418  }
3419  }
3420  else
3421  {
3422  /* Call the Driver */
3424  }
3425  }
3426  else
3427  {
3429  Irp->IoStatus.Status = Status;
3430  }
3431  }
3432  else
3433  {
3434  /* Call the Driver */
3436  }
3437 
3438  /* Check if we're waiting for the IRP to complete */
3439  if (Status == STATUS_PENDING)
3440  {
3441  /* Check if this was async I/O */
3442  if (LocalEvent)
3443  {
3444  /* Then to a non-alertable wait */
3446  Executive,
3447  PreviousMode,
3448  FALSE,
3449  NULL);
3450  if (Status == STATUS_USER_APC)
3451  {
3452  /* Abort the request */
3454  }
3455 
3456  /* Set the final status */
3457  Status = KernelIosb.Status;
3458 
3459  /* Enter SEH to write the IOSB back */
3460  _SEH2_TRY
3461  {
3462  /* Write it back to the caller */
3463  *IoStatusBlock = KernelIosb;
3464  }
3466  {
3467  /* Get the exception code */
3469  }
3470  _SEH2_END;
3471 
3472  /* Free the event */
3474  }
3475  else
3476  {
3477  /* Wait for the IRP */
3479  Executive,
3480  PreviousMode,
3481  (FileObject->Flags &
3482  FO_ALERTABLE_IO) != 0,
3483  NULL);
3484  if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED))
3485  {
3486  /* Abort the request */
3488  }
3489 
3490  /* Set the final status */
3491  Status = FileObject->FinalStatus;
3492 
3493  /* Release the file lock */
3495  }
3496  }
3497  else
3498  {
3499  /* Free the event if we had one */
3500  if (LocalEvent)
3501  {
3502  /* Clear it in the IRP for completion */
3503  Irp->UserEvent = NULL;
3505  }
3506 
3507  /* Set the caller IOSB */
3508  Irp->UserIosb = IoStatusBlock;
3509 
3510  /* The IRP wasn't completed, complete it ourselves */
3511  NormalRoutine = NULL;
3512  NormalContext = NULL;
3514  IopCompleteRequest(&Irp->Tail.Apc,
3515  &NormalRoutine,
3516  &NormalContext,
3517  (PVOID*)&FileObject,
3518  &NormalContext);
3520 
3521  /* Release the file object if we had locked it*/
3522  if (!LocalEvent) IopUnlockFileObject(FileObject);
3523  }
3524 
3525  if (TargetHandle != NULL)
3526  {
3528  }
3529 
3530  /* Return the Status */
3531  return Status;
3532 }
3533 
3534 /*
3535  * @unimplemented
3536  */
3537 NTSTATUS
3538 NTAPI
3541  IN PVOID Buffer,
3543 {
3544  UNIMPLEMENTED;
3545  return STATUS_NOT_IMPLEMENTED;
3546 }
3547 
3548 /*
3549  * @implemented
3550  */
3551 NTSTATUS
3552 NTAPI
3557  IN ULONG Key OPTIONAL)
3558 {
3560  PLARGE_INTEGER LocalLength = NULL;
3561  PIRP Irp;
3562  PIO_STACK_LOCATION StackPtr;
3564  PKEVENT Event = NULL;
3565  BOOLEAN LocalEvent = FALSE;
3567  LARGE_INTEGER CapturedByteOffset, CapturedLength;
3568  NTSTATUS Status;
3570  IO_STATUS_BLOCK KernelIosb;
3572  PAGED_CODE();
3573  CapturedByteOffset.QuadPart = 0;
3574  CapturedLength.QuadPart = 0;
3575  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3576 
3577  /* Get File Object */
3579  0,
3581  PreviousMode,
3582  (PVOID*)&FileObject,
3584  if (!NT_SUCCESS(Status)) return Status;
3585 
3586  /* Check if we're called from user mode */
3587  if (PreviousMode != KernelMode)
3588  {
3589  /* Must have either FILE_READ_DATA or FILE_WRITE_DATA access */
3590  if (!(HandleInformation.GrantedAccess &
3592  {
3594  return STATUS_ACCESS_DENIED;
3595  }
3596 
3597  /* Enter SEH for probing */
3598  _SEH2_TRY
3599  {
3600  /* Probe the I/O Status block */
3602 
3603  /* Probe and capture the large integers */
3604  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3605  CapturedLength = ProbeForReadLargeInteger(Length);
3606  }
3608  {
3609  /* Dereference the object and return exception code */
3612  }
3613  _SEH2_END;
3614  }
3615  else
3616  {
3617  /* Otherwise, capture them directly */
3618  CapturedByteOffset = *ByteOffset;
3619  CapturedLength = *Length;
3620  }
3621 
3622  /* Check if this is a direct open or not */
3623  if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3624  {
3625  DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3626  }
3627  else
3628  {
3630  }
3631 
3632  /* Try to do it the FastIO way if possible */
3633  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3635  {
3637  &CapturedByteOffset,
3638  &CapturedLength,
3640  Key,
3641  &KernelIosb,
3642  DeviceObject))
3643  {
3644  /* Write the IOSB back */
3645  _SEH2_TRY
3646  {
3647  *IoStatusBlock = KernelIosb;
3648  }
3650  {
3651  KernelIosb.Status = _SEH2_GetExceptionCode();
3652  }
3653  _SEH2_END;
3654 
3655  /* We're done with FastIO! */
3657  return KernelIosb.Status;
3658  }
3659  }
3660 
3661  /* Check if we should use Sync IO or not */
3662  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3663  {
3664  /* Lock it */
3666  if (Status != STATUS_SUCCESS)
3667  {
3669  return Status;
3670  }
3671  }
3672  else
3673  {
3674  /* Use local event */
3676  if (!Event)
3677  {
3680  }
3682  LocalEvent = TRUE;
3683  }
3684 
3685  /* Clear File Object event */
3686  KeClearEvent(&FileObject->Event);
3687 
3688  /* Allocate the IRP */
3689  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
3690  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
3691 
3692  /* Set up the IRP */
3693  Irp->RequestorMode = PreviousMode;
3694  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
3695  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
3696  Irp->UserEvent = (LocalEvent) ? Event : NULL;
3697  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3698  Irp->Tail.Overlay.OriginalFileObject = FileObject;
3699  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3700 
3701  /* Set up Stack Data */
3702  StackPtr = IoGetNextIrpStackLocation(Irp);
3703  StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
3704  StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
3705  StackPtr->FileObject = FileObject;
3706 
3707  /* Enter SEH */
3708  _SEH2_TRY
3709  {
3710  /* Allocate a buffer */
3711  LocalLength = ExAllocatePoolWithTag(NonPagedPool,
3712  sizeof(LARGE_INTEGER),
3713  TAG_LOCK);
3714 
3715  /* Set the length */
3716  *LocalLength = CapturedLength;
3717  Irp->Tail.Overlay.AuxiliaryBuffer = (PVOID)LocalLength;
3718  StackPtr->Parameters.LockControl.Length = LocalLength;
3719  }
3721  {
3722  /* Allocating failed, clean up and return the exception code */
3724  if (LocalLength) ExFreePoolWithTag(LocalLength, TAG_LOCK);
3725 
3726  /* Return the exception code */
3728  }
3729  _SEH2_END;
3730 
3731  /* Set Parameters */
3732  StackPtr->Parameters.LockControl.ByteOffset = CapturedByteOffset;
3733  StackPtr->Parameters.LockControl.Key = Key;
3734 
3735  /* Call the Driver */
3737  Irp,
3738  FileObject,
3739  FALSE,
3740  PreviousMode,
3741  !LocalEvent,
3743 
3744  /* Check if this was async I/O */
3745  if (LocalEvent)
3746  {
3747  /* It was, finalize this request */
3749  Event,
3750  Irp,
3751  PreviousMode,
3752  &KernelIosb,
3753  IoStatusBlock);
3754  }
3755 
3756  /* Return status */
3757  return Status;
3758 }
3759 
3760 /*
3761  * @implemented
3762  */
3763 NTSTATUS
3764 NTAPI
3770  IN PVOID Buffer,
3771  IN ULONG Length,
3774 {
3775  NTSTATUS Status;
3777  PIRP Irp;
3779  PIO_STACK_LOCATION StackPtr;
3781  PKEVENT EventObject = NULL;
3782  LARGE_INTEGER CapturedByteOffset;
3783  ULONG CapturedKey = 0;
3784  BOOLEAN Synchronous = FALSE;
3785  PMDL Mdl;
3786  OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
3788  IO_STATUS_BLOCK KernelIosb;
3789  BOOLEAN Success;
3790 
3791  PAGED_CODE();
3792  CapturedByteOffset.QuadPart = 0;
3793  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3794 
3795  /* Get File Object for write */
3797  PreviousMode,
3798  &FileObject,
3799  &ObjectHandleInfo);
3800  if (!NT_SUCCESS(Status)) return Status;
3801 
3802  /* Get the device object */
3804 
3805  /* Validate User-Mode Buffers */
3806  if (PreviousMode != KernelMode)
3807  {
3808  _SEH2_TRY
3809  {
3810  /* Probe the status block */
3812 
3813  /* Probe the read buffer */
3814  ProbeForRead(Buffer, Length, 1);
3815 
3816  /* Check if we got a byte offset */
3817  if (ByteOffset)
3818  {
3819  /* Capture and probe it */
3820  CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
3821  }
3822 
3823  /* Can't use an I/O completion port and an APC at the same time */
3824  if ((FileObject->CompletionContext) && (ApcRoutine))
3825  {
3826  /* Fail */
3828  return STATUS_INVALID_PARAMETER;
3829  }
3830 
3831  /* Perform additional checks for non-cached file access */
3833  {
3834  /* Fail if Length is not sector size aligned
3835  * Perform a quick check for 2^ sector sizes
3836  * If it fails, try a more standard way
3837  */
3838  if ((DeviceObject->SectorSize != 0) &&
3839  ((DeviceObject->SectorSize - 1) & Length) != 0)
3840  {
3841  if (Length % DeviceObject->SectorSize != 0)
3842  {
3843  /* Release the file object and and fail */
3845  return STATUS_INVALID_PARAMETER;
3846  }
3847  }
3848 
3849  /* Fail if buffer doesn't match alignment requirements */
3850  if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
3851  {
3852  /* Release the file object and and fail */
3854  return STATUS_INVALID_PARAMETER;
3855  }
3856 
3857  if (ByteOffset)
3858  {
3859  /* Fail if ByteOffset is not sector size aligned */
3860  if ((DeviceObject->SectorSize != 0) &&
3861  (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
3862  {
3863  /* Only if that's not specific values for synchronous IO */
3864  if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) &&
3865  (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION ||
3867  {
3868  /* Release the file object and and fail */
3870  return STATUS_INVALID_PARAMETER;
3871  }
3872  }
3873  }
3874  }
3875 
3876  /* Capture and probe the key */
3877  if (Key) CapturedKey = ProbeForReadUlong(Key);
3878  }
3880  {
3881  /* Release the file object and return the exception code */
3884  }
3885  _SEH2_END;
3886  }
3887  else
3888  {
3889  /* Kernel mode: capture directly */
3890  if (ByteOffset) CapturedByteOffset = *ByteOffset;
3891  if (Key) CapturedKey = *Key;
3892  }
3893 
3894  /* Check for invalid offset */
3895  if (CapturedByteOffset.QuadPart < -2)
3896  {
3897  /* -1 is FILE_WRITE_TO_END_OF_FILE */
3898  /* -2 is FILE_USE_FILE_POINTER_POSITION */
3900  return STATUS_INVALID_PARAMETER;
3901  }
3902 
3903  /* Check if this is an append operation */
3904  if ((ObjectHandleInfo.GrantedAccess &
3906  {
3907  /* Give the drivers something to understand */
3908  CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3909  CapturedByteOffset.u.HighPart = -1;
3910  }
3911 
3912  /* Check for event */
3913  if (Event)
3914  {
3915  /* Reference it */
3919  PreviousMode,
3920  (PVOID*)&EventObject,
3921  NULL);
3922  if (!NT_SUCCESS(Status))
3923  {
3924  /* Fail */
3926  return Status;
3927  }
3928 
3929  /* Otherwise reset the event */
3930  KeClearEvent(EventObject);
3931  }
3932 
3933  /* Check if we should use Sync IO or not */
3934  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3935  {
3936  /* Lock the file object */
3938  if (Status != STATUS_SUCCESS)
3939  {
3940  if (EventObject) ObDereferenceObject(EventObject);
3942  return Status;
3943  }
3944 
3945  /* Check if we don't have a byte offset available */
3946  if (!(ByteOffset) ||
3947  ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
3948  (CapturedByteOffset.u.HighPart == -1)))
3949  {
3950  /* Use the Current Byte Offset instead */
3951  CapturedByteOffset = FileObject->CurrentByteOffset;
3952  }
3953 
3954  /* If the file is cached, try fast I/O */
3955  if (FileObject->PrivateCacheMap)
3956  {
3957  /* Perform fast write */
3958  FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
3960 
3962  &CapturedByteOffset,
3963  Length,
3964  TRUE,
3965  CapturedKey,
3966  Buffer,
3967  &KernelIosb,
3968  DeviceObject);
3969 
3970  /* Only accept the result if it was successful */
3971  if (Success &&
3972  KernelIosb.Status == STATUS_SUCCESS)
3973  {
3974  /* Fast path -- update transfer & operation counts */
3977  (ULONG)KernelIosb.Information);
3978 
3979  /* Enter SEH to write the IOSB back */
3980  _SEH2_TRY
3981  {
3982  /* Write it back to the caller */
3983  *IoStatusBlock = KernelIosb;
3984  }
3986  {
3987  /* The caller's IOSB was invalid, so fail */
3988  if (EventObject) ObDereferenceObject(EventObject);
3992  }
3993  _SEH2_END;
3994 
3995  /* Signal the completion event */
3996  if (EventObject)
3997  {
3998  KeSetEvent(EventObject, 0, FALSE);
3999  ObDereferenceObject(EventObject);
4000  }
4001 
4002  /* Clean up */
4005  return KernelIosb.Status;
4006  }
4007  }
4008 
4009  /* Remember we are sync */
4010  Synchronous = TRUE;
4011  }
4012  else if (!(ByteOffset) &&
4013  !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))
4014  {
4015  /* Otherwise, this was async I/O without a byte offset, so fail */
4016  if (EventObject) ObDereferenceObject(EventObject);
4018  return STATUS_INVALID_PARAMETER;
4019  }
4020 
4021  /* Clear the File Object's event */
4022  KeClearEvent(&FileObject->Event);
4023 
4024  /* Allocate the IRP */
4025  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4026  if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
4027 
4028  /* Set the IRP */
4029  Irp->Tail.Overlay.OriginalFileObject = FileObject;
4030  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4031  Irp->RequestorMode = PreviousMode;
4032  Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
4033  Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
4034  Irp->UserIosb = IoStatusBlock;
4035  Irp->UserEvent = EventObject;
4036  Irp->PendingReturned = FALSE;
4037  Irp->Cancel = FALSE;
4038  Irp->CancelRoutine = NULL;
4039  Irp->AssociatedIrp.SystemBuffer = NULL;
4040  Irp->MdlAddress = NULL;
4041 
4042  /* Set the Stack Data */
4043  StackPtr = IoGetNextIrpStackLocation(Irp);
4044  StackPtr->MajorFunction = IRP_MJ_WRITE;
4045  StackPtr->FileObject = FileObject;
4046  StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?
4047  SL_WRITE_THROUGH : 0;
4048  StackPtr->Parameters.Write.Key = CapturedKey;
4049  StackPtr->Parameters.Write.Length = Length;
4050  StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;
4051 
4052  /* Check if this is buffered I/O */
4053  if (DeviceObject->Flags & DO_BUFFERED_IO)
4054  {
4055  /* Check if we have a buffer length */
4056  if (Length)
4057  {
4058  /* Enter SEH */
4059  _SEH2_TRY
4060  {
4061  /* Allocate a buffer */
4062  Irp->AssociatedIrp.SystemBuffer =
4064  Length,
4065  TAG_SYSB);
4066 
4067  /* Copy the data into it */
4068  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
4069  }
4071  {
4072  /* Allocating failed, clean up and return the exception code */
4073  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4075  }
4076  _SEH2_END;
4077 
4078  /* Set the flags */
4080  }
4081  else
4082  {
4083  /* Not writing anything */
4084  Irp->Flags = IRP_BUFFERED_IO;
4085  }
4086  }
4087  else if (DeviceObject->Flags & DO_DIRECT_IO)
4088  {
4089  /* Check if we have a buffer length */
4090  if (Length)
4091  {
4092  _SEH2_TRY
4093  {
4094  /* Allocate an MDL */
4096  if (!Mdl)
4099  }
4101  {
4102  /* Allocating failed, clean up and return the exception code */
4103  IopCleanupAfterException(FileObject, Irp, EventObject, NULL);
4105  }
4106  _SEH2_END;
4107  }
4108 
4109  /* No allocation flags */
4110  Irp->Flags = 0;
4111  }
4112  else
4113  {
4114  /* No allocation flags, and use the buffer directly */
4115  Irp->Flags = 0;
4116  Irp->UserBuffer = Buffer;
4117  }
4118 
4119  /* Now set the deferred read flags */
4121 
4122  if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
4123 
4124  /* Perform the call */
4126  Irp,
4127  FileObject,
4128  TRUE,
4129  PreviousMode,
4130  Synchronous,
4132 }
4133 
4134 NTSTATUS
4135 NTAPI
4138  IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
4139  IN PVOID UserApcContext OPTIONAL,
4140  OUT PIO_STATUS_BLOCK UserIoStatusBlock,
4141  IN FILE_SEGMENT_ELEMENT BufferDescription [],
4145 {
4146  UNIMPLEMENTED;
4147  return STATUS_NOT_IMPLEMENTED;
4148 }
4149 
4150 /*
4151  * @implemented
4152  */
4153 NTSTATUS
4154 NTAPI
4157  OUT PVOID FsInformation,
4158  IN ULONG Length,
4160 {
4162  PIRP Irp;
4163  PIO_STACK_LOCATION StackPtr;
4165  PKEVENT Event = NULL;
4166  BOOLEAN LocalEvent = FALSE;
4168  NTSTATUS Status;
4169  IO_STATUS_BLOCK KernelIosb;
4170  PAGED_CODE();
4171  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4172 
4173  /* Check if we're called from user mode */
4174  if (PreviousMode != KernelMode)
4175  {
4176  /* Validate the information class */
4177  if ((FsInformationClass < 0) ||
4180  {
4181  /* Invalid class */
4183  }
4184 
4185  /* Validate the length */
4187  {
4188  /* Invalid length */
4190  }
4191 
4192  /* Enter SEH for probing */
4193  _SEH2_TRY
4194  {
4195  /* Probe the I/O Status block */
4197 
4198  /* Probe the information */
4199  ProbeForWrite(FsInformation, Length, sizeof(ULONG));
4200  }
4202  {
4203  /* Return the exception code */
4205  }
4206  _SEH2_END;
4207  }
4208 
4209  /* Get File Object */
4214  PreviousMode,
4215  (PVOID*)&FileObject,
4216  NULL);
4217  if (!NT_SUCCESS(Status)) return Status;
4218 
4219  /* Only allow direct device open for FileFsDeviceInformation */
4222  {
4225  }
4226 
4227  /* Check if we should use Sync IO or not */
4228  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4229  {
4230  /* Lock it */
4232  if (Status != STATUS_SUCCESS)
4233  {
4235  return Status;
4236  }
4237  }
4238 
4239  /*
4240  * Quick path for FileFsDeviceInformation - the kernel has enough
4241  * info to reply instead of the driver, excepted for network file systems
4242  */
4245  {
4246  PFILE_FS_DEVICE_INFORMATION FsDeviceInfo = FsInformation;
4247  DeviceObject = FileObject->DeviceObject;
4248 
4249  _SEH2_TRY
4250  {
4251  FsDeviceInfo->DeviceType = DeviceObject->DeviceType;
4252 
4253  /* Complete characteristcs with mount status if relevant */
4254  FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
4256  {
4258  }
4259 
4262  }
4264  {
4265  /* Check if we had a file lock */
4267  {
4268  /* Release it */
4270  }
4271 
4272  /* Dereference the FO */
4274 
4276  }
4277  _SEH2_END;
4278 
4279  /* Check if we had a file lock */
4281  {
4282  /* Release it */
4284  }
4285 
4286  /* Dereference the FO */
4288 
4289  return STATUS_SUCCESS;
4290  }
4291  /* This is to be handled by the kernel, not by FSD */
4293  {
4295 
4296  _SEH2_TRY
4297  {
4298  /* Allocate our local structure */
4300 
4301  /* And copy back caller data */
4302  RtlCopyMemory(DriverPathInfo, FsInformation, Length);
4303 
4304  /* Is the driver in the IO path? */
4306  (PFILE_FS_DRIVER_PATH_INFORMATION)DriverPathInfo,
4307  Length);
4308  /* We failed, don't continue execution */
4309  if (!NT_SUCCESS(Status))
4310  {
4312  }
4313 
4314  /* We succeed, copy back info */
4315  ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath;
4316 
4317  /* We're done */
4320  }
4322  {
4324  }
4325  _SEH2_END;
4326 
4327  /* Don't leak */
4328  if (DriverPathInfo != NULL)
4329  {
4330  ExFreePoolWithTag(DriverPathInfo, TAG_IO);
4331  }
4332 
4333  /* Check if we had a file lock */
4335  {
4336  /* Release it */
4338  }
4339 
4340  /* Dereference the FO */
4342 
4343  return Status;
4344  }
4345 
4347  {
4348  /* Use local event */
4350  if (!Event)
4351  {
4354  }
4356  LocalEvent = TRUE;
4357  }
4358 
4359  /* Get the device object */
4361 
4362  /* Clear File Object event */
4363  KeClearEvent(&FileObject->Event);
4364 
4365  /* Allocate the IRP */
4366  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4367  if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, Event);
4368 
4369  /* Set up the IRP */
4370  Irp->RequestorMode = PreviousMode;
4371  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4372  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4373  Irp->UserEvent = (LocalEvent) ? Event : NULL;
4374  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4375  Irp->Tail.Overlay.OriginalFileObject = FileObject;
4376  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4377  Irp->UserBuffer = FsInformation;
4378  Irp->AssociatedIrp.SystemBuffer = NULL;
4379  Irp->MdlAddress = NULL;
4380 
4381  /* Set up Stack Data */
4382  StackPtr = IoGetNextIrpStackLocation(Irp);
4384  StackPtr->FileObject = FileObject;
4385 
4386  /* Enter SEH */
4387  _SEH2_TRY
4388  {
4389  /* Allocate a buffer */
4390  Irp->AssociatedIrp.SystemBuffer =
4392  Length,
4393  TAG_SYSB);
4394  }
4396  {
4397  /* Allocating failed, clean up and return the exception code */
4400  }
4401  _SEH2_END;
4402 
4403  /* Set the flags for this buffered + deferred I/O */
4404  Irp->Flags |= (IRP_BUFFERED_IO |
4408 
4409  /* Set Parameters */
4410  StackPtr->Parameters.QueryVolume.Length = Length;
4411  StackPtr->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
4412 
4413  /* Call the Driver */
4415  Irp,
4416  FileObject,
4417  TRUE,
4418  PreviousMode,
4419  !LocalEvent,
4421 
4422  /* Check if this was async I/O */
4423  if (LocalEvent)
4424  {
4425  /* It was, finalize this request */
4427  Event,
4428  Irp,
4429  PreviousMode,
4430  &KernelIosb,
4431  IoStatusBlock);
4432  }
4433 
4434  /* Return status */
4435  return Status;
4436 }
4437 
4438 /*
4439  * @implemented
4440  */
4441 NTSTATUS
4442 NTAPI
4445  IN PVOID FsInformation,
4446  IN ULONG Length,
4448 {
4450  PIRP Irp;
4451  PIO_STACK_LOCATION StackPtr;
4453  PKEVENT Event = NULL;
4454  BOOLEAN LocalEvent = FALSE;
4456  NTSTATUS Status;
4457  IO_STATUS_BLOCK KernelIosb;
4459  PAGED_CODE();
4460  IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4461 
4462  /* Check if we're called from user mode */
4463  if (PreviousMode != KernelMode)
4464  {
4465  /* Validate the information class */
4466  if ((FsInformationClass < 0) ||
4469  {
4470  /* Invalid class */
4472  }
4473 
4474  /* Validate the length */
4476  {
4477  /* Invalid length */
4479  }
4480 
4481  /* Enter SEH for probing */
4482  _SEH2_TRY
4483  {
4484  /* Probe the I/O Status block */
4486 
4487  /* Probe the information */
4488  ProbeForRead(FsInformation, Length, sizeof(ULONG));
4489  }
4491  {
4492  /* Return the exception code */
4494  }
4495  _SEH2_END;
4496  }
4497 
4498  /* Get File Object */
4503  PreviousMode,
4504  (PVOID*)&FileObject,
4505  NULL);
4506  if (!NT_SUCCESS(Status)) return Status;
4507 
4508  /* Get target device for notification */
4511 
4512  /* Check if we should use Sync IO or not */
4513  if (FileObject->Flags & FO_SYNCHRONOUS_IO)
4514  {
4515  /* Lock it */
4517  if (Status != STATUS_SUCCESS)
4518  {
4521  return Status;
4522  }
4523  }
4524  else
4525  {
4526  /* Use local event */
4528  if (!Event)
4529  {
4533  }
4535  LocalEvent = TRUE;
4536  }
4537 
4538  /* Get the device object */
4540 
4541  /* Clear File Object event */
4542  KeClearEvent(&FileObject->Event);
4543 
4544  /* Allocate the IRP */
4545  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
4546  if (!Irp)
4547  {
4550  }
4551 
4552  /* Set up the IRP */
4553  Irp->RequestorMode = PreviousMode;
4554  Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
4555  Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock;
4556  Irp->UserEvent = (LocalEvent) ? Event : NULL;
4557  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
4558  Irp->Tail.Overlay.OriginalFileObject = FileObject;
4559  Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
4560  Irp->UserBuffer = FsInformation;
4561  Irp->AssociatedIrp.SystemBuffer = NULL;
4562  Irp->MdlAddress = NULL;
4563 
4564  /* Set up Stack Data */
4565  StackPtr = IoGetNextIrpStackLocation(Irp);
4567  StackPtr->FileObject = FileObject;
4568 
4569  /* Enter SEH */
4570  _SEH2_TRY
4571  {
4572  /* Allocate a buffer */
4573  Irp->AssociatedIrp.SystemBuffer =
4575  Length,
4576  TAG_SYSB);
4577 
4578  /* Copy the data into it */
4579  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FsInformation, Length);
4580  }
4582  {
4583  /* Allocating failed, clean up and return the exception code */
4587  }
4588  _SEH2_END;
4589 
4590  /* Set the flags for this buffered + deferred I/O */
4592 
4593  /* Set Parameters */
4594  StackPtr->Parameters.SetVolume.Length = Length;
4595  StackPtr->Parameters.SetVolume.FsInformationClass = FsInformationClass;
4596 
4597  /* Call the Driver */
4599  Irp,
4600  FileObject,
4601  FALSE,
4602  PreviousMode,
4603  !LocalEvent,
4605 
4606  /* Check if this was async I/O */
4607  if (LocalEvent)
4608  {
4609  /* It was, finalize this request */
4611