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.

515 lines
15 KiB

  1. /****************************************************************************/
  2. // io.c
  3. //
  4. // Kernel file I/O utility functions.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <ntddk.h>
  9. #include <ctxdd.h>
  10. //
  11. // External references
  12. //
  13. VOID IoQueueThreadIrp(IN PIRP);
  14. /*=============================================================================
  15. == Internal Functions Defined
  16. =============================================================================*/
  17. NTSTATUS
  18. _CtxDoFileIo(
  19. IN ULONG MajorFunction,
  20. IN PFILE_OBJECT fileObject,
  21. IN PVOID Buffer,
  22. IN ULONG Length,
  23. IN PKEVENT pEvent,
  24. OUT PIO_STATUS_BLOCK pIosb,
  25. OUT PIRP *ppIrp
  26. );
  27. NTSTATUS
  28. _CtxDeviceControlComplete(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN PIRP Irp,
  31. IN PVOID Context
  32. );
  33. /*******************************************************************************
  34. * CtxReadFile
  35. *
  36. * Kernel read file routine.
  37. *
  38. * ENTRY:
  39. * fileObject (input)
  40. * pointer to file object for I/O
  41. * Buffer (input)
  42. * pointer to read buffer
  43. * Length (input)
  44. * length of read buffer
  45. * pEvent (input)
  46. * pointer to I/O event (optional)
  47. * pIosb (output)
  48. * pointer to IoStatus block (optional)
  49. ******************************************************************************/
  50. NTSTATUS CtxReadFile(
  51. IN PFILE_OBJECT fileObject,
  52. IN PVOID Buffer,
  53. IN ULONG Length,
  54. IN PKEVENT pEvent OPTIONAL,
  55. OUT PIO_STATUS_BLOCK pIosb OPTIONAL,
  56. OUT PIRP *ppIrp OPTIONAL)
  57. {
  58. return _CtxDoFileIo(IRP_MJ_READ, fileObject, Buffer, Length, pEvent, pIosb, ppIrp);
  59. }
  60. /*******************************************************************************
  61. * CtxWriteFile
  62. *
  63. * Kernel write file routine.
  64. *
  65. * ENTRY:
  66. * fileObject (input)
  67. * pointer to file object for I/O
  68. * Buffer (input)
  69. * pointer to write buffer
  70. * Length (input)
  71. * length of write buffer
  72. * pEvent (input)
  73. * pointer to I/O event (optional)
  74. * pIosb (output)
  75. * pointer to IoStatus block (optional)
  76. ******************************************************************************/
  77. NTSTATUS CtxWriteFile(
  78. IN PFILE_OBJECT fileObject,
  79. IN PVOID Buffer,
  80. IN ULONG Length,
  81. IN PKEVENT pEvent OPTIONAL,
  82. OUT PIO_STATUS_BLOCK pIosb OPTIONAL,
  83. OUT PIRP *ppIrp OPTIONAL)
  84. {
  85. return _CtxDoFileIo(IRP_MJ_WRITE, fileObject, Buffer, Length, pEvent, pIosb, ppIrp);
  86. }
  87. NTSTATUS _CtxDoFileIo(
  88. IN ULONG MajorFunction,
  89. IN PFILE_OBJECT fileObject,
  90. IN PVOID Buffer,
  91. IN ULONG Length,
  92. IN PKEVENT pEvent,
  93. OUT PIO_STATUS_BLOCK pIosb,
  94. OUT PIRP *ppIrp)
  95. {
  96. PDEVICE_OBJECT deviceObject;
  97. LARGE_INTEGER Offset;
  98. PIRP irp;
  99. PIO_STACK_LOCATION irpSp;
  100. NTSTATUS status;
  101. KIRQL irql;
  102. static IO_STATUS_BLOCK Iosb;
  103. /*
  104. * We don't support synchronous (i.e. locked) file I/O.
  105. */
  106. ASSERT( !(fileObject->Flags & FO_SYNCHRONOUS_IO) );
  107. if ((fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  108. return STATUS_INVALID_PARAMETER_MIX;
  109. }
  110. /*
  111. * If caller specified an event, clear it before we begin.
  112. */
  113. if (pEvent) {
  114. KeClearEvent(pEvent);
  115. }
  116. /*
  117. * If the caller does not supply an IOSB, supply
  118. * a static one to avoid the overhead of the exception
  119. * handler in the IO completion APC. Since the caller(s)
  120. * do not care about the result, we can point all such
  121. * callers to the same one.
  122. */
  123. if (pIosb == NULL) {
  124. pIosb = &Iosb;
  125. }
  126. /*
  127. * Get the DeviceObject for this file
  128. */
  129. deviceObject = IoGetRelatedDeviceObject(fileObject);
  130. /*
  131. * Build the IRP for this request
  132. */
  133. Offset.LowPart = FILE_WRITE_TO_END_OF_FILE;
  134. Offset.HighPart = -1;
  135. irp = IoBuildAsynchronousFsdRequest(MajorFunction, deviceObject,
  136. Buffer, Length, &Offset, pIosb);
  137. if (irp == NULL)
  138. return STATUS_INSUFFICIENT_RESOURCES;
  139. /*
  140. * Save callers event pointer.
  141. * Also, we must set IRP_SYNCHRONOUS_API in the IRP flags so that
  142. * the I/O completion code will NOT attempt to dereference the
  143. * event object, since it is not a real object manager object.
  144. */
  145. irp->UserEvent = pEvent;
  146. irp->Flags |= IRP_SYNCHRONOUS_API;
  147. /*
  148. * Reference the file object since it will be dereferenced in the
  149. * I/O completion code, and save a pointer to it in the IRP.
  150. */
  151. ObReferenceObject(fileObject);
  152. irp->Tail.Overlay.OriginalFileObject = fileObject;
  153. irpSp = IoGetNextIrpStackLocation(irp);
  154. irpSp->FileObject = fileObject;
  155. /*
  156. * Set the address of the current thread in the packet so the
  157. * completion code will have a context to execute in.
  158. */
  159. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  160. //
  161. // Queue the IRP to the current thread
  162. //
  163. IoQueueThreadIrp(irp);
  164. //
  165. // Call driver
  166. //
  167. status = IoCallDriver( deviceObject, irp );
  168. //
  169. // If irp->UserEvent == NULL, IO completion will set the file
  170. // object event and status.
  171. //
  172. if (pEvent == NULL) {
  173. if (status == STATUS_PENDING) {
  174. status = KeWaitForSingleObject(&fileObject->Event,
  175. Executive,
  176. KernelMode, // Prevent KSTACK from paging
  177. FALSE, // Non-alertable
  178. (PLARGE_INTEGER)NULL);
  179. ASSERT(status != STATUS_ALERTED);
  180. ASSERT(status != STATUS_USER_APC);
  181. status = fileObject->FinalStatus;
  182. }
  183. }
  184. // This crappy function interface is broken -- returning the IRP
  185. // pointer could corrupt the system, since it could be completed
  186. // and deallocated before the return completes and the caller
  187. // attempts to use the pointer. To get the IRP back the caller
  188. // would have had to set a completion routine, but we use
  189. // IoBuildAsynchronousFsdRequest() which does not allow that.
  190. // Want to change the interface to get rid of the OPTIONAL
  191. // junk -- TermDD only uses the write() interface and always
  192. // passes NULL for everything -- but who knows whether Citrix
  193. // uses this internally?
  194. // Set the return pointer to NULL to cause the caller to fault.
  195. if (pEvent != NULL && ppIrp != NULL)
  196. *ppIrp = NULL;
  197. return status;
  198. }
  199. /*******************************************************************************
  200. * CtxDeviceIoControlFile
  201. *
  202. * Kernel DeviceIoControl routine
  203. *
  204. * ENTRY:
  205. * fileObject (input)
  206. * pointer to file object for I/O
  207. * IoControlCode (input)
  208. * Io control code
  209. * InputBuffer (input)
  210. * pointer to input buffer (optional)
  211. * InputBufferLength (input)
  212. * length of input buffer
  213. * OutputBuffer (input)
  214. * pointer to output buffer (optional)
  215. * OutputBufferLength (input)
  216. * length of output buffer
  217. * InternalDeviceIoControl (input)
  218. * if TRUE, use IOCTL_INTERNAL_DEVICE_IO_CONTROL
  219. * pEvent (input)
  220. * pointer to I/O event (optional)
  221. * pIosb (output)
  222. * pointer to IoStatus block (optional)
  223. ******************************************************************************/
  224. NTSTATUS CtxDeviceIoControlFile(
  225. IN PFILE_OBJECT fileObject,
  226. IN ULONG IoControlCode,
  227. IN PVOID InputBuffer OPTIONAL,
  228. IN ULONG InputBufferLength,
  229. OUT PVOID OutputBuffer OPTIONAL,
  230. IN ULONG OutputBufferLength,
  231. IN BOOLEAN InternalDeviceIoControl,
  232. IN PKEVENT pEvent OPTIONAL,
  233. OUT PIO_STATUS_BLOCK pIosb,
  234. OUT PIRP *ppIrp OPTIONAL)
  235. {
  236. PDEVICE_OBJECT deviceObject;
  237. PIRP irp;
  238. PIO_STACK_LOCATION irpSp;
  239. NTSTATUS status;
  240. /*
  241. * We don't support synchronous (i.e. locked) file I/O.
  242. */
  243. ASSERT( !(fileObject->Flags & FO_SYNCHRONOUS_IO) );
  244. if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) ) {
  245. return( STATUS_INVALID_PARAMETER_MIX );
  246. }
  247. /*
  248. * If caller specified an event, clear it before we begin.
  249. */
  250. if (pEvent) {
  251. KeClearEvent(pEvent);
  252. }
  253. /*
  254. * Get the DeviceObject for this file
  255. */
  256. deviceObject = IoGetRelatedDeviceObject( fileObject );
  257. /*
  258. * Build the IRP for this request
  259. */
  260. irp = IoBuildDeviceIoControlRequest( IoControlCode, deviceObject,
  261. InputBuffer, InputBufferLength,
  262. OutputBuffer, OutputBufferLength,
  263. InternalDeviceIoControl,
  264. pEvent, pIosb );
  265. if ( irp == NULL )
  266. return( STATUS_INSUFFICIENT_RESOURCES );
  267. /*
  268. * Reference the file object since it will be dereferenced in the
  269. * I/O completion code, and save a pointer to it in the IRP.
  270. * Also, we must set IRP_SYNCHRONOUS_API in the IRP flags so that
  271. * the I/O completion code will NOT attempt to dereference the
  272. * event object, since it is not a real object manager object.
  273. */
  274. ObReferenceObject( fileObject );
  275. irp->Tail.Overlay.OriginalFileObject = fileObject;
  276. irpSp = IoGetNextIrpStackLocation( irp );
  277. irpSp->FileObject = fileObject;
  278. irp->Flags |= IRP_SYNCHRONOUS_API;
  279. /*
  280. * Call the driver
  281. */
  282. status = IoCallDriver(deviceObject, irp);
  283. /*
  284. * If the caller did not specify a wait event and the I/O is pending,
  285. * then we must wait for the I/O to complete before we return.
  286. */
  287. if (pEvent == NULL) {
  288. if (status == STATUS_PENDING) {
  289. status = KeWaitForSingleObject(&fileObject->Event, UserRequest,
  290. KernelMode, FALSE, NULL);
  291. if (status == STATUS_SUCCESS)
  292. status = fileObject->FinalStatus;
  293. }
  294. /*
  295. * Caller specified a wait event.
  296. * Return the Irp pointer if the caller specified a return pointer.
  297. */
  298. } else {
  299. if (ppIrp)
  300. *ppIrp = irp;
  301. }
  302. return status;
  303. }
  304. /*******************************************************************************
  305. * CtxInternalDeviceIoControlFile
  306. *
  307. * Kernel DeviceIoControl routine
  308. *
  309. * ENTRY:
  310. * fileObject (input)
  311. * pointer to file object for I/O
  312. * IrpParameters (input)
  313. * information to write to the parameters section of the
  314. * stack location of the IRP.
  315. * IrpParametersLength (input)
  316. * length of the parameter information. Cannot be greater than 16.
  317. * MdlBuffer (input)
  318. * if non-NULL, a buffer of nonpaged pool to be mapped
  319. * into an MDL and placed in the MdlAddress field of the IRP.
  320. * MdlBufferLength (input)
  321. * the size of the buffer pointed to by MdlBuffer.
  322. * MinorFunction (input)
  323. * the minor function code for the request.
  324. * pEvent (input)
  325. * pointer to I/O event (optional)
  326. * pIosb (output)
  327. * pointer to IoStatus block (optional)
  328. ******************************************************************************/
  329. NTSTATUS CtxInternalDeviceIoControlFile(
  330. IN PFILE_OBJECT fileObject,
  331. IN PVOID IrpParameters,
  332. IN ULONG IrpParametersLength,
  333. IN PVOID MdlBuffer OPTIONAL,
  334. IN ULONG MdlBufferLength,
  335. IN UCHAR MinorFunction,
  336. IN PKEVENT pEvent OPTIONAL,
  337. OUT PIO_STATUS_BLOCK pIosb OPTIONAL,
  338. OUT PIRP *ppIrp OPTIONAL)
  339. {
  340. PDEVICE_OBJECT deviceObject;
  341. PIRP irp;
  342. PIO_STACK_LOCATION irpSp;
  343. PMDL mdl;
  344. NTSTATUS status;
  345. /*
  346. * We don't support synchronous (i.e. locked) file I/O.
  347. */
  348. ASSERT( !(fileObject->Flags & FO_SYNCHRONOUS_IO) );
  349. if ( (fileObject->Flags & FO_SYNCHRONOUS_IO) ) {
  350. return( STATUS_INVALID_PARAMETER_MIX );
  351. }
  352. /*
  353. * If caller specified an event, clear it before we begin.
  354. */
  355. if ( pEvent ) {
  356. KeClearEvent( pEvent );
  357. }
  358. /*
  359. * Get the DeviceObject for this file
  360. */
  361. deviceObject = IoGetRelatedDeviceObject( fileObject );
  362. /*
  363. * Build the IRP for this request
  364. */
  365. irp = IoBuildDeviceIoControlRequest( 0, deviceObject,
  366. NULL, 0,
  367. NULL, 0,
  368. TRUE,
  369. pEvent, pIosb );
  370. if ( irp == NULL )
  371. return( STATUS_INSUFFICIENT_RESOURCES );
  372. /*
  373. * If an MDL buffer was specified, get an MDL, map the buffer,
  374. * and place the MDL pointer in the IRP.
  375. */
  376. if ( MdlBuffer != NULL ) {
  377. mdl = IoAllocateMdl(
  378. MdlBuffer,
  379. MdlBufferLength,
  380. FALSE,
  381. FALSE,
  382. irp
  383. );
  384. if ( mdl == NULL ) {
  385. IoFreeIrp( irp );
  386. ObDereferenceObject( fileObject );
  387. return STATUS_INSUFFICIENT_RESOURCES;
  388. }
  389. MmBuildMdlForNonPagedPool( mdl );
  390. } else {
  391. irp->MdlAddress = NULL;
  392. }
  393. /*
  394. * Reference the file object since it will be dereferenced in the
  395. * I/O completion code, and save a pointer to it in the IRP.
  396. * Also, we must set IRP_SYNCHRONOUS_API in the IRP flags so that
  397. * the I/O completion code will NOT attempt to dereference the
  398. * event object, since it is not a real object manager object.
  399. */
  400. ObReferenceObject( fileObject );
  401. irp->Tail.Overlay.OriginalFileObject = fileObject;
  402. irpSp = IoGetNextIrpStackLocation( irp );
  403. irpSp->FileObject = fileObject;
  404. irp->Flags |= IRP_SYNCHRONOUS_API;
  405. /*
  406. * Fill in the service-dependent parameters for the request.
  407. */
  408. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  409. irpSp->MinorFunction = MinorFunction;
  410. ASSERT( IrpParametersLength <= sizeof(irpSp->Parameters) );
  411. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  412. /*
  413. * Set up a completion routine which we'll use to free the MDL
  414. * allocated previously.
  415. */
  416. IoSetCompletionRoutine( irp, _CtxDeviceControlComplete, NULL, TRUE, TRUE, TRUE );
  417. /*
  418. * Call the driver
  419. */
  420. status = IoCallDriver( deviceObject, irp );
  421. /*
  422. * If the caller did not specify a wait event and the I/O is pending,
  423. * then we must wait for the I/O to complete before we return.
  424. */
  425. if ( pEvent == NULL ) {
  426. if ( status == STATUS_PENDING ) {
  427. status = KeWaitForSingleObject( &fileObject->Event, UserRequest, KernelMode, FALSE, NULL );
  428. if ( status == STATUS_SUCCESS )
  429. status = fileObject->FinalStatus;
  430. }
  431. /*
  432. * Caller specified a wait event.
  433. * Return the Irp pointer if the caller specified a return pointer.
  434. */
  435. } else {
  436. if ( ppIrp )
  437. *ppIrp = irp;
  438. }
  439. return( status );
  440. }
  441. NTSTATUS _CtxDeviceControlComplete(
  442. IN PDEVICE_OBJECT DeviceObject,
  443. IN PIRP Irp,
  444. IN PVOID Context)
  445. {
  446. //
  447. // If there was an MDL in the IRP, free it and reset the pointer to
  448. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  449. // in an IRP, which is why we do it here.
  450. //
  451. if ( Irp->MdlAddress != NULL ) {
  452. IoFreeMdl( Irp->MdlAddress );
  453. Irp->MdlAddress = NULL;
  454. }
  455. return( STATUS_SUCCESS );
  456. }