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.

1075 lines
29 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. misc.c
  5. Abstract:
  6. This module contains the code to implement the NtFlushBuffersFile,
  7. NtSetNewSizeFile, IoQueueWorkItem, and NtCancelIoFile system services
  8. for the NT I/O system.
  9. Author:
  10. Darryl E. Havens (darrylh) 22-Jun-1989
  11. Environment:
  12. Kernel mode only
  13. Revision History:
  14. --*/
  15. #include "iomgr.h"
  16. //
  17. // Local function prototypes follow
  18. //
  19. VOID
  20. IopProcessWorkItem(
  21. IN PVOID Parameter
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, NtCancelIoFile)
  25. #pragma alloc_text(PAGE, NtDeleteFile)
  26. #pragma alloc_text(PAGE, NtFlushBuffersFile)
  27. #pragma alloc_text(PAGE, NtQueryAttributesFile)
  28. #pragma alloc_text(PAGE, NtQueryFullAttributesFile)
  29. #pragma alloc_text(PAGE, IopProcessWorkItem)
  30. #endif
  31. NTSTATUS
  32. NtCancelIoFile(
  33. IN HANDLE FileHandle,
  34. OUT PIO_STATUS_BLOCK IoStatusBlock
  35. )
  36. /*++
  37. Routine Description:
  38. This service causes all pending I/O operations for the specified file to be
  39. marked as canceled. Most types of operations can be canceled immediately,
  40. while others may continue toward completion before they are actually
  41. canceled and the caller is notified.
  42. Only those pending operations that were issued by the current thread using
  43. the specified handle are canceled. Any operations issued for the file by
  44. any other thread or any other process continues normally.
  45. Arguments:
  46. FileHandle - Supplies a handle to the file whose operations are to be
  47. canceled.
  48. IoStatusBlock - Address of the caller's I/O status block.
  49. Return Value:
  50. The status returned is the final completion status of the operation.
  51. --*/
  52. {
  53. PIRP irp;
  54. NTSTATUS status;
  55. PFILE_OBJECT fileObject;
  56. KPROCESSOR_MODE requestorMode;
  57. PETHREAD thread;
  58. BOOLEAN found = FALSE;
  59. PLIST_ENTRY header;
  60. PLIST_ENTRY entry;
  61. KIRQL irql;
  62. PAGED_CODE();
  63. //
  64. // Get the address of the current thread. The thread contains a list of
  65. // the pending operations for this file.
  66. //
  67. thread = PsGetCurrentThread();
  68. //
  69. // Get the previous mode; i.e., the mode of the caller.
  70. //
  71. requestorMode = KeGetPreviousModeByThread(&thread->Tcb);
  72. if (requestorMode != KernelMode) {
  73. //
  74. // The caller's access mode is user, so probe each of the arguments
  75. // and capture them as necessary. If any failures occur, the condition
  76. // handler will be invoked to handle them. It will simply cleanup and
  77. // return an access violation status code back to the system service
  78. // dispatcher.
  79. //
  80. try {
  81. //
  82. // The IoStatusBlock parameter must be writeable by the caller.
  83. //
  84. ProbeForWriteIoStatus( IoStatusBlock );
  85. } except(EXCEPTION_EXECUTE_HANDLER) {
  86. //
  87. // An exception was incurred attempting to probe the caller'
  88. // I/O status block. Simply return an appropriate error status
  89. // code.
  90. //
  91. return GetExceptionCode();
  92. }
  93. }
  94. //
  95. // There were no blatant errors so far, so reference the file object so
  96. // the target device object can be found. Note that if the handle does
  97. // not refer to a file object, or if the caller does not have the required
  98. // access to the file, then it will fail.
  99. //
  100. status = ObReferenceObjectByHandle( FileHandle,
  101. 0,
  102. IoFileObjectType,
  103. requestorMode,
  104. (PVOID *) &fileObject,
  105. NULL );
  106. if (!NT_SUCCESS( status )) {
  107. return(status);
  108. }
  109. //
  110. // Note that here the I/O system would normally make a check to determine
  111. // whether or not the file was opened for synchronous I/O. If it was, then
  112. // it would attempt to exclusively acquire the file object lock. However,
  113. // since this service is attempting to cancel all of the I/O for the file,
  114. // it does not make much sense to wait until it has all completed before
  115. // attempting to cancel it.
  116. //
  117. //
  118. // Update the operation count statistic for the current process for
  119. // operations other than read and write.
  120. //
  121. IopUpdateOtherOperationCount();
  122. //
  123. // Walk the list of IRPs on the thread's pending I/O queue looking for IRPs
  124. // which specify the same file as the FileHandle refers to. For each IRP
  125. // found, set its cancel flag. If no IRPs are found, simply complete the
  126. // I/O here. The only synchronization needed here is to block out all APCs
  127. // for this thread so that no I/O can complete and remove packets from the
  128. // queue. No considerations need be made for multi-processing since this
  129. // thread can only be running on one processor at a time and this routine
  130. // has control of the thread for now.
  131. //
  132. KeRaiseIrql( APC_LEVEL, &irql );
  133. header = &thread->IrpList;
  134. entry = thread->IrpList.Flink;
  135. while (header != entry) {
  136. //
  137. // An IRP has been found for this thread. If the IRP refers to the
  138. // appropriate file object, set its cancel flag and remember that it
  139. // was found; otherwise, simply continue the loop.
  140. //
  141. irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
  142. if (irp->Tail.Overlay.OriginalFileObject == fileObject) {
  143. found = TRUE;
  144. IoCancelIrp( irp );
  145. }
  146. entry = entry->Flink;
  147. }
  148. //
  149. // Lower the IRQL back down to what it was on entry to this procedure.
  150. //
  151. KeLowerIrql( irql );
  152. if (found) {
  153. LARGE_INTEGER interval;
  154. //
  155. // Delay execution for a time and let the request
  156. // finish. The delay time is 10ms.
  157. //
  158. interval.QuadPart = -10 * 1000 * 10;
  159. //
  160. // Wait for a while so the canceled requests can complete.
  161. //
  162. while (found) {
  163. (VOID) KeDelayExecutionThread( KernelMode, FALSE, &interval );
  164. found = FALSE;
  165. //
  166. // Raise the IRQL to prevent modification to the IRP list by the
  167. // thread's APC routine.
  168. //
  169. KeRaiseIrql( APC_LEVEL, &irql );
  170. //
  171. // Check the IRP list for requests which refer to the specified
  172. // file object.
  173. //
  174. entry = thread->IrpList.Flink;
  175. while (header != entry) {
  176. //
  177. // An IRP has been found for this thread. If the IRP refers
  178. // to the appropriate file object, remember that it
  179. // was found; otherwise, simply continue the loop.
  180. //
  181. irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
  182. if (irp->Tail.Overlay.OriginalFileObject == fileObject) {
  183. found = TRUE;
  184. break;
  185. }
  186. entry = entry->Flink;
  187. }
  188. //
  189. // Lower the IRQL back down to what it was on entry to this procedure.
  190. //
  191. KeLowerIrql( irql );
  192. }
  193. }
  194. try {
  195. //
  196. // Write the status back to the user.
  197. //
  198. IoStatusBlock->Status = STATUS_SUCCESS;
  199. IoStatusBlock->Information = 0L;
  200. } except(EXCEPTION_EXECUTE_HANDLER) {
  201. //
  202. // An exception was incurred attempting to write the caller's
  203. // I/O status block; however, the service completed sucessfully so
  204. // just return sucess.
  205. //
  206. }
  207. //
  208. // Dereference the file object.
  209. //
  210. ObDereferenceObject( fileObject );
  211. return STATUS_SUCCESS;
  212. }
  213. NTSTATUS
  214. NtDeleteFile(
  215. IN POBJECT_ATTRIBUTES ObjectAttributes
  216. )
  217. /*++
  218. Routine Description:
  219. This service deletes the specified file.
  220. Arguments:
  221. ObjectAttributes - Supplies the attributes to be used for file object (name,
  222. SECURITY_DESCRIPTOR, etc.)
  223. Return Value:
  224. The status returned is the final completion status of the operation.
  225. --*/
  226. {
  227. KPROCESSOR_MODE requestorMode;
  228. NTSTATUS status;
  229. OPEN_PACKET openPacket;
  230. DUMMY_FILE_OBJECT localFileObject;
  231. HANDLE handle;
  232. PAGED_CODE();
  233. //
  234. // Get the previous mode; i.e., the mode of the caller.
  235. //
  236. requestorMode = KeGetPreviousMode();
  237. //
  238. // Build a parse open packet that tells the parse method to open the file
  239. // for open for delete access w/the delete bit set, and then close it.
  240. //
  241. RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) );
  242. openPacket.Type = IO_TYPE_OPEN_PACKET;
  243. openPacket.Size = sizeof( OPEN_PACKET );
  244. openPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
  245. openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  246. openPacket.Disposition = FILE_OPEN;
  247. openPacket.DeleteOnly = TRUE;
  248. openPacket.TraversedMountPoint = FALSE;
  249. openPacket.LocalFileObject = &localFileObject;
  250. //
  251. // Update the open count for this process.
  252. //
  253. IopUpdateOtherOperationCount();
  254. //
  255. // Open the object by its name. Because of the special DeleteOnly flag
  256. // set in the open packet, the parse routine will open the file, and
  257. // then realize that it is only deleting the file, and will therefore
  258. // immediately dereference the file. This will cause the cleanup and
  259. // the close to be sent to the file system, thus causing the file to
  260. // be deleted.
  261. //
  262. status = ObOpenObjectByName( ObjectAttributes,
  263. (POBJECT_TYPE) NULL,
  264. requestorMode,
  265. NULL,
  266. DELETE,
  267. &openPacket,
  268. &handle );
  269. //
  270. // The operation is successful if the parse check field of the open packet
  271. // indicates that the parse routine was actually invoked, and the final
  272. // status field of the packet is set to success.
  273. //
  274. if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) {
  275. return status;
  276. } else {
  277. return openPacket.FinalStatus;
  278. }
  279. }
  280. NTSTATUS
  281. NtFlushBuffersFile(
  282. IN HANDLE FileHandle,
  283. OUT PIO_STATUS_BLOCK IoStatusBlock
  284. )
  285. /*++
  286. Routine Description:
  287. This service causes all buffered data to the file to be written.
  288. Arguments:
  289. FileHandle - Supplies a handle to the file whose buffers should be flushed.
  290. IoStatusBlock - Address of the caller's I/O status block.
  291. Return Value:
  292. The status returned is the final completion status of the operation.
  293. --*/
  294. {
  295. PIRP irp;
  296. NTSTATUS status;
  297. PFILE_OBJECT fileObject;
  298. PDEVICE_OBJECT deviceObject;
  299. PKEVENT event;
  300. KPROCESSOR_MODE requestorMode;
  301. PIO_STACK_LOCATION irpSp;
  302. IO_STATUS_BLOCK localIoStatus;
  303. OBJECT_HANDLE_INFORMATION objectHandleInformation;
  304. BOOLEAN synchronousIo;
  305. PETHREAD CurrentThread;
  306. PAGED_CODE();
  307. //
  308. // Get the previous mode; i.e., the mode of the caller.
  309. //
  310. CurrentThread = PsGetCurrentThread ();
  311. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  312. if (requestorMode != KernelMode) {
  313. //
  314. // The caller's access mode is not kernel so probe each of the arguments
  315. // and capture them as necessary. If any failures occur, the condition
  316. // handler will be invoked to handle them. It will simply cleanup and
  317. // return an access violation status code back to the system service
  318. // dispatcher.
  319. //
  320. try {
  321. //
  322. // The IoStatusBlock parameter must be writeable by the caller.
  323. //
  324. ProbeForWriteIoStatus( IoStatusBlock );
  325. } except(EXCEPTION_EXECUTE_HANDLER) {
  326. //
  327. // An exception was incurred attempting to probe the caller's
  328. // I/O status block. Simply return an appropriate error status
  329. // code.
  330. //
  331. return GetExceptionCode();
  332. }
  333. }
  334. //
  335. // There were no blatant errors so far, so reference the file object so
  336. // the target device object can be found. Note that if the handle does
  337. // not refer to a file object, or if the caller does not have the required
  338. // access to the file, then it will fail.
  339. //
  340. status = ObReferenceObjectByHandle( FileHandle,
  341. 0,
  342. IoFileObjectType,
  343. requestorMode,
  344. (PVOID *) &fileObject,
  345. &objectHandleInformation );
  346. if (!NT_SUCCESS( status )) {
  347. return status;
  348. }
  349. //
  350. // Ensure that the caller has either WRITE or APPEND access to the file
  351. // before allowing this call to continue. This is especially important
  352. // if the caller opened a volume, where a flush operation may flush more
  353. // than what this opener has written to buffers. Note however that if
  354. // this is a pipe, then the APPEND access cannot be made since this
  355. // access code is overlaid with the CREATE_PIPE_INSTANCE access.
  356. //
  357. if (SeComputeGrantedAccesses( objectHandleInformation.GrantedAccess,
  358. (!(fileObject->Flags & FO_NAMED_PIPE) ?
  359. FILE_APPEND_DATA : 0) |
  360. FILE_WRITE_DATA ) == 0) {
  361. ObDereferenceObject( fileObject );
  362. return STATUS_ACCESS_DENIED;
  363. }
  364. //
  365. // Make a special check here to determine whether this is a synchronous
  366. // I/O operation. If it is, then wait here until the file is owned by
  367. // the current thread. If this is not a (serialized) synchronous I/O
  368. // operation, then allocate and initialize the local event.
  369. //
  370. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  371. BOOLEAN interrupted;
  372. if (!IopAcquireFastLock( fileObject )) {
  373. status = IopAcquireFileObjectLock( fileObject,
  374. requestorMode,
  375. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  376. &interrupted );
  377. if (interrupted) {
  378. ObDereferenceObject( fileObject );
  379. return status;
  380. }
  381. }
  382. synchronousIo = TRUE;
  383. } else {
  384. //
  385. // This is a synchronous API being invoked for a file that is opened
  386. // for asynchronous I/O. This means that this system service is
  387. // to synchronize the completion of the operation before returning
  388. // to the caller. A local event is used to do this.
  389. //
  390. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  391. if (event == NULL) {
  392. ObDereferenceObject( fileObject );
  393. return STATUS_INSUFFICIENT_RESOURCES;
  394. }
  395. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  396. synchronousIo = FALSE;
  397. }
  398. //
  399. // Set the file object to the Not-Signaled state.
  400. //
  401. KeClearEvent( &fileObject->Event );
  402. //
  403. // Get the address of the target device object.
  404. //
  405. deviceObject = IoGetRelatedDeviceObject( fileObject );
  406. //
  407. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  408. // The allocation is performed with an exception handler in case the
  409. // caller does not have enough quota to allocate the packet.
  410. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  411. if (!irp) {
  412. //
  413. // An exception was incurred while attempting to allocate the IRP.
  414. // Cleanup and return an appropriate error status code.
  415. //
  416. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  417. ExFreePool( event );
  418. }
  419. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  420. return STATUS_INSUFFICIENT_RESOURCES;
  421. }
  422. irp->Tail.Overlay.OriginalFileObject = fileObject;
  423. irp->Tail.Overlay.Thread = CurrentThread;
  424. irp->RequestorMode = requestorMode;
  425. //
  426. // Fill in the service independent parameters in the IRP.
  427. //
  428. if (synchronousIo) {
  429. irp->UserEvent = (PKEVENT) NULL;
  430. irp->UserIosb = IoStatusBlock;
  431. } else {
  432. irp->UserEvent = event;
  433. irp->UserIosb = &localIoStatus;
  434. irp->Flags = IRP_SYNCHRONOUS_API;
  435. }
  436. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  437. //
  438. // Get a pointer to the stack location for the first driver. This is used
  439. // to pass the original function codes and parameters.
  440. //
  441. irpSp = IoGetNextIrpStackLocation( irp );
  442. irpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
  443. irpSp->FileObject = fileObject;
  444. //
  445. // Queue the packet, call the driver, and synchronize appopriately with
  446. // I/O completion.
  447. //
  448. status = IopSynchronousServiceTail( deviceObject,
  449. irp,
  450. fileObject,
  451. FALSE,
  452. requestorMode,
  453. synchronousIo,
  454. OtherTransfer );
  455. //
  456. // If the file for this operation was not opened for synchronous I/O, then
  457. // synchronization of completion of the I/O operation has not yet occurred
  458. // since the allocated event must be used for synchronous APIs on files
  459. // opened for asynchronous I/O. Synchronize the completion of the I/O
  460. // operation now.
  461. //
  462. if (!synchronousIo) {
  463. status = IopSynchronousApiServiceTail( status,
  464. event,
  465. irp,
  466. requestorMode,
  467. &localIoStatus,
  468. IoStatusBlock );
  469. }
  470. return status;
  471. }
  472. NTSTATUS
  473. NtQueryAttributesFile(
  474. IN POBJECT_ATTRIBUTES ObjectAttributes,
  475. OUT PFILE_BASIC_INFORMATION FileInformation
  476. )
  477. /*++
  478. Routine Description:
  479. This service queries the basic attributes information for a specified file.
  480. Arguments:
  481. ObjectAttributes - Supplies the attributes to be used for file object (name,
  482. SECURITY_DESCRIPTOR, etc.)
  483. FileInformation - Supplies an output buffer to receive the returned file
  484. attributes information.
  485. Return Value:
  486. The status returned is the final completion status of the operation.
  487. --*/
  488. {
  489. KPROCESSOR_MODE requestorMode;
  490. NTSTATUS status;
  491. OPEN_PACKET openPacket;
  492. DUMMY_FILE_OBJECT localFileObject;
  493. FILE_NETWORK_OPEN_INFORMATION networkInformation;
  494. HANDLE handle;
  495. PAGED_CODE();
  496. //
  497. // Get the previous mode; i.e., the mode of the caller.
  498. //
  499. requestorMode = KeGetPreviousMode();
  500. if (requestorMode != KernelMode) {
  501. try {
  502. //
  503. // The caller's mode is not kernel, so probe the output buffer.
  504. //
  505. ProbeForWriteSmallStructure( FileInformation,
  506. sizeof( FILE_BASIC_INFORMATION ),
  507. sizeof( ULONG_PTR ));
  508. } except(EXCEPTION_EXECUTE_HANDLER) {
  509. //
  510. // An exception was incurred while probing the caller's parameters.
  511. // Simply return an appropriate error status code.
  512. //
  513. return GetExceptionCode();
  514. }
  515. }
  516. //
  517. // Build a parse open packet that tells the parse method to open the file,
  518. // query the file's basic attributes, and close the file.
  519. //
  520. RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) );
  521. openPacket.Type = IO_TYPE_OPEN_PACKET;
  522. openPacket.Size = sizeof( OPEN_PACKET );
  523. openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  524. openPacket.Disposition = FILE_OPEN;
  525. openPacket.CreateOptions = FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT;
  526. openPacket.BasicInformation = FileInformation;
  527. openPacket.NetworkInformation = &networkInformation;
  528. openPacket.QueryOnly = TRUE;
  529. openPacket.TraversedMountPoint = FALSE;
  530. openPacket.LocalFileObject = &localFileObject;
  531. //
  532. // Update the open count for this process.
  533. //
  534. IopUpdateOtherOperationCount();
  535. //
  536. // Open the object by its name. Because of the special QueryOnly flag set
  537. // in the open packet, the parse routine will open the file, and then
  538. // realize that it is only performing a query. It will therefore perform
  539. // the query, and immediately close the file.
  540. //
  541. status = ObOpenObjectByName( ObjectAttributes,
  542. (POBJECT_TYPE) NULL,
  543. requestorMode,
  544. NULL,
  545. FILE_READ_ATTRIBUTES,
  546. &openPacket,
  547. &handle );
  548. //
  549. // The operation is successful if the parse check field of the open packet
  550. // indicates that the parse routine was actually invoked, and the final
  551. // status field of the packet is set to success.
  552. //
  553. if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) {
  554. return status;
  555. } else {
  556. return openPacket.FinalStatus;
  557. }
  558. }
  559. NTSTATUS
  560. NtQueryFullAttributesFile(
  561. IN POBJECT_ATTRIBUTES ObjectAttributes,
  562. OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
  563. )
  564. /*++
  565. Routine Description:
  566. This service queries the network attributes information for a specified
  567. file.
  568. Arguments:
  569. ObjectAttributes - Supplies the attributes to be used for file object (name,
  570. SECURITY_DESCRIPTOR, etc.)
  571. FileInformation - Supplies an output buffer to receive the returned file
  572. attributes information.
  573. Return Value:
  574. The status returned is the final completion status of the operation.
  575. --*/
  576. {
  577. KPROCESSOR_MODE requestorMode;
  578. NTSTATUS status;
  579. OPEN_PACKET openPacket;
  580. DUMMY_FILE_OBJECT localFileObject;
  581. FILE_NETWORK_OPEN_INFORMATION networkInformation;
  582. HANDLE handle;
  583. PAGED_CODE();
  584. //
  585. // Get the previous mode; i.e., the mode of the caller.
  586. //
  587. requestorMode = KeGetPreviousMode();
  588. if (requestorMode != KernelMode) {
  589. try {
  590. //
  591. // The caller's mode is not kernel, so probe the output buffer.
  592. //
  593. ProbeForWriteSmallStructure( FileInformation,
  594. sizeof( FILE_NETWORK_OPEN_INFORMATION ),
  595. #if defined(_X86_)
  596. sizeof( LONG ));
  597. #else
  598. sizeof( LONGLONG ));
  599. #endif // defined(_X86_)
  600. } except(EXCEPTION_EXECUTE_HANDLER) {
  601. //
  602. // An exception was incurred while probing the caller's parameters.
  603. // Simply return an appropriate error status code.
  604. //
  605. return GetExceptionCode();
  606. }
  607. }
  608. //
  609. // Build a parse open packet that tells the parse method to open the file,
  610. // query the file's full attributes, and close the file.
  611. //
  612. RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) );
  613. openPacket.Type = IO_TYPE_OPEN_PACKET;
  614. openPacket.Size = sizeof( OPEN_PACKET );
  615. openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  616. openPacket.Disposition = FILE_OPEN;
  617. openPacket.CreateOptions = FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT;
  618. openPacket.QueryOnly = TRUE;
  619. openPacket.FullAttributes = TRUE;
  620. openPacket.TraversedMountPoint = FALSE;
  621. openPacket.LocalFileObject = &localFileObject;
  622. if (requestorMode != KernelMode) {
  623. openPacket.NetworkInformation = &networkInformation;
  624. } else {
  625. openPacket.NetworkInformation = FileInformation;
  626. }
  627. //
  628. // Update the open count for this process.
  629. //
  630. IopUpdateOtherOperationCount();
  631. //
  632. // Open the object by its name. Because of the special QueryOnly flag set
  633. // in the open packet, the parse routine will open the file, and then
  634. // realize that it is only performing a query. It will therefore perform
  635. // the query, and immediately close the file.
  636. //
  637. status = ObOpenObjectByName( ObjectAttributes,
  638. (POBJECT_TYPE) NULL,
  639. requestorMode,
  640. NULL,
  641. FILE_READ_ATTRIBUTES,
  642. &openPacket,
  643. &handle );
  644. //
  645. // The operation is successful if the parse check field of the open packet
  646. // indicates that the parse routine was actually invoked, and the final
  647. // status field of the packet is set to success.
  648. //
  649. if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) {
  650. return status;
  651. } else {
  652. status = openPacket.FinalStatus;
  653. }
  654. if (NT_SUCCESS( status )) {
  655. if (requestorMode != KernelMode) {
  656. try {
  657. //
  658. // The query worked, so copy the returned information to the
  659. // caller's output buffer.
  660. //
  661. RtlCopyMemory( FileInformation,
  662. &networkInformation,
  663. sizeof( FILE_NETWORK_OPEN_INFORMATION ) );
  664. } except(EXCEPTION_EXECUTE_HANDLER) {
  665. status = GetExceptionCode();
  666. }
  667. }
  668. }
  669. return status;
  670. }
  671. PIO_WORKITEM
  672. IoAllocateWorkItem(
  673. PDEVICE_OBJECT DeviceObject
  674. )
  675. {
  676. PIO_WORKITEM ioWorkItem;
  677. PWORK_QUEUE_ITEM exWorkItem;
  678. //
  679. // Allocate a new workitem structure.
  680. //
  681. ioWorkItem = ExAllocatePool( NonPagedPool, sizeof( IO_WORKITEM ));
  682. if (ioWorkItem != NULL) {
  683. //
  684. // Initialize the invariant portions of both ioWorkItem and
  685. // exWorkItem.
  686. //
  687. #if DBG
  688. ioWorkItem->Size = sizeof( IO_WORKITEM );
  689. #endif
  690. ioWorkItem->DeviceObject = DeviceObject;
  691. exWorkItem = &ioWorkItem->WorkItem;
  692. ExInitializeWorkItem( exWorkItem, IopProcessWorkItem, ioWorkItem );
  693. }
  694. return ioWorkItem;
  695. }
  696. VOID
  697. IoFreeWorkItem(
  698. PIO_WORKITEM IoWorkItem
  699. )
  700. /*++
  701. Routine Description:
  702. This function is the "wrapper" routine for IoQueueWorkItem. It calls
  703. the original worker function, then dereferences the device object to
  704. (possibly) allow the driver object to go away.
  705. Arguments:
  706. Parameter - Supplies a pointer to an IO_WORKITEM for us to process.
  707. Return Value:
  708. None
  709. --*/
  710. {
  711. ASSERT( IoWorkItem->Size == sizeof( IO_WORKITEM ));
  712. ExFreePool( IoWorkItem );
  713. }
  714. VOID
  715. IoQueueWorkItem(
  716. IN PIO_WORKITEM IoWorkItem,
  717. IN PIO_WORKITEM_ROUTINE WorkerRoutine,
  718. IN WORK_QUEUE_TYPE QueueType,
  719. IN PVOID Context
  720. )
  721. /*++
  722. Routine Description:
  723. This function inserts a work item into a work queue that is processed
  724. by a worker thread of the corresponding type. It effectively
  725. "wraps" ExQueueWorkItem, ensuring that the device object is referenced
  726. for the duration of the call.
  727. Arguments:
  728. IoWorkItem - Supplies a pointer to the work item to add the the queue.
  729. This structure must have been allocated via IoAllocateWorkItem().
  730. WorkerRoutine - Supplies a pointer to the routine that is to be called
  731. in system thread context.
  732. QueueType - Specifies the type of work queue that the work item
  733. should be placed in.
  734. Context - Supplies the context parameter for the callback routine.
  735. Return Value:
  736. None
  737. --*/
  738. {
  739. PWORK_QUEUE_ITEM exWorkItem;
  740. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  741. ASSERT( IoWorkItem->Size == sizeof( IO_WORKITEM ));
  742. //
  743. // Keep a reference on the device object so it doesn't go away.
  744. //
  745. ObReferenceObject( IoWorkItem->DeviceObject );
  746. //
  747. // Initialize the fields in IoWorkItem
  748. //
  749. IoWorkItem->Routine = WorkerRoutine;
  750. IoWorkItem->Context = Context;
  751. //
  752. // Get a pointer to the ExWorkItem, queue it, and return.
  753. // IopProcessWorkItem() will perform the dereference.
  754. //
  755. exWorkItem = &IoWorkItem->WorkItem;
  756. ExQueueWorkItem( exWorkItem, QueueType );
  757. }
  758. VOID
  759. IopProcessWorkItem(
  760. IN PVOID Parameter
  761. )
  762. /*++
  763. Routine Description:
  764. This function is the "wrapper" routine for IoQueueWorkItem. It calls
  765. the original worker function, then dereferences the device object to
  766. (possibly) allow the driver object to go away.
  767. Arguments:
  768. Parameter - Supplies a pointer to an IO_WORKITEM for us to process.
  769. Return Value:
  770. None
  771. --*/
  772. {
  773. PIO_WORKITEM ioWorkItem;
  774. PDEVICE_OBJECT deviceObject;
  775. PAGED_CODE();
  776. //
  777. // Get a pointer to the ioWorkItem and store a copy of DeviceObject
  778. // locally. This allow us to function properly if the worker routine
  779. // elects to free the work item.
  780. //
  781. ioWorkItem = (PIO_WORKITEM)Parameter;
  782. deviceObject = ioWorkItem->DeviceObject;
  783. //
  784. // Call the original worker.
  785. //
  786. ioWorkItem->Routine( deviceObject,
  787. ioWorkItem->Context );
  788. //
  789. // Now we can dereference the device object, since its code is no longer
  790. // being executed for this work item.
  791. //
  792. ObDereferenceObject( deviceObject );
  793. }