Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

505 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vdm.c
  5. Abstract:
  6. This module supplies the entry point to the system for manipulating vdms.
  7. Author:
  8. Dave Hastings (daveh) 6-Apr-1992
  9. Revision History:
  10. --*/
  11. #if defined (_X86_)
  12. #include "vdmp.h"
  13. #endif
  14. #include <ntos.h>
  15. #include <vdmntos.h>
  16. #include <ntvdmp.h>
  17. #include <zwapi.h>
  18. #include <fsrtl.h>
  19. typedef struct _QueryDirPoolData {
  20. KEVENT kevent;
  21. UNICODE_STRING FileName;
  22. WCHAR FileNameBuf[1];
  23. } QDIR_POOLDATA, *PQDIR_POOLDATA;
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE, VdmQueryDirectoryFile)
  26. #endif
  27. #if !defined(i386)
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, NtVdmControl)
  30. #endif
  31. NTSTATUS
  32. NtVdmControl(
  33. IN VDMSERVICECLASS Service,
  34. IN OUT PVOID ServiceData
  35. )
  36. /*++
  37. Routine Description:
  38. This routine is the entry point for controlling Vdms.
  39. On risc it returns STATUS_NOT_IMPLEMENTED.
  40. On 386 the entry point is in i386\vdmentry.c
  41. Arguments:
  42. Service -- Specifies what service is to be performed
  43. ServiceData -- Supplies a pointer to service specific data
  44. Return Value:
  45. --*/
  46. {
  47. PAGED_CODE();
  48. if (Service == VdmQueryDir) {
  49. return VdmQueryDirectoryFile(ServiceData);
  50. }
  51. return STATUS_NOT_IMPLEMENTED;
  52. }
  53. #endif
  54. extern POBJECT_TYPE IoFileObjectType;
  55. NTSTATUS
  56. VdmQueryDirectoryFile(
  57. PVDMQUERYDIRINFO pVdmQueryDir
  58. )
  59. /*++
  60. This VDM specific service allows vdm to restart searches at a specified
  61. location in the dir search by using the FileIndex, FileName parameters
  62. passed back from previous query calls.
  63. See NtQueryDirectoryFile for additional documentation.
  64. Arguments: PVDMQUERYDIRINFO pVdmQueryDir
  65. FileHandle - Supplies a handle to the directory file for which information
  66. should be returned.
  67. FileInformation - Supplies a buffer to receive the requested information
  68. returned about the contents of the directory.
  69. Length - Supplies the length, in bytes, of the FileInformation buffer.
  70. FileName - Supplies a file name within the specified directory.
  71. FileIndex - Supplies a file index within the specified directory.
  72. The FileInformationClass is assumed to be FILE_BOTH_DIR_INFORMATION
  73. The Caller's mode is assumed to be UserMode
  74. Synchronous IO is used
  75. --*/
  76. {
  77. KIRQL irql;
  78. NTSTATUS status;
  79. PKEVENT Event;
  80. HANDLE FileHandle;
  81. IO_STATUS_BLOCK IoStatusBlock;
  82. PVOID FileInformation;
  83. ULONG Length;
  84. UNICODE_STRING FileName;
  85. PUNICODE_STRING pFileNameSrc;
  86. ULONG FileIndex;
  87. PQDIR_POOLDATA QDirPoolData = NULL;
  88. PMDL mdl;
  89. PIRP irp;
  90. PIO_STACK_LOCATION irpSp;
  91. PCHAR SystemBuffer;
  92. PFILE_OBJECT fileObject;
  93. PDEVICE_OBJECT DeviceObject;
  94. PAGED_CODE();
  95. //
  96. // We assume that the caller is usermode, so verify all parameters
  97. // accordingly
  98. //
  99. try {
  100. //
  101. // Copy out the callers service data into local variables
  102. //
  103. ProbeForRead( pVdmQueryDir, sizeof(VDMQUERYDIRINFO), sizeof(ULONG));
  104. FileHandle = pVdmQueryDir->FileHandle;
  105. FileInformation = pVdmQueryDir->FileInformation;
  106. Length = pVdmQueryDir->Length;
  107. FileIndex = pVdmQueryDir->FileIndex;
  108. pFileNameSrc = pVdmQueryDir->FileName;
  109. //
  110. // Ensure that we have a valid file name string
  111. //
  112. //
  113. // check for pVdmQueryDir->Filename validity first
  114. //
  115. if (NULL == pFileNameSrc) {
  116. return(STATUS_INVALID_PARAMETER);
  117. }
  118. FileName = ProbeAndReadUnicodeString(pFileNameSrc);
  119. if (!FileName.Length ||
  120. FileName.Length > MAXIMUM_FILENAME_LENGTH<<1) {
  121. return(STATUS_INVALID_PARAMETER);
  122. }
  123. ProbeForRead(FileName.Buffer, FileName.Length, sizeof( UCHAR ));
  124. //
  125. // The FileInformation buffer must be writeable by the caller.
  126. //
  127. ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
  128. //
  129. // Ensure that the caller's supplied buffer is at least large enough
  130. // to contain the fixed part of the structure required for this
  131. // query.
  132. //
  133. if (Length < sizeof(FILE_BOTH_DIR_INFORMATION)) {
  134. return STATUS_INFO_LENGTH_MISMATCH;
  135. }
  136. //
  137. // Allocate from nonpaged pool a buffer large enough to contain
  138. // the file name, and the kevent used to wait for io.
  139. //
  140. QDirPoolData = (PQDIR_POOLDATA) ExAllocatePoolWithQuotaTag(
  141. NonPagedPool,
  142. sizeof(QDIR_POOLDATA) + FileName.Length,
  143. ' MDV');
  144. //
  145. // Capture the file name string into the nonpaged pool block.
  146. //
  147. QDirPoolData->FileName.Length = FileName.Length;
  148. QDirPoolData->FileName.MaximumLength = FileName.Length;
  149. QDirPoolData->FileName.Buffer = QDirPoolData->FileNameBuf;
  150. RtlCopyMemory( QDirPoolData->FileNameBuf,
  151. FileName.Buffer,
  152. FileName.Length );
  153. } except(EXCEPTION_EXECUTE_HANDLER) {
  154. if (QDirPoolData) {
  155. ExFreePool(QDirPoolData);
  156. }
  157. return GetExceptionCode();
  158. }
  159. //
  160. // There were no blatant errors so far, so reference the file object so
  161. // the target device object can be found. Note that if the handle does
  162. // not refer to a file object, or if the caller does not have the required
  163. // access to the file, then it will fail.
  164. //
  165. status = ObReferenceObjectByHandle( FileHandle,
  166. FILE_LIST_DIRECTORY,
  167. IoFileObjectType,
  168. UserMode,
  169. (PVOID *) &fileObject,
  170. (POBJECT_HANDLE_INFORMATION) NULL );
  171. if (!NT_SUCCESS( status )) {
  172. if (QDirPoolData) {
  173. ExFreePool(QDirPoolData);
  174. }
  175. return status;
  176. }
  177. //
  178. // We don't handle FO_SYNCHRONOUS_IO, because it requires
  179. // io internal functionality. Ntvdm can get away with this
  180. // because it serializes access to the dir handle.
  181. //
  182. //
  183. // Initialize the kernel event that will signal I/O completion
  184. //
  185. Event = &QDirPoolData->kevent;
  186. KeInitializeEvent(Event, SynchronizationEvent, FALSE);
  187. //
  188. // Set the file object to the Not-Signaled state.
  189. //
  190. KeClearEvent( &fileObject->Event );
  191. //
  192. // Get the address of the target device object.
  193. //
  194. DeviceObject = IoGetRelatedDeviceObject( fileObject );
  195. //
  196. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  197. // The allocation is performed with an exception handler in case the
  198. // caller does not have enough quota to allocate the packet.
  199. irp = IoAllocateIrp( DeviceObject->StackSize, TRUE );
  200. if (!irp) {
  201. //
  202. // An IRP could not be allocated. Cleanup and return an appropriate
  203. // error status code.
  204. //
  205. ObDereferenceObject( fileObject );
  206. if (QDirPoolData) {
  207. ExFreePool(QDirPoolData);
  208. }
  209. return STATUS_INSUFFICIENT_RESOURCES;
  210. }
  211. //
  212. // Fill in the service independent parameters in the IRP.
  213. //
  214. irp->Flags = (ULONG)IRP_SYNCHRONOUS_API;
  215. irp->RequestorMode = UserMode;
  216. irp->UserIosb = &IoStatusBlock;
  217. irp->UserEvent = Event;
  218. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  219. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  220. SystemBuffer = NULL;
  221. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  222. irp->Tail.Overlay.OriginalFileObject = fileObject;
  223. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  224. irp->MdlAddress = NULL;
  225. //
  226. // Get a pointer to the stack location for the first driver. This will be
  227. // used to pass the function codes and parameters.
  228. //
  229. irpSp = IoGetNextIrpStackLocation( irp );
  230. irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
  231. irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
  232. irpSp->FileObject = fileObject;
  233. //
  234. // Copy the caller's parameters to the service-specific portion of the
  235. // IRP.
  236. //
  237. irpSp->Parameters.QueryDirectory.Length = Length;
  238. irpSp->Parameters.QueryDirectory.FileInformationClass = FileBothDirectoryInformation;
  239. irpSp->Parameters.QueryDirectory.FileIndex = FileIndex;
  240. if (QDirPoolData->FileName.Length) {
  241. irpSp->Parameters.QueryDirectory.FileName = (PSTRING)&QDirPoolData->FileName;
  242. } else {
  243. irpSp->Parameters.QueryDirectory.FileName = NULL;
  244. }
  245. irpSp->Flags = SL_INDEX_SPECIFIED;
  246. //
  247. // Now determine whether this driver expects to have data buffered to it
  248. // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO
  249. // flag in the device object. If the flag is set, then a system buffer is
  250. // allocated and the driver's data will be copied into it. Otherwise, a
  251. // Memory Descriptor List (MDL) is allocated and the caller's buffer is
  252. // locked down using it.
  253. //
  254. if (DeviceObject->Flags & DO_BUFFERED_IO) {
  255. //
  256. // The file system wants buffered I/O. Pass the address of the
  257. // "system buffer" in the IRP. Note that we don't want the buffer
  258. // deallocated, nor do we want the I/O system to copy to a user
  259. // buffer, so we don't set the corresponding flags in irp->Flags.
  260. //
  261. try {
  262. //
  263. // Allocate the intermediary system buffer from nonpaged pool and
  264. // charge quota for it.
  265. //
  266. SystemBuffer = ExAllocatePoolWithQuotaTag( NonPagedPool,
  267. Length,
  268. ' MDV' );
  269. irp->AssociatedIrp.SystemBuffer = SystemBuffer;
  270. } except(EXCEPTION_EXECUTE_HANDLER) {
  271. IoFreeIrp(irp);
  272. ObDereferenceObject( fileObject );
  273. if (QDirPoolData) {
  274. ExFreePool(QDirPoolData);
  275. }
  276. return GetExceptionCode();
  277. }
  278. } else if (DeviceObject->Flags & DO_DIRECT_IO) {
  279. //
  280. // This is a direct I/O operation. Allocate an MDL and invoke the
  281. // memory management routine to lock the buffer into memory. This is
  282. // done using an exception handler that will perform cleanup if the
  283. // operation fails.
  284. //
  285. mdl = (PMDL) NULL;
  286. try {
  287. //
  288. // Allocate an MDL, charging quota for it, and hang it off of the
  289. // IRP. Probe and lock the pages associated with the caller's
  290. // buffer for write access and fill in the MDL with the PFNs of
  291. // those pages.
  292. //
  293. mdl = IoAllocateMdl( FileInformation, Length, FALSE, TRUE, irp );
  294. if (mdl == NULL) {
  295. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  296. }
  297. MmProbeAndLockPages( mdl, UserMode, IoWriteAccess );
  298. } except(EXCEPTION_EXECUTE_HANDLER) {
  299. if (irp->MdlAddress != NULL) {
  300. IoFreeMdl( irp->MdlAddress );
  301. }
  302. IoFreeIrp(irp);
  303. ObDereferenceObject( fileObject );
  304. if (QDirPoolData) {
  305. ExFreePool(QDirPoolData);
  306. }
  307. return GetExceptionCode();
  308. }
  309. } else {
  310. //
  311. // Pass the address of the user's buffer so the driver has access to
  312. // it. It is now the driver's responsibility to do everything.
  313. //
  314. irp->UserBuffer = FileInformation;
  315. }
  316. //
  317. // Insert the packet at the head of the IRP list for the thread.
  318. //
  319. KeRaiseIrql( APC_LEVEL, &irql );
  320. InsertHeadList( &irp->Tail.Overlay.Thread->IrpList,
  321. &irp->ThreadListEntry );
  322. KeLowerIrql( irql );
  323. //
  324. // invoke the driver and wait for it to complete
  325. //
  326. status = IoCallDriver(DeviceObject, irp);
  327. if (status == STATUS_PENDING) {
  328. status = KeWaitForSingleObject(
  329. Event,
  330. UserRequest,
  331. UserMode,
  332. FALSE,
  333. NULL );
  334. }
  335. if (NT_SUCCESS(status)) {
  336. status = IoStatusBlock.Status;
  337. if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
  338. if (SystemBuffer) {
  339. try {
  340. RtlCopyMemory( FileInformation,
  341. SystemBuffer,
  342. IoStatusBlock.Information
  343. );
  344. } except(EXCEPTION_EXECUTE_HANDLER) {
  345. status = GetExceptionCode();
  346. }
  347. }
  348. }
  349. }
  350. //
  351. // Cleanup any memory allocated
  352. //
  353. if (QDirPoolData) {
  354. ExFreePool(QDirPoolData);
  355. }
  356. if (SystemBuffer) {
  357. ExFreePool(SystemBuffer);
  358. }
  359. return status;
  360. }