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.

551 lines
15 KiB

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