Leaked source code of windows server 2003
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.

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