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.

1776 lines
58 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. qsinfo.c
  5. Abstract:
  6. This module contains the code to implement the NtQueryInformationFile and
  7. NtSetInformationFile system services for the NT I/O system.
  8. Author:
  9. Darryl E. Havens (darrylh) 6-Jun-1989
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. //
  16. // Create local definitions for long flag names to make code slightly more
  17. // readable.
  18. //
  19. #define FSIO_A FILE_SYNCHRONOUS_IO_ALERT
  20. #define FSIO_NA FILE_SYNCHRONOUS_IO_NONALERT
  21. //
  22. // Forward declarations of local routines.
  23. //
  24. ULONG
  25. IopGetModeInformation(
  26. IN PFILE_OBJECT FileObject
  27. );
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, IopGetModeInformation)
  30. #pragma alloc_text(PAGE, NtQueryInformationFile)
  31. #pragma alloc_text(PAGE, NtSetInformationFile)
  32. #endif
  33. ULONG
  34. IopGetModeInformation(
  35. IN PFILE_OBJECT FileObject
  36. )
  37. /*++
  38. Routine Description:
  39. This encapsulates extracting and translating the mode bits from
  40. the passed file object, to be returned from a query information call.
  41. Arguments:
  42. FileObject - Specifies the file object for which to return Mode info.
  43. Return Value:
  44. The translated mode information is returned.
  45. --*/
  46. {
  47. ULONG mode = 0;
  48. if (FileObject->Flags & FO_WRITE_THROUGH) {
  49. mode = FILE_WRITE_THROUGH;
  50. }
  51. if (FileObject->Flags & FO_SEQUENTIAL_ONLY) {
  52. mode |= FILE_SEQUENTIAL_ONLY;
  53. }
  54. if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  55. mode |= FILE_NO_INTERMEDIATE_BUFFERING;
  56. }
  57. if (FileObject->Flags & FO_SYNCHRONOUS_IO) {
  58. if (FileObject->Flags & FO_ALERTABLE_IO) {
  59. mode |= FILE_SYNCHRONOUS_IO_ALERT;
  60. } else {
  61. mode |= FILE_SYNCHRONOUS_IO_NONALERT;
  62. }
  63. }
  64. if (FileObject->Flags & FO_DELETE_ON_CLOSE) {
  65. mode |= FILE_DELETE_ON_CLOSE;
  66. }
  67. return mode;
  68. }
  69. NTSTATUS
  70. NtQueryInformationFile(
  71. IN HANDLE FileHandle,
  72. OUT PIO_STATUS_BLOCK IoStatusBlock,
  73. OUT PVOID FileInformation,
  74. IN ULONG Length,
  75. IN FILE_INFORMATION_CLASS FileInformationClass
  76. )
  77. /*++
  78. Routine Description:
  79. This service returns the requested information about a specified file.
  80. The information returned is determined by the FileInformationClass that
  81. is specified, and it is placed into the caller's FileInformation buffer.
  82. Arguments:
  83. FileHandle - Supplies a handle to the file about which the requested
  84. information should be returned.
  85. IoStatusBlock - Address of the caller's I/O status block.
  86. FileInformation - Supplies a buffer to receive the requested information
  87. returned about the file.
  88. Length - Supplies the length, in bytes, of the FileInformation buffer.
  89. FileInformationClass - Specifies the type of information which should be
  90. returned about the file.
  91. Return Value:
  92. The status returned is the final completion status of the operation.
  93. --*/
  94. {
  95. PIRP irp;
  96. NTSTATUS status;
  97. PFILE_OBJECT fileObject;
  98. PDEVICE_OBJECT deviceObject;
  99. PFAST_IO_DISPATCH fastIoDispatch;
  100. PKEVENT event = (PKEVENT) NULL;
  101. KPROCESSOR_MODE requestorMode;
  102. PIO_STACK_LOCATION irpSp;
  103. IO_STATUS_BLOCK localIoStatus = {0};
  104. OBJECT_HANDLE_INFORMATION handleInformation;
  105. BOOLEAN synchronousIo;
  106. BOOLEAN skipDriver;
  107. PETHREAD CurrentThread;
  108. PAGED_CODE();
  109. //
  110. // Get the previous mode; i.e., the mode of the caller.
  111. //
  112. CurrentThread = PsGetCurrentThread ();
  113. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  114. if (requestorMode != KernelMode) {
  115. //
  116. // Ensure that the FileInformationClass parameter is legal for querying
  117. // information about the file.
  118. //
  119. if ((ULONG) FileInformationClass >= FileMaximumInformation ||
  120. !IopQueryOperationLength[FileInformationClass]) {
  121. return STATUS_INVALID_INFO_CLASS;
  122. }
  123. //
  124. // Ensure that the supplied buffer is large enough to contain the
  125. // information associated with the specified set operation that is
  126. // to be performed.
  127. //
  128. if (Length < (ULONG) IopQueryOperationLength[FileInformationClass]) {
  129. return STATUS_INFO_LENGTH_MISMATCH;
  130. }
  131. //
  132. // The caller's access mode is not kernel so probe each of the arguments
  133. // and capture them as necessary. If any failures occur, the condition
  134. // handler will be invoked to handle them. It will simply cleanup and
  135. // return an access violation status code back to the system service
  136. // dispatcher.
  137. //
  138. try {
  139. //
  140. // The IoStatusBlock parameter must be writeable by the caller.
  141. //
  142. ProbeForWriteIoStatus( IoStatusBlock );
  143. //
  144. // The FileInformation buffer must be writeable by the caller.
  145. //
  146. #if defined(_X86_)
  147. ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
  148. #elif defined(_WIN64)
  149. //
  150. // If we are a wow64 process, follow the X86 rules
  151. //
  152. if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) {
  153. ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
  154. } else {
  155. ProbeForWrite( FileInformation,
  156. Length,
  157. IopQuerySetAlignmentRequirement[FileInformationClass] );
  158. }
  159. #else
  160. ProbeForWrite( FileInformation,
  161. Length,
  162. IopQuerySetAlignmentRequirement[FileInformationClass] );
  163. #endif
  164. } except(EXCEPTION_EXECUTE_HANDLER) {
  165. //
  166. // An exception was incurred while probing the caller's
  167. // parameters. Simply return an appropriate error status
  168. // code.
  169. //
  170. return GetExceptionCode();
  171. }
  172. #if DBG
  173. } else {
  174. //
  175. // The caller's mode is kernel. Ensure that at least the information
  176. // class and lengths are appropriate.
  177. //
  178. if ((ULONG) FileInformationClass >= FileMaximumInformation ||
  179. !IopQueryOperationLength[FileInformationClass]) {
  180. return STATUS_INVALID_INFO_CLASS;
  181. }
  182. if (Length < (ULONG) IopQueryOperationLength[FileInformationClass]) {
  183. return STATUS_INFO_LENGTH_MISMATCH;
  184. }
  185. #endif // DBG
  186. }
  187. //
  188. // There were no blatant errors so far, so reference the file object so
  189. // the target device object can be found. Note that if the handle does
  190. // not refer to a file object, or if the caller does not have the required
  191. // access to the file, then it will fail.
  192. //
  193. status = ObReferenceObjectByHandle( FileHandle,
  194. IopQueryOperationAccess[FileInformationClass],
  195. IoFileObjectType,
  196. requestorMode,
  197. (PVOID *) &fileObject,
  198. &handleInformation);
  199. if (!NT_SUCCESS( status )) {
  200. return status;
  201. }
  202. //
  203. // Get the address of the target device object. If this file represents
  204. // a device that was opened directly, then simply use the device or its
  205. // attached device(s) directly. Also get the address of the Fast Io
  206. // dispatch structure.
  207. //
  208. if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  209. deviceObject = IoGetRelatedDeviceObject( fileObject );
  210. } else {
  211. deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
  212. }
  213. fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  214. //
  215. // Make a special check here to determine whether this is a synchronous
  216. // I/O operation. If it is, then wait here until the file is owned by
  217. // the current thread. If this is not a (serialized) synchronous I/O
  218. // operation, then allocate and initialize the local event.
  219. //
  220. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  221. BOOLEAN interrupted;
  222. if (!IopAcquireFastLock( fileObject )) {
  223. status = IopAcquireFileObjectLock( fileObject,
  224. requestorMode,
  225. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  226. &interrupted );
  227. if (interrupted) {
  228. ObDereferenceObject( fileObject );
  229. return status;
  230. }
  231. }
  232. //
  233. // Make a special check here to determine whether or not the caller
  234. // is attempting to query the file position pointer. If so, then
  235. // return it immediately and get out.
  236. //
  237. if (FileInformationClass == FilePositionInformation) {
  238. //
  239. // The caller has requested the current file position context
  240. // information. This is a relatively frequent call, so it is
  241. // optimized here to cut through the normal IRP path.
  242. //
  243. // Begin by establishing a condition handler and attempting to
  244. // return both the file position information as well as the I/O
  245. // status block. If writing the output buffer fails, then return
  246. // an appropriate error status code. If writing the I/O status
  247. // block fails, then ignore the error. This is what would
  248. // normally happen were everything to go through normal special
  249. // kernel APC processing.
  250. //
  251. BOOLEAN writingBuffer = TRUE;
  252. PFILE_POSITION_INFORMATION fileInformation = FileInformation;
  253. try {
  254. //
  255. // Return the current position information.
  256. //
  257. fileInformation->CurrentByteOffset = fileObject->CurrentByteOffset;
  258. writingBuffer = FALSE;
  259. //
  260. // Write the I/O status block.
  261. //
  262. IoStatusBlock->Status = STATUS_SUCCESS;
  263. IoStatusBlock->Information = sizeof( FILE_POSITION_INFORMATION );
  264. } except( EXCEPTION_EXECUTE_HANDLER ) {
  265. //
  266. // One of writing the caller's buffer or writing the I/O
  267. // status block failed. Set the final status appropriately.
  268. //
  269. if (writingBuffer) {
  270. status = GetExceptionCode();
  271. }
  272. }
  273. //
  274. // Note that the state of the event in the file object has not yet
  275. // been reset, so it need not be set either. Therefore, simply
  276. // cleanup and return.
  277. //
  278. IopReleaseFileObjectLock( fileObject );
  279. ObDereferenceObject( fileObject );
  280. return status;
  281. //
  282. // Also do a special check if the caller it doing a query for basic or
  283. // standard information and if so then try the fast query calls if they
  284. // exist.
  285. //
  286. } else if (fastIoDispatch &&
  287. (((FileInformationClass == FileBasicInformation) &&
  288. fastIoDispatch->FastIoQueryBasicInfo) ||
  289. ((FileInformationClass == FileStandardInformation) &&
  290. fastIoDispatch->FastIoQueryStandardInfo))) {
  291. IO_STATUS_BLOCK localIoStatus;
  292. BOOLEAN queryResult = FALSE;
  293. BOOLEAN writingStatus = FALSE;
  294. //
  295. // Do the query and setting of the IoStatusBlock inside an exception
  296. // handler. Note that if an exception occurs, other than writing
  297. // the status back, then the IRP route will be taken. If an error
  298. // occurs attempting to write the status back to the caller's buffer
  299. // then it will be ignored, just as it would be on the long path.
  300. //
  301. try {
  302. if (FileInformationClass == FileBasicInformation) {
  303. queryResult = fastIoDispatch->FastIoQueryBasicInfo( fileObject,
  304. TRUE,
  305. FileInformation,
  306. &localIoStatus,
  307. deviceObject );
  308. } else {
  309. queryResult = fastIoDispatch->FastIoQueryStandardInfo( fileObject,
  310. TRUE,
  311. FileInformation,
  312. &localIoStatus,
  313. deviceObject );
  314. }
  315. if (queryResult) {
  316. status = localIoStatus.Status;
  317. writingStatus = TRUE;
  318. *IoStatusBlock = localIoStatus;
  319. }
  320. } except( EXCEPTION_EXECUTE_HANDLER ) {
  321. //
  322. // If the result of the preceeding block is an exception that
  323. // occurred after the Fast I/O path itself, then the query
  324. // actually succeeded so everything is done already, but the
  325. // user's I/O status buffer is not writable. This case is
  326. // ignored to be consistent w/the long path.
  327. //
  328. if (!writingStatus) {
  329. status = GetExceptionCode();
  330. }
  331. }
  332. //
  333. // If the results of the preceeding statement block is true, then
  334. // the fast query call succeeeded, so simply cleanup and return.
  335. //
  336. if (queryResult) {
  337. //
  338. // Note that once again, the event in the file object has not
  339. // yet been set reset, so it need not be set to the Signaled
  340. // state, so simply cleanup and return.
  341. //
  342. IopReleaseFileObjectLock( fileObject );
  343. ObDereferenceObject( fileObject );
  344. return status;
  345. }
  346. }
  347. synchronousIo = TRUE;
  348. } else {
  349. //
  350. // This is a synchronous API being invoked for a file that is opened
  351. // for asynchronous I/O. This means that this system service is
  352. // to synchronize the completion of the operation before returning
  353. // to the caller. A local event is used to do this.
  354. //
  355. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  356. if (event == NULL) {
  357. ObDereferenceObject( fileObject );
  358. return STATUS_INSUFFICIENT_RESOURCES;
  359. }
  360. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  361. synchronousIo = FALSE;
  362. }
  363. //
  364. // Set the file object to the Not-Signaled state.
  365. //
  366. KeClearEvent( &fileObject->Event );
  367. //
  368. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  369. // The allocation is performed with an exception handler in case the
  370. // caller does not have enough quota to allocate the packet.
  371. //
  372. irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
  373. if (!irp) {
  374. //
  375. // An IRP could not be allocated. Cleanup and return an appropriate
  376. // error status code.
  377. //
  378. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  379. ExFreePool( event );
  380. }
  381. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  382. return STATUS_INSUFFICIENT_RESOURCES;
  383. }
  384. irp->Tail.Overlay.OriginalFileObject = fileObject;
  385. irp->Tail.Overlay.Thread = CurrentThread;
  386. irp->RequestorMode = requestorMode;
  387. //
  388. // Fill in the service independent parameters in the IRP.
  389. //
  390. if (synchronousIo) {
  391. irp->UserEvent = (PKEVENT) NULL;
  392. irp->UserIosb = IoStatusBlock;
  393. } else {
  394. irp->UserEvent = event;
  395. irp->UserIosb = &localIoStatus;
  396. irp->Flags = IRP_SYNCHRONOUS_API;
  397. }
  398. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  399. //
  400. // Get a pointer to the stack location for the first driver. This will be
  401. // used to pass the original function codes and parameters.
  402. //
  403. irpSp = IoGetNextIrpStackLocation( irp );
  404. irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
  405. irpSp->FileObject = fileObject;
  406. //
  407. // Allocate a buffer which should be used to put the information into by
  408. // the driver. This will be copied back to the caller's buffer when the
  409. // service completes. This is done by setting the flag which says that
  410. // this is an input operation.
  411. //
  412. irp->UserBuffer = FileInformation;
  413. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  414. irp->MdlAddress = (PMDL) NULL;
  415. try {
  416. //
  417. // Allocate the system buffer using an exception handler so that
  418. // errors can be caught and handled.
  419. //
  420. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  421. Length );
  422. } except(EXCEPTION_EXECUTE_HANDLER) {
  423. //
  424. // An exception was incurred by attempting to allocate the intermediary
  425. // system buffer. Cleanup everything and return an appropriate error
  426. // status code.
  427. //
  428. IopExceptionCleanup( fileObject,
  429. irp,
  430. (PKEVENT) NULL,
  431. event );
  432. return GetExceptionCode();
  433. }
  434. irp->Flags |= IRP_BUFFERED_IO |
  435. IRP_DEALLOCATE_BUFFER |
  436. IRP_INPUT_OPERATION |
  437. IRP_DEFER_IO_COMPLETION;
  438. //
  439. // Copy the caller's parameters to the service-specific portion of the
  440. // IRP.
  441. //
  442. irpSp->Parameters.QueryFile.Length = Length;
  443. irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
  444. //
  445. // Insert the packet at the head of the IRP list for the thread.
  446. //
  447. IopQueueThreadIrp( irp );
  448. //
  449. // Update the operation count statistic for the current process for
  450. // operations other than read and write.
  451. //
  452. IopUpdateOtherOperationCount();
  453. //
  454. // Everything is now set to invoke the device driver with this request.
  455. // However, it is possible that the information that the caller wants
  456. // is device independent. If this is the case, then the request can
  457. // be satisfied here without having to have all of the drivers implement
  458. // the same code. Note that having the IRP is still necessary since
  459. // the I/O completion code requires it.
  460. //
  461. skipDriver = FALSE;
  462. if (FileInformationClass == FileAccessInformation) {
  463. PFILE_ACCESS_INFORMATION accessBuffer = irp->AssociatedIrp.SystemBuffer;
  464. //
  465. // Return the access information for this file.
  466. //
  467. accessBuffer->AccessFlags = handleInformation.GrantedAccess;
  468. //
  469. // Complete the I/O operation.
  470. //
  471. irp->IoStatus.Information = sizeof( FILE_ACCESS_INFORMATION );
  472. skipDriver = TRUE;
  473. } else if (FileInformationClass == FileModeInformation) {
  474. PFILE_MODE_INFORMATION modeBuffer = irp->AssociatedIrp.SystemBuffer;
  475. //
  476. // Return the mode information for this file.
  477. //
  478. modeBuffer->Mode = IopGetModeInformation( fileObject );
  479. //
  480. // Complete the I/O operation.
  481. //
  482. irp->IoStatus.Information = sizeof( FILE_MODE_INFORMATION );
  483. skipDriver = TRUE;
  484. } else if (FileInformationClass == FileAlignmentInformation) {
  485. PFILE_ALIGNMENT_INFORMATION alignmentInformation = irp->AssociatedIrp.SystemBuffer;
  486. //
  487. // Return the alignment information for this file.
  488. //
  489. alignmentInformation->AlignmentRequirement = deviceObject->AlignmentRequirement;
  490. //
  491. // Complete the I/O operation.
  492. //
  493. irp->IoStatus.Information = sizeof( FILE_ALIGNMENT_INFORMATION );
  494. skipDriver = TRUE;
  495. } else if (FileInformationClass == FileAllInformation) {
  496. PFILE_ALL_INFORMATION allInformation = irp->AssociatedIrp.SystemBuffer;
  497. //
  498. // The caller has requested all of the information about the file.
  499. // This request is handled specially because the service will fill
  500. // in the Access and Mode and Alignment information in the buffer
  501. // and then pass the buffer to the driver to fill in the remainder.
  502. //
  503. // Begin by returning the Access information for the file.
  504. //
  505. allInformation->AccessInformation.AccessFlags =
  506. handleInformation.GrantedAccess;
  507. //
  508. // Return the mode information for this file.
  509. //
  510. allInformation->ModeInformation.Mode =
  511. IopGetModeInformation( fileObject );
  512. //
  513. // Return the alignment information for this file.
  514. //
  515. allInformation->AlignmentInformation.AlignmentRequirement =
  516. deviceObject->AlignmentRequirement;
  517. //
  518. // Finally, set the information field of the IoStatus block in the IRP
  519. // to account for the amount information already filled in and invoke
  520. // the driver to fill in the remainder.
  521. //
  522. irp->IoStatus.Information = sizeof( FILE_ACCESS_INFORMATION ) +
  523. sizeof( FILE_MODE_INFORMATION ) +
  524. sizeof( FILE_ALIGNMENT_INFORMATION );
  525. }
  526. if (skipDriver) {
  527. //
  528. // The requested operation has already been performed. Simply
  529. // set the final status in the packet and the return state.
  530. //
  531. status = STATUS_SUCCESS;
  532. irp->IoStatus.Status = STATUS_SUCCESS;
  533. } else {
  534. //
  535. // This is not a request that can be [completely] performed here, so
  536. // invoke the driver at its appropriate dispatch entry with the IRP.
  537. //
  538. status = IoCallDriver( deviceObject, irp );
  539. }
  540. //
  541. // If this operation was a synchronous I/O operation, check the return
  542. // status to determine whether or not to wait on the file object. If
  543. // the file object is to be waited on, wait for the operation to complete
  544. // and obtain the final status from the file object itself.
  545. //
  546. if (status == STATUS_PENDING) {
  547. if (synchronousIo) {
  548. status = KeWaitForSingleObject( &fileObject->Event,
  549. Executive,
  550. requestorMode,
  551. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  552. (PLARGE_INTEGER) NULL );
  553. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  554. //
  555. // The wait request has ended either because the thread was
  556. // alerted or an APC was queued to this thread, because of
  557. // thread rundown or CTRL/C processing. In either case, try
  558. // to bail out of this I/O request carefully so that the IRP
  559. // completes before this routine exists so that synchronization
  560. // with the file object will remain intact.
  561. //
  562. IopCancelAlertedRequest( &fileObject->Event, irp );
  563. }
  564. status = fileObject->FinalStatus;
  565. IopReleaseFileObjectLock( fileObject );
  566. } else {
  567. //
  568. // This is a normal synchronous I/O operation, as opposed to a
  569. // serialized synchronous I/O operation. For this case, wait for
  570. // the local event and copy the final status information back to
  571. // the caller.
  572. //
  573. status = KeWaitForSingleObject( event,
  574. Executive,
  575. requestorMode,
  576. FALSE,
  577. (PLARGE_INTEGER) NULL );
  578. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  579. //
  580. // The wait request has ended either because the thread was
  581. // alerted or an APC was queued to this thread, because of
  582. // thread rundown or CTRL/C processing. In either case, try
  583. // to bail out of this I/O request carefully so that the IRP
  584. // completes before this routine exists or the event will not
  585. // be around to set to the Signaled state.
  586. //
  587. IopCancelAlertedRequest( event, irp );
  588. }
  589. status = localIoStatus.Status;
  590. try {
  591. *IoStatusBlock = localIoStatus;
  592. } except(EXCEPTION_EXECUTE_HANDLER) {
  593. //
  594. // An exception occurred attempting to write the caller's I/O
  595. // status block. Simply change the final status of the operation
  596. // to the exception code.
  597. //
  598. status = GetExceptionCode();
  599. }
  600. ExFreePool( event );
  601. }
  602. } else {
  603. //
  604. // The I/O operation finished without return a status of pending.
  605. // This means that the operation has not been through I/O completion,
  606. // so it must be done here.
  607. //
  608. PKNORMAL_ROUTINE normalRoutine;
  609. PVOID normalContext;
  610. KIRQL irql;
  611. if (!synchronousIo) {
  612. //
  613. // This is not a synchronous I/O operation, it is a synchronous
  614. // I/O API to a file opened for asynchronous I/O. Since this
  615. // code path need never wait on the allocated and supplied event,
  616. // get rid of it so that it doesn't have to be set to the
  617. // Signaled state by the I/O completion code.
  618. //
  619. irp->UserEvent = (PKEVENT) NULL;
  620. ExFreePool( event );
  621. }
  622. irp->UserIosb = IoStatusBlock;
  623. KeRaiseIrql( APC_LEVEL, &irql );
  624. IopCompleteRequest( &irp->Tail.Apc,
  625. &normalRoutine,
  626. &normalContext,
  627. (PVOID *) &fileObject,
  628. &normalContext );
  629. KeLowerIrql( irql );
  630. if (synchronousIo) {
  631. IopReleaseFileObjectLock( fileObject );
  632. }
  633. }
  634. return status;
  635. }
  636. NTSTATUS
  637. NtSetInformationFile(
  638. IN HANDLE FileHandle,
  639. OUT PIO_STATUS_BLOCK IoStatusBlock,
  640. IN PVOID FileInformation,
  641. IN ULONG Length,
  642. IN FILE_INFORMATION_CLASS FileInformationClass
  643. )
  644. /*++
  645. Routine Description:
  646. This service changes the provided information about a specified file. The
  647. information that is changed is determined by the FileInformationClass that
  648. is specified. The new information is taken from the FileInformation buffer.
  649. Arguments:
  650. FileHandle - Supplies a handle to the file whose information should be
  651. changed.
  652. IoStatusBlock - Address of the caller's I/O status block.
  653. FileInformation - Supplies a buffer containing the information which should
  654. be changed on the file.
  655. Length - Supplies the length, in bytes, of the FileInformation buffer.
  656. FileInformationClass - Specifies the type of information which should be
  657. changed about the file.
  658. Return Value:
  659. The status returned is the final completion status of the operation.
  660. --*/
  661. {
  662. PIRP irp;
  663. NTSTATUS status;
  664. PFILE_OBJECT fileObject;
  665. PDEVICE_OBJECT deviceObject;
  666. PKEVENT event = (PKEVENT) NULL;
  667. KPROCESSOR_MODE requestorMode;
  668. PIO_STACK_LOCATION irpSp;
  669. IO_STATUS_BLOCK localIoStatus = {0};
  670. HANDLE targetHandle = (HANDLE) NULL;
  671. BOOLEAN synchronousIo;
  672. PETHREAD CurrentThread;
  673. PAGED_CODE();
  674. //
  675. // Get the previous mode; i.e., the mode of the caller.
  676. //
  677. CurrentThread = PsGetCurrentThread ();
  678. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  679. if (requestorMode != KernelMode) {
  680. //
  681. // Ensure that the FileInformationClass parameter is legal for setting
  682. // information about the file.
  683. //
  684. if ((ULONG) FileInformationClass >= FileMaximumInformation ||
  685. !IopSetOperationLength[FileInformationClass]) {
  686. return STATUS_INVALID_INFO_CLASS;
  687. }
  688. //
  689. // Ensure that the supplied buffer is large enough to contain the
  690. // information associated with the specified set operation that is
  691. // to be performed.
  692. //
  693. if (Length < (ULONG) IopSetOperationLength[FileInformationClass]) {
  694. return STATUS_INFO_LENGTH_MISMATCH;
  695. }
  696. //
  697. // The caller's access mode is user, so probe each of the arguments
  698. // and capture them as necessary. If any failures occur, the condition
  699. // handler will be invoked to handle them. It will simply cleanup and
  700. // return an access violation status code back to the system service
  701. // dispatcher.
  702. //
  703. try {
  704. //
  705. // The IoStatusBlock parameter must be writeable by the caller.
  706. //
  707. ProbeForWriteIoStatus( IoStatusBlock );
  708. //
  709. // The FileInformation buffer must be readable by the caller.
  710. //
  711. #if defined(_X86_)
  712. ProbeForRead( FileInformation,
  713. Length,
  714. Length == sizeof( BOOLEAN ) ? sizeof( BOOLEAN ) : sizeof( ULONG ) );
  715. #elif defined(_WIN64)
  716. // If we are a wow64 process, follow the X86 rules
  717. if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) {
  718. ProbeForRead( FileInformation,
  719. Length,
  720. Length == sizeof( BOOLEAN ) ? sizeof( BOOLEAN ) : sizeof( ULONG ) );
  721. }
  722. else {
  723. ProbeForRead( FileInformation,
  724. Length,
  725. IopQuerySetAlignmentRequirement[FileInformationClass] );
  726. }
  727. #else
  728. ProbeForRead( FileInformation,
  729. Length,
  730. IopQuerySetAlignmentRequirement[FileInformationClass] );
  731. #endif
  732. } except(EXCEPTION_EXECUTE_HANDLER) {
  733. //
  734. // An exception was incurred while probing the caller's parameters.
  735. // Simply return an appropriate error status code.
  736. //
  737. return GetExceptionCode();
  738. }
  739. #if DBG
  740. } else {
  741. //
  742. // The caller's mode is kernel. Ensure that at least the information
  743. // class and lengths are appropriate.
  744. //
  745. if ((ULONG) FileInformationClass >= FileMaximumInformation ||
  746. !IopSetOperationLength[FileInformationClass]) {
  747. return STATUS_INVALID_INFO_CLASS;
  748. }
  749. if (Length < (ULONG) IopSetOperationLength[FileInformationClass]) {
  750. return STATUS_INFO_LENGTH_MISMATCH;
  751. }
  752. #endif // DBG
  753. }
  754. //
  755. // There were no blatant errors so far, so reference the file object so
  756. // the target device object can be found. Note that if the handle does
  757. // not refer to a file object, or if the caller does not have the required
  758. // access to the file, then it will fail.
  759. //
  760. status = ObReferenceObjectByHandle( FileHandle,
  761. IopSetOperationAccess[FileInformationClass],
  762. IoFileObjectType,
  763. requestorMode,
  764. (PVOID *) &fileObject,
  765. NULL );
  766. if (!NT_SUCCESS( status )) {
  767. return status;
  768. }
  769. //
  770. // Get the address of the target device object. If this file represents
  771. // a device that was opened directly, then simply use the device or its
  772. // attached device(s) directly.
  773. //
  774. if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  775. deviceObject = IoGetRelatedDeviceObject( fileObject );
  776. } else {
  777. deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
  778. }
  779. //
  780. // Make a special check here to determine whether this is a synchronous
  781. // I/O operation. If it is, then wait here until the file is owned by
  782. // the current thread. If this is not a (serialized) synchronous I/O
  783. // operation, then allocate and initialize the local event.
  784. //
  785. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  786. BOOLEAN interrupted;
  787. if (!IopAcquireFastLock( fileObject )) {
  788. status = IopAcquireFileObjectLock( fileObject,
  789. requestorMode,
  790. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  791. &interrupted );
  792. if (interrupted) {
  793. ObDereferenceObject( fileObject );
  794. return status;
  795. }
  796. }
  797. //
  798. // Make a special check here to determine whether or not the caller
  799. // is attempting to set the file position pointer information. If so,
  800. // then set it immediately and get out.
  801. //
  802. if (FileInformationClass == FilePositionInformation) {
  803. //
  804. // The caller has requested setting the current file position
  805. // context information. This is a relatively frequent call, so
  806. // it is optimized here to cut through the normal IRP path.
  807. //
  808. // Begin by checking to see whether the file was opened with no
  809. // intermediate buffering. If so, then the file pointer must be
  810. // set in a manner consistent with the alignment requirement of
  811. // read and write operations to a non-buffered file.
  812. //
  813. PFILE_POSITION_INFORMATION fileInformation = FileInformation;
  814. LARGE_INTEGER currentByteOffset;
  815. try {
  816. //
  817. // Attempt to read the position information from the buffer.
  818. //
  819. currentByteOffset.QuadPart = fileInformation->CurrentByteOffset.QuadPart;
  820. } except( EXCEPTION_EXECUTE_HANDLER ) {
  821. IopReleaseFileObjectLock( fileObject );
  822. ObDereferenceObject( fileObject );
  823. return GetExceptionCode();
  824. }
  825. if ((fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING &&
  826. (deviceObject->SectorSize &&
  827. (currentByteOffset.LowPart &
  828. (deviceObject->SectorSize - 1)))) ||
  829. currentByteOffset.HighPart < 0) {
  830. status = STATUS_INVALID_PARAMETER;
  831. } else {
  832. //
  833. // Set the current file position information.
  834. //
  835. fileObject->CurrentByteOffset.QuadPart = currentByteOffset.QuadPart;
  836. try {
  837. //
  838. // Write the I/O status block.
  839. //
  840. IoStatusBlock->Status = STATUS_SUCCESS;
  841. IoStatusBlock->Information = 0;
  842. } except( EXCEPTION_EXECUTE_HANDLER ) {
  843. //
  844. // Writes to I/O status blocks are ignored since the
  845. // operation succeeded.
  846. //
  847. NOTHING;
  848. }
  849. }
  850. //
  851. // Update the transfer count statistic for the current process for
  852. // operations other than read and write.
  853. //
  854. IopUpdateOtherTransferCount( Length );
  855. //
  856. // Note that the file object's event has not yet been reset,
  857. // so it is not necessary to set it to the Signaled state, since
  858. // that is it's state at this point by definition. Therefore,
  859. // simply cleanup and return.
  860. //
  861. IopReleaseFileObjectLock( fileObject );
  862. ObDereferenceObject( fileObject );
  863. return status;
  864. }
  865. synchronousIo = TRUE;
  866. } else {
  867. //
  868. // This is a synchronous API being invoked for a file that is opened
  869. // for asynchronous I/O. This means that this system service is
  870. // to synchronize the completion of the operation before returning
  871. // to the caller. A local event is used to do this.
  872. //
  873. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  874. if (event == NULL) {
  875. ObDereferenceObject( fileObject );
  876. return STATUS_INSUFFICIENT_RESOURCES;
  877. }
  878. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  879. synchronousIo = FALSE;
  880. }
  881. //
  882. // Set the file object to the Not-Signaled state.
  883. //
  884. KeClearEvent( &fileObject->Event );
  885. //
  886. // If a link is being tracked, handle this out-of-line.
  887. //
  888. if (FileInformationClass == FileTrackingInformation) {
  889. status = IopTrackLink( fileObject,
  890. &localIoStatus,
  891. FileInformation,
  892. Length,
  893. synchronousIo ? &fileObject->Event : event,
  894. requestorMode );
  895. if (NT_SUCCESS( status )) {
  896. try {
  897. IoStatusBlock->Information = 0;
  898. IoStatusBlock->Status = status;
  899. } except(EXCEPTION_EXECUTE_HANDLER) {
  900. NOTHING;
  901. }
  902. }
  903. if (synchronousIo) {
  904. IopReleaseFileObjectLock( fileObject );
  905. } else {
  906. ExFreePool( event );
  907. }
  908. ObDereferenceObject( fileObject );
  909. return status;
  910. }
  911. //
  912. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  913. // The allocation is performed with an exception handler in case the
  914. // caller does not have enough quota to allocate the packet.
  915. irp = IoAllocateIrp( deviceObject->StackSize, !synchronousIo );
  916. if (!irp) {
  917. //
  918. // An IRP could not be allocated. Cleanup and return an appropriate
  919. // error status code.
  920. //
  921. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  922. ExFreePool( event );
  923. }
  924. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  925. return STATUS_INSUFFICIENT_RESOURCES;
  926. }
  927. irp->Tail.Overlay.OriginalFileObject = fileObject;
  928. irp->Tail.Overlay.Thread = CurrentThread;
  929. irp->RequestorMode = requestorMode;
  930. //
  931. // Fill in the service independent parameters in the IRP.
  932. //
  933. if (synchronousIo) {
  934. irp->UserEvent = (PKEVENT) NULL;
  935. irp->UserIosb = IoStatusBlock;
  936. } else {
  937. irp->UserEvent = event;
  938. irp->UserIosb = &localIoStatus;
  939. irp->Flags = IRP_SYNCHRONOUS_API;
  940. }
  941. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  942. //
  943. // Get a pointer to the stack location for the first driver. This will
  944. // be used to pass the original function codes and parameters.
  945. //
  946. irpSp = IoGetNextIrpStackLocation( irp );
  947. irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
  948. irpSp->FileObject = fileObject;
  949. //
  950. // Allocate a buffer and copy the information that is to be set on the
  951. // file into it. Also, set the flags so that the completion code will
  952. // properly handle getting rid of the buffer and will not attempt to
  953. // copy data.
  954. //
  955. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  956. irp->MdlAddress = (PMDL) NULL;
  957. try {
  958. PVOID systemBuffer;
  959. systemBuffer =
  960. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  961. Length );
  962. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
  963. FileInformation,
  964. Length );
  965. //
  966. // Negative file offsets are illegal.
  967. //
  968. ASSERT((FIELD_OFFSET(FILE_END_OF_FILE_INFORMATION, EndOfFile) |
  969. FIELD_OFFSET(FILE_ALLOCATION_INFORMATION, AllocationSize) |
  970. FIELD_OFFSET(FILE_POSITION_INFORMATION, CurrentByteOffset)) == 0);
  971. if (((FileInformationClass == FileEndOfFileInformation) ||
  972. (FileInformationClass == FileAllocationInformation) ||
  973. (FileInformationClass == FilePositionInformation)) &&
  974. (((PFILE_POSITION_INFORMATION)systemBuffer)->CurrentByteOffset.HighPart < 0)) {
  975. ExRaiseStatus(STATUS_INVALID_PARAMETER);
  976. }
  977. } except(EXCEPTION_EXECUTE_HANDLER) {
  978. //
  979. // An exception was incurred while allocating the intermediary
  980. // system buffer or while copying the caller's data into the
  981. // buffer. Cleanup and return an appropriate error status code.
  982. //
  983. IopExceptionCleanup( fileObject,
  984. irp,
  985. (PKEVENT) NULL,
  986. event );
  987. return GetExceptionCode();
  988. }
  989. irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_DEFER_IO_COMPLETION;
  990. //
  991. // Copy the caller's parameters to the service-specific portion of the
  992. // IRP.
  993. //
  994. irpSp->Parameters.SetFile.Length = Length;
  995. irpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
  996. //
  997. // Insert the packet at the head of the IRP list for the thread.
  998. //
  999. IopQueueThreadIrp( irp );
  1000. //
  1001. // Update the operation count statistic for the current process for
  1002. // operations other than read and write.
  1003. //
  1004. IopUpdateOtherOperationCount();
  1005. //
  1006. // Everything is now set to invoke the device driver with this request.
  1007. // However, it is possible that the information that the caller wants
  1008. // to set is device independent. If this is the case, then the request
  1009. // can be satisfied here without having to have all of the drivers
  1010. // implement the same code. Note that having the IRP is still necessary
  1011. // since the I/O completion code requires it.
  1012. //
  1013. if (FileInformationClass == FileModeInformation) {
  1014. PFILE_MODE_INFORMATION modeBuffer = irp->AssociatedIrp.SystemBuffer;
  1015. //
  1016. // Set the various flags in the mode field for the file object, if
  1017. // they are reasonable. There are 4 different invalid combinations
  1018. // that the caller may not specify:
  1019. //
  1020. // 1) An invalid flag was set in the mode field. Not all Create/
  1021. // Open options may be changed.
  1022. //
  1023. // 2) The caller set one of the synchronous I/O flags (alert or
  1024. // nonalert), but the file is not opened for synchronous I/O.
  1025. //
  1026. // 3) The file is opened for synchronous I/O but the caller did
  1027. // not set either of the synchronous I/O flags (alert or non-
  1028. // alert).
  1029. //
  1030. // 4) The caller set both of the synchronous I/O flags (alert and
  1031. // nonalert).
  1032. //
  1033. if ((modeBuffer->Mode & ~FILE_VALID_SET_FLAGS) ||
  1034. ((modeBuffer->Mode & (FSIO_A | FSIO_NA)) && (!(fileObject->Flags & FO_SYNCHRONOUS_IO))) ||
  1035. ((!(modeBuffer->Mode & (FSIO_A | FSIO_NA))) && (fileObject->Flags & FO_SYNCHRONOUS_IO)) ||
  1036. (((modeBuffer->Mode & FSIO_A) && (modeBuffer->Mode & FSIO_NA) ))) {
  1037. status = STATUS_INVALID_PARAMETER;
  1038. } else {
  1039. //
  1040. // Set or clear the appropriate flags in the file object.
  1041. //
  1042. if (!(fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)) {
  1043. if (modeBuffer->Mode & FILE_WRITE_THROUGH) {
  1044. fileObject->Flags |= FO_WRITE_THROUGH;
  1045. } else {
  1046. fileObject->Flags &= ~FO_WRITE_THROUGH;
  1047. }
  1048. }
  1049. if (modeBuffer->Mode & FILE_SEQUENTIAL_ONLY) {
  1050. fileObject->Flags |= FO_SEQUENTIAL_ONLY;
  1051. } else {
  1052. fileObject->Flags &= ~FO_SEQUENTIAL_ONLY;
  1053. }
  1054. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  1055. if (modeBuffer->Mode & FSIO_A) {
  1056. fileObject->Flags |= FO_ALERTABLE_IO;
  1057. } else {
  1058. fileObject->Flags &= ~FO_ALERTABLE_IO;
  1059. }
  1060. }
  1061. status = STATUS_SUCCESS;
  1062. }
  1063. //
  1064. // Complete the I/O operation.
  1065. //
  1066. irp->IoStatus.Status = status;
  1067. irp->IoStatus.Information = 0L;
  1068. } else if (FileInformationClass == FileRenameInformation ||
  1069. FileInformationClass == FileLinkInformation ||
  1070. FileInformationClass == FileMoveClusterInformation) {
  1071. //
  1072. // Note that following code depends on the fact that the rename
  1073. // information, link information and copy-on-write information
  1074. // structures look exactly the same.
  1075. //
  1076. PFILE_RENAME_INFORMATION renameBuffer = irp->AssociatedIrp.SystemBuffer;
  1077. //
  1078. // The information being set is a variable-length structure with
  1079. // embedded size information. Walk the structure to ensure that
  1080. // it is valid so the driver does not walk off the end and incur
  1081. // an access violation in kernel mode.
  1082. //
  1083. if (renameBuffer->FileNameLength <= 0 || (renameBuffer->FileNameLength & (sizeof(WCHAR) -1))) {
  1084. status = STATUS_INVALID_PARAMETER;
  1085. irp->IoStatus.Status = status;
  1086. } else if ((ULONG) (Length - FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName[0] )) < renameBuffer->FileNameLength) {
  1087. status = STATUS_INVALID_PARAMETER;
  1088. irp->IoStatus.Status = status;
  1089. } else {
  1090. //
  1091. // Copy the value of the replace BOOLEAN (or the ClusterCount field)
  1092. // from the caller's buffer to the I/O stack location parameter
  1093. // field where it is expected by file systems.
  1094. //
  1095. if (FileInformationClass == FileMoveClusterInformation) {
  1096. irpSp->Parameters.SetFile.ClusterCount =
  1097. ((FILE_MOVE_CLUSTER_INFORMATION *) renameBuffer)->ClusterCount;
  1098. } else {
  1099. irpSp->Parameters.SetFile.ReplaceIfExists = renameBuffer->ReplaceIfExists;
  1100. }
  1101. //
  1102. // Check to see whether or not a fully qualified pathname was
  1103. // supplied. If so, then more processing is required.
  1104. //
  1105. if (renameBuffer->FileName[0] == (WCHAR) OBJ_NAME_PATH_SEPARATOR ||
  1106. renameBuffer->RootDirectory) {
  1107. //
  1108. // A fully qualified file name was specified as the target of
  1109. // the rename operation. Attempt to open the target file and
  1110. // ensure that the replacement policy for the file is consistent
  1111. // with the caller's request, and ensure that the file is on the
  1112. // same volume.
  1113. //
  1114. status = IopOpenLinkOrRenameTarget( &targetHandle,
  1115. irp,
  1116. renameBuffer,
  1117. fileObject );
  1118. if (!NT_SUCCESS( status )) {
  1119. irp->IoStatus.Status = status;
  1120. } else {
  1121. //
  1122. // The fully qualified file name specifies a file on the
  1123. // same volume and if it exists, then the caller specified
  1124. // that it should be replaced.
  1125. //
  1126. status = IoCallDriver( deviceObject, irp );
  1127. }
  1128. } else {
  1129. //
  1130. // This is a simple rename operation, so call the driver and
  1131. // let it perform the rename operation within the same directory
  1132. // as the source file.
  1133. //
  1134. status = IoCallDriver( deviceObject, irp );
  1135. }
  1136. }
  1137. } else if (FileInformationClass == FileShortNameInformation) {
  1138. PFILE_NAME_INFORMATION shortnameBuffer = irp->AssociatedIrp.SystemBuffer;
  1139. //
  1140. // The information being set is a variable-length structure with
  1141. // embedded size information. Walk the structure to ensure that
  1142. // it is valid so the driver does not walk off the end and incur
  1143. // an access violation in kernel mode.
  1144. //
  1145. if (shortnameBuffer->FileNameLength <= 0) {
  1146. status = STATUS_INVALID_PARAMETER;
  1147. irp->IoStatus.Status = status;
  1148. } else if ((ULONG) (Length - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName[0] )) < shortnameBuffer->FileNameLength) {
  1149. status = STATUS_INVALID_PARAMETER;
  1150. irp->IoStatus.Status = status;
  1151. //
  1152. // The short name must not begin with a separator character.
  1153. //
  1154. } else if (shortnameBuffer->FileName[0] == (WCHAR) OBJ_NAME_PATH_SEPARATOR) {
  1155. status = STATUS_INVALID_PARAMETER;
  1156. irp->IoStatus.Status = status;
  1157. //
  1158. // Pass the request to the driver below.
  1159. //
  1160. } else {
  1161. status = IoCallDriver( deviceObject, irp );
  1162. }
  1163. } else if (FileInformationClass == FileDispositionInformation) {
  1164. PFILE_DISPOSITION_INFORMATION disposition = irp->AssociatedIrp.SystemBuffer;
  1165. //
  1166. // Check to see whether the disposition delete field has been set to
  1167. // TRUE and, if so, copy the handle being used to do this to the IRP
  1168. // stack location parameter.
  1169. //
  1170. if (disposition->DeleteFile) {
  1171. irpSp->Parameters.SetFile.DeleteHandle = FileHandle;
  1172. }
  1173. //
  1174. // Simply invoke the driver to perform the (un)delete operation.
  1175. //
  1176. status = IoCallDriver( deviceObject, irp );
  1177. } else if (FileInformationClass == FileCompletionInformation) {
  1178. PFILE_COMPLETION_INFORMATION completion = irp->AssociatedIrp.SystemBuffer;
  1179. PIO_COMPLETION_CONTEXT context;
  1180. PVOID portObject;
  1181. //
  1182. // It is an error if this file object already has an LPC port associated
  1183. // with it.
  1184. //
  1185. if (fileObject->CompletionContext || fileObject->Flags & FO_SYNCHRONOUS_IO) {
  1186. status = STATUS_INVALID_PARAMETER;
  1187. } else {
  1188. //
  1189. // Attempt to reference the port object by its handle and convert it
  1190. // into a pointer to the port object itself.
  1191. //
  1192. status = ObReferenceObjectByHandle( completion->Port,
  1193. IO_COMPLETION_MODIFY_STATE,
  1194. IoCompletionObjectType,
  1195. requestorMode,
  1196. (PVOID *) &portObject,
  1197. NULL );
  1198. if (NT_SUCCESS( status )) {
  1199. //
  1200. // Allocate the memory to be associated w/this file object
  1201. //
  1202. context = ExAllocatePoolWithTag( PagedPool,
  1203. sizeof( IO_COMPLETION_CONTEXT ),
  1204. 'cCoI' );
  1205. if (!context) {
  1206. ObDereferenceObject( portObject );
  1207. status = STATUS_INSUFFICIENT_RESOURCES;
  1208. } else {
  1209. //
  1210. // Everything was successful. Capture the completion port
  1211. // and the key.
  1212. //
  1213. context->Port = portObject;
  1214. context->Key = completion->Key;
  1215. if (!InterlockedCompareExchangePointer( &fileObject->CompletionContext, context, NULL )) {
  1216. status = STATUS_SUCCESS;
  1217. } else {
  1218. //
  1219. // Someone set the completion context after the check.
  1220. // Simply drop everything on the floor and return an
  1221. // error.
  1222. //
  1223. ExFreePool( context );
  1224. ObDereferenceObject( portObject );
  1225. status = STATUS_PORT_ALREADY_SET;
  1226. }
  1227. }
  1228. }
  1229. }
  1230. //
  1231. // Complete the I/O operation.
  1232. //
  1233. irp->IoStatus.Status = status;
  1234. irp->IoStatus.Information = 0;
  1235. } else {
  1236. //
  1237. // This is not a request that can be performed here, so invoke the
  1238. // driver at its appropriate dispatch entry with the IRP.
  1239. //
  1240. status = IoCallDriver( deviceObject, irp );
  1241. }
  1242. //
  1243. // If this operation was a synchronous I/O operation, check the return
  1244. // status to determine whether or not to wait on the file object. If
  1245. // the file object is to be waited on, wait for the operation to complete
  1246. // and obtain the final status from the file object itself.
  1247. //
  1248. if (status == STATUS_PENDING) {
  1249. if (synchronousIo) {
  1250. status = KeWaitForSingleObject( &fileObject->Event,
  1251. Executive,
  1252. requestorMode,
  1253. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  1254. (PLARGE_INTEGER) NULL );
  1255. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  1256. //
  1257. // The wait request has ended either because the thread was
  1258. // alerted or an APC was queued to this thread, because of
  1259. // thread rundown or CTRL/C processing. In either case, try
  1260. // to bail out of this I/O request carefully so that the IRP
  1261. // completes before this routine exists so that synchronization
  1262. // with the file object will remain intact.
  1263. //
  1264. IopCancelAlertedRequest( &fileObject->Event, irp );
  1265. }
  1266. status = fileObject->FinalStatus;
  1267. IopReleaseFileObjectLock( fileObject );
  1268. } else {
  1269. //
  1270. // This is a normal synchronous I/O operation, as opposed to a
  1271. // serialized synchronous I/O operation. For this case, wait for
  1272. // the local event and copy the final status information back to
  1273. // the caller.
  1274. //
  1275. status = KeWaitForSingleObject( event,
  1276. Executive,
  1277. requestorMode,
  1278. FALSE,
  1279. (PLARGE_INTEGER) NULL );
  1280. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  1281. //
  1282. // The wait request has ended either because the thread was
  1283. // alerted or an APC was queued to this thread, because of
  1284. // thread rundown or CTRL/C processing. In either case, try
  1285. // to bail out of this I/O request carefully so that the IRP
  1286. // completes before this routine exists or the event will not
  1287. // be around to set to the Signaled state.
  1288. //
  1289. IopCancelAlertedRequest( event, irp );
  1290. }
  1291. status = localIoStatus.Status;
  1292. try {
  1293. *IoStatusBlock = localIoStatus;
  1294. } except(EXCEPTION_EXECUTE_HANDLER) {
  1295. //
  1296. // An exception occurred attempting to write the caller's I/O
  1297. // status block. Simply change the final status of the
  1298. // operation to the exception code.
  1299. //
  1300. status = GetExceptionCode();
  1301. }
  1302. ExFreePool( event );
  1303. }
  1304. } else {
  1305. //
  1306. // The I/O operation finished without return a status of pending.
  1307. // This means that the operation has not been through I/O completion,
  1308. // so it must be done here.
  1309. //
  1310. PKNORMAL_ROUTINE normalRoutine;
  1311. PVOID normalContext;
  1312. KIRQL irql;
  1313. if (!synchronousIo) {
  1314. //
  1315. // This is not a synchronous I/O operation, it is a synchronous
  1316. // I/O API to a file opened for asynchronous I/O. Since this
  1317. // code path need never wait on the allocated and supplied event,
  1318. // get rid of it so that it doesn't have to be set to the
  1319. // Signaled state by the I/O completion code.
  1320. //
  1321. irp->UserEvent = (PKEVENT) NULL;
  1322. ExFreePool( event );
  1323. }
  1324. irp->UserIosb = IoStatusBlock;
  1325. KeRaiseIrql( APC_LEVEL, &irql );
  1326. IopCompleteRequest( &irp->Tail.Apc,
  1327. &normalRoutine,
  1328. &normalContext,
  1329. (PVOID *) &fileObject,
  1330. &normalContext );
  1331. KeLowerIrql( irql );
  1332. if (synchronousIo) {
  1333. IopReleaseFileObjectLock( fileObject );
  1334. }
  1335. }
  1336. //
  1337. // If there was a target handle generated because of a rename operation,
  1338. // close it now.
  1339. //
  1340. if (targetHandle) {
  1341. ObCloseHandle( targetHandle, KernelMode );
  1342. }
  1343. return status;
  1344. }