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