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.

10652 lines
314 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. internal.c
  5. Abstract:
  6. This module contains the internal subroutines used by the I/O system.
  7. Author:
  8. Darryl E. Havens (darrylh) 18-Apr-1989
  9. Nar Ganapathy (narg) 1/1/1999
  10. Environment:
  11. Kernel mode, local to I/O system
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. #pragma hdrstop
  16. #include <ioevent.h>
  17. #include <hdlsblk.h>
  18. #include <hdlsterm.h>
  19. //PLJTMP
  20. #if defined(_X86_)
  21. VOID
  22. RtlAssert(
  23. IN PVOID FailedAssertion,
  24. IN PVOID FileName,
  25. IN ULONG LineNumber,
  26. IN PCHAR Message OPTIONAL
  27. );
  28. #endif
  29. //PLJTMPend
  30. #define IsFileLocal( FileObject ) ( !((FileObject)->DeviceObject->Characteristics & FILE_REMOTE_DEVICE) )
  31. #define IO_MAX_ALLOCATE_IRP_TRIES 30*60 // Try for 7 minutes
  32. #define IO_INFINITE_RETRIES -1 // Try for ever
  33. typedef LINK_TRACKING_INFORMATION FILE_VOLUMEID_WITH_TYPE, *PFILE_VOLUMEID_WITH_TYPE;
  34. typedef struct _TRACKING_BUFFER {
  35. FILE_TRACKING_INFORMATION TrackingInformation;
  36. UCHAR Buffer[256];
  37. } TRACKING_BUFFER, *PTRACKING_BUFFER;
  38. typedef struct _REMOTE_LINK_BUFFER {
  39. REMOTE_LINK_TRACKING_INFORMATION TrackingInformation;
  40. UCHAR Buffer[256];
  41. } REMOTE_LINK_BUFFER, *PREMOTE_LINK_BUFFER;
  42. PIRP IopDeadIrp;
  43. NTSTATUS
  44. IopResurrectDriver(
  45. PDRIVER_OBJECT DriverObject
  46. );
  47. VOID
  48. IopUserRundown(
  49. IN PKAPC Apc
  50. );
  51. VOID
  52. IopMarshalIds(
  53. OUT PTRACKING_BUFFER TrackingBuffer,
  54. IN PFILE_VOLUMEID_WITH_TYPE TargetVolumeId,
  55. IN PFILE_OBJECTID_BUFFER TargetObjectId,
  56. IN PFILE_TRACKING_INFORMATION TrackingInfo
  57. );
  58. VOID
  59. IopUnMarshalIds(
  60. IN FILE_TRACKING_INFORMATION * TrackingInformation,
  61. OUT FILE_VOLUMEID_WITH_TYPE * TargetVolumeId,
  62. OUT GUID * TargetObjectId,
  63. OUT GUID * TargetMachineId
  64. );
  65. NTSTATUS
  66. IopBootLogToFile(
  67. PUNICODE_STRING String
  68. );
  69. VOID
  70. IopCopyBootLogRegistryToFile(
  71. VOID
  72. );
  73. #ifdef ALLOC_PRAGMA
  74. VOID
  75. IopRaiseHardError(
  76. IN PVOID NormalContext,
  77. IN PVOID SystemArgument1,
  78. IN PVOID SystemArgument2
  79. );
  80. VOID
  81. IopApcHardError(
  82. IN PVOID StartContext
  83. );
  84. PVPB
  85. IopMountInitializeVpb(
  86. IN PDEVICE_OBJECT DeviceObject,
  87. IN PDEVICE_OBJECT AttachedDevice,
  88. IN ULONG RawMountOnly
  89. );
  90. #pragma alloc_text(PAGE, IopAbortRequest)
  91. #pragma alloc_text(PAGE, IopAcquireFileObjectLock)
  92. #pragma alloc_text(PAGE, IopAllocateIrpCleanup)
  93. #pragma alloc_text(PAGE, IopCallDriverReinitializationRoutines)
  94. #pragma alloc_text(PAGE, IopCancelAlertedRequest)
  95. #pragma alloc_text(PAGE, IopCheckGetQuotaBufferValidity)
  96. #pragma alloc_text(PAGE, IopConnectLinkTrackingPort)
  97. #pragma alloc_text(PAGE, IopDeallocateApc)
  98. #pragma alloc_text(PAGE, IopExceptionCleanup)
  99. #pragma alloc_text(PAGE, IopGetDriverNameFromKeyNode)
  100. #pragma alloc_text(PAGE, IopGetFileInformation)
  101. #pragma alloc_text(PAGE, IopGetRegistryKeyInformation)
  102. #pragma alloc_text(PAGE, IopGetRegistryValue)
  103. #pragma alloc_text(PAGE, IopGetRegistryValues)
  104. #pragma alloc_text(PAGE, IopGetSetObjectId)
  105. #pragma alloc_text(PAGE, IopGetVolumeId)
  106. #pragma alloc_text(PAGE, IopInvalidateVolumesForDevice)
  107. #pragma alloc_text(PAGE, IopIsSameMachine)
  108. #pragma alloc_text(PAGE, IopLoadDriver)
  109. #pragma alloc_text(PAGE, IopLoadFileSystemDriver)
  110. #pragma alloc_text(PAGE, IopLoadUnloadDriver)
  111. #pragma alloc_text(PAGE, IopMountVolume)
  112. #pragma alloc_text(PAGE, IopMarshalIds)
  113. #pragma alloc_text(PAGE, IopOpenLinkOrRenameTarget)
  114. #pragma alloc_text(PAGE, IopOpenRegistryKey)
  115. #pragma alloc_text(PAGE, IopQueryXxxInformation)
  116. #pragma alloc_text(PAGE, IopRaiseHardError)
  117. #pragma alloc_text(PAGE, IopApcHardError)
  118. #pragma alloc_text(PAGE, IopRaiseInformationalHardError)
  119. #pragma alloc_text(PAGE, IopReadyDeviceObjects)
  120. #pragma alloc_text(PAGE, IopReferenceDriverObjectByName)
  121. #pragma alloc_text(PAGE, IopUnMarshalIds)
  122. #pragma alloc_text(PAGE, IopSendMessageToTrackService)
  123. #pragma alloc_text(PAGE, IopSetEaOrQuotaInformationFile)
  124. #pragma alloc_text(PAGE, IopSetRemoteLink)
  125. #pragma alloc_text(PAGE, IopStartApcHardError)
  126. #pragma alloc_text(PAGE, IopSynchronousApiServiceTail)
  127. #pragma alloc_text(PAGE, IopSynchronousServiceTail)
  128. #pragma alloc_text(PAGE, IopTrackLink)
  129. #pragma alloc_text(PAGE, IopUserCompletion)
  130. #pragma alloc_text(PAGE, IopUserRundown)
  131. #pragma alloc_text(PAGE, IopXxxControlFile)
  132. #pragma alloc_text(PAGE, IopLookupBusStringFromID)
  133. #pragma alloc_text(PAGE, IopSafebootDriverLoad)
  134. #pragma alloc_text(PAGE, IopInitializeBootLogging)
  135. #pragma alloc_text(PAGE, IopBootLog)
  136. #pragma alloc_text(PAGE, IopCopyBootLogRegistryToFile)
  137. #pragma alloc_text(PAGE, IopBootLogToFile)
  138. #pragma alloc_text(PAGE, IopHardErrorThread)
  139. #pragma alloc_text(PAGE, IopGetBasicInformationFile)
  140. #pragma alloc_text(PAGE, IopBuildFullDriverPath)
  141. #endif
  142. VOID
  143. IopAbortRequest(
  144. IN PKAPC Apc
  145. )
  146. /*++
  147. Routine Description:
  148. This routine is invoked to abort an I/O request. It is invoked during the
  149. rundown of a thread.
  150. Arguments:
  151. Apc - Pointer to the kernel APC structure. This structure is contained
  152. within the I/O Request Packet (IRP) itself.
  153. Return Value:
  154. None.
  155. --*/
  156. {
  157. PAGED_CODE();
  158. //
  159. // Invoke the normal special kernel APC routine.
  160. //
  161. IopCompleteRequest( Apc,
  162. &Apc->NormalRoutine,
  163. &Apc->NormalContext,
  164. &Apc->SystemArgument1,
  165. &Apc->SystemArgument2 );
  166. }
  167. NTSTATUS
  168. IopAcquireFileObjectLock(
  169. IN PFILE_OBJECT FileObject,
  170. IN KPROCESSOR_MODE RequestorMode,
  171. IN BOOLEAN Alertable,
  172. OUT PBOOLEAN Interrupted
  173. )
  174. /*++
  175. Routine Description:
  176. This routine is invoked to acquire the lock for a file object whenever
  177. there is contention and obtaining the fast lock for the file failed.
  178. Arguments:
  179. FileObject - Pointer to the file object whose lock is to be acquired.
  180. RequestorMode - Processor access mode of the caller.
  181. Alertable - Indicates whether or not the lock should be obtained in an
  182. alertable manner.
  183. Interrupted - A variable to receive a BOOLEAN that indicates whether or
  184. not the attempt to acquire the lock was interrupted by an alert or
  185. an APC.
  186. Return Value:
  187. The function status is the final status of the operation.
  188. --*/
  189. {
  190. NTSTATUS status;
  191. PAGED_CODE();
  192. //
  193. // Assume that the function will not be interrupted by an alert or an
  194. // APC while attempting to acquire the lock.
  195. //
  196. *Interrupted = FALSE;
  197. //
  198. // Loop attempting to acquire the lock for the file object.
  199. //
  200. InterlockedIncrement (&FileObject->Waiters);
  201. for (;;) {
  202. if (!FileObject->Busy) {
  203. //
  204. // The file object appears to be un-owned, try to acquire it
  205. //
  206. if (IopAcquireFastLock ( FileObject ) ) {
  207. //
  208. // Object was acquired. Remove our count and return success
  209. //
  210. InterlockedDecrement (&FileObject->Waiters);
  211. return STATUS_SUCCESS;
  212. }
  213. }
  214. //
  215. // Wait for the event that indicates that the thread that currently
  216. // owns the file object has released it.
  217. //
  218. status = KeWaitForSingleObject( &FileObject->Lock,
  219. Executive,
  220. RequestorMode,
  221. Alertable,
  222. (PLARGE_INTEGER) NULL );
  223. //
  224. // If the above wait was interrupted, then indicate so and return.
  225. // Before returning, however, check the state of the ownership of
  226. // the file object itself. If it is not currently owned (the busy
  227. // flag is clear), then check to see whether or not there are any
  228. // other waiters. If so, then set the event to the signaled state
  229. // again so that they wake up and check the state of the busy flag.
  230. //
  231. if (status == STATUS_USER_APC || status == STATUS_ALERTED) {
  232. InterlockedDecrement (&FileObject->Waiters);
  233. if (!FileObject->Busy && FileObject->Waiters) {
  234. KeSetEvent( &FileObject->Lock, 0, FALSE );
  235. }
  236. *Interrupted = TRUE;
  237. return status;
  238. }
  239. }
  240. }
  241. VOID
  242. IopAllocateIrpCleanup(
  243. IN PFILE_OBJECT FileObject,
  244. IN PKEVENT EventObject OPTIONAL
  245. )
  246. /*++
  247. Routine Description:
  248. This routine is invoked internally by those system services that attempt
  249. to allocate an IRP and fail. This routine cleans up the file object
  250. and any event object that has been references and releases any locks
  251. that were taken out.
  252. Arguments:
  253. FileObject - Pointer to the file object being worked on.
  254. EventObject - Optional pointer to a referenced event to be dereferenced.
  255. Return Value:
  256. None.
  257. --*/
  258. {
  259. PAGED_CODE();
  260. //
  261. // Begin by dereferencing the event, if one was specified.
  262. //
  263. if (ARGUMENT_PRESENT( EventObject )) {
  264. ObDereferenceObject( EventObject );
  265. }
  266. //
  267. // Release the synchronization semaphore if it is currently held and
  268. // dereference the file object.
  269. //
  270. if (FileObject->Flags & FO_SYNCHRONOUS_IO) {
  271. IopReleaseFileObjectLock( FileObject );
  272. }
  273. ObDereferenceObject( FileObject );
  274. return;
  275. }
  276. PIRP
  277. IopAllocateIrpMustSucceed(
  278. IN CCHAR StackSize
  279. )
  280. /*++
  281. Routine Description:
  282. This routine is invoked to allocate an IRP when there are no appropriate
  283. packets remaining on the look-aside list, and no memory was available
  284. from the general non-paged pool, and yet, the code path requiring the
  285. packet has no way of backing out and simply returning an error. There-
  286. fore, it must allocate an IRP. Hence, this routine is called to allocate
  287. that packet.
  288. Arguments:
  289. StackSize - Supplies the number of IRP I/O stack locations that the
  290. packet must have when allocated.
  291. Return Value:
  292. A pointer to the allocated I/O Request Packet.
  293. --*/
  294. {
  295. PIRP irp;
  296. USHORT packetSize;
  297. LONG numTries;
  298. LARGE_INTEGER interval;
  299. //
  300. // Attempt to allocate the IRP normally and failing that,
  301. // wait a second and try again. If we exhaust 7 minutes then
  302. // allocate the IRP from nonpaged must succeed pool.
  303. //
  304. numTries = IO_INFINITE_RETRIES;
  305. irp = IoAllocateIrp(StackSize, FALSE);
  306. while (!irp && numTries) {
  307. interval.QuadPart = -1000 * 1000 * 10; // 10 Msec.
  308. KeDelayExecutionThread(KernelMode, FALSE, &interval);
  309. irp = IoAllocateIrp(StackSize, FALSE);
  310. if (numTries != IO_INFINITE_RETRIES) {
  311. numTries--;
  312. }
  313. }
  314. //
  315. // We tried for seven minutes and we have not freed memory.
  316. // Its time to try the must succeed pool.
  317. //
  318. if (!irp) {
  319. packetSize = IoSizeOfIrp(StackSize);
  320. irp = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, packetSize, ' prI');
  321. IoInitializeIrp(irp, packetSize, StackSize);
  322. irp->AllocationFlags |= IRP_ALLOCATED_MUST_SUCCEED;
  323. }
  324. return irp;
  325. }
  326. VOID
  327. IopApcHardError(
  328. IN PVOID StartContext
  329. )
  330. /*++
  331. Routine Description:
  332. This function is invoked when we need to do a hard error pop-up, but the
  333. Irp's originating thread is at APC level, ie. IoPageRead. We in a special
  334. purpose thread that will go away when the user responds to the pop-up.
  335. Arguments:
  336. StartContext - Startup context, contains a IOP_APC_HARD_ERROR_PACKET.
  337. Return Value:
  338. None.
  339. --*/
  340. {
  341. PIOP_APC_HARD_ERROR_PACKET packet;
  342. packet = StartContext;
  343. IopRaiseHardError( packet->Irp, packet->Vpb, packet->RealDeviceObject );
  344. ExFreePool( packet );
  345. }
  346. VOID
  347. IopCancelAlertedRequest(
  348. IN PKEVENT Event,
  349. IN PIRP Irp
  350. )
  351. /*++
  352. Routine Description:
  353. This routine is invoked when a synchronous I/O operation that is blocked in
  354. the I/O system needs to be canceled because the thread making the request has
  355. either been alerted because it is going away or because of a CTRL/C. This
  356. routine carefully attempts to work its way out of the current operation so
  357. that local events or other local data will not be accessed once the service
  358. being interrupted returns.
  359. Arguments:
  360. Event - The address of a kernel event that will be set to the Signaled state
  361. by I/O completion when the request is complete.
  362. Irp - Pointer to the I/O Request Packet (IRP) representing the current request.
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. KIRQL irql;
  368. LARGE_INTEGER deltaTime;
  369. BOOLEAN canceled;
  370. PAGED_CODE();
  371. //
  372. // Begin by blocking special kernel APCs so that the request cannot
  373. // complete.
  374. //
  375. KeRaiseIrql( APC_LEVEL, &irql );
  376. //
  377. // Check the state of the event to determine whether or not the
  378. // packet has already been completed.
  379. //
  380. if (KeReadStateEvent( Event ) == 0) {
  381. //
  382. // The packet has not been completed, so attempt to cancel it.
  383. //
  384. canceled = IoCancelIrp( Irp );
  385. KeLowerIrql( irql );
  386. if (canceled) {
  387. //
  388. // The packet had a cancel routine, so it was canceled. Loop,
  389. // waiting for the packet to complete. This should occur almost
  390. // immediately.
  391. //
  392. deltaTime.QuadPart = - 10 * 1000 * 10;
  393. while (KeReadStateEvent( Event ) == 0) {
  394. KeDelayExecutionThread( KernelMode, FALSE, &deltaTime );
  395. }
  396. } else {
  397. //
  398. // The packet did not have a cancel routine, so simply wait for
  399. // the event to be set to the Signaled state. This will save
  400. // CPU time by not looping, since it is not known when the packet
  401. // will actually complete. Note, however, that the cancel flag
  402. // is set in the packet, so should a driver examine the flag
  403. // at some point in the future, it will immediately stop
  404. // processing the request.
  405. //
  406. (VOID) KeWaitForSingleObject( Event,
  407. Executive,
  408. KernelMode,
  409. FALSE,
  410. (PLARGE_INTEGER) NULL );
  411. }
  412. } else {
  413. //
  414. // The packet has already been completed, so simply lower the
  415. // IRQL back to its original value and exit.
  416. //
  417. KeLowerIrql( irql );
  418. }
  419. }
  420. NTSTATUS
  421. IopCheckGetQuotaBufferValidity(
  422. IN PFILE_GET_QUOTA_INFORMATION QuotaBuffer,
  423. IN ULONG QuotaLength,
  424. OUT PULONG_PTR ErrorOffset
  425. )
  426. /*++
  427. Routine Description:
  428. This routine checks the validity of the specified get quota buffer to
  429. guarantee that its format is proper, no fields hang over, that it is
  430. not recursive, etc.
  431. Arguments:
  432. QuotaBuffer - Pointer to the buffer containing the get quota structure
  433. array to be checked.
  434. QuotaLength - Specifies the length of the quota buffer.
  435. ErrorOffset - A variable to receive the offset of the offending entry
  436. in the quota buffer if an error is incurred. This variable is only
  437. valid if an error occurs.
  438. Return Value:
  439. The function value is STATUS_SUCCESS if the get quota buffer contains a
  440. valid, properly formed list, otherwise STATUS_QUOTA_LIST_INCONSISTENT.
  441. --*/
  442. {
  443. #define GET_OFFSET_LENGTH( CurrentSid, SidBase ) ( (ULONG) ((PCHAR) CurrentSid - (PCHAR) SidBase) )
  444. LONG tempLength;
  445. LONG entrySize;
  446. PFILE_GET_QUOTA_INFORMATION sids;
  447. PAGED_CODE();
  448. //
  449. // Walk the buffer and ensure that its format is valid. That is, ensure
  450. // that it does not walk off the end of the buffer, is not recursive, etc.
  451. //
  452. sids = QuotaBuffer;
  453. tempLength = QuotaLength;
  454. for (;;) {
  455. //
  456. // Ensure that the current entry is valid.
  457. //
  458. if ((tempLength < (LONG) (FIELD_OFFSET(FILE_GET_QUOTA_INFORMATION, Sid.SubAuthority) +
  459. sizeof (sids->Sid.SubAuthority))) ||
  460. !RtlValidSid( &sids->Sid)) {
  461. *ErrorOffset = GET_OFFSET_LENGTH( sids, QuotaBuffer );
  462. return STATUS_QUOTA_LIST_INCONSISTENT;
  463. }
  464. //
  465. // Get the size of the current entry in the buffer.
  466. //
  467. entrySize = FIELD_OFFSET( FILE_GET_QUOTA_INFORMATION, Sid ) + RtlLengthSid( (&sids->Sid) );
  468. if (sids->NextEntryOffset) {
  469. //
  470. // There is another entry in the buffer and it must be longword
  471. // aligned. Ensure that the offset indicates that it is. If it
  472. // isn't, return an invalid parameter status.
  473. //
  474. if (entrySize > (LONG) sids->NextEntryOffset ||
  475. sids->NextEntryOffset & (sizeof( ULONG ) - 1)) {
  476. *ErrorOffset = GET_OFFSET_LENGTH( sids, QuotaBuffer );
  477. return STATUS_QUOTA_LIST_INCONSISTENT;
  478. } else {
  479. //
  480. // There is another entry in the buffer, so account for the
  481. // size of the current entry in the length and get a pointer
  482. // to the next entry.
  483. //
  484. tempLength -= sids->NextEntryOffset;
  485. if (tempLength < 0) {
  486. *ErrorOffset = GET_OFFSET_LENGTH( sids, QuotaBuffer );
  487. return STATUS_QUOTA_LIST_INCONSISTENT;
  488. }
  489. sids = (PFILE_GET_QUOTA_INFORMATION) ((PCHAR) sids + sids->NextEntryOffset);
  490. }
  491. } else {
  492. //
  493. // There are no other entries in the buffer. Simply account for
  494. // the overall buffer length according to the size of the current
  495. // entry and exit the loop.
  496. //
  497. tempLength -= entrySize;
  498. break;
  499. }
  500. }
  501. //
  502. // All of the entries in the buffer have been processed. Check to see
  503. // whether the overall buffer length went negative. If so, return an
  504. // error.
  505. //
  506. if (tempLength < 0) {
  507. *ErrorOffset = GET_OFFSET_LENGTH( sids, QuotaBuffer );
  508. return STATUS_QUOTA_LIST_INCONSISTENT;
  509. }
  510. //
  511. // The format of the get quota buffer was correct, so simply return a
  512. // success status code.
  513. //
  514. return STATUS_SUCCESS;
  515. }
  516. VOID
  517. IopCompleteUnloadOrDelete(
  518. IN PDEVICE_OBJECT DeviceObject,
  519. IN BOOLEAN OnCleanStack,
  520. IN KIRQL Irql
  521. )
  522. /*++
  523. Routine Description:
  524. This routine is invoked when the reference count on a device object
  525. transitions to a zero and the driver is mark for unload or device has
  526. been marked for delete. This means that it may be possible to actually
  527. unload the driver or delete the device object. If all
  528. of the devices have a reference count of zero, then the driver is
  529. actually unloaded. Note that in order to ensure that this routine is
  530. not invoked twice, at the same time, on two different processors, the
  531. I/O database spin lock is still held at this point.
  532. Arguments:
  533. DeviceObject - Supplies a pointer to one of the driver's device objects,
  534. namely the one whose reference count just went to zero.
  535. OnCleanStack - Indicates whether the current thread is in the middle a
  536. driver operation.
  537. Irql - Specifies the IRQL of the processor at the time that the I/O
  538. database lock was acquired.
  539. Return Value:
  540. None.
  541. --*/
  542. {
  543. PDRIVER_OBJECT driverObject;
  544. PDEVICE_OBJECT deviceObject;
  545. PDEVICE_OBJECT baseDeviceObject;
  546. PDEVICE_OBJECT attachedDeviceObject;
  547. PDEVOBJ_EXTENSION deviceExtension;
  548. BOOLEAN unload = TRUE;
  549. driverObject = DeviceObject->DriverObject;
  550. if (DeviceObject->DeviceObjectExtension->ExtensionFlags & DOE_REMOVE_PENDING) {
  551. //
  552. // Run some tests to determine if it is an appropriate time to notify
  553. // PnP that all file objects in the attachment chain have gone away.
  554. //
  555. baseDeviceObject = IopGetDeviceAttachmentBase( DeviceObject );
  556. deviceExtension = baseDeviceObject->DeviceObjectExtension;
  557. ASSERT(deviceExtension->DeviceNode != NULL);
  558. //
  559. // baseDeviceObject is a PDO, this is a PnP stack. See if
  560. // an IRP_MN_REMOVE_DEVICE is pending.
  561. //
  562. // ASSERT(deviceNode->Flags & DNF_REMOVE_PENDING_CLOSES);
  563. //
  564. // PnP wants to be notified as soon as all refcounts on all devices in
  565. // this attachment chain go away.
  566. //
  567. attachedDeviceObject = baseDeviceObject;
  568. while (attachedDeviceObject != NULL) {
  569. if (attachedDeviceObject->ReferenceCount != 0) {
  570. //
  571. // At least one device object in the attachment chain has
  572. // an outstanding open.
  573. //
  574. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  575. return;
  576. }
  577. attachedDeviceObject = attachedDeviceObject->AttachedDevice;
  578. }
  579. //
  580. // Now one more time changing DOE_REMOVE_PENDING to
  581. // DOE_REMOVE_PROCESSED.
  582. //
  583. attachedDeviceObject = baseDeviceObject;
  584. while (attachedDeviceObject != NULL) {
  585. deviceExtension = attachedDeviceObject->DeviceObjectExtension;
  586. deviceExtension->ExtensionFlags &= ~DOE_REMOVE_PENDING;
  587. deviceExtension->ExtensionFlags |= DOE_REMOVE_PROCESSED;
  588. attachedDeviceObject = attachedDeviceObject->AttachedDevice;
  589. }
  590. //
  591. // It is time to give PnP the notification it was waiting for. We have
  592. // to release the spinlock before doing so.
  593. //
  594. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  595. IopChainDereferenceComplete( baseDeviceObject, OnCleanStack );
  596. return;
  597. }
  598. if (DeviceObject->DeviceObjectExtension->ExtensionFlags & DOE_DELETE_PENDING) {
  599. if ((DeviceObject->DeviceObjectExtension->ExtensionFlags &
  600. DOE_UNLOAD_PENDING) == 0 ||
  601. driverObject->Flags & DRVO_UNLOAD_INVOKED) {
  602. unload = FALSE;
  603. }
  604. //
  605. // If another device is attached to this device, inform the former's
  606. // driver that the device is being deleted.
  607. //
  608. if (DeviceObject->AttachedDevice) {
  609. PFAST_IO_DISPATCH fastIoDispatch = DeviceObject->AttachedDevice->DriverObject->FastIoDispatch;
  610. PDEVICE_OBJECT attachedDevice = DeviceObject->AttachedDevice;
  611. //
  612. // Increment the device reference count so the detach routine
  613. // does not recurse back to here.
  614. //
  615. DeviceObject->ReferenceCount++;
  616. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  617. if (fastIoDispatch &&
  618. fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET( FAST_IO_DISPATCH, FastIoDetachDevice ) &&
  619. fastIoDispatch->FastIoDetachDevice) {
  620. (fastIoDispatch->FastIoDetachDevice)( attachedDevice, DeviceObject );
  621. }
  622. Irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  623. //
  624. // Restore the reference count value.
  625. //
  626. DeviceObject->ReferenceCount--;
  627. if (DeviceObject->AttachedDevice ||
  628. DeviceObject->ReferenceCount != 0) {
  629. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  630. return;
  631. }
  632. }
  633. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  634. //
  635. // Deallocate the memory for the security descriptor that was allocated
  636. // for this device object.
  637. //
  638. if (DeviceObject->SecurityDescriptor != (PSECURITY_DESCRIPTOR) NULL) {
  639. ObDereferenceSecurityDescriptor( DeviceObject->SecurityDescriptor, 1 );
  640. }
  641. //
  642. // Remove this device object from the driver object's list.
  643. //
  644. IopInsertRemoveDevice( DeviceObject->DriverObject, DeviceObject, FALSE );
  645. //
  646. // Finally, dereference the object so it is deleted.
  647. //
  648. ObDereferenceObject( DeviceObject );
  649. //
  650. // Return if the unload does not need to be done.
  651. //
  652. if (!unload) {
  653. return;
  654. }
  655. //
  656. // Reacquire the spin lock make sure the unload routine does has
  657. // not been called.
  658. //
  659. Irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  660. if (driverObject->Flags & DRVO_UNLOAD_INVOKED) {
  661. //
  662. // Some other thread is doing the unload, release the lock and return.
  663. //
  664. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  665. return;
  666. }
  667. }
  668. //
  669. // Scan the list of device objects for this driver, looking for a
  670. // non-zero reference count. If any reference count is non-zero, then
  671. // the driver may not be unloaded.
  672. //
  673. deviceObject = driverObject->DeviceObject;
  674. while (deviceObject) {
  675. if (deviceObject->ReferenceCount || deviceObject->AttachedDevice ||
  676. deviceObject->DeviceObjectExtension->ExtensionFlags & (DOE_DELETE_PENDING | DOE_REMOVE_PENDING)) {
  677. unload = FALSE;
  678. break;
  679. }
  680. deviceObject = deviceObject->NextDevice;
  681. }
  682. //
  683. // If this is a base filesystem driver and we still have device objects
  684. // skip the unload.
  685. //
  686. if (driverObject->Flags & DRVO_BASE_FILESYSTEM_DRIVER && driverObject->DeviceObject) {
  687. unload = FALSE;
  688. }
  689. if (unload) {
  690. driverObject->Flags |= DRVO_UNLOAD_INVOKED;
  691. }
  692. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, Irql );
  693. //
  694. // If the reference counts for all of the devices is zero, then this
  695. // driver can now be unloaded.
  696. //
  697. if (unload) {
  698. LOAD_PACKET loadPacket;
  699. KeInitializeEvent( &loadPacket.Event, NotificationEvent, FALSE );
  700. loadPacket.DriverObject = driverObject;
  701. if (OnCleanStack) {
  702. IopLoadUnloadDriver(&loadPacket);
  703. } else {
  704. ExInitializeWorkItem( &loadPacket.WorkQueueItem,
  705. IopLoadUnloadDriver,
  706. &loadPacket );
  707. ExQueueWorkItem( &loadPacket.WorkQueueItem, DelayedWorkQueue );
  708. (VOID) KeWaitForSingleObject( &loadPacket.Event,
  709. Executive,
  710. KernelMode,
  711. FALSE,
  712. (PLARGE_INTEGER) NULL );
  713. }
  714. ObMakeTemporaryObject( driverObject );
  715. ObDereferenceObject( driverObject );
  716. }
  717. }
  718. VOID
  719. IopCompletePageWrite(
  720. IN PKAPC Apc,
  721. IN PKNORMAL_ROUTINE *NormalRoutine,
  722. IN PVOID *NormalContext,
  723. IN PVOID *SystemArgument1,
  724. IN PVOID *SystemArgument2
  725. )
  726. /*++
  727. Routine Description:
  728. This routine executes as a special kernel APC routine in the context of
  729. the Modified Page Writer (MPW) system thread when an out-page operation
  730. has completed.
  731. This routine performs the following tasks:
  732. o The I/O status is copied.
  733. o The Modified Page Writer's APC routine is invoked.
  734. Arguments:
  735. Apc - Supplies a pointer to kernel APC structure.
  736. NormalRoutine - Supplies a pointer to a pointer to the normal function
  737. that was specified when the APC was initialized.
  738. NormalContext - Supplies a pointer to a pointer to an arbitrary data
  739. structure that was specified when the APC was initialized.
  740. SystemArgument1 - Supplies a pointer to an argument that contains an
  741. argument that is unused by this routine.
  742. SystemArgument2 - Supplies a pointer to an argument that contains an
  743. argument that is unused by this routine.
  744. Return Value:
  745. None.
  746. --*/
  747. {
  748. PIRP irp;
  749. PIO_APC_ROUTINE apcRoutine;
  750. PVOID apcContext;
  751. PIO_STATUS_BLOCK ioStatus;
  752. UNREFERENCED_PARAMETER( NormalRoutine );
  753. UNREFERENCED_PARAMETER( NormalContext );
  754. UNREFERENCED_PARAMETER( SystemArgument1 );
  755. UNREFERENCED_PARAMETER( SystemArgument2 );
  756. //
  757. // Begin by getting the address of the I/O Request Packet from the APC.
  758. //
  759. irp = CONTAINING_RECORD( Apc, IRP, Tail.Apc );
  760. //
  761. // If this I/O operation did not complete successfully through the
  762. // dispatch routine of the driver, then drop everything on the floor
  763. // now and return to the original call point in the MPW.
  764. //
  765. if (!irp->PendingReturned && NT_ERROR( irp->IoStatus.Status )) {
  766. IoFreeIrp( irp );
  767. return;
  768. }
  769. //
  770. // Copy the I/O status from the IRP into the caller's I/O status block.
  771. //
  772. *irp->UserIosb = irp->IoStatus;
  773. //
  774. // Copy the pertinent information from the I/O Request Packet into locals
  775. // and free it.
  776. //
  777. apcRoutine = irp->Overlay.AsynchronousParameters.UserApcRoutine;
  778. apcContext = irp->Overlay.AsynchronousParameters.UserApcContext;
  779. ioStatus = irp->UserIosb;
  780. IoFreeIrp( irp );
  781. //
  782. // Finally, invoke the MPW's APC routine.
  783. //
  784. apcRoutine( apcContext, ioStatus, 0 );
  785. return;
  786. }
  787. VOID
  788. IopCompleteRequest(
  789. IN PKAPC Apc,
  790. IN PKNORMAL_ROUTINE *NormalRoutine,
  791. IN PVOID *NormalContext,
  792. IN PVOID *SystemArgument1,
  793. IN PVOID *SystemArgument2
  794. )
  795. /*++
  796. Routine Description:
  797. This routine executes as a special kernel APC routine in the context of
  798. the thread which originally requested the I/O operation which is now
  799. being completed.
  800. This routine performs the following tasks:
  801. o A check is made to determine whether the specified request ended
  802. with an error status. If so, and the error code qualifies as one
  803. which should be reported to an error port, then an error port is
  804. looked for in the thread/process. If one exists, then this routine
  805. will attempt to set up an LPC to it. Otherwise, it will attempt to
  806. set up an LPC to the system error port.
  807. o Copy buffers.
  808. o Free MDLs.
  809. o Copy I/O status.
  810. o Set event, if any and dereference if appropriate.
  811. o Dequeue the IRP from the thread queue as pending I/O request.
  812. o Queue APC to thread, if any.
  813. o If no APC is to be queued, then free the packet now.
  814. Arguments:
  815. Apc - Supplies a pointer to kernel APC structure.
  816. NormalRoutine - Supplies a pointer to a pointer to the normal function
  817. that was specified when the APC was initialied.
  818. NormalContext - Supplies a pointer to a pointer to an arbitrary data
  819. structure that was specified when the APC was initialized.
  820. SystemArgument1 - Supplies a pointer to an argument that contains the
  821. address of the original file object for this I/O operation.
  822. SystemArgument2 - Supplies a pointer to an argument that contains an
  823. argument that is used by this routine only in the case of STATUS_REPARSE.
  824. Return Value:
  825. None.
  826. --*/
  827. {
  828. #define SynchronousIo( Irp, FileObject ) ( \
  829. (Irp->Flags & IRP_SYNCHRONOUS_API) || \
  830. (FileObject == NULL ? 0 : FileObject->Flags & FO_SYNCHRONOUS_IO) )
  831. PIRP irp;
  832. PMDL mdl, nextMdl;
  833. PETHREAD thread;
  834. PFILE_OBJECT fileObject;
  835. NTSTATUS status;
  836. UNREFERENCED_PARAMETER( NormalRoutine );
  837. UNREFERENCED_PARAMETER( NormalContext );
  838. //
  839. // Begin by getting the address of the I/O Request Packet. Also, get
  840. // the address of the current thread and the address of the original file
  841. // object for this I/O operation.
  842. //
  843. irp = CONTAINING_RECORD( Apc, IRP, Tail.Apc );
  844. thread = PsGetCurrentThread();
  845. fileObject = (PFILE_OBJECT) *SystemArgument1;
  846. IOVP_COMPLETE_REQUEST(Apc, SystemArgument1, SystemArgument2);
  847. //
  848. // Ensure that the packet is not being completed with a minus one. This
  849. // is apparently a common problem in some drivers, and has no meaning
  850. // as a status code.
  851. //
  852. ASSERT( irp->IoStatus.Status != 0xffffffff );
  853. //
  854. // See if we need to do the name transmogrify work.
  855. //
  856. if ( *SystemArgument2 != NULL ) {
  857. PREPARSE_DATA_BUFFER reparseBuffer = NULL;
  858. //
  859. // The IO_REPARSE_TAG_MOUNT_POINT tag needs attention.
  860. //
  861. if ( irp->IoStatus.Status == STATUS_REPARSE &&
  862. irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT ) {
  863. reparseBuffer = (PREPARSE_DATA_BUFFER) *SystemArgument2;
  864. ASSERT( reparseBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT );
  865. ASSERT( reparseBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  866. ASSERT( reparseBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  867. IopDoNameTransmogrify( irp,
  868. fileObject,
  869. reparseBuffer );
  870. }
  871. }
  872. //
  873. // Check to see whether there is any data in a system buffer which needs
  874. // to be copied to the caller's buffer. If so, copy the data and then
  875. // free the system buffer if necessary.
  876. //
  877. if (irp->Flags & IRP_BUFFERED_IO) {
  878. //
  879. // Copy the data if this was an input operation. Note that no copy
  880. // is performed if the status indicates that a verify operation is
  881. // required, or if the final status was an error-level severity.
  882. //
  883. if (irp->Flags & IRP_INPUT_OPERATION &&
  884. irp->IoStatus.Status != STATUS_VERIFY_REQUIRED &&
  885. !NT_ERROR( irp->IoStatus.Status )) {
  886. //
  887. // Copy the information from the system buffer to the caller's
  888. // buffer. This is done with an exception handler in case
  889. // the operation fails because the caller's address space
  890. // has gone away, or it's protection has been changed while
  891. // the service was executing.
  892. //
  893. try {
  894. RtlCopyMemory( irp->UserBuffer,
  895. irp->AssociatedIrp.SystemBuffer,
  896. irp->IoStatus.Information );
  897. } except(IopExceptionFilter(GetExceptionInformation(), &status)) {
  898. //
  899. // An exception occurred while attempting to copy the
  900. // system buffer contents to the caller's buffer. Set
  901. // a new I/O completion status.
  902. // If the status is a special one set by Mm then we need to
  903. // return here and the operation will be retried in
  904. // IoRetryIrpCompletions.
  905. //
  906. if (status == STATUS_MULTIPLE_FAULT_VIOLATION) {
  907. irp->Tail.Overlay.OriginalFileObject = fileObject; /* Wiped out by APC overlay */
  908. irp->Flags |= IRP_RETRY_IO_COMPLETION;
  909. return;
  910. }
  911. irp->IoStatus.Status = GetExceptionCode();
  912. }
  913. }
  914. //
  915. // Free the buffer if needed.
  916. //
  917. if (irp->Flags & IRP_DEALLOCATE_BUFFER) {
  918. ExFreePool( irp->AssociatedIrp.SystemBuffer );
  919. }
  920. }
  921. irp->Flags &= ~(IRP_DEALLOCATE_BUFFER|IRP_BUFFERED_IO);
  922. //
  923. // If there is an MDL (or MDLs) associated with this I/O request,
  924. // Free it (them) here. This is accomplished by walking the MDL list
  925. // hanging off of the IRP and deallocating each MDL encountered.
  926. //
  927. if (irp->MdlAddress) {
  928. for (mdl = irp->MdlAddress; mdl != NULL; mdl = nextMdl) {
  929. nextMdl = mdl->Next;
  930. IoFreeMdl( mdl );
  931. }
  932. }
  933. irp->MdlAddress = NULL;
  934. //
  935. // Check to see whether or not the I/O operation actually completed. If
  936. // it did, then proceed normally. Otherwise, cleanup everything and get
  937. // out of here.
  938. //
  939. if (!NT_ERROR( irp->IoStatus.Status ) ||
  940. (NT_ERROR( irp->IoStatus.Status ) &&
  941. irp->PendingReturned &&
  942. !SynchronousIo( irp, fileObject ))) {
  943. PVOID port = NULL;
  944. PVOID key;
  945. BOOLEAN createOperation = FALSE;
  946. //
  947. // If there is an I/O completion port object associated w/this request,
  948. // save it here so that the file object can be dereferenced.
  949. //
  950. if (fileObject && fileObject->CompletionContext) {
  951. port = fileObject->CompletionContext->Port;
  952. key = fileObject->CompletionContext->Key;
  953. }
  954. //
  955. // Copy the I/O status from the IRP into the caller's I/O status
  956. // block. This is done using an exception handler in case the caller's
  957. // virtual address space for the I/O status block was deleted or
  958. // its protection was changed to readonly. Note that if the I/O
  959. // status block cannot be written, the error is simply ignored since
  960. // there is no way to tell the caller that something went wrong.
  961. // This is, of course, by definition, since the I/O status block
  962. // is where the caller will attempt to look for errors in the first
  963. // place!
  964. //
  965. try {
  966. //
  967. // Since HasOverlappedIoCompleted and GetOverlappedResult only
  968. // look at the Status field of the UserIosb to determine if the
  969. // IRP has completed, the Information field must be written
  970. // before the Status field.
  971. //
  972. #if defined(_WIN64)
  973. PIO_STATUS_BLOCK32 UserIosb32;
  974. //
  975. // If the caller passes a 32 bit IOSB the ApcRoutine has the LSB set to 1
  976. //
  977. if (IopIsIosb32(irp->Overlay.AsynchronousParameters.UserApcRoutine)) {
  978. UserIosb32 = (PIO_STATUS_BLOCK32)irp->UserIosb;
  979. UserIosb32->Information = (ULONG)irp->IoStatus.Information;
  980. KeMemoryBarrier ();
  981. UserIosb32->Status = (NTSTATUS)irp->IoStatus.Status;
  982. } else {
  983. irp->UserIosb->Information = irp->IoStatus.Information;
  984. KeMemoryBarrier ();
  985. irp->UserIosb->Status = irp->IoStatus.Status;
  986. }
  987. #else
  988. irp->UserIosb->Information = irp->IoStatus.Information;
  989. KeMemoryBarrier ();
  990. irp->UserIosb->Status = irp->IoStatus.Status;
  991. #endif /*_WIN64 */
  992. } except(IopExceptionFilter(GetExceptionInformation(), &status)) {
  993. //
  994. // An exception was incurred attempting to write the caller's
  995. // I/O status block. Simply continue executing as if nothing
  996. // ever happened since nothing can be done about it anyway.
  997. // If the status is a multiple fault status, this is a special
  998. // status sent by the Memory manager. Mark the IRP and return from
  999. // this routine. Mm will call us back later and we will retry this
  1000. // operation (IoRetryIrpCompletions)
  1001. //
  1002. if (status == STATUS_MULTIPLE_FAULT_VIOLATION) {
  1003. irp->Tail.Overlay.OriginalFileObject = fileObject; /* Wiped out by APC overlay */
  1004. irp->Flags |= IRP_RETRY_IO_COMPLETION;
  1005. return;
  1006. }
  1007. }
  1008. //
  1009. // Determine whether the caller supplied an event that needs to be set
  1010. // to the Signaled state. If so, then set it; otherwise, set the event
  1011. // in the file object to the Signaled state.
  1012. //
  1013. // It is possible for the event to have been specified as a PKEVENT if
  1014. // this was an I/O operation hand-built for an FSP or an FSD, or
  1015. // some other types of operations such as synchronous I/O APIs. In
  1016. // any of these cases, the event was not referenced since it is not an
  1017. // object manager event, so it should not be dereferenced.
  1018. //
  1019. // Also, it is possible for there not to be a file object for this IRP.
  1020. // This occurs when an FSP is doing I/O operations to a device driver on
  1021. // behalf of a process doing I/O to a file. The file object cannot be
  1022. // dereferenced if this is the case. If this operation was a create
  1023. // operation then the object should not be dereferenced either. This
  1024. // is because the reference count must be one or it will go away for
  1025. // the caller (not much point in making an object that just got created
  1026. // go away).
  1027. //
  1028. if (irp->UserEvent) {
  1029. (VOID) KeSetEvent( irp->UserEvent, 0, FALSE );
  1030. if (fileObject) {
  1031. if (!(irp->Flags & IRP_SYNCHRONOUS_API)) {
  1032. ObDereferenceObject( irp->UserEvent );
  1033. }
  1034. if (fileObject->Flags & FO_SYNCHRONOUS_IO && !(irp->Flags & IRP_OB_QUERY_NAME)) {
  1035. (VOID) KeSetEvent( &fileObject->Event, 0, FALSE );
  1036. fileObject->FinalStatus = irp->IoStatus.Status;
  1037. }
  1038. if (irp->Flags & IRP_CREATE_OPERATION) {
  1039. createOperation = TRUE;
  1040. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  1041. }
  1042. }
  1043. } else if (fileObject) {
  1044. (VOID) KeSetEvent( &fileObject->Event, 0, FALSE );
  1045. fileObject->FinalStatus = irp->IoStatus.Status;
  1046. if (irp->Flags & IRP_CREATE_OPERATION) {
  1047. createOperation = TRUE;
  1048. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  1049. }
  1050. }
  1051. //
  1052. // If this is normal I/O, update the transfer count for this process.
  1053. //
  1054. if (!(irp->Flags & IRP_CREATE_OPERATION)) {
  1055. if (irp->Flags & IRP_READ_OPERATION) {
  1056. IopUpdateReadTransferCount( (ULONG) irp->IoStatus.Information );
  1057. } else if (irp->Flags & IRP_WRITE_OPERATION) {
  1058. IopUpdateWriteTransferCount( (ULONG) irp->IoStatus.Information );
  1059. } else {
  1060. //
  1061. // If the information field contains a pointer then skip the update.
  1062. // Some PNP IRPs contain this.
  1063. //
  1064. if (!((ULONG) irp->IoStatus.Information & 0x80000000)) {
  1065. IopUpdateOtherTransferCount( (ULONG) irp->IoStatus.Information );
  1066. }
  1067. }
  1068. }
  1069. //
  1070. // Dequeue the packet from the thread's pending I/O request list.
  1071. //
  1072. IopDequeueThreadIrp( irp );
  1073. //
  1074. // If the caller requested an APC, queue it to the thread. If not, then
  1075. // simply free the packet now.
  1076. //
  1077. #ifdef _WIN64
  1078. //
  1079. // For 64 bit systems clear the LSB field of the ApcRoutine that indicates whether
  1080. // the IOSB is a 32 bit IOSB or a 64 bit IOSB.
  1081. //
  1082. irp->Overlay.AsynchronousParameters.UserApcRoutine =
  1083. (PIO_APC_ROUTINE)((LONG_PTR)(irp->Overlay.AsynchronousParameters.UserApcRoutine) & ~1);
  1084. #endif
  1085. if (irp->Overlay.AsynchronousParameters.UserApcRoutine) {
  1086. KeInitializeApc( &irp->Tail.Apc,
  1087. &thread->Tcb,
  1088. CurrentApcEnvironment,
  1089. IopUserCompletion,
  1090. (PKRUNDOWN_ROUTINE) IopUserRundown,
  1091. (PKNORMAL_ROUTINE) irp->Overlay.AsynchronousParameters.UserApcRoutine,
  1092. irp->RequestorMode,
  1093. irp->Overlay.AsynchronousParameters.UserApcContext );
  1094. KeInsertQueueApc( &irp->Tail.Apc,
  1095. irp->UserIosb,
  1096. NULL,
  1097. 2 );
  1098. } else if (port && irp->Overlay.AsynchronousParameters.UserApcContext) {
  1099. //
  1100. // If there is a completion context associated w/this I/O operation,
  1101. // send the message to the port. Tag completion packet as an Irp.
  1102. //
  1103. irp->Tail.CompletionKey = key;
  1104. irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;
  1105. KeInsertQueue( (PKQUEUE) port,
  1106. &irp->Tail.Overlay.ListEntry );
  1107. } else {
  1108. //
  1109. // Free the IRP now since it is no longer needed.
  1110. //
  1111. IoFreeIrp( irp );
  1112. }
  1113. if (fileObject && !createOperation) {
  1114. //
  1115. // Dereference the file object now.
  1116. //
  1117. ObDereferenceObject( fileObject );
  1118. }
  1119. } else {
  1120. if (irp->PendingReturned && fileObject) {
  1121. //
  1122. // This is an I/O operation that completed as an error for
  1123. // which a pending status was returned and the I/O operation
  1124. // is synchronous. For this case, the I/O system is waiting
  1125. // on behalf of the caller. If the reason that the I/O was
  1126. // synchronous is that the file object was opened for synchronous
  1127. // I/O, then the event associated with the file object is set
  1128. // to the signaled state. If the I/O operation was synchronous
  1129. // because this is a synchronous API, then the event is set to
  1130. // the signaled state.
  1131. //
  1132. // Note also that the status must be returned for both types
  1133. // of synchronous I/O. If this is a synchronous API, then the
  1134. // I/O system supplies its own status block so it can simply
  1135. // be written; otherwise, the I/O system will obtain the final
  1136. // status from the file object itself.
  1137. //
  1138. if (irp->Flags & IRP_SYNCHRONOUS_API) {
  1139. *irp->UserIosb = irp->IoStatus;
  1140. if (irp->UserEvent) {
  1141. (VOID) KeSetEvent( irp->UserEvent, 0, FALSE );
  1142. } else {
  1143. (VOID) KeSetEvent( &fileObject->Event, 0, FALSE );
  1144. }
  1145. } else {
  1146. fileObject->FinalStatus = irp->IoStatus.Status;
  1147. (VOID) KeSetEvent( &fileObject->Event, 0, FALSE );
  1148. }
  1149. }
  1150. //
  1151. // The operation was incomplete. Perform the general cleanup. Note
  1152. // that everything is basically dropped on the floor without doing
  1153. // anything. That is:
  1154. //
  1155. // IoStatusBlock - Do nothing.
  1156. // Event - Dereference without setting to Signaled state.
  1157. // FileObject - Dereference without setting to Signaled state.
  1158. // ApcRoutine - Do nothing.
  1159. //
  1160. if (fileObject) {
  1161. if (!(irp->Flags & IRP_CREATE_OPERATION)) {
  1162. ObDereferenceObject( fileObject );
  1163. }
  1164. }
  1165. if (irp->UserEvent &&
  1166. fileObject &&
  1167. !(irp->Flags & IRP_SYNCHRONOUS_API)) {
  1168. ObDereferenceObject( irp->UserEvent );
  1169. }
  1170. IopDequeueThreadIrp( irp );
  1171. IoFreeIrp( irp );
  1172. }
  1173. }
  1174. VOID
  1175. IopConnectLinkTrackingPort(
  1176. IN PVOID Parameter
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. This routine is invoked to connect to the user-mode link tracking service's
  1181. LPC port. It makes a connection which establishes a handle to the port,
  1182. and then creates a referenced object pointer to the port.
  1183. Arguments:
  1184. Parameter - Pointer to the link tracking packet.
  1185. Return Value:
  1186. None.
  1187. --*/
  1188. {
  1189. #define MESSAGE_SIZE ( (2 * sizeof( FILE_VOLUMEID_WITH_TYPE )) + \
  1190. sizeof( FILE_OBJECTID_BUFFER ) + \
  1191. sizeof( GUID ) + \
  1192. sizeof( NTSTATUS ) + \
  1193. sizeof( ULONG ) )
  1194. PLINK_TRACKING_PACKET ltp;
  1195. HANDLE serviceHandle;
  1196. NTSTATUS status;
  1197. PAGED_CODE();
  1198. //
  1199. // Begin by getting a pointer to the link tracking packet.
  1200. //
  1201. ltp = (PLINK_TRACKING_PACKET) Parameter;
  1202. //
  1203. // Ensure that the port has not already been opened.
  1204. //
  1205. status = STATUS_SUCCESS;
  1206. if (!IopLinkTrackingServiceObject) {
  1207. UNICODE_STRING portName;
  1208. ULONG maxMessageLength;
  1209. SECURITY_QUALITY_OF_SERVICE dynamicQos;
  1210. if (KeReadStateEvent( IopLinkTrackingServiceEvent )) {
  1211. //
  1212. // Attempt to open a handle to the port.
  1213. //
  1214. //
  1215. // Set up the security quality of service parameters to use over the
  1216. // port. Use the most efficient (least overhead) which is dynamic
  1217. // rather than static tracking.
  1218. //
  1219. dynamicQos.ImpersonationLevel = SecurityImpersonation;
  1220. dynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1221. dynamicQos.EffectiveOnly = TRUE;
  1222. //
  1223. // Generate the string structure for describing the port.
  1224. //
  1225. RtlInitUnicodeString( &portName, L"\\Security\\TRKWKS_PORT" );
  1226. status = NtConnectPort( &serviceHandle,
  1227. &portName,
  1228. &dynamicQos,
  1229. (PPORT_VIEW) NULL,
  1230. (PREMOTE_PORT_VIEW) NULL,
  1231. &maxMessageLength,
  1232. (PVOID) NULL,
  1233. (PULONG) NULL );
  1234. if (NT_SUCCESS( status )) {
  1235. if (maxMessageLength >= MESSAGE_SIZE) {
  1236. status = ObReferenceObjectByHandle( serviceHandle,
  1237. 0,
  1238. LpcPortObjectType,
  1239. KernelMode,
  1240. &IopLinkTrackingServiceObject,
  1241. NULL );
  1242. NtClose( serviceHandle );
  1243. } else {
  1244. NtClose( serviceHandle );
  1245. status = STATUS_INVALID_PARAMETER;
  1246. }
  1247. }
  1248. } else {
  1249. //
  1250. // The service has not been started so the port does not exist.
  1251. //
  1252. status = STATUS_OBJECT_NAME_NOT_FOUND;
  1253. }
  1254. }
  1255. //
  1256. // Return final status and wake the caller up.
  1257. //
  1258. ltp->FinalStatus = status;
  1259. KeSetEvent( &ltp->Event, 0, FALSE );
  1260. }
  1261. VOID
  1262. IopDisassociateThreadIrp(
  1263. VOID
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. This routine is invoked when the I/O requests for a thread are being
  1268. cancelled, but there is a packet at the end of the thread's queue that
  1269. has not been completed for such a long period of time that it has timed
  1270. out. It is this routine's responsibility to try to disassociate that
  1271. IRP with this thread.
  1272. Arguments:
  1273. None.
  1274. Return Value:
  1275. None.
  1276. --*/
  1277. {
  1278. KIRQL irql;
  1279. KIRQL spIrql;
  1280. PIRP irp;
  1281. PETHREAD thread;
  1282. PLIST_ENTRY entry;
  1283. PIO_STACK_LOCATION irpSp;
  1284. PDEVICE_OBJECT deviceObject;
  1285. NTSTATUS status;
  1286. PIO_ERROR_LOG_PACKET errorLogEntry;
  1287. //
  1288. // Begin by ensuring that the packet has not already been removed from
  1289. // the thread's queue.
  1290. //
  1291. KeRaiseIrql( APC_LEVEL, &irql );
  1292. thread = PsGetCurrentThread();
  1293. //
  1294. // If there are no packets on the IRP list, then simply return now.
  1295. // All of the packets have been fully completed, so the caller will also
  1296. // simply return to its caller.
  1297. //
  1298. if (IsListEmpty( &thread->IrpList )) {
  1299. KeLowerIrql( irql );
  1300. return;
  1301. }
  1302. //
  1303. // Get a pointer to the first packet on the queue, and begin examining
  1304. // it. Note that because the processor is at raised IRQL, and because
  1305. // the packet can only be removed in the context of the currently
  1306. // executing thread, that it is not possible for the packet to be removed
  1307. // from the list. On the other hand, it IS possible for the packet to
  1308. // be queued to the thread's APC list at this point, and this must be
  1309. // blocked/synchronized in order to examine the request.
  1310. //
  1311. // Begin, therefore, by acquiring the I/O completion spinlock, so that
  1312. // the packet can be safely examined.
  1313. //
  1314. spIrql = KeAcquireQueuedSpinLock( LockQueueIoCompletionLock );
  1315. //
  1316. // Check to see whether or not the packet has been completed (that is,
  1317. // queued to the current thread). If not, change threads.
  1318. //
  1319. entry = thread->IrpList.Flink;
  1320. irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
  1321. if (irp->CurrentLocation == irp->StackCount + 2) {
  1322. //
  1323. // The request has just gone through enough of completion that
  1324. // queueing it to the thread is inevitable. Simply release the
  1325. // lock and return.
  1326. //
  1327. KeReleaseQueuedSpinLock( LockQueueIoCompletionLock, spIrql );
  1328. KeLowerIrql( irql );
  1329. return;
  1330. }
  1331. //
  1332. // The packet has been located, and it is not going through completion
  1333. // at this point. Switch threads, so that it will not complete through
  1334. // this thread, remove the request from this thread's queue, and release
  1335. // the spinlock. Final processing of the IRP will occur when I/O
  1336. // completion notices that there is no thread associated with the
  1337. // request. It will essentially drop the I/O on the floor.
  1338. //
  1339. // Also, while the request is still held, attempt to determine on which
  1340. // device object the operation is being performed.
  1341. //
  1342. ////
  1343. ////DbgPrint( "Disassociating Irp: %x\n", irp );
  1344. ////DbgBreakPoint();
  1345. ////
  1346. IopDeadIrp = irp;
  1347. irp->Tail.Overlay.Thread = (PETHREAD) NULL;
  1348. entry = RemoveHeadList( &thread->IrpList );
  1349. // Initialize the thread entry. Otherwise the assertion in IoFreeIrp
  1350. // called via IopDeadIrp will fail.
  1351. InitializeListHead (&(irp)->ThreadListEntry);
  1352. irpSp = IoGetCurrentIrpStackLocation( irp );
  1353. if (irp->CurrentLocation <= irp->StackCount) {
  1354. deviceObject = irpSp->DeviceObject;
  1355. } else {
  1356. deviceObject = (PDEVICE_OBJECT) NULL;
  1357. }
  1358. KeReleaseQueuedSpinLock( LockQueueIoCompletionLock, spIrql );
  1359. KeLowerIrql( irql );
  1360. //
  1361. // If a device object could be identified then try to write to the event log about this
  1362. // device object.
  1363. //
  1364. if (deviceObject) {
  1365. errorLogEntry = IoAllocateErrorLogEntry(deviceObject, sizeof(IO_ERROR_LOG_PACKET));
  1366. if (errorLogEntry) {
  1367. errorLogEntry->ErrorCode = IO_DRIVER_CANCEL_TIMEOUT;
  1368. IoWriteErrorLogEntry(errorLogEntry);
  1369. }
  1370. }
  1371. return;
  1372. }
  1373. VOID
  1374. IopDeallocateApc(
  1375. IN PKAPC Apc,
  1376. IN PKNORMAL_ROUTINE *NormalRoutine,
  1377. IN PVOID *NormalContext,
  1378. IN PVOID *SystemArgument1,
  1379. IN PVOID *SystemArgument2
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. This routine is invoked to deallocate an APC that was used to queue a
  1384. request to a target thread. It simple deallocates the APC.
  1385. Arguments:
  1386. Apc - Supplies a pointer to kernel APC structure.
  1387. NormalRoutine - Supplies a pointer to a pointer to the normal function
  1388. that was specified when the APC was initialied.
  1389. NormalContext - Supplies a pointer to a pointer to an arbitrary data
  1390. structure that was specified when the APC was initialized.
  1391. SystemArgument1, SystemArgument2 - Supplies a set of two pointers to
  1392. two arguments that contain untyped data.
  1393. Return Value:
  1394. None.
  1395. --*/
  1396. {
  1397. UNREFERENCED_PARAMETER( NormalRoutine );
  1398. UNREFERENCED_PARAMETER( NormalContext );
  1399. UNREFERENCED_PARAMETER( SystemArgument1 );
  1400. UNREFERENCED_PARAMETER( SystemArgument2 );
  1401. PAGED_CODE();
  1402. //
  1403. // Free the APC.
  1404. //
  1405. ExFreePool( Apc );
  1406. }
  1407. VOID
  1408. IopDropIrp(
  1409. IN PIRP Irp,
  1410. IN PFILE_OBJECT FileObject
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. This routine attempts to drop everything about the specified IRP on the
  1415. floor.
  1416. Arguments:
  1417. Irp - Supplies the I/O Request Packet to be completed to the bit bucket.
  1418. FileObject - Supplies the file object for which the I/O Request Packet was
  1419. bound.
  1420. Return Value:
  1421. None.
  1422. --*/
  1423. {
  1424. PMDL mdl;
  1425. PMDL nextMdl;
  1426. //
  1427. // Free the resources associated with the IRP.
  1428. //
  1429. if (Irp->Flags & IRP_DEALLOCATE_BUFFER) {
  1430. ExFreePool( Irp->AssociatedIrp.SystemBuffer );
  1431. }
  1432. if (Irp->MdlAddress) {
  1433. for (mdl = Irp->MdlAddress; mdl; mdl = nextMdl) {
  1434. nextMdl = mdl->Next;
  1435. IoFreeMdl( mdl );
  1436. }
  1437. }
  1438. if (Irp->UserEvent &&
  1439. FileObject &&
  1440. !(Irp->Flags & IRP_SYNCHRONOUS_API)) {
  1441. ObDereferenceObject( Irp->UserEvent );
  1442. }
  1443. if (FileObject && !(Irp->Flags & IRP_CREATE_OPERATION)) {
  1444. ObDereferenceObject( FileObject );
  1445. }
  1446. //
  1447. // Finally, free the IRP itself.
  1448. //
  1449. IoFreeIrp( Irp );
  1450. }
  1451. LONG
  1452. IopExceptionFilter(
  1453. IN PEXCEPTION_POINTERS ExceptionPointer,
  1454. OUT PNTSTATUS ExceptionCode
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. This routine is invoked when an exception occurs to determine whether or
  1459. not the exception was due to an error that caused an in-page error status
  1460. code exception to be raised. If so, then this routine changes the code
  1461. in the exception record to the actual error code that was originally
  1462. raised.
  1463. Arguments:
  1464. ExceptionPointer - Pointer to the exception record.
  1465. ExceptionCode - Variable to receive actual exception code.
  1466. Return Value:
  1467. The function value indicates that the exception handler is to be executed.
  1468. --*/
  1469. {
  1470. //
  1471. // Simply check for an in-page error status code and, if the conditions
  1472. // are right, replace it with the actual status code.
  1473. //
  1474. *ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
  1475. if (*ExceptionCode == STATUS_IN_PAGE_ERROR &&
  1476. ExceptionPointer->ExceptionRecord->NumberParameters >= 3) {
  1477. *ExceptionCode = (LONG) ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
  1478. }
  1479. //
  1480. // Translate alignment warnings into alignment errors.
  1481. //
  1482. if (*ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) {
  1483. *ExceptionCode = STATUS_DATATYPE_MISALIGNMENT_ERROR;
  1484. }
  1485. return EXCEPTION_EXECUTE_HANDLER;
  1486. }
  1487. VOID
  1488. IopExceptionCleanup(
  1489. IN PFILE_OBJECT FileObject,
  1490. IN PIRP Irp,
  1491. IN PKEVENT EventObject OPTIONAL,
  1492. IN PKEVENT KernelEvent OPTIONAL
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. This routine performs generalized cleanup for the I/O system services when
  1497. an exception occurs during caller parameter processing. This routine
  1498. performs the following steps:
  1499. o If a system buffer was allocated it is freed.
  1500. o If an MDL was allocated it is freed.
  1501. o The IRP is freed.
  1502. o If the file object is opened for synchronous I/O, the semaphore
  1503. is released.
  1504. o If an event object was referenced it is dereferenced.
  1505. o If a kernel event was allocated, free it.
  1506. o The file object is dereferenced.
  1507. Arguments:
  1508. FileObject - Pointer to the file object currently being worked on.
  1509. Irp - Pointer to the IRP allocated to handle the I/O request.
  1510. EventObject - Optional pointer to a referenced event object.
  1511. KernelEvent - Optional pointer to an allocated kernel event.
  1512. Return Value:
  1513. None.
  1514. --*/
  1515. {
  1516. PAGED_CODE();
  1517. //
  1518. // If a system buffer was allocated from nonpaged pool, free it.
  1519. //
  1520. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  1521. ExFreePool( Irp->AssociatedIrp.SystemBuffer );
  1522. }
  1523. //
  1524. // If an MDL was allocated, free it.
  1525. //
  1526. if (Irp->MdlAddress != NULL) {
  1527. IoFreeMdl( Irp->MdlAddress );
  1528. }
  1529. //
  1530. // Free the I/O Request Packet.
  1531. //
  1532. IoFreeIrp( Irp );
  1533. //
  1534. // Finally, release the synchronization semaphore if it is currently
  1535. // held, dereference the event if one was specified, free the kernel
  1536. // event if one was allocated, and dereference the file object.
  1537. //
  1538. if (FileObject->Flags & FO_SYNCHRONOUS_IO) {
  1539. IopReleaseFileObjectLock( FileObject );
  1540. }
  1541. if (ARGUMENT_PRESENT( EventObject )) {
  1542. ObDereferenceObject( EventObject );
  1543. }
  1544. if (ARGUMENT_PRESENT( KernelEvent )) {
  1545. ExFreePool( KernelEvent );
  1546. }
  1547. ObDereferenceObject( FileObject );
  1548. return;
  1549. }
  1550. VOID
  1551. IopFreeIrpAndMdls(
  1552. IN PIRP Irp
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. This routine frees the specified I/O Request Packet and all of its Memory
  1557. Descriptor Lists.
  1558. Arguments:
  1559. Irp - Pointer to the I/O Request Packet to be freed.
  1560. Return Value:
  1561. None.
  1562. --*/
  1563. {
  1564. PMDL mdl;
  1565. PMDL nextMdl;
  1566. //
  1567. // If there are any MDLs that need to be freed, free them now.
  1568. //
  1569. for (mdl = Irp->MdlAddress; mdl != (PMDL) NULL; mdl = nextMdl) {
  1570. nextMdl = mdl->Next;
  1571. IoFreeMdl( mdl );
  1572. }
  1573. //
  1574. // Free the IRP.
  1575. //
  1576. IoFreeIrp( Irp );
  1577. return;
  1578. }
  1579. NTSTATUS
  1580. IopGetDriverNameFromKeyNode(
  1581. IN HANDLE KeyHandle,
  1582. OUT PUNICODE_STRING DriverName
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. Given a handle to a driver service list key in the registry, return the
  1587. name that represents the Object Manager name space string that should
  1588. be used to locate/create the driver object.
  1589. Arguments:
  1590. KeyHandle - Supplies a handle to driver service entry in the registry.
  1591. DriverName - Supplies a Unicode string descriptor variable in which the
  1592. name of the driver is returned.
  1593. Return Value:
  1594. The function value is the final status of the operation.
  1595. --*/
  1596. {
  1597. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1598. PKEY_BASIC_INFORMATION keyBasicInformation;
  1599. ULONG keyBasicLength;
  1600. NTSTATUS status;
  1601. PAGED_CODE();
  1602. //
  1603. // Get the optional object name for this driver from the value for this
  1604. // key. If one exists, then its name overrides the default name of the
  1605. // driver.
  1606. //
  1607. status = IopGetRegistryValue( KeyHandle,
  1608. L"ObjectName",
  1609. &keyValueInformation );
  1610. if (NT_SUCCESS( status )) {
  1611. PWSTR src, dst;
  1612. ULONG i;
  1613. //
  1614. // The driver entry specifies an object name. This overrides the
  1615. // default name for the driver. Use this name to open the driver
  1616. // object.
  1617. //
  1618. if (!keyValueInformation->DataLength) {
  1619. ExFreePool( keyValueInformation );
  1620. return STATUS_ILL_FORMED_SERVICE_ENTRY;
  1621. }
  1622. DriverName->Length = (USHORT) (keyValueInformation->DataLength - sizeof( WCHAR ));
  1623. DriverName->MaximumLength = (USHORT) keyValueInformation->DataLength;
  1624. src = (PWSTR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  1625. dst = (PWSTR) keyValueInformation;
  1626. for (i = DriverName->Length; i; i--) {
  1627. *dst++ = *src++;
  1628. }
  1629. DriverName->Buffer = (PWSTR) keyValueInformation;
  1630. } else {
  1631. PULONG driverType;
  1632. PWSTR baseObjectName;
  1633. UNICODE_STRING remainderName;
  1634. //
  1635. // The driver node does not specify an object name, so determine
  1636. // what the default name for the driver object should be based on
  1637. // the information in the key.
  1638. //
  1639. status = IopGetRegistryValue( KeyHandle,
  1640. L"Type",
  1641. &keyValueInformation );
  1642. if (!NT_SUCCESS( status ) || !keyValueInformation->DataLength) {
  1643. //
  1644. // There must be some type of "Type" associated with this driver,
  1645. // either DRIVER or FILE_SYSTEM. Otherwise, this node is ill-
  1646. // formed.
  1647. //
  1648. if (NT_SUCCESS( status )) {
  1649. ExFreePool( keyValueInformation );
  1650. }
  1651. return STATUS_ILL_FORMED_SERVICE_ENTRY;
  1652. }
  1653. //
  1654. // Now determine whether the type of this entry is a driver or a
  1655. // file system. Begin by assuming that it is a device driver.
  1656. //
  1657. baseObjectName = L"\\Driver\\";
  1658. DriverName->Length = 8*2;
  1659. driverType = (PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  1660. if (*driverType == FileSystemType ||
  1661. *driverType == RecognizerType) {
  1662. baseObjectName = L"\\FileSystem\\";
  1663. DriverName->Length = 12*2;
  1664. }
  1665. //
  1666. // Get the name of the key that is being used to describe this
  1667. // driver. This will return just the last component of the name
  1668. // string, which can be used to formulate the name of the driver.
  1669. //
  1670. status = ZwQueryKey( KeyHandle,
  1671. KeyBasicInformation,
  1672. (PVOID) NULL,
  1673. 0,
  1674. &keyBasicLength );
  1675. keyBasicInformation = ExAllocatePool( NonPagedPool, keyBasicLength );
  1676. if (!keyBasicInformation) {
  1677. ExFreePool( keyValueInformation );
  1678. return STATUS_INSUFFICIENT_RESOURCES;
  1679. }
  1680. status = ZwQueryKey( KeyHandle,
  1681. KeyBasicInformation,
  1682. keyBasicInformation,
  1683. keyBasicLength,
  1684. &keyBasicLength );
  1685. if (!NT_SUCCESS( status )) {
  1686. ExFreePool( keyBasicInformation );
  1687. ExFreePool( keyValueInformation );
  1688. return status;
  1689. }
  1690. //
  1691. // Allocate a buffer from pool that is large enough to contain the
  1692. // entire name string of the driver object.
  1693. //
  1694. DriverName->MaximumLength = (USHORT) (DriverName->Length + keyBasicInformation->NameLength);
  1695. DriverName->Buffer = ExAllocatePool( NonPagedPool,
  1696. DriverName->MaximumLength );
  1697. if (!DriverName->Buffer) {
  1698. ExFreePool( keyBasicInformation );
  1699. ExFreePool( keyValueInformation );
  1700. return STATUS_INSUFFICIENT_RESOURCES;
  1701. }
  1702. //
  1703. // Now form the name of the object to be opened.
  1704. //
  1705. DriverName->Length = 0;
  1706. RtlAppendUnicodeToString( DriverName, baseObjectName );
  1707. remainderName.Length = (USHORT) keyBasicInformation->NameLength;
  1708. remainderName.MaximumLength = remainderName.Length;
  1709. remainderName.Buffer = &keyBasicInformation->Name[0];
  1710. RtlAppendUnicodeStringToString( DriverName, &remainderName );
  1711. ExFreePool( keyBasicInformation );
  1712. ExFreePool( keyValueInformation );
  1713. }
  1714. //
  1715. // Finally, simply return to the caller with the name filled in. Note
  1716. // that the caller must free the buffer pointed to by the Buffer field
  1717. // of the Unicode string descriptor.
  1718. //
  1719. return STATUS_SUCCESS;
  1720. }
  1721. NTSTATUS
  1722. IopGetFileInformation(
  1723. IN PFILE_OBJECT FileObject,
  1724. IN ULONG Length,
  1725. IN FILE_INFORMATION_CLASS FileInformationClass,
  1726. OUT PVOID FileInformation,
  1727. OUT PULONG ReturnedLength
  1728. )
  1729. /*++
  1730. Routine Description:
  1731. This routine is invoked to asynchronously obtain the name or other information
  1732. of a file object when the file was opened for synchronous I/O, and the previous mode of the
  1733. caller was kernel mode, and the query was done through the Object Manager.
  1734. In this case, the situation is likely that the Lazy Writer has incurred a
  1735. write error, and it is attempting to obtain the name of the file so that it
  1736. can output a popup. In doing so, a deadlock can occur because another
  1737. thread has locked the file object synchronous I/O lock. Hence, this routine
  1738. obtains the name of the file w/o acquiring that lock.
  1739. Arguments:
  1740. FileObject - A pointer to the file object whose name is to be queried.
  1741. Length - Supplies the length of the buffer to receive the name.
  1742. FileInformation - A pointer to the buffer to receive the name.
  1743. ReturnedLength - A variable to receive the length of the name returned.
  1744. Return Value:
  1745. The status returned is the final completion status of the operation.
  1746. --*/
  1747. {
  1748. PIRP irp;
  1749. NTSTATUS status;
  1750. PDEVICE_OBJECT deviceObject;
  1751. KEVENT event;
  1752. PIO_STACK_LOCATION irpSp;
  1753. IO_STATUS_BLOCK localIoStatus;
  1754. PAGED_CODE();
  1755. //
  1756. // Reference the file object here so that no special checks need be made
  1757. // in I/O completion to determine whether or not to dereference the file
  1758. // object.
  1759. //
  1760. ObReferenceObject( FileObject );
  1761. //
  1762. // Initialize an event that will be used to synchronize the completion of
  1763. // the query operation. Note that this is the only way to synchronize this
  1764. // since the file object itself cannot be used since it was opened for
  1765. // synchronous I/O and may be busy.
  1766. //
  1767. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  1768. //
  1769. // Get the address of the target device object.
  1770. //
  1771. deviceObject = IoGetRelatedDeviceObject( FileObject );
  1772. //
  1773. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  1774. //
  1775. irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
  1776. if (!irp) {
  1777. //
  1778. // An IRP could not be allocated. Cleanup and return an appropriate
  1779. // error status code.
  1780. //
  1781. ObDereferenceObject( FileObject );
  1782. return STATUS_INSUFFICIENT_RESOURCES;
  1783. }
  1784. irp->Tail.Overlay.OriginalFileObject = FileObject;
  1785. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1786. irp->RequestorMode = KernelMode;
  1787. //
  1788. // Fill in the service independent parameters in the IRP. Note that the
  1789. // setting of the special query name flag in the packet guarantees that the
  1790. // standard completion for a synchronous file object will not occur because
  1791. // this flag communicates to the I/O completion that it should not do so.
  1792. //
  1793. irp->UserEvent = &event;
  1794. irp->Flags = IRP_SYNCHRONOUS_API | IRP_OB_QUERY_NAME;
  1795. irp->UserIosb = &localIoStatus;
  1796. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  1797. //
  1798. // Get a pointer to the stack location for the first driver. This will be
  1799. // used to pass the original function codes and parameters.
  1800. //
  1801. irpSp = IoGetNextIrpStackLocation( irp );
  1802. irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
  1803. irpSp->FileObject = FileObject;
  1804. //
  1805. // Set the system buffer address to the address of the caller's buffer and
  1806. // set the flags so that the buffer is not deallocated.
  1807. //
  1808. irp->AssociatedIrp.SystemBuffer = FileInformation;
  1809. irp->Flags |= IRP_BUFFERED_IO;
  1810. //
  1811. // Copy the caller's parameters to the service-specific portion of the
  1812. // IRP.
  1813. //
  1814. irpSp->Parameters.QueryFile.Length = Length;
  1815. irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
  1816. //
  1817. // Insert the packet at the head of the IRP list for the thread.
  1818. //
  1819. IopQueueThreadIrp( irp );
  1820. //
  1821. // Now simply invoke the driver at its dispatch entry with the IRP.
  1822. //
  1823. status = IoCallDriver( deviceObject, irp );
  1824. //
  1825. // Now get the final status of the operation once the request completes
  1826. // and return the length of the buffer written.
  1827. //
  1828. if (status == STATUS_PENDING) {
  1829. (VOID) KeWaitForSingleObject( &event,
  1830. Executive,
  1831. KernelMode,
  1832. FALSE,
  1833. (PLARGE_INTEGER) NULL );
  1834. status = localIoStatus.Status;
  1835. }
  1836. *ReturnedLength = (ULONG) localIoStatus.Information;
  1837. return status;
  1838. }
  1839. BOOLEAN
  1840. IopGetMountFlag(
  1841. IN PDEVICE_OBJECT DeviceObject
  1842. )
  1843. /*++
  1844. Routine Description:
  1845. This routine is invoked to determine whether or not the specified device
  1846. is mounted.
  1847. Arguments:
  1848. DeviceObject - Supplies a pointer to the device object for which the mount
  1849. flag is tested.
  1850. Return Value:
  1851. The function value is TRUE if the specified device is mounted, otherwise
  1852. FALSE.
  1853. --*/
  1854. {
  1855. KIRQL irql;
  1856. BOOLEAN deviceMounted = FALSE;
  1857. //
  1858. // Check to see whether or not the device is mounted. Note that the caller
  1859. // has probably already looked to see whether or not the device has a VPB
  1860. // outside of owning the lock, so simply get the lock and check it again
  1861. // to start with, rather than checking to see whether or not the device
  1862. // still has a VPB without holding the lock.
  1863. //
  1864. irql = KeAcquireQueuedSpinLock( LockQueueIoVpbLock );
  1865. if (DeviceObject->Vpb) {
  1866. if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
  1867. deviceMounted = TRUE;
  1868. }
  1869. }
  1870. KeReleaseQueuedSpinLock( LockQueueIoVpbLock, irql );
  1871. return deviceMounted;
  1872. }
  1873. NTSTATUS
  1874. IopGetRegistryKeyInformation(
  1875. IN HANDLE KeyHandle,
  1876. OUT PKEY_FULL_INFORMATION *Information
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. This routine is invoked to retrieve the full key information for a
  1881. registry key. This is done by querying the full key information
  1882. of the key with a zero-length buffer to determine the size of the data,
  1883. and then allocating a buffer and actually querying the data into the buffer.
  1884. It is the responsibility of the caller to free the buffer.
  1885. Arguments:
  1886. KeyHandle - Supplies the key handle whose full key information is to
  1887. be queried
  1888. Information - Returns a pointer to the allocated data buffer.
  1889. Return Value:
  1890. The function value is the final status of the query operation.
  1891. --*/
  1892. {
  1893. NTSTATUS status;
  1894. PKEY_FULL_INFORMATION infoBuffer;
  1895. ULONG keyInfoLength;
  1896. PAGED_CODE();
  1897. //
  1898. // Figure out how big the data value is so that a buffer of the
  1899. // appropriate size can be allocated.
  1900. //
  1901. status = ZwQueryKey( KeyHandle,
  1902. KeyFullInformation,
  1903. (PVOID) NULL,
  1904. 0,
  1905. &keyInfoLength );
  1906. if (status != STATUS_BUFFER_OVERFLOW &&
  1907. status != STATUS_BUFFER_TOO_SMALL) {
  1908. return status;
  1909. }
  1910. //
  1911. // Allocate a buffer large enough to contain the entire key data.
  1912. //
  1913. infoBuffer = ExAllocatePool( NonPagedPool, keyInfoLength );
  1914. if (!infoBuffer) {
  1915. return STATUS_INSUFFICIENT_RESOURCES;
  1916. }
  1917. //
  1918. // Query the full key data for the key.
  1919. //
  1920. status = ZwQueryKey( KeyHandle,
  1921. KeyFullInformation,
  1922. infoBuffer,
  1923. keyInfoLength,
  1924. &keyInfoLength );
  1925. if (!NT_SUCCESS( status )) {
  1926. ExFreePool( infoBuffer );
  1927. return status;
  1928. }
  1929. //
  1930. // Everything worked, so simply return the address of the allocated
  1931. // buffer to the caller, who is now responsible for freeing it.
  1932. //
  1933. *Information = infoBuffer;
  1934. return STATUS_SUCCESS;
  1935. }
  1936. NTSTATUS
  1937. IopGetRegistryValue(
  1938. IN HANDLE KeyHandle,
  1939. IN PWSTR ValueName,
  1940. OUT PKEY_VALUE_FULL_INFORMATION *Information
  1941. )
  1942. /*++
  1943. Routine Description:
  1944. This routine is invoked to retrieve the data for a registry key's value.
  1945. This is done by querying the value of the key with a zero-length buffer
  1946. to determine the size of the value, and then allocating a buffer and
  1947. actually querying the value into the buffer.
  1948. It is the responsibility of the caller to free the buffer.
  1949. Arguments:
  1950. KeyHandle - Supplies the key handle whose value is to be queried
  1951. ValueName - Supplies the null-terminated Unicode name of the value.
  1952. Information - Returns a pointer to the allocated data buffer.
  1953. Return Value:
  1954. The function value is the final status of the query operation.
  1955. --*/
  1956. {
  1957. UNICODE_STRING unicodeString;
  1958. NTSTATUS status;
  1959. PKEY_VALUE_FULL_INFORMATION infoBuffer;
  1960. ULONG keyValueLength, guessSize, dataSize;
  1961. PAGED_CODE();
  1962. RtlInitUnicodeString( &unicodeString, ValueName );
  1963. //
  1964. // Set an initial size to try when loading a key. Note that
  1965. // KeyValueFullInformation already comes with a single WCHAR of data.
  1966. //
  1967. guessSize = sizeof(KEY_VALUE_FULL_INFORMATION) +
  1968. wcslen(ValueName)*sizeof(WCHAR);
  1969. //
  1970. // Now round up to a natural alignment. This needs to be done because our
  1971. // data member will naturally aligned as well.
  1972. //
  1973. guessSize = (ULONG) ALIGN_POINTER_OFFSET(guessSize);
  1974. //
  1975. // Set the data cache length to a ULONG's worth of data, because most data
  1976. // we read via this function is type REG_DWORD.
  1977. //
  1978. guessSize += sizeof(ULONG);
  1979. infoBuffer = ExAllocatePool(NonPagedPool, guessSize);
  1980. if (!infoBuffer) {
  1981. return STATUS_INSUFFICIENT_RESOURCES;
  1982. }
  1983. //
  1984. // Figure out how big the data value is so that a buffer of the
  1985. // appropriate size can be allocated.
  1986. //
  1987. status = ZwQueryValueKey( KeyHandle,
  1988. &unicodeString,
  1989. KeyValueFullInformation,
  1990. (PVOID) infoBuffer,
  1991. guessSize,
  1992. &keyValueLength );
  1993. if (NT_SUCCESS(status)) {
  1994. //
  1995. // First guess worked, bail!
  1996. //
  1997. *Information = infoBuffer;
  1998. return STATUS_SUCCESS;
  1999. }
  2000. ExFreePool(infoBuffer);
  2001. if (status != STATUS_BUFFER_OVERFLOW &&
  2002. status != STATUS_BUFFER_TOO_SMALL) {
  2003. ASSERT(!NT_SUCCESS(status));
  2004. return status;
  2005. }
  2006. //
  2007. // Allocate a buffer large enough to contain the entire key data value.
  2008. //
  2009. infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength );
  2010. if (!infoBuffer) {
  2011. return STATUS_INSUFFICIENT_RESOURCES;
  2012. }
  2013. //
  2014. // Query the data for the key value.
  2015. //
  2016. status = ZwQueryValueKey( KeyHandle,
  2017. &unicodeString,
  2018. KeyValueFullInformation,
  2019. infoBuffer,
  2020. keyValueLength,
  2021. &keyValueLength );
  2022. if (!NT_SUCCESS( status )) {
  2023. ExFreePool( infoBuffer );
  2024. return status;
  2025. }
  2026. //
  2027. // Everything worked, so simply return the address of the allocated
  2028. // buffer to the caller, who is now responsible for freeing it.
  2029. //
  2030. *Information = infoBuffer;
  2031. return STATUS_SUCCESS;
  2032. }
  2033. NTSTATUS
  2034. IopGetRegistryValues(
  2035. IN HANDLE KeyHandle,
  2036. IN PKEY_VALUE_FULL_INFORMATION *ValueList
  2037. )
  2038. /*++
  2039. Routine Description:
  2040. This routine is invoked to retrieve the *three* types of data for a
  2041. registry key's. This is done by calling the IopGetRegistryValue function
  2042. with the three valid key names.
  2043. It is the responsibility of the caller to free the three buffers.
  2044. Arguments:
  2045. KeyHandle - Supplies the key handle whose value is to be queried
  2046. ValueList - Pointer to a buffer in which the three pointers to the value
  2047. entries will be stored.
  2048. Return Value:
  2049. The function value is the final status of the query operation.
  2050. Note:
  2051. The values are stored in the order represented by the I/O query device
  2052. data format.
  2053. --*/
  2054. {
  2055. NTSTATUS status;
  2056. PAGED_CODE();
  2057. //
  2058. // Zero out all entries initially.
  2059. //
  2060. *ValueList = NULL;
  2061. *(ValueList + 1) = NULL;
  2062. *(ValueList + 2) = NULL;
  2063. //
  2064. // Get the information for each of the three types of entries available.
  2065. // Each time, check if an internal error occurred; If the object name was
  2066. // not found, it only means not data was present, and this does not
  2067. // constitute an error.
  2068. //
  2069. status = IopGetRegistryValue( KeyHandle,
  2070. L"Identifier",
  2071. ValueList );
  2072. if (!NT_SUCCESS( status ) && (status != STATUS_OBJECT_NAME_NOT_FOUND)) {
  2073. return status;
  2074. }
  2075. status = IopGetRegistryValue( KeyHandle,
  2076. L"Configuration Data",
  2077. ++ValueList );
  2078. if (!NT_SUCCESS( status ) && (status != STATUS_OBJECT_NAME_NOT_FOUND)) {
  2079. return status;
  2080. }
  2081. status = IopGetRegistryValue( KeyHandle,
  2082. L"Component Information",
  2083. ++ValueList );
  2084. if (!NT_SUCCESS( status ) && (status != STATUS_OBJECT_NAME_NOT_FOUND)) {
  2085. return status;
  2086. }
  2087. return STATUS_SUCCESS;
  2088. }
  2089. NTSTATUS
  2090. IopGetSetObjectId(
  2091. IN PFILE_OBJECT FileObject,
  2092. IN OUT PVOID Buffer,
  2093. IN ULONG Length,
  2094. IN ULONG Function
  2095. )
  2096. /*++
  2097. Routine Description:
  2098. This routine is invoked to obtain or set the object ID for a file. If
  2099. one does not exist for the file, then one is created, provided that the
  2100. underlying file system supports object IDs in the first place (query).
  2101. Arguments:
  2102. FileObject - Supplies a pointer to the referenced file object whose ID is
  2103. to be returned or set.
  2104. Buffer - A variable to receive the object ID of the file (query) or that
  2105. contains the object ID that is to be set on the file.
  2106. Length - The length of the Buffer.
  2107. Function - The FSCTL to send.
  2108. FSCTL_LMR_GET_LINK_TRACKING_INFORMATION;
  2109. FSCTL_CREATE_OR_GET_OBJECT_ID;
  2110. FSCTL_GET_OBJECT_ID;
  2111. FSCTL_SET_OBJECT_ID_EXTENDED;
  2112. FSCTL_LMR_SET_LINK_TRACKING_INFORMATION;
  2113. FSCTL_SET_OBJECT_ID_EXTENDED;
  2114. FSCTL_SET_OBJECT_ID;
  2115. FSCTL_DELETE_OBJECT_ID;
  2116. Return Value:
  2117. The status returned is the final completion status of the operation.
  2118. --*/
  2119. {
  2120. IO_STATUS_BLOCK ioStatus;
  2121. NTSTATUS status;
  2122. PIRP irp;
  2123. KEVENT event;
  2124. PIO_STACK_LOCATION irpSp;
  2125. PDEVICE_OBJECT deviceObject;
  2126. PAGED_CODE();
  2127. //
  2128. // Initialize the event structure to synchronize completion of the I/O
  2129. // request.
  2130. //
  2131. KeInitializeEvent( &event,
  2132. NotificationEvent,
  2133. FALSE );
  2134. //
  2135. // Build an I/O Request Packet to be sent to the file system driver to get
  2136. // the object ID.
  2137. //
  2138. deviceObject = IoGetRelatedDeviceObject( FileObject );
  2139. irp = IoBuildDeviceIoControlRequest( Function,
  2140. deviceObject,
  2141. NULL,
  2142. 0,
  2143. NULL,
  2144. 0,
  2145. FALSE,
  2146. &event,
  2147. &ioStatus );
  2148. if (!irp) {
  2149. return STATUS_INSUFFICIENT_RESOURCES;
  2150. }
  2151. //
  2152. // Fill in the remainder of the IRP to retrieve the object ID for the
  2153. // file.
  2154. //
  2155. irp->Flags |= IRP_SYNCHRONOUS_API;
  2156. irp->UserBuffer = Buffer;
  2157. irp->AssociatedIrp.SystemBuffer = Buffer;
  2158. irp->Tail.Overlay.OriginalFileObject = FileObject;
  2159. irpSp = IoGetNextIrpStackLocation( irp );
  2160. irpSp->FileObject = FileObject;
  2161. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  2162. irpSp->MinorFunction = IRP_MN_KERNEL_CALL;
  2163. if (Function == FSCTL_LMR_GET_LINK_TRACKING_INFORMATION ||
  2164. Function == FSCTL_CREATE_OR_GET_OBJECT_ID ||
  2165. Function == FSCTL_GET_OBJECT_ID ) {
  2166. irpSp->Parameters.FileSystemControl.OutputBufferLength = Length;
  2167. } else {
  2168. irpSp->Parameters.FileSystemControl.InputBufferLength = Length;
  2169. }
  2170. //
  2171. // Take out another reference to the file object to guarantee that it does
  2172. // not get deleted.
  2173. //
  2174. ObReferenceObject( FileObject );
  2175. //
  2176. // Call the driver to get the request.
  2177. //
  2178. status = IoCallDriver( deviceObject, irp );
  2179. //
  2180. // Synchronize completion of the request.
  2181. //
  2182. if (status == STATUS_PENDING) {
  2183. status = KeWaitForSingleObject( &event,
  2184. Executive,
  2185. KernelMode,
  2186. FALSE,
  2187. (PLARGE_INTEGER) NULL );
  2188. status = ioStatus.Status;
  2189. }
  2190. return status;
  2191. }
  2192. NTSTATUS
  2193. IopGetVolumeId(
  2194. IN PFILE_OBJECT FileObject,
  2195. IN OUT PFILE_VOLUMEID_WITH_TYPE ObjectId,
  2196. IN ULONG Length
  2197. )
  2198. /*++
  2199. Routine Description:
  2200. This routine is invoked by the I/O System link tracking code to obtain the
  2201. volume ID for a file that has been moved or is being moved between volumes
  2202. and potentially between systems.
  2203. Arguments:
  2204. FileObject - Supplies the file object for the file.
  2205. ObjectId - A buffer to receive the volume object ID.
  2206. Length - Length of the buffer.
  2207. Return Value:
  2208. The final function value is the final completion status of the operation.
  2209. --*/
  2210. {
  2211. IO_STATUS_BLOCK ioStatus;
  2212. NTSTATUS status;
  2213. PIRP irp;
  2214. KEVENT event;
  2215. PIO_STACK_LOCATION irpSp;
  2216. PDEVICE_OBJECT deviceObject;
  2217. FILE_FS_OBJECTID_INFORMATION volumeId;
  2218. PAGED_CODE();
  2219. //
  2220. // Initialize the event structure to synchronize completion of the I/O
  2221. // request.
  2222. //
  2223. KeInitializeEvent( &event,
  2224. NotificationEvent,
  2225. FALSE );
  2226. //
  2227. // Build an I/O Request Packet to be sent to the file system driver to get
  2228. // the volume ID.
  2229. //
  2230. deviceObject = IoGetRelatedDeviceObject( FileObject );
  2231. irp = IoBuildDeviceIoControlRequest( 0,
  2232. deviceObject,
  2233. NULL,
  2234. 0,
  2235. NULL,
  2236. 0,
  2237. FALSE,
  2238. &event,
  2239. &ioStatus );
  2240. if (!irp) {
  2241. return STATUS_INSUFFICIENT_RESOURCES;
  2242. }
  2243. //
  2244. // Fill in the remainder of the IRP to retrieve the volume ID for the
  2245. // file.
  2246. //
  2247. irp->Flags |= IRP_SYNCHRONOUS_API;
  2248. irp->UserBuffer = &volumeId;
  2249. irp->AssociatedIrp.SystemBuffer = &volumeId;
  2250. irp->Tail.Overlay.OriginalFileObject = FileObject;
  2251. irpSp = IoGetNextIrpStackLocation( irp );
  2252. irpSp->FileObject = FileObject;
  2253. irpSp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
  2254. irpSp->Parameters.QueryVolume.Length = sizeof( volumeId );
  2255. irpSp->Parameters.QueryVolume.FsInformationClass = FileFsObjectIdInformation;
  2256. //
  2257. // Take out another reference to the file object to guarantee that it does
  2258. // not get deleted.
  2259. //
  2260. ObReferenceObject( FileObject );
  2261. //
  2262. // Call the driver to get the request.
  2263. //
  2264. status = IoCallDriver( deviceObject, irp );
  2265. //
  2266. // Synchronize completion of the request.
  2267. //
  2268. if (status == STATUS_PENDING) {
  2269. status = KeWaitForSingleObject( &event,
  2270. Executive,
  2271. KernelMode,
  2272. FALSE,
  2273. (PLARGE_INTEGER) NULL );
  2274. status = ioStatus.Status;
  2275. }
  2276. //
  2277. // If the file system returned the volume ID, copy it to the caller's
  2278. // buffer and set the file system tracking type.
  2279. //
  2280. if (NT_SUCCESS( status )) {
  2281. ObjectId->Type = NtfsLinkTrackingInformation;
  2282. RtlCopyMemory( ObjectId->VolumeId,
  2283. &volumeId.ObjectId,
  2284. sizeof( GUID ) );
  2285. }
  2286. return status;
  2287. }
  2288. PIOP_HARD_ERROR_PACKET
  2289. IopRemoveHardErrorPacket(
  2290. VOID
  2291. )
  2292. {
  2293. PIOP_HARD_ERROR_PACKET hardErrorPacket;
  2294. KIRQL oldIrql;
  2295. PVOID entry;
  2296. ExAcquireFastLock( &IopHardError.WorkQueueSpinLock, &oldIrql );
  2297. //
  2298. // The work queue structures are now exclusively owned, so remove the
  2299. // first packet from the head of the list.
  2300. //
  2301. entry = RemoveHeadList( &IopHardError.WorkQueue );
  2302. hardErrorPacket = CONTAINING_RECORD( entry,
  2303. IOP_HARD_ERROR_PACKET,
  2304. WorkQueueLinks );
  2305. IopCurrentHardError = hardErrorPacket;
  2306. ExReleaseFastLock( &IopHardError.WorkQueueSpinLock, oldIrql );
  2307. return hardErrorPacket;
  2308. }
  2309. BOOLEAN
  2310. IopCheckHardErrorEmpty(
  2311. VOID
  2312. )
  2313. {
  2314. BOOLEAN MoreEntries;
  2315. KIRQL oldIrql;
  2316. MoreEntries = TRUE;
  2317. ExAcquireFastLock( &IopHardError.WorkQueueSpinLock, &oldIrql );
  2318. IopCurrentHardError = NULL;
  2319. if ( IsListEmpty( &IopHardError.WorkQueue ) ) {
  2320. IopHardError.ThreadStarted = FALSE;
  2321. MoreEntries = FALSE;
  2322. }
  2323. ExReleaseFastLock( &IopHardError.WorkQueueSpinLock, oldIrql );
  2324. return MoreEntries;
  2325. }
  2326. VOID
  2327. IopHardErrorThread(
  2328. IN PVOID StartContext
  2329. )
  2330. /*++
  2331. Routine Description:
  2332. This function waits for work on the IopHardErrorQueue, and all calls
  2333. IopRaiseInformationalHardError to actually perform the pop-ups.
  2334. Arguments:
  2335. StartContext - Startup context; not used.
  2336. Return Value:
  2337. None.
  2338. --*/
  2339. {
  2340. ULONG parameterPresent;
  2341. ULONG_PTR errorParameter;
  2342. ULONG errorResponse;
  2343. BOOLEAN MoreEntries;
  2344. PIOP_HARD_ERROR_PACKET hardErrorPacket;
  2345. UNREFERENCED_PARAMETER( StartContext );
  2346. PAGED_CODE();
  2347. //
  2348. // Loop, waiting forever for a hard error packet to be sent to this thread.
  2349. // When one is placed onto the queue, wake up, process it, and continue
  2350. // the loop.
  2351. //
  2352. MoreEntries = TRUE;
  2353. do {
  2354. (VOID) KeWaitForSingleObject( &IopHardError.WorkQueueSemaphore,
  2355. Executive,
  2356. KernelMode,
  2357. FALSE,
  2358. (PLARGE_INTEGER) NULL );
  2359. hardErrorPacket = IopRemoveHardErrorPacket();
  2360. //
  2361. // Simply raise the hard error if the system is ready to accept one.
  2362. //
  2363. errorParameter = (ULONG_PTR) &hardErrorPacket->String;
  2364. parameterPresent = (hardErrorPacket->String.Buffer != NULL);
  2365. if (ExReadyForErrors) {
  2366. (VOID) ExRaiseHardError( hardErrorPacket->ErrorStatus,
  2367. parameterPresent,
  2368. parameterPresent,
  2369. parameterPresent ? &errorParameter : NULL,
  2370. OptionOkNoWait,
  2371. &errorResponse );
  2372. }
  2373. //
  2374. // If this was the last entry, exit the thread and mark it as so.
  2375. //
  2376. MoreEntries = IopCheckHardErrorEmpty();
  2377. //
  2378. // Now free the packet and the buffer, if one was specified.
  2379. //
  2380. if (hardErrorPacket->String.Buffer) {
  2381. ExFreePool( hardErrorPacket->String.Buffer );
  2382. }
  2383. ExFreePool( hardErrorPacket );
  2384. } while ( MoreEntries );
  2385. }
  2386. NTSTATUS
  2387. IopInvalidDeviceRequest(
  2388. IN PDEVICE_OBJECT DeviceObject,
  2389. IN PIRP Irp
  2390. )
  2391. /*++
  2392. Routine Description:
  2393. This function is the default dispatch routine for all driver entries
  2394. not implemented by drivers that have been loaded into the system. Its
  2395. responsibility is simply to set the status in the packet to indicate
  2396. that the operation requested is invalid for this device type, and then
  2397. complete the packet.
  2398. Arguments:
  2399. DeviceObject - Specifies the device object for which this request is
  2400. bound. Ignored by this routine.
  2401. Irp - Specifies the address of the I/O Request Packet (IRP) for this
  2402. request.
  2403. Return Value:
  2404. The final status is always STATUS_INVALID_DEVICE_REQUEST.
  2405. --*/
  2406. {
  2407. UNREFERENCED_PARAMETER( DeviceObject );
  2408. //
  2409. // Simply store the appropriate status, complete the request, and return
  2410. // the same status stored in the packet.
  2411. //
  2412. if ((IoGetCurrentIrpStackLocation(Irp))->MajorFunction == IRP_MJ_POWER) {
  2413. PoStartNextPowerIrp(Irp);
  2414. }
  2415. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  2416. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2417. return STATUS_INVALID_DEVICE_REQUEST;
  2418. }
  2419. BOOLEAN
  2420. IopIsSameMachine(
  2421. IN PFILE_OBJECT SourceFile,
  2422. IN HANDLE TargetFile
  2423. )
  2424. /*++
  2425. Routine Description:
  2426. This routine is invoked to determine whether two file objects that represent
  2427. files on remote machines actually reside on the same physical system.
  2428. Arguments:
  2429. SourceFile - Supplies the file object for the first file.
  2430. TargetFile - Supplies the file object for the second file.
  2431. Return Value:
  2432. The final function value is TRUE if the files reside on the same machine,
  2433. otherwise FALSE is returned.
  2434. --*/
  2435. {
  2436. PDEVICE_OBJECT deviceObject;
  2437. PFAST_IO_DISPATCH fastIoDispatch;
  2438. NTSTATUS status = STATUS_NOT_SAME_DEVICE;
  2439. IO_STATUS_BLOCK ioStatus;
  2440. HANDLE target = TargetFile;
  2441. PAGED_CODE();
  2442. //
  2443. // Simply invoke the device I/O control function to determine whether or
  2444. // not the two files are on the same server. If the fast I/O path does
  2445. // not exist, or the function fails for any reason, then the two files are
  2446. // assumed to not be on the same machine. Note that this simply means
  2447. // that there will be a performance penalty on open of the target, but
  2448. // the above will only fail if the two files really aren't on the same
  2449. // machine in the first place, or if there's a filter that doesn't under-
  2450. // stand what is being done here.
  2451. //
  2452. deviceObject = IoGetRelatedDeviceObject( SourceFile );
  2453. fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  2454. if (fastIoDispatch && fastIoDispatch->FastIoDeviceControl) {
  2455. if (fastIoDispatch->FastIoDeviceControl( SourceFile,
  2456. TRUE,
  2457. (PVOID) &target,
  2458. sizeof( target ),
  2459. (PVOID) NULL,
  2460. 0,
  2461. IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER,
  2462. &ioStatus,
  2463. deviceObject )) {
  2464. status = ioStatus.Status;
  2465. }
  2466. }
  2467. return status == STATUS_SUCCESS;
  2468. }
  2469. NTSTATUS
  2470. IopBuildFullDriverPath(
  2471. IN PUNICODE_STRING KeyName,
  2472. IN HANDLE KeyHandle,
  2473. OUT PUNICODE_STRING FullPath
  2474. )
  2475. /*++
  2476. Routine Description:
  2477. This routine builds up the full path for the driver. If ImagePath is
  2478. specified, use it or else prepend the standard drivers path.
  2479. Arguments:
  2480. KeyHandle - Supplies a handle to the driver service node in the registry
  2481. that describes the driver to be loaded.
  2482. CheckForSafeBoot - If TRUE, the driver will be loaded only if it belongs
  2483. to the list of safe mode OK binaries.
  2484. FullPath - Full driver path is returned in this.
  2485. Return Value:
  2486. STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
  2487. --*/
  2488. {
  2489. NTSTATUS status;
  2490. PWCHAR path, name, ext;
  2491. ULONG pathLength, nameLength, extLength;
  2492. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2493. FullPath->Length = FullPath->MaximumLength = 0;
  2494. FullPath->Buffer = NULL;
  2495. extLength = nameLength = pathLength = 0;
  2496. keyValueInformation = NULL;
  2497. status = IopGetRegistryValue( KeyHandle,
  2498. L"ImagePath",
  2499. &keyValueInformation);
  2500. if (NT_SUCCESS(status) && keyValueInformation->DataLength) {
  2501. nameLength = keyValueInformation->DataLength - sizeof(WCHAR);
  2502. name = (PWCHAR)KEY_VALUE_DATA(keyValueInformation);
  2503. if (name[0] != L'\\') {
  2504. path = L"\\SystemRoot\\";
  2505. pathLength = sizeof(L"\\SystemRoot\\") - sizeof(UNICODE_NULL);
  2506. }
  2507. } else {
  2508. nameLength = KeyName->Length;
  2509. name = KeyName->Buffer;
  2510. pathLength = sizeof(L"\\SystemRoot\\System32\\Drivers\\") - sizeof(UNICODE_NULL);
  2511. path = L"\\SystemRoot\\System32\\Drivers\\";
  2512. extLength = sizeof(L".SYS") - sizeof(UNICODE_NULL);
  2513. ext = L".SYS";
  2514. }
  2515. //
  2516. // Allocate storage for the full path.
  2517. //
  2518. FullPath->MaximumLength = (USHORT)(pathLength + nameLength + extLength + sizeof(UNICODE_NULL));
  2519. FullPath->Buffer = ExAllocatePool(PagedPool, FullPath->MaximumLength);
  2520. if (FullPath->Buffer) {
  2521. FullPath->Length = FullPath->MaximumLength - sizeof(UNICODE_NULL);
  2522. //
  2523. // Create the full path by combining path, name and ext.
  2524. //
  2525. if (pathLength) {
  2526. RtlCopyMemory(FullPath->Buffer, path, pathLength);
  2527. }
  2528. if (nameLength) {
  2529. RtlCopyMemory((PUCHAR)FullPath->Buffer + pathLength, name, nameLength);
  2530. }
  2531. if (extLength) {
  2532. RtlCopyMemory((PUCHAR)FullPath->Buffer + pathLength + nameLength, ext, extLength);
  2533. }
  2534. //
  2535. // NULL terminate the full path.
  2536. //
  2537. FullPath->Buffer[FullPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
  2538. status = STATUS_SUCCESS;
  2539. } else {
  2540. FullPath->MaximumLength = 0;
  2541. status = STATUS_INSUFFICIENT_RESOURCES;
  2542. }
  2543. //
  2544. // Clean up on the way out.
  2545. //
  2546. if (keyValueInformation) {
  2547. ExFreePool(keyValueInformation);
  2548. }
  2549. return status;
  2550. }
  2551. NTSTATUS
  2552. IopLoadDriver(
  2553. IN HANDLE KeyHandle,
  2554. IN BOOLEAN CheckForSafeBoot,
  2555. IN BOOLEAN IsFilter,
  2556. OUT NTSTATUS *DriverEntryStatus
  2557. )
  2558. /*++
  2559. Routine Description:
  2560. This routine is invoked to load a device or file system driver, either
  2561. during system initialization, or dynamically while the system is running.
  2562. Arguments:
  2563. KeyHandle - Supplies a handle to the driver service node in the registry
  2564. that describes the driver to be loaded.
  2565. IsFilter - TRUE if the driver is a WDM filter, FALSE otherwise.
  2566. CheckForSafeBoot - If TRUE, the driver will be loaded only if it belongs
  2567. to the list of safe mode OK binaries.
  2568. DriverEntryStatus - Receives status returned by DriverEntry(...)
  2569. Return Value:
  2570. The function value is the final status of the load operation. If
  2571. STATUS_FAILED_DRIVER_ENTRY is returned, the driver's return value
  2572. is stored in DriverEntryStatus.
  2573. Notes:
  2574. Note that this routine closes the KeyHandle before returning.
  2575. --*/
  2576. {
  2577. NTSTATUS status;
  2578. PLIST_ENTRY nextEntry;
  2579. PKLDR_DATA_TABLE_ENTRY driverEntry;
  2580. PKEY_BASIC_INFORMATION keyBasicInformation = NULL;
  2581. ULONG keyBasicLength;
  2582. UNICODE_STRING baseName;
  2583. UNICODE_STRING serviceName = {0, 0, NULL};
  2584. OBJECT_ATTRIBUTES objectAttributes;
  2585. PVOID sectionPointer;
  2586. UNICODE_STRING driverName;
  2587. PDRIVER_OBJECT driverObject;
  2588. PIMAGE_NT_HEADERS ntHeaders;
  2589. PVOID imageBaseAddress;
  2590. ULONG_PTR entryPoint;
  2591. HANDLE driverHandle;
  2592. ULONG i;
  2593. POBJECT_NAME_INFORMATION registryPath;
  2594. #if DBG
  2595. LARGE_INTEGER stime, etime;
  2596. ULONG dtime;
  2597. #endif
  2598. PAGED_CODE();
  2599. driverName.Buffer = (PWSTR) NULL;
  2600. *DriverEntryStatus = STATUS_SUCCESS;
  2601. baseName.Buffer = NULL;
  2602. //
  2603. // Begin by formulating the name of the driver image file to be loaded.
  2604. // Note that this is used to determine whether or not the driver has
  2605. // already been loaded by the OS loader, not necessarily in actually
  2606. // loading the driver image, since the node can override that name.
  2607. //
  2608. status = NtQueryKey( KeyHandle,
  2609. KeyBasicInformation,
  2610. (PVOID) NULL,
  2611. 0,
  2612. &keyBasicLength );
  2613. if (status != STATUS_BUFFER_OVERFLOW &&
  2614. status != STATUS_BUFFER_TOO_SMALL) {
  2615. status = STATUS_ILL_FORMED_SERVICE_ENTRY;
  2616. goto IopLoadExit;
  2617. }
  2618. keyBasicInformation = ExAllocatePool( NonPagedPool,
  2619. keyBasicLength + (4 * 2) );
  2620. if (!keyBasicInformation) {
  2621. status = STATUS_INSUFFICIENT_RESOURCES;
  2622. goto IopLoadExit;
  2623. }
  2624. status = NtQueryKey( KeyHandle,
  2625. KeyBasicInformation,
  2626. keyBasicInformation,
  2627. keyBasicLength,
  2628. &keyBasicLength );
  2629. if (!NT_SUCCESS( status )) {
  2630. goto IopLoadExit;
  2631. }
  2632. //
  2633. // Create a Unicode string descriptor which forms the name of the
  2634. // driver.
  2635. //
  2636. baseName.Length = (USHORT) keyBasicInformation->NameLength;
  2637. baseName.MaximumLength = (USHORT) (baseName.Length + (4 * 2));
  2638. baseName.Buffer = &keyBasicInformation->Name[0];
  2639. serviceName.Buffer = ExAllocatePool(PagedPool, baseName.Length + sizeof(UNICODE_NULL));
  2640. if (serviceName.Buffer) {
  2641. serviceName.Length = baseName.Length;
  2642. serviceName.MaximumLength = serviceName.Length + sizeof(UNICODE_NULL);
  2643. RtlCopyMemory(serviceName.Buffer, baseName.Buffer, baseName.Length);
  2644. serviceName.Buffer[serviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
  2645. }
  2646. #if DBG
  2647. else {
  2648. DbgPrint("IopLoadDriver: No memory available for Service Keyname\n");
  2649. }
  2650. #endif
  2651. RtlAppendUnicodeToString( &baseName, L".SYS" );
  2652. //
  2653. // Log the file name
  2654. //
  2655. HeadlessKernelAddLogEntry(HEADLESS_LOG_LOADING_FILENAME, &baseName);
  2656. if (CheckForSafeBoot && InitSafeBootMode) {
  2657. BOOLEAN GroupIsGood = FALSE;
  2658. UNICODE_STRING string;
  2659. PKEY_VALUE_PARTIAL_INFORMATION keyValue;
  2660. UCHAR nameBuffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 64];
  2661. ULONG length;
  2662. RtlInitUnicodeString( &string, L"Group" );
  2663. keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)nameBuffer;
  2664. RtlZeroMemory(nameBuffer, sizeof(nameBuffer));
  2665. status = NtQueryValueKey(
  2666. KeyHandle,
  2667. &string,
  2668. KeyValuePartialInformation,
  2669. keyValue,
  2670. sizeof(nameBuffer),
  2671. &length
  2672. );
  2673. if (NT_SUCCESS(status)) {
  2674. string.Length = (USHORT)(keyValue->DataLength - sizeof(WCHAR));
  2675. string.MaximumLength = string.Length;
  2676. string.Buffer = (PWSTR)keyValue->Data;
  2677. if (IopSafebootDriverLoad(&string)) {
  2678. GroupIsGood = TRUE;
  2679. }
  2680. }
  2681. if (!GroupIsGood && !IopSafebootDriverLoad(&baseName)) {
  2682. //
  2683. // don't load the driver
  2684. //
  2685. IopBootLog(&baseName, FALSE);
  2686. DbgPrint("SAFEBOOT: skipping device = %wZ(%wZ)\n",&baseName,&string);
  2687. HeadlessKernelAddLogEntry(HEADLESS_LOG_LOAD_SUCCESSFUL, NULL);
  2688. return STATUS_SUCCESS;
  2689. }
  2690. }
  2691. //
  2692. // See if this driver has already been loaded by the boot loader.
  2693. //
  2694. //
  2695. // No need to do KeEnterCriticalRegion as this is called
  2696. // from system process only.
  2697. //
  2698. ExAcquireResourceSharedLite( &PsLoadedModuleResource, TRUE );
  2699. nextEntry = PsLoadedModuleList.Flink;
  2700. while (nextEntry != &PsLoadedModuleList) {
  2701. //
  2702. // Look at the next boot driver in the list.
  2703. //
  2704. driverEntry = CONTAINING_RECORD( nextEntry,
  2705. KLDR_DATA_TABLE_ENTRY,
  2706. InLoadOrderLinks );
  2707. //
  2708. // If this is not the kernel image (ntoskrnl) and not the HAL (hal),
  2709. // then this is a driver, so initialize it.
  2710. //
  2711. if (RtlEqualString( (PSTRING) &baseName,
  2712. (PSTRING) &driverEntry->FullDllName,
  2713. TRUE )) {
  2714. status = STATUS_IMAGE_ALREADY_LOADED;
  2715. ExReleaseResourceLite( &PsLoadedModuleResource );
  2716. IopBootLog(&baseName, TRUE);
  2717. baseName.Buffer = NULL;
  2718. goto IopLoadExit;
  2719. }
  2720. nextEntry = nextEntry->Flink;
  2721. }
  2722. ExReleaseResourceLite( &PsLoadedModuleResource );
  2723. //
  2724. // This driver has not already been loaded by the OS loader. Form the
  2725. // full path name for this driver.
  2726. //
  2727. status = IopBuildFullDriverPath(&serviceName, KeyHandle, &baseName);
  2728. if (!NT_SUCCESS(status)) {
  2729. baseName.Buffer = NULL;
  2730. goto IopLoadExit;
  2731. }
  2732. //
  2733. // Now get the name of the driver object.
  2734. //
  2735. status = IopGetDriverNameFromKeyNode( KeyHandle,
  2736. &driverName );
  2737. if (!NT_SUCCESS( status )) {
  2738. goto IopLoadExit;
  2739. }
  2740. InitializeObjectAttributes( &objectAttributes,
  2741. &driverName,
  2742. OBJ_PERMANENT,
  2743. (HANDLE) NULL,
  2744. (PSECURITY_DESCRIPTOR) NULL );
  2745. //
  2746. // Load the driver image into memory. If this fails partway through
  2747. // the operation, then it will automatically be unloaded.
  2748. //
  2749. status = MmLoadSystemImage( &baseName,
  2750. NULL,
  2751. NULL,
  2752. 0,
  2753. &sectionPointer,
  2754. (PVOID *) &imageBaseAddress );
  2755. if (!NT_SUCCESS( status )) {
  2756. //
  2757. // If the image was not already loaded then exit.
  2758. //
  2759. if (status != STATUS_IMAGE_ALREADY_LOADED) {
  2760. IopBootLog(&baseName, FALSE);
  2761. goto IopLoadExit;
  2762. }
  2763. //
  2764. // Open the driver object.
  2765. //
  2766. status = ObOpenObjectByName( &objectAttributes,
  2767. IoDriverObjectType,
  2768. KernelMode,
  2769. NULL,
  2770. 0,
  2771. NULL,
  2772. &driverHandle );
  2773. if (!NT_SUCCESS( status )) {
  2774. IopBootLog(&baseName, FALSE);
  2775. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  2776. //
  2777. // Adjust the exit code so that we can distinguish drivers that
  2778. // aren't present from drivers that are present but have had
  2779. // their driver objects made temporary.
  2780. //
  2781. status = STATUS_DRIVER_FAILED_PRIOR_UNLOAD;
  2782. }
  2783. goto IopLoadExit;
  2784. }
  2785. //
  2786. // Reference the handle and obtain a pointer to the driver object so that
  2787. // the handle can be deleted without the object going away.
  2788. //
  2789. status = ObReferenceObjectByHandle( driverHandle,
  2790. 0,
  2791. IoDriverObjectType,
  2792. KeGetPreviousMode(),
  2793. (PVOID *) &driverObject,
  2794. (POBJECT_HANDLE_INFORMATION) NULL );
  2795. NtClose( driverHandle );
  2796. if (!NT_SUCCESS( status )) {
  2797. IopBootLog(&baseName, FALSE);
  2798. goto IopLoadExit;
  2799. }
  2800. status = IopResurrectDriver( driverObject );
  2801. //
  2802. // Regardless of the status the driver object should be dereferenced.
  2803. // if the unload has already run then driver is almost gone. If
  2804. // the driver has been resurrected then the I/O system still has its
  2805. // original reference.
  2806. //
  2807. ObDereferenceObject( driverObject );
  2808. IopBootLog(&baseName, FALSE);
  2809. goto IopLoadExit;
  2810. } else {
  2811. ntHeaders = RtlImageNtHeader( imageBaseAddress );
  2812. //
  2813. // Check should this driver be loaded. If yes, the enum subkey
  2814. // of the service will be prepared.
  2815. //
  2816. status = IopPrepareDriverLoading (&serviceName, KeyHandle, imageBaseAddress, IsFilter);
  2817. if (!NT_SUCCESS(status)) {
  2818. MmUnloadSystemImage(sectionPointer);
  2819. IopBootLog(&baseName, FALSE);
  2820. goto IopLoadExit;
  2821. }
  2822. }
  2823. //
  2824. // The driver image has now been loaded into memory. Create the driver
  2825. // object that represents this image.
  2826. //
  2827. status = ObCreateObject( KeGetPreviousMode(),
  2828. IoDriverObjectType,
  2829. &objectAttributes,
  2830. KernelMode,
  2831. (PVOID) NULL,
  2832. (ULONG) (sizeof( DRIVER_OBJECT ) + sizeof ( DRIVER_EXTENSION )),
  2833. 0,
  2834. 0,
  2835. (PVOID *) &driverObject );
  2836. if (!NT_SUCCESS( status )) {
  2837. IopBootLog(&baseName, FALSE);
  2838. goto IopLoadExit;
  2839. }
  2840. //
  2841. // Initialize this driver object and insert it into the object table.
  2842. //
  2843. RtlZeroMemory( driverObject, sizeof( DRIVER_OBJECT ) + sizeof ( DRIVER_EXTENSION) );
  2844. driverObject->DriverExtension = (PDRIVER_EXTENSION) (driverObject + 1);
  2845. driverObject->DriverExtension->DriverObject = driverObject;
  2846. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  2847. driverObject->MajorFunction[i] = IopInvalidDeviceRequest;
  2848. }
  2849. driverObject->Type = IO_TYPE_DRIVER;
  2850. driverObject->Size = sizeof( DRIVER_OBJECT );
  2851. ntHeaders = RtlImageNtHeader( imageBaseAddress );
  2852. entryPoint = ntHeaders->OptionalHeader.AddressOfEntryPoint;
  2853. entryPoint += (ULONG_PTR) imageBaseAddress;
  2854. if (!(ntHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER)) {
  2855. driverObject->Flags |= DRVO_LEGACY_DRIVER;
  2856. }
  2857. driverObject->DriverInit = (PDRIVER_INITIALIZE) entryPoint;
  2858. driverObject->DriverSection = sectionPointer;
  2859. driverObject->DriverStart = imageBaseAddress;
  2860. driverObject->DriverSize = ntHeaders->OptionalHeader.SizeOfImage;
  2861. status = ObInsertObject( driverObject,
  2862. (PACCESS_STATE) NULL,
  2863. FILE_READ_DATA,
  2864. 0,
  2865. (PVOID *) NULL,
  2866. &driverHandle );
  2867. if (!NT_SUCCESS( status )) {
  2868. IopBootLog(&baseName, FALSE);
  2869. goto IopLoadExit;
  2870. }
  2871. //
  2872. // Reference the handle and obtain a pointer to the driver object so that
  2873. // the handle can be deleted without the object going away.
  2874. //
  2875. status = ObReferenceObjectByHandle( driverHandle,
  2876. 0,
  2877. IoDriverObjectType,
  2878. KeGetPreviousMode(),
  2879. (PVOID *) &driverObject,
  2880. (POBJECT_HANDLE_INFORMATION) NULL );
  2881. ASSERT(status == STATUS_SUCCESS);
  2882. NtClose( driverHandle );
  2883. //
  2884. // Load the Registry information in the appropriate fields of the device
  2885. // object.
  2886. //
  2887. driverObject->HardwareDatabase =
  2888. &CmRegistryMachineHardwareDescriptionSystemName;
  2889. //
  2890. // Store the name of the device driver in the driver object so that it
  2891. // can be easily found by the error log thread.
  2892. //
  2893. driverObject->DriverName.Buffer = ExAllocatePool( PagedPool,
  2894. driverName.MaximumLength );
  2895. if (driverObject->DriverName.Buffer) {
  2896. driverObject->DriverName.MaximumLength = driverName.MaximumLength;
  2897. driverObject->DriverName.Length = driverName.Length;
  2898. RtlCopyMemory( driverObject->DriverName.Buffer,
  2899. driverName.Buffer,
  2900. driverName.MaximumLength );
  2901. }
  2902. //
  2903. // Query the name of the registry path for this driver so that it can
  2904. // be passed to the driver.
  2905. //
  2906. registryPath = ExAllocatePool( NonPagedPool, PAGE_SIZE );
  2907. if (!registryPath) {
  2908. ObMakeTemporaryObject( driverObject );
  2909. ObDereferenceObject( driverObject );
  2910. status = STATUS_INSUFFICIENT_RESOURCES;
  2911. goto IopLoadExit;
  2912. }
  2913. status = NtQueryObject( KeyHandle,
  2914. ObjectNameInformation,
  2915. registryPath,
  2916. PAGE_SIZE,
  2917. &i );
  2918. if (!NT_SUCCESS( status )) {
  2919. ObMakeTemporaryObject( driverObject );
  2920. ObDereferenceObject( driverObject );
  2921. ExFreePool( registryPath );
  2922. goto IopLoadExit;
  2923. }
  2924. #if DBG
  2925. KeQuerySystemTime (&stime);
  2926. #endif
  2927. //
  2928. // Store the service key name of the device driver in the driver object
  2929. //
  2930. if (serviceName.Buffer) {
  2931. driverObject->DriverExtension->ServiceKeyName.Buffer =
  2932. ExAllocatePool( NonPagedPool, serviceName.MaximumLength );
  2933. if (driverObject->DriverExtension->ServiceKeyName.Buffer) {
  2934. driverObject->DriverExtension->ServiceKeyName.MaximumLength = serviceName.MaximumLength;
  2935. driverObject->DriverExtension->ServiceKeyName.Length = serviceName.Length;
  2936. RtlCopyMemory( driverObject->DriverExtension->ServiceKeyName.Buffer,
  2937. serviceName.Buffer,
  2938. serviceName.MaximumLength );
  2939. }
  2940. }
  2941. //
  2942. // Now invoke the driver's initialization routine to initialize itself.
  2943. //
  2944. status = driverObject->DriverInit( driverObject, &registryPath->Name );
  2945. *DriverEntryStatus = status;
  2946. if (!NT_SUCCESS(status)) {
  2947. status = STATUS_FAILED_DRIVER_ENTRY;
  2948. }
  2949. #if DBG
  2950. //
  2951. // If DriverInit took longer than 5 seconds, print a message.
  2952. //
  2953. KeQuerySystemTime (&etime);
  2954. dtime = (ULONG) ((etime.QuadPart - stime.QuadPart) / 1000000);
  2955. if (dtime > 50) {
  2956. DbgPrint( "IOLOAD: Driver %wZ took %d.%ds to %s\n",
  2957. &driverName,
  2958. dtime/10,
  2959. dtime%10,
  2960. NT_SUCCESS(status) ? "initialize" : "fail initialization"
  2961. );
  2962. }
  2963. #endif
  2964. //
  2965. // Workaround for broken NT 4.0 3D labs driver
  2966. // They zero out some function table entries by mistake.
  2967. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  2968. if (driverObject->MajorFunction[i] == NULL) {
  2969. ASSERT(driverObject->MajorFunction[i] != NULL);
  2970. driverObject->MajorFunction[i] = IopInvalidDeviceRequest;
  2971. }
  2972. }
  2973. //
  2974. // If DriverInit doesn't work, then simply unload the image and mark the driver
  2975. // object as temporary. This will cause everything to be deleted.
  2976. //
  2977. ExFreePool( registryPath );
  2978. //
  2979. // If we load the driver because we think it is a legacy driver and
  2980. // it does not create any device object in its DriverEntry. We will
  2981. // unload this driver.
  2982. //
  2983. if (NT_SUCCESS(status) && !IopIsLegacyDriver(driverObject)) {
  2984. status = IopPnpDriverStarted(driverObject, KeyHandle, &serviceName);
  2985. if (!NT_SUCCESS(status)) {
  2986. if (driverObject->DriverUnload) {
  2987. driverObject->Flags |= DRVO_UNLOAD_INVOKED;
  2988. driverObject->DriverUnload(driverObject);
  2989. IopBootLog(&baseName, FALSE);
  2990. } else {
  2991. #if DBG
  2992. DbgPrint("IopLoadDriver: A PnP driver %wZ does not support DriverUnload routine.\n", &driverName);
  2993. // ASSERT(0);
  2994. #endif
  2995. }
  2996. }
  2997. }
  2998. if (!NT_SUCCESS( status )) {
  2999. ObMakeTemporaryObject( driverObject );
  3000. ObDereferenceObject( driverObject );
  3001. } else {
  3002. //
  3003. // Free the memory occupied by the driver's initialization routines.
  3004. //
  3005. IopBootLog(&baseName, TRUE);
  3006. MmFreeDriverInitialization( driverObject->DriverSection );
  3007. IopReadyDeviceObjects( driverObject );
  3008. }
  3009. IopLoadExit:
  3010. if (NT_SUCCESS(status) || (status == STATUS_IMAGE_ALREADY_LOADED)) {
  3011. HeadlessKernelAddLogEntry(HEADLESS_LOG_LOAD_SUCCESSFUL, NULL);
  3012. } else {
  3013. HeadlessKernelAddLogEntry(HEADLESS_LOG_LOAD_FAILED, NULL);
  3014. }
  3015. //
  3016. // Free any pool that was allocated by this routine that has not yet
  3017. // been freed.
  3018. //
  3019. if (driverName.Buffer != NULL) {
  3020. ExFreePool( driverName.Buffer );
  3021. }
  3022. if (keyBasicInformation != NULL) {
  3023. ExFreePool( keyBasicInformation );
  3024. }
  3025. if (serviceName.Buffer != NULL) {
  3026. ExFreePool(serviceName.Buffer);
  3027. }
  3028. if (baseName.Buffer != NULL) {
  3029. ExFreePool(baseName.Buffer);
  3030. }
  3031. //
  3032. // If this routine is about to return a failure, then let the Configuration
  3033. // Manager know about it. But, if STATUS_PLUGPLAY_NO_DEVICE, the device was
  3034. // disabled by hardware profile. In this case we don't need to report it.
  3035. //
  3036. if (!NT_SUCCESS( status ) && (status != STATUS_PLUGPLAY_NO_DEVICE)) {
  3037. NTSTATUS lStatus;
  3038. PULONG errorControl;
  3039. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  3040. if (status != STATUS_IMAGE_ALREADY_LOADED) {
  3041. //
  3042. // If driver was loaded, do not call IopDriverLoadingFailed to change
  3043. // the driver loading status. Because, obviously, the driver is
  3044. // running.
  3045. //
  3046. IopDriverLoadingFailed(KeyHandle, NULL);
  3047. lStatus = IopGetRegistryValue( KeyHandle,
  3048. L"ErrorControl",
  3049. &keyValueInformation );
  3050. if (!NT_SUCCESS( lStatus ) || !keyValueInformation->DataLength) {
  3051. if (NT_SUCCESS( lStatus )) {
  3052. ExFreePool( keyValueInformation );
  3053. }
  3054. } else {
  3055. errorControl = (PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
  3056. CmBootLastKnownGood( *errorControl );
  3057. ExFreePool( keyValueInformation );
  3058. }
  3059. }
  3060. }
  3061. //
  3062. // Close the caller's handle and return the final status from the load
  3063. // operation.
  3064. //
  3065. NtClose( KeyHandle );
  3066. return status;
  3067. }
  3068. PDEVICE_OBJECT
  3069. IopGetDeviceAttachmentBase(
  3070. IN PDEVICE_OBJECT DeviceObject
  3071. )
  3072. /*++
  3073. Routine Description:
  3074. This routine returns the lowest level device object associated with
  3075. the specified device.
  3076. Arguments:
  3077. DeviceObject - Supplies a pointer to the device for which the bottom of
  3078. attachment chain is to be found.
  3079. Return Value:
  3080. The function value is a reference to the lowest level device attached
  3081. to the specified device. If the supplied device object is that device
  3082. object, then a pointer to it is returned.
  3083. N.B. Caller must own the IopDatabaseLock.
  3084. --*/
  3085. {
  3086. PDEVICE_OBJECT baseDeviceObject;
  3087. PDEVOBJ_EXTENSION deviceExtension;
  3088. //
  3089. // Descend down the attachment chain until we find a device object
  3090. // that isn't attached to anything else.
  3091. //
  3092. baseDeviceObject = DeviceObject;
  3093. deviceExtension = baseDeviceObject->DeviceObjectExtension;
  3094. while (deviceExtension->AttachedTo != NULL) {
  3095. baseDeviceObject = deviceExtension->AttachedTo;
  3096. deviceExtension = baseDeviceObject->DeviceObjectExtension;
  3097. }
  3098. return baseDeviceObject;
  3099. }
  3100. VOID
  3101. IopDecrementDeviceObjectRef(
  3102. IN PDEVICE_OBJECT DeviceObject,
  3103. IN BOOLEAN AlwaysUnload,
  3104. IN BOOLEAN OnCleanStack
  3105. )
  3106. /*++
  3107. Routine Description:
  3108. The routine decrements the reference count on a device object. If the
  3109. reference count goes to zero and the device object is a candidate for deletion
  3110. then IopCompleteUnloadOrDelete is called. A device object is subject for
  3111. deletion if the AlwaysUnload flag is true, or the device object is pending
  3112. deletion or the driver is pending unload.
  3113. Arguments:
  3114. DeviceObject - Supplies the device object whose reference count is to be
  3115. decremented.
  3116. AlwaysUnload - Indicates if the driver should be unloaded regardless of the
  3117. state of the unload flag.
  3118. OnCleanStack - Indicates whether the current thread is in the middle a
  3119. driver operation.
  3120. Return Value:
  3121. None.
  3122. --*/
  3123. {
  3124. KIRQL irql;
  3125. //
  3126. // Decrement the reference count on the device object. If this is the last
  3127. // last reason that this mini-file system recognizer needs to stay around,
  3128. // then unload it.
  3129. //
  3130. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  3131. ASSERT( DeviceObject->ReferenceCount > 0 );
  3132. DeviceObject->ReferenceCount--;
  3133. if (!DeviceObject->ReferenceCount && (AlwaysUnload ||
  3134. DeviceObject->DeviceObjectExtension->ExtensionFlags &
  3135. (DOE_DELETE_PENDING | DOE_UNLOAD_PENDING | DOE_REMOVE_PENDING))) {
  3136. IopCompleteUnloadOrDelete( DeviceObject, OnCleanStack, irql );
  3137. } else {
  3138. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  3139. }
  3140. }
  3141. VOID
  3142. IopLoadFileSystemDriver(
  3143. IN PDEVICE_OBJECT DeviceObject
  3144. )
  3145. /*++
  3146. Routine Description:
  3147. This routine is invoked when a mini-file system recognizer driver recognizes
  3148. a volume as being a particular file system, but the driver for that file
  3149. system has not yet been loaded. This function allows the mini-driver to
  3150. load the real file system, and remove itself from the system, so that the
  3151. real file system can mount the device in question.
  3152. Arguments:
  3153. DeviceObject - Registered file system device object for the mini-driver.
  3154. Return Value:
  3155. None.
  3156. --*/
  3157. {
  3158. KEVENT event;
  3159. NTSTATUS status;
  3160. IO_STATUS_BLOCK ioStatus;
  3161. PIRP irp;
  3162. PIO_STACK_LOCATION irpSp;
  3163. PDEVICE_OBJECT attachedDevice;
  3164. PAGED_CODE();
  3165. attachedDevice = DeviceObject;
  3166. while (attachedDevice->AttachedDevice) {
  3167. attachedDevice = attachedDevice->AttachedDevice;
  3168. }
  3169. //
  3170. // Begin by building an I/O Request Packet to have the mini-file system
  3171. // driver load the real file system.
  3172. //
  3173. KeInitializeEvent( &event, NotificationEvent, FALSE );
  3174. irp = IoBuildDeviceIoControlRequest( IRP_MJ_DEVICE_CONTROL,
  3175. attachedDevice,
  3176. (PVOID) NULL,
  3177. 0,
  3178. (PVOID) NULL,
  3179. 0,
  3180. FALSE,
  3181. &event,
  3182. &ioStatus );
  3183. if (irp) {
  3184. //
  3185. // Change the actual major and minor function codes to be a file system
  3186. // control with a minor function code of load FS driver.
  3187. //
  3188. irpSp = IoGetNextIrpStackLocation( irp );
  3189. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  3190. irpSp->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
  3191. //
  3192. // Now issue the request.
  3193. //
  3194. status = IoCallDriver( attachedDevice, irp );
  3195. if (status == STATUS_PENDING) {
  3196. (VOID) KeWaitForSingleObject( &event,
  3197. Executive,
  3198. KernelMode,
  3199. FALSE,
  3200. (PLARGE_INTEGER) NULL );
  3201. }
  3202. }
  3203. //
  3204. // Decrement the reference count on the device object. If this is the last
  3205. // last reason that this mini-file system recognizer needs to stay around,
  3206. // then unload it.
  3207. //
  3208. IopDecrementDeviceObjectRef(DeviceObject, TRUE, TRUE);
  3209. return;
  3210. }
  3211. VOID
  3212. IopLoadUnloadDriver(
  3213. IN PVOID Parameter
  3214. )
  3215. /*++
  3216. Routine Description:
  3217. This routine is executed as an EX worker thread routine when a driver is
  3218. to be loaded or unloaded dynamically. It is used because some drivers
  3219. need to create system threads in the context of the system process, which
  3220. cannot be done in the context of the caller of the system service that
  3221. was invoked to load or unload the specified driver.
  3222. Arguments:
  3223. Parameter - Pointer to the load packet describing what work is to be
  3224. done.
  3225. Return Value:
  3226. None.
  3227. --*/
  3228. {
  3229. PLOAD_PACKET loadPacket;
  3230. NTSTATUS status, driverEntryStatus;
  3231. HANDLE keyHandle;
  3232. PAGED_CODE();
  3233. //
  3234. // Begin by getting a pointer to the load packet.
  3235. //
  3236. loadPacket = (PLOAD_PACKET) Parameter;
  3237. //
  3238. // If the driver object field of the packet is non-NULL, then this is
  3239. // a request to complete the unload of a driver. Simply invoke the
  3240. // driver's unload routine. Note that the final status of the unload
  3241. // is ignored, so it is not set here.
  3242. //
  3243. if (loadPacket->DriverObject) {
  3244. loadPacket->DriverObject->DriverUnload( loadPacket->DriverObject );
  3245. status = STATUS_SUCCESS;
  3246. } else {
  3247. PLIST_ENTRY entry;
  3248. PREINIT_PACKET reinitEntry;
  3249. //
  3250. // The driver specified by the DriverServiceName is to be loaded.
  3251. // Begin by opening the registry node for this driver. Note
  3252. // that if this is successful, then the load driver routine is
  3253. // responsible for closing the handle.
  3254. //
  3255. status = IopOpenRegistryKey( &keyHandle,
  3256. (HANDLE) NULL,
  3257. loadPacket->DriverServiceName,
  3258. KEY_READ,
  3259. FALSE );
  3260. if (NT_SUCCESS( status )) {
  3261. //
  3262. // Invoke the internal common routine to perform the work.
  3263. // This is the same routine that is used by the I/O system
  3264. // initialization code to load drivers.
  3265. //
  3266. status = IopLoadDriver( keyHandle, TRUE, FALSE, &driverEntryStatus );
  3267. if (status == STATUS_FAILED_DRIVER_ENTRY) {
  3268. status = driverEntryStatus;
  3269. } else if (status == STATUS_DRIVER_FAILED_PRIOR_UNLOAD) {
  3270. //
  3271. // Keep legacy behavior (don't change status code)
  3272. //
  3273. status = STATUS_OBJECT_NAME_NOT_FOUND;
  3274. }
  3275. IopCallDriverReinitializationRoutines();
  3276. }
  3277. }
  3278. //
  3279. // Set the final status of the load or unload operation, and indicate to
  3280. // the caller that the operation is now complete.
  3281. //
  3282. loadPacket->FinalStatus = status;
  3283. (VOID) KeSetEvent( &loadPacket->Event, 0, FALSE );
  3284. }
  3285. NTSTATUS
  3286. IopMountVolume(
  3287. IN PDEVICE_OBJECT DeviceObject,
  3288. IN BOOLEAN AllowRawMount,
  3289. IN BOOLEAN DeviceLockAlreadyHeld,
  3290. IN BOOLEAN Alertable,
  3291. OUT PVPB *Vpb
  3292. )
  3293. /*++
  3294. Routine Description:
  3295. This routine is used to mount a volume on the specified device. The Volume
  3296. Parameter Block (VPB) for the specified device is a "clean" VPB. That is,
  3297. it indicates that the volume has never been mounted. It is up to the file
  3298. system that eventually mounts the volume to determine whether the volume is,
  3299. or has been, mounted elsewhere.
  3300. Arguments:
  3301. DeviceObject - Pointer to device object on which the volume is to be
  3302. mounted.
  3303. AllowRawMount - This parameter tells us if we should continue our
  3304. filesystem search to include the Raw file system. This flag will
  3305. only be passed in as TRUE as a result of a DASD open.
  3306. DeviceLockAlreadyHeld - If TRUE, then the caller has already acquired
  3307. the device lock and we should not attempt to acquire it. This is
  3308. currently passed in as TRUE when called from IoVerifyVolume.
  3309. Return Value:
  3310. The function value is a successful status code if a volume was successfully
  3311. mounted on the device. Otherwise, an error code is returned.
  3312. --*/
  3313. {
  3314. NTSTATUS status;
  3315. KEVENT event;
  3316. PIRP irp;
  3317. PDEVICE_OBJECT fsDeviceObject;
  3318. PDEVICE_OBJECT attachedDevice;
  3319. PLIST_ENTRY entry;
  3320. PLIST_ENTRY queueHeader;
  3321. IO_STATUS_BLOCK ioStatus;
  3322. PIO_STACK_LOCATION irpSp;
  3323. ULONG extraStack;
  3324. LIST_ENTRY dummy;
  3325. ULONG rawMountOnly;
  3326. ULONG numRegOps;
  3327. PETHREAD CurrentThread;
  3328. PAGED_CODE();
  3329. CurrentThread = PsGetCurrentThread ();
  3330. //
  3331. // Obtain the lock for the device to be mounted. This guarantees that
  3332. // only one thread is attempting to mount (or verify) this particular
  3333. // device at a time.
  3334. //
  3335. if (!DeviceLockAlreadyHeld) {
  3336. status = KeWaitForSingleObject( &DeviceObject->DeviceLock,
  3337. Executive,
  3338. KeGetPreviousModeByThread(&CurrentThread->Tcb),
  3339. Alertable,
  3340. (PLARGE_INTEGER) NULL );
  3341. //
  3342. // If the wait ended because of an alert or an APC, return now
  3343. // without mounting the device. Note that as the wait for the
  3344. // event was unsuccessful, we do not set it on exit.
  3345. //
  3346. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  3347. return status;
  3348. }
  3349. }
  3350. //
  3351. // Now acquire the resource database lock for the I/O system to perform this
  3352. // operation. This resource protects access to the file system queue.
  3353. //
  3354. KeEnterCriticalRegionThread(&CurrentThread->Tcb);
  3355. (VOID) ExAcquireResourceSharedLite( &IopDatabaseResource, TRUE );
  3356. //
  3357. // Check the 'mounted' flag of the VPB to ensure that it is still clear.
  3358. // If it is, then no one has gotten in before this to mount the volume.
  3359. // Attempt to mount the volume in this case.
  3360. //
  3361. if ((DeviceObject->Vpb->Flags & (VPB_MOUNTED | VPB_REMOVE_PENDING)) == 0) {
  3362. //
  3363. // This volume has never been mounted. Initialize the event and set the
  3364. // status to unsuccessful to set up for the loop. Also if the device
  3365. // has the verify bit set, clear it.
  3366. //
  3367. KeInitializeEvent( &event, NotificationEvent, FALSE );
  3368. status = STATUS_UNSUCCESSFUL;
  3369. DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
  3370. //
  3371. // Get the actual device that this volume is to be mounted on. This
  3372. // device is the final device in the list of devices which are attached
  3373. // to the specified real device.
  3374. //
  3375. attachedDevice = DeviceObject;
  3376. while (attachedDevice->AttachedDevice) {
  3377. attachedDevice = attachedDevice->AttachedDevice;
  3378. }
  3379. //
  3380. // Reference the device object so it cannot go away.
  3381. //
  3382. ObReferenceObject( attachedDevice );
  3383. //
  3384. // Determine which type of file system should be invoked based on
  3385. // the device type of the device being mounted.
  3386. //
  3387. if (DeviceObject->DeviceType == FILE_DEVICE_DISK ||
  3388. DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) {
  3389. queueHeader = &IopDiskFileSystemQueueHead;
  3390. } else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) {
  3391. queueHeader = &IopCdRomFileSystemQueueHead;
  3392. } else {
  3393. queueHeader = &IopTapeFileSystemQueueHead;
  3394. }
  3395. rawMountOnly = (DeviceObject->Vpb->Flags & VPB_RAW_MOUNT);
  3396. //
  3397. // Now loop through each of the file systems which have been loaded in
  3398. // the system to see whether anyone understands the media in the device.
  3399. //
  3400. for (entry = queueHeader->Flink;
  3401. entry != queueHeader && !NT_SUCCESS( status );
  3402. entry = entry->Flink) {
  3403. PDEVICE_OBJECT savedFsDeviceObject;
  3404. //
  3405. // If this is the final entry (Raw file system), and it is also
  3406. // not the first entry, and a raw mount is not permitted, then
  3407. // break out of the loop at this point, as this volume cannot
  3408. // be mounted for the caller's purposes.
  3409. //
  3410. if (!AllowRawMount && entry->Flink == queueHeader && entry != queueHeader->Flink) {
  3411. break;
  3412. }
  3413. //
  3414. // If raw mount is the only one requested and this is not the last entry on the list
  3415. // then skip.
  3416. //
  3417. if (rawMountOnly && (entry->Flink != queueHeader)) {
  3418. continue;
  3419. }
  3420. fsDeviceObject = CONTAINING_RECORD( entry, DEVICE_OBJECT, Queue.ListEntry );
  3421. savedFsDeviceObject = fsDeviceObject;
  3422. //
  3423. // It is possible that the file system has been attached to, so
  3424. // walk the attached list for the file system. The number of stack
  3425. // locations that must be allocated in the IRP must include one for
  3426. // the file system itself, and then one for each driver that is
  3427. // attached to it. Account for all of the stack locations required
  3428. // to get through the mount process.
  3429. //
  3430. extraStack = 1;
  3431. while (fsDeviceObject->AttachedDevice) {
  3432. fsDeviceObject = fsDeviceObject->AttachedDevice;
  3433. extraStack++;
  3434. }
  3435. //
  3436. // Another file system has been found and the volume has still not
  3437. // been mounted. Attempt to mount the volume using this file
  3438. // system.
  3439. //
  3440. // Begin by resetting the event being used for synchronization with
  3441. // the I/O operation.
  3442. //
  3443. KeClearEvent( &event );
  3444. //
  3445. // Allocate and initialize an IRP for this mount operation. Notice
  3446. // that the flags for this operation appear the same as a page read
  3447. // operation. This is because the completion code for both of the
  3448. // operations is exactly the same logic.
  3449. //
  3450. irp = IoAllocateIrp ((CCHAR) (attachedDevice->StackSize + extraStack), FALSE);
  3451. if ( !irp ) {
  3452. status = STATUS_INSUFFICIENT_RESOURCES;
  3453. break;
  3454. }
  3455. irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
  3456. irp->RequestorMode = KernelMode;
  3457. irp->UserEvent = &event;
  3458. irp->UserIosb = &ioStatus;
  3459. irp->Tail.Overlay.Thread = CurrentThread;
  3460. irpSp = IoGetNextIrpStackLocation( irp );
  3461. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  3462. irpSp->MinorFunction = IRP_MN_MOUNT_VOLUME;
  3463. irpSp->Flags = AllowRawMount;
  3464. irpSp->Parameters.MountVolume.Vpb = DeviceObject->Vpb;
  3465. irpSp->Parameters.MountVolume.DeviceObject = attachedDevice;
  3466. numRegOps = IopFsRegistrationOps;
  3467. //
  3468. // Increment the number of reasons that this driver cannot
  3469. // be unloaded. Note that this must be done while still
  3470. // holding the database resource.
  3471. //
  3472. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  3473. &savedFsDeviceObject->ReferenceCount );
  3474. ExReleaseResourceLite( &IopDatabaseResource );
  3475. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  3476. status = IoCallDriver( fsDeviceObject, irp );
  3477. //
  3478. // Wait for the I/O operation to complete.
  3479. //
  3480. if (status == STATUS_PENDING) {
  3481. (VOID) KeWaitForSingleObject( &event,
  3482. Executive,
  3483. KernelMode,
  3484. FALSE,
  3485. (PLARGE_INTEGER) NULL );
  3486. } else {
  3487. //
  3488. // Ensure that the proper status value gets picked up.
  3489. //
  3490. ioStatus.Status = status;
  3491. ioStatus.Information = 0;
  3492. }
  3493. KeEnterCriticalRegionThread(&CurrentThread->Tcb);
  3494. (VOID) ExAcquireResourceSharedLite( &IopDatabaseResource, TRUE );
  3495. //
  3496. // Decrement the number of reasons that this driver cannot be unloaded.
  3497. // If the device object is for FSREC it could not have gotten de-registered
  3498. // here. It should get de-registered only at the time of loading the driver
  3499. // which should happen later.
  3500. //
  3501. IopInterlockedDecrementUlong( LockQueueIoDatabaseLock,
  3502. &savedFsDeviceObject->ReferenceCount );
  3503. //
  3504. // If the operation was successful then set the VPB as mounted.
  3505. //
  3506. if (NT_SUCCESS( ioStatus.Status )) {
  3507. status = ioStatus.Status;
  3508. *Vpb = IopMountInitializeVpb(DeviceObject, attachedDevice, rawMountOnly);
  3509. } else {
  3510. //
  3511. // The mount operation failed. Make a special check here to
  3512. // determine whether or not a popup was enabled, and if so,
  3513. // check to see whether or not the operation was to be aborted.
  3514. // If so, bail out now and return the error to the caller.
  3515. //
  3516. status = ioStatus.Status;
  3517. if (IoIsErrorUserInduced(status) &&
  3518. ioStatus.Information == IOP_ABORT) {
  3519. break;
  3520. }
  3521. //
  3522. // If there were any registrations or unregistrations during the period
  3523. // we unlocked the database resource bail out and start all over again.
  3524. //
  3525. if (numRegOps != IopFsRegistrationOps) {
  3526. //
  3527. // Reset the list back to the beginning and start over
  3528. // again.
  3529. //
  3530. dummy.Flink = queueHeader->Flink;
  3531. entry = &dummy;
  3532. status = STATUS_UNRECOGNIZED_VOLUME;
  3533. }
  3534. //
  3535. // Also check to see whether or not this is a volume that has
  3536. // been recognized, but the file system for it needs to be
  3537. // loaded. If so, drop the locks held at this point, tell the
  3538. // mini-file system recognizer to load the driver, and then
  3539. // reacquire the locks.
  3540. //
  3541. if (status == STATUS_FS_DRIVER_REQUIRED) {
  3542. //
  3543. // Increment the number of reasons that this driver cannot
  3544. // be unloaded. Note that this must be done while still
  3545. // holding the database resource.
  3546. //
  3547. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  3548. &savedFsDeviceObject->ReferenceCount );
  3549. ExReleaseResourceLite( &IopDatabaseResource );
  3550. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  3551. if (!DeviceLockAlreadyHeld) {
  3552. KeSetEvent( &DeviceObject->DeviceLock, 0, FALSE );
  3553. }
  3554. IopLoadFileSystemDriver( savedFsDeviceObject );
  3555. //
  3556. // Now reacquire the locks, in the correct order, and check
  3557. // to see if the volume has been mounted before we could
  3558. // get back. If so, exit; otherwise, restart the file
  3559. // file system queue scan from the beginning.
  3560. //
  3561. if (!DeviceLockAlreadyHeld) {
  3562. status = KeWaitForSingleObject( &DeviceObject->DeviceLock,
  3563. Executive,
  3564. KeGetPreviousModeByThread(&CurrentThread->Tcb),
  3565. Alertable,
  3566. (PLARGE_INTEGER) NULL );
  3567. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  3568. //
  3569. // The device was not mounted by us so
  3570. // drop the reference before returning.
  3571. //
  3572. ObDereferenceObject( attachedDevice );
  3573. return status;
  3574. }
  3575. }
  3576. KeEnterCriticalRegionThread(&CurrentThread->Tcb);
  3577. (VOID) ExAcquireResourceSharedLite( &IopDatabaseResource, TRUE );
  3578. if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
  3579. //
  3580. // This volume was mounted before we got back.
  3581. // Hence deref the attachedDevice as the other thread
  3582. // that got the reference is the one that's going to be
  3583. // used by the filesystem.
  3584. //
  3585. ObDereferenceObject( attachedDevice );
  3586. status = STATUS_SUCCESS;
  3587. break;
  3588. }
  3589. //
  3590. // Reset the list back to the beginning and start over
  3591. // again.
  3592. //
  3593. dummy.Flink = queueHeader->Flink;
  3594. entry = &dummy;
  3595. status = STATUS_UNRECOGNIZED_VOLUME;
  3596. }
  3597. //
  3598. // If the error wasn't STATUS_UNRECOGNIZED_VOLUME, and this
  3599. // request is not going to the Raw file system, then there
  3600. // is no reason to continue looping.
  3601. //
  3602. if (!AllowRawMount && (status != STATUS_UNRECOGNIZED_VOLUME) &&
  3603. FsRtlIsTotalDeviceFailure(status)) {
  3604. break;
  3605. }
  3606. }
  3607. }
  3608. if (!NT_SUCCESS(status)) {
  3609. //
  3610. // The device was not mounted by us so
  3611. // drop the reference.
  3612. //
  3613. ObDereferenceObject( attachedDevice );
  3614. }
  3615. } else if((DeviceObject->Vpb->Flags & VPB_REMOVE_PENDING) != 0) {
  3616. //
  3617. // Pnp is attempting to remove this volume. Don't allow the mount.
  3618. //
  3619. status = STATUS_DEVICE_DOES_NOT_EXIST;
  3620. } else {
  3621. //
  3622. // The volume for this device has already been mounted. Return a
  3623. // success code.
  3624. //
  3625. status = STATUS_SUCCESS;
  3626. }
  3627. ExReleaseResourceLite( &IopDatabaseResource );
  3628. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  3629. //
  3630. // Release the I/O database resource lock and the synchronization event for
  3631. // the device.
  3632. //
  3633. if (!DeviceLockAlreadyHeld) {
  3634. KeSetEvent( &DeviceObject->DeviceLock, 0, FALSE );
  3635. }
  3636. //
  3637. // Finally, if the mount operation failed, and the target device is the
  3638. // boot partition, then bugcheck the system. It is not possible for the
  3639. // system to run properly if the system's boot partition cannot be mounted.
  3640. //
  3641. // Note: Don't bugcheck if the system is already booted.
  3642. //
  3643. if (!NT_SUCCESS( status ) &&
  3644. DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION &&
  3645. InitializationPhase < 2) {
  3646. KeBugCheckEx( UNMOUNTABLE_BOOT_VOLUME, (ULONG_PTR) DeviceObject, status, 0, 0 );
  3647. }
  3648. return status;
  3649. }
  3650. NTSTATUS
  3651. IopInvalidateVolumesForDevice(
  3652. IN PDEVICE_OBJECT DeviceObject
  3653. )
  3654. /*++
  3655. Routine Description:
  3656. This routine is used to force filesystems to, as completely as possible, throw
  3657. out volumes which remain referenced for a given device.
  3658. Arguments:
  3659. DeviceObject - Pointer to device object for which volumes are to be
  3660. invalidated.
  3661. Return Value:
  3662. The function value is a successful status code if all filesystems accepted the
  3663. operation. Otherwise, an error code is returned.
  3664. --*/
  3665. {
  3666. NTSTATUS status;
  3667. NTSTATUS finalStatus;
  3668. KEVENT event;
  3669. PIRP irp;
  3670. PDEVICE_OBJECT fsDeviceObject;
  3671. PDEVICE_OBJECT attachedDevice;
  3672. PFILE_OBJECT storageFileObject;
  3673. HANDLE storageHandle;
  3674. PLIST_ENTRY entry;
  3675. PLIST_ENTRY queueHeader;
  3676. IO_STATUS_BLOCK ioStatus;
  3677. PIO_STACK_LOCATION irpSp;
  3678. PKTHREAD CurrentThread;
  3679. PAGED_CODE();
  3680. //
  3681. // Get the actual device that could be mounted on.
  3682. // Note that there could be multiple device objects on the stack that has a
  3683. // VPB and could be potentially mounted on by FS. So we call the FS with every
  3684. // device object that has a VPB. This is really a stupid brute force approach but
  3685. // this is not a high performance path and is backwards compatible.
  3686. //
  3687. for (attachedDevice = DeviceObject ;attachedDevice; attachedDevice = attachedDevice->AttachedDevice) {
  3688. //
  3689. // If the device object has no VPB skip.
  3690. //
  3691. if (!attachedDevice->Vpb) {
  3692. continue;
  3693. }
  3694. //
  3695. // Synchronize against mounts.
  3696. //
  3697. KeWaitForSingleObject(&(attachedDevice->DeviceLock),
  3698. Executive,
  3699. KernelMode,
  3700. FALSE,
  3701. NULL);
  3702. //
  3703. // Get a handle to this device for use in the fsctl. The way we have to do
  3704. // this is kind of loopy: note we wind up with two references to clean up.
  3705. //
  3706. // The only use of this fileobject/handle is to communicate the device to
  3707. // invalidate volumes on. It isn't used for anything else, and must not be.
  3708. //
  3709. try {
  3710. storageFileObject = NULL;
  3711. storageFileObject = IoCreateStreamFileObjectLite( NULL, attachedDevice );
  3712. storageFileObject->Vpb = attachedDevice->Vpb;
  3713. storageHandle = NULL;
  3714. status = ObOpenObjectByPointer( storageFileObject,
  3715. OBJ_KERNEL_HANDLE,
  3716. NULL,
  3717. 0,
  3718. IoFileObjectType,
  3719. KernelMode,
  3720. &storageHandle );
  3721. } except(EXCEPTION_EXECUTE_HANDLER) {
  3722. status = GetExceptionCode();
  3723. }
  3724. if (NT_SUCCESS( status )) {
  3725. //
  3726. // Now acquire the resource database lock for the I/O system to perform this
  3727. // operation. This resource protects access to the file system queue.
  3728. //
  3729. CurrentThread = KeGetCurrentThread ();
  3730. KeEnterCriticalRegionThread(CurrentThread);
  3731. (VOID) ExAcquireResourceSharedLite( &IopDatabaseResource, TRUE );
  3732. //
  3733. // Determine which type of file system should be invoked based on
  3734. // the device type of the device being invalidated.
  3735. //
  3736. if (DeviceObject->DeviceType == FILE_DEVICE_DISK ||
  3737. DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) {
  3738. queueHeader = &IopDiskFileSystemQueueHead;
  3739. } else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) {
  3740. queueHeader = &IopCdRomFileSystemQueueHead;
  3741. } else {
  3742. queueHeader = &IopTapeFileSystemQueueHead;
  3743. }
  3744. //
  3745. // Initialize the event and set the status to set up
  3746. // for the loop.
  3747. //
  3748. KeInitializeEvent( &event, NotificationEvent, FALSE );
  3749. finalStatus = STATUS_SUCCESS;
  3750. //
  3751. // Now loop through each of the file systems which have been loaded in
  3752. // the system and ask them to invalidate volumes they have had mounted
  3753. // on it.
  3754. //
  3755. for (entry = queueHeader->Flink;
  3756. entry != queueHeader;
  3757. entry = entry->Flink) {
  3758. //
  3759. // If this is the final entry (Raw file system), then break out of the
  3760. // loop at this point, as volumes cannot be invalidated for the caller's
  3761. // purposes in Raw.
  3762. //
  3763. if (entry->Flink == queueHeader) {
  3764. break;
  3765. }
  3766. fsDeviceObject = CONTAINING_RECORD( entry, DEVICE_OBJECT, Queue.ListEntry );
  3767. //
  3768. // It is possible that the file system has been attached to, so
  3769. // walk the attached list for the file system.
  3770. //
  3771. while (fsDeviceObject->AttachedDevice) {
  3772. fsDeviceObject = fsDeviceObject->AttachedDevice;
  3773. }
  3774. //
  3775. // Another file system has been found. Attempt to invalidate volumes
  3776. // using this file system.
  3777. //
  3778. // Begin by resetting the event being used for synchronization with
  3779. // the I/O operation.
  3780. //
  3781. KeClearEvent( &event );
  3782. //
  3783. // Build an IRP for this operation.
  3784. //
  3785. irp = IoBuildDeviceIoControlRequest( FSCTL_INVALIDATE_VOLUMES,
  3786. fsDeviceObject,
  3787. &storageHandle,
  3788. sizeof(HANDLE),
  3789. NULL,
  3790. 0,
  3791. FALSE,
  3792. &event,
  3793. &ioStatus );
  3794. if (irp == NULL) {
  3795. finalStatus = STATUS_INSUFFICIENT_RESOURCES;
  3796. break;
  3797. }
  3798. irpSp = IoGetNextIrpStackLocation( irp );
  3799. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  3800. status = IoCallDriver( fsDeviceObject, irp );
  3801. //
  3802. // Wait for the I/O operation to complete.
  3803. //
  3804. if (status == STATUS_PENDING) {
  3805. (VOID) KeWaitForSingleObject( &event,
  3806. Executive,
  3807. KernelMode,
  3808. FALSE,
  3809. (PLARGE_INTEGER) NULL );
  3810. status = ioStatus.Status;
  3811. } else {
  3812. //
  3813. // Ensure that the proper status value gets picked up.
  3814. //
  3815. ioStatus.Status = status;
  3816. ioStatus.Information = 0;
  3817. }
  3818. //
  3819. // Commute status' indicating the operation is not implemented
  3820. // to success. If a filesystem does not implement, it must not
  3821. // hold volumes that are not mounted.
  3822. //
  3823. if (status == STATUS_INVALID_DEVICE_REQUEST ||
  3824. status == STATUS_NOT_IMPLEMENTED) {
  3825. status = STATUS_SUCCESS;
  3826. }
  3827. //
  3828. // Hand back the first failure we get, but plow on anyway.
  3829. //
  3830. if (NT_SUCCESS( finalStatus ) && !NT_SUCCESS( status )) {
  3831. finalStatus = status;
  3832. }
  3833. }
  3834. ExReleaseResourceLite( &IopDatabaseResource );
  3835. KeLeaveCriticalRegionThread(CurrentThread);
  3836. if (storageFileObject) {
  3837. ObDereferenceObject( storageFileObject );
  3838. if (storageHandle) {
  3839. ZwClose( storageHandle ); // Note that this is a close for which the FS has not
  3840. // gotten the corresponding open.
  3841. }
  3842. }
  3843. //
  3844. // Unlock the device lock to let mounts go
  3845. //
  3846. KeSetEvent(&(attachedDevice->DeviceLock), IO_NO_INCREMENT, FALSE);
  3847. status = finalStatus;
  3848. }
  3849. }
  3850. return status;
  3851. }
  3852. BOOLEAN
  3853. IopNotifyPnpWhenChainDereferenced(
  3854. IN PDEVICE_OBJECT *PhysicalDeviceObjects,
  3855. IN ULONG DeviceObjectCount,
  3856. IN BOOLEAN Query,
  3857. OUT PDEVICE_OBJECT *VetoingDevice
  3858. )
  3859. /*++
  3860. Routine Description:
  3861. Called by PnP when processing a Surprise Removal or a Query Remove.
  3862. In the case of Surprise Removal this function will set DOE_REMOVE_PENDING
  3863. in the device extension flags of the each PDO and all its attached devices.
  3864. For each PDO (and its attachment chain) which currently has a zero
  3865. ReferenceCount DOE_REMOVE_PENDING is reset and DOE_REMOVE_PROCESSED is
  3866. set. IopChainDereferenceComplete is then called to notify PnP that
  3867. this PDO is ready for removal.
  3868. Then as each remaining PDO and its attachment chain's ReferenceCount drops
  3869. to zero IopCheckUnloadOrDelete will call IopChainDereferenceComplete
  3870. (supplied by PnP).
  3871. In the case of Query Remove this function set DOE_REMOVE_PROCESSED on the
  3872. PDO and all its attached devices to prevent further opens. It also checks
  3873. to see if the ReferenceCount for all the PDOs and their attached devices is
  3874. zero. If so it leaves the DOE_REMOVE_PROCESSED set and returns FALSE. If
  3875. not, it resets the DOE_REMOVE_PROCESSED on all the PDOs and their attached
  3876. devices and returns TRUE.
  3877. Arguments:
  3878. PhysicalDeviceObjects List of PDEVICE_OBJECTs for all of the PDOs to be
  3879. checked.
  3880. DeviceObjectCount Count of PDEVICE_OBJECTs in PhysicalDeviceObjects.
  3881. Query TRUE if this is for a Query Remove.
  3882. VetoingDevice Only used for Query Remove, Set to first PDO with a
  3883. ReferenceCount not equal to zero. This is used to
  3884. provide feedback to the user as to why the query
  3885. may have failed.
  3886. Return Value:
  3887. If Query is set then the return value is TRUE if there are outstanding
  3888. opens on any of the PDOs or the attached devices, otherwise FALSE is
  3889. returned.
  3890. If Query is NOT set then the return value is always TRUE.
  3891. --*/
  3892. {
  3893. PDEVOBJ_EXTENSION deviceExtension;
  3894. PDEVICE_OBJECT deviceObject;
  3895. PDEVICE_OBJECT attachedDeviceObject;
  3896. ULONG referenced;
  3897. ULONG pass1SetFlag;
  3898. ULONG pass1ClearFlag;
  3899. LONG i;
  3900. KIRQL irql;
  3901. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  3902. if (Query) {
  3903. pass1SetFlag = DOE_REMOVE_PROCESSED;
  3904. pass1ClearFlag = 0;
  3905. } else {
  3906. pass1SetFlag = DOE_REMOVE_PENDING;
  3907. pass1ClearFlag = DOE_REMOVE_PROCESSED;
  3908. }
  3909. for (i = 0; i < (LONG)DeviceObjectCount; i++) {
  3910. deviceObject = PhysicalDeviceObjects[i];
  3911. deviceExtension = deviceObject->DeviceObjectExtension;
  3912. ASSERT( deviceExtension->DeviceNode != NULL );
  3913. //
  3914. // Assume that at least one device object has a reference. Walk the
  3915. // entire chain marking them with DOE_REMOVE_PENDING.
  3916. //
  3917. //
  3918. // We don't actually care how many aggregate references there actually
  3919. // are. All we're interested in is whether there are any. So we'll OR
  3920. // them together rather than adding them. That way we don't have to do
  3921. // testing or branching and we don't have to worry about overflow in the
  3922. // highly unlikely event that there are a total of more references than
  3923. // will fit in a ULONG.
  3924. //
  3925. referenced = 0;
  3926. attachedDeviceObject = deviceObject;
  3927. do {
  3928. deviceExtension = attachedDeviceObject->DeviceObjectExtension;
  3929. ASSERT(deviceExtension != NULL);
  3930. ASSERT(!(deviceExtension->ExtensionFlags & pass1SetFlag));
  3931. deviceExtension->ExtensionFlags &= ~pass1ClearFlag;
  3932. deviceExtension->ExtensionFlags |= pass1SetFlag;
  3933. referenced |= attachedDeviceObject->ReferenceCount;
  3934. attachedDeviceObject = attachedDeviceObject->AttachedDevice;
  3935. } while (attachedDeviceObject != NULL);
  3936. if (!Query && referenced == 0) {
  3937. //
  3938. // There aren't any outstanding references, retraverse the chain and
  3939. // mark them all DOE_REMOVE_PROCESSED. This will still prevent any
  3940. // opens or attaches from occuring but we won't call
  3941. // IopChainDereferenceComplete in IopCompleteUnloadOrDelete.
  3942. //
  3943. attachedDeviceObject = deviceObject;
  3944. do {
  3945. deviceExtension = attachedDeviceObject->DeviceObjectExtension;
  3946. deviceExtension->ExtensionFlags &= ~DOE_REMOVE_PENDING;
  3947. deviceExtension->ExtensionFlags |= DOE_REMOVE_PROCESSED;
  3948. attachedDeviceObject = attachedDeviceObject->AttachedDevice;
  3949. } while (attachedDeviceObject != NULL);
  3950. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  3951. IopChainDereferenceComplete( deviceObject, TRUE );
  3952. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  3953. } else if (Query && referenced != 0) {
  3954. break;
  3955. }
  3956. }
  3957. if (Query && referenced != 0) {
  3958. if (VetoingDevice != NULL) {
  3959. *VetoingDevice = deviceObject;
  3960. }
  3961. for (; i >= 0; i--) {
  3962. deviceObject = PhysicalDeviceObjects[i];
  3963. deviceExtension = deviceObject->DeviceObjectExtension;
  3964. //
  3965. // There are outstanding references, retraverse the chain and
  3966. // unset DOE_REMOVE_PROCESSED.
  3967. //
  3968. attachedDeviceObject = deviceObject;
  3969. do {
  3970. deviceExtension = attachedDeviceObject->DeviceObjectExtension;
  3971. deviceExtension->ExtensionFlags &= ~DOE_REMOVE_PROCESSED;
  3972. attachedDeviceObject = attachedDeviceObject->AttachedDevice;
  3973. } while (attachedDeviceObject != NULL);
  3974. }
  3975. }
  3976. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  3977. return !Query || referenced != 0;
  3978. }
  3979. NTSTATUS
  3980. IopOpenLinkOrRenameTarget(
  3981. OUT PHANDLE TargetHandle,
  3982. IN PIRP Irp,
  3983. IN PVOID RenameBuffer,
  3984. IN PFILE_OBJECT FileObject
  3985. )
  3986. /*++
  3987. Routine Description:
  3988. This routine is invoked by the rename, set link and set copy-on-write code
  3989. in the I/O system's NtSetInformationFile system service when the caller has
  3990. specified a fully qualified file name as the target of a rename, set link,
  3991. or set copy-on-write operation. This routine attempts to open the parent
  3992. of the specified file and checks the following:
  3993. o If the file itself exists, then the caller must have specified that
  3994. the target is to be replaced, otherwise an error is returned.
  3995. o Ensures that the target file specification refers to the same volume
  3996. upon which the source file exists.
  3997. Arguments:
  3998. TargetHandle - Supplies the address of a variable to return the handle to
  3999. the opened target file if no errors have occurred.
  4000. Irp - Supplies a pointer to the IRP that represents the current rename
  4001. request.
  4002. RenameBuffer - Supplies a pointer to the system intermediate buffer that
  4003. contains the caller's rename parameters.
  4004. FileObject - Supplies a pointer to the file object representing the file
  4005. being renamed.
  4006. Return Value:
  4007. The function value is the final status of the operation.
  4008. Note:
  4009. This function assumes that the layout of a rename, set link and set
  4010. copy-on-write information structure are exactly the same.
  4011. --*/
  4012. {
  4013. NTSTATUS status;
  4014. IO_STATUS_BLOCK ioStatus;
  4015. HANDLE handle;
  4016. OBJECT_ATTRIBUTES objectAttributes;
  4017. UNICODE_STRING newFileName;
  4018. PIO_STACK_LOCATION irpSp;
  4019. PFILE_OBJECT targetFileObject;
  4020. OBJECT_HANDLE_INFORMATION handleInformation;
  4021. PFILE_RENAME_INFORMATION renameBuffer = RenameBuffer;
  4022. FILE_BASIC_INFORMATION basicInformation;
  4023. ACCESS_MASK accessMask;
  4024. PAGED_CODE();
  4025. ASSERT( sizeof( FILE_RENAME_INFORMATION ) ==
  4026. sizeof( FILE_LINK_INFORMATION ) );
  4027. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, ReplaceIfExists ) ==
  4028. FIELD_OFFSET( FILE_LINK_INFORMATION, ReplaceIfExists ) );
  4029. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, RootDirectory ) ==
  4030. FIELD_OFFSET( FILE_LINK_INFORMATION, RootDirectory ) );
  4031. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, FileNameLength ) ==
  4032. FIELD_OFFSET( FILE_LINK_INFORMATION, FileNameLength ) );
  4033. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName ) ==
  4034. FIELD_OFFSET( FILE_LINK_INFORMATION, FileName ) );
  4035. ASSERT( sizeof( FILE_RENAME_INFORMATION ) ==
  4036. sizeof( FILE_MOVE_CLUSTER_INFORMATION ) );
  4037. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, ReplaceIfExists ) ==
  4038. FIELD_OFFSET( FILE_MOVE_CLUSTER_INFORMATION, ClusterCount ) );
  4039. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, RootDirectory ) ==
  4040. FIELD_OFFSET( FILE_MOVE_CLUSTER_INFORMATION, RootDirectory ) );
  4041. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, FileNameLength ) ==
  4042. FIELD_OFFSET( FILE_MOVE_CLUSTER_INFORMATION, FileNameLength ) );
  4043. ASSERT( FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName ) ==
  4044. FIELD_OFFSET( FILE_MOVE_CLUSTER_INFORMATION, FileName ) );
  4045. //
  4046. // Check if the fileobject is a directory or a regular file.
  4047. // The access mask is different based on that behaviour.
  4048. //
  4049. accessMask = FILE_WRITE_DATA;
  4050. if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  4051. status = IopGetBasicInformationFile(FileObject, &basicInformation);
  4052. if (!NT_SUCCESS(status)) {
  4053. return status;
  4054. }
  4055. if (basicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  4056. accessMask = FILE_ADD_SUBDIRECTORY;
  4057. }
  4058. }
  4059. //
  4060. // A fully qualified file name was specified. Begin by attempting to open
  4061. // the parent directory of the specified target file.
  4062. //
  4063. newFileName.Length = (USHORT) renameBuffer->FileNameLength;
  4064. newFileName.MaximumLength = (USHORT) renameBuffer->FileNameLength;
  4065. newFileName.Buffer = renameBuffer->FileName;
  4066. InitializeObjectAttributes( &objectAttributes,
  4067. &newFileName,
  4068. (FileObject->Flags & FO_OPENED_CASE_SENSITIVE ? 0 : OBJ_CASE_INSENSITIVE)|OBJ_KERNEL_HANDLE,
  4069. renameBuffer->RootDirectory,
  4070. (PSECURITY_DESCRIPTOR) NULL );
  4071. //
  4072. // Check if the fileobject is not to the top of the stack.
  4073. //
  4074. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  4075. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =
  4076. (PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  4077. ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
  4078. status = IoCreateFileSpecifyDeviceObjectHint( &handle,
  4079. accessMask | SYNCHRONIZE,
  4080. &objectAttributes,
  4081. &ioStatus,
  4082. (PLARGE_INTEGER) NULL,
  4083. 0,
  4084. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4085. FILE_OPEN,
  4086. FILE_OPEN_FOR_BACKUP_INTENT,
  4087. (PVOID) NULL,
  4088. 0L,
  4089. CreateFileTypeNone,
  4090. (PVOID) NULL,
  4091. IO_NO_PARAMETER_CHECKING |
  4092. IO_OPEN_TARGET_DIRECTORY |
  4093. IO_FORCE_ACCESS_CHECK |
  4094. IOP_CREATE_USE_TOP_DEVICE_OBJECT_HINT,
  4095. fileObjectExtension->TopDeviceObjectHint );
  4096. } else {
  4097. status = IoCreateFile( &handle,
  4098. accessMask | SYNCHRONIZE,
  4099. &objectAttributes,
  4100. &ioStatus,
  4101. (PLARGE_INTEGER) NULL,
  4102. 0,
  4103. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4104. FILE_OPEN,
  4105. FILE_OPEN_FOR_BACKUP_INTENT,
  4106. (PVOID) NULL,
  4107. 0L,
  4108. CreateFileTypeNone,
  4109. (PVOID) NULL,
  4110. IO_NO_PARAMETER_CHECKING |
  4111. IO_OPEN_TARGET_DIRECTORY |
  4112. IO_FORCE_ACCESS_CHECK );
  4113. }
  4114. if (NT_SUCCESS( status )) {
  4115. //
  4116. // The open operation for the target file's parent directory was
  4117. // successful. Check to see whether or not the file exists.
  4118. //
  4119. irpSp = IoGetNextIrpStackLocation( Irp );
  4120. if (irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation &&
  4121. !renameBuffer->ReplaceIfExists &&
  4122. ioStatus.Information == FILE_EXISTS) {
  4123. //
  4124. // The target file exists, and the caller does not want to replace
  4125. // it. This is a name collision error so cleanup and return.
  4126. //
  4127. ObCloseHandle( handle , KernelMode);
  4128. status = STATUS_OBJECT_NAME_COLLISION;
  4129. } else {
  4130. //
  4131. // Everything up to this point is fine, so dereference the handle
  4132. // to a pointer to the file object and ensure that the two file
  4133. // specifications refer to the same device.
  4134. //
  4135. status = ObReferenceObjectByHandle( handle,
  4136. accessMask,
  4137. IoFileObjectType,
  4138. KernelMode,
  4139. (PVOID *) &targetFileObject,
  4140. &handleInformation );
  4141. if (NT_SUCCESS( status )) {
  4142. ObDereferenceObject( targetFileObject );
  4143. if (IoGetRelatedDeviceObject( targetFileObject) !=
  4144. IoGetRelatedDeviceObject( FileObject )) {
  4145. //
  4146. // The two files refer to different devices. Clean everything
  4147. // up and return an appropriate error.
  4148. //
  4149. ObCloseHandle( handle, KernelMode );
  4150. status = STATUS_NOT_SAME_DEVICE;
  4151. } else {
  4152. //
  4153. // Otherwise, everything worked, so allow the rename operation
  4154. // to continue.
  4155. //
  4156. irpSp->Parameters.SetFile.FileObject = targetFileObject;
  4157. *TargetHandle = handle;
  4158. status = STATUS_SUCCESS;
  4159. }
  4160. } else {
  4161. //
  4162. // There was an error referencing the handle to what should
  4163. // have been the target directory. This generally means that
  4164. // there was a resource problem or the handle was invalid, etc.
  4165. // Simply attempt to close the handle and return the error.
  4166. //
  4167. ObCloseHandle( handle , KernelMode);
  4168. }
  4169. }
  4170. }
  4171. //
  4172. // Return the final status of the operation.
  4173. //
  4174. return status;
  4175. }
  4176. NTSTATUS
  4177. IopOpenRegistryKey(
  4178. OUT PHANDLE Handle,
  4179. IN HANDLE BaseHandle OPTIONAL,
  4180. IN PUNICODE_STRING KeyName,
  4181. IN ACCESS_MASK DesiredAccess,
  4182. IN BOOLEAN Create
  4183. )
  4184. /*++
  4185. Routine Description:
  4186. Opens or creates a VOLATILE registry key using the name passed in based
  4187. at the BaseHandle node.
  4188. Arguments:
  4189. Handle - Pointer to the handle which will contain the registry key that
  4190. was opened.
  4191. BaseHandle - Handle to the base path from which the key must be opened.
  4192. KeyName - Name of the Key that must be opened/created.
  4193. DesiredAccess - Specifies the desired access that the caller needs to
  4194. the key.
  4195. Create - Determines if the key is to be created if it does not exist.
  4196. Return Value:
  4197. The function value is the final status of the operation.
  4198. --*/
  4199. {
  4200. OBJECT_ATTRIBUTES objectAttributes;
  4201. ULONG disposition;
  4202. PAGED_CODE();
  4203. //
  4204. // Initialize the object for the key.
  4205. //
  4206. InitializeObjectAttributes( &objectAttributes,
  4207. KeyName,
  4208. OBJ_CASE_INSENSITIVE,
  4209. BaseHandle,
  4210. (PSECURITY_DESCRIPTOR) NULL );
  4211. //
  4212. // Create the key or open it, as appropriate based on the caller's
  4213. // wishes.
  4214. //
  4215. if (Create) {
  4216. return ZwCreateKey( Handle,
  4217. DesiredAccess,
  4218. &objectAttributes,
  4219. 0,
  4220. (PUNICODE_STRING) NULL,
  4221. REG_OPTION_VOLATILE,
  4222. &disposition );
  4223. } else {
  4224. return ZwOpenKey( Handle,
  4225. DesiredAccess,
  4226. &objectAttributes );
  4227. }
  4228. }
  4229. NTSTATUS
  4230. IopQueryXxxInformation(
  4231. IN PFILE_OBJECT FileObject,
  4232. IN ULONG InformationClass,
  4233. IN ULONG Length,
  4234. OUT PVOID Information,
  4235. OUT PULONG ReturnedLength,
  4236. IN BOOLEAN FileInformation
  4237. )
  4238. /*++
  4239. Routine Description:
  4240. This routine returns the requested information about a specified file
  4241. or volume. The information returned is determined by the class that
  4242. is specified, and it is placed into the caller's output buffer.
  4243. Arguments:
  4244. FileObject - Supplies a pointer to the file object about which the requested
  4245. information is returned.
  4246. FsInformationClass - Specifies the type of information which should be
  4247. returned about the file/volume.
  4248. Length - Supplies the length of the buffer in bytes.
  4249. FsInformation - Supplies a buffer to receive the requested information
  4250. returned about the file. This buffer must not be pageable and must
  4251. reside in system space.
  4252. ReturnedLength - Supplies a variable that is to receive the length of the
  4253. information written to the buffer.
  4254. FileInformation - Boolean that indicates whether the information requested
  4255. is for a file or a volume.
  4256. Return Value:
  4257. The status returned is the final completion status of the operation.
  4258. --*/
  4259. {
  4260. PIRP irp;
  4261. NTSTATUS status;
  4262. PDEVICE_OBJECT deviceObject;
  4263. KEVENT event;
  4264. PIO_STACK_LOCATION irpSp;
  4265. IO_STATUS_BLOCK localIoStatus;
  4266. BOOLEAN synchronousIo;
  4267. PAGED_CODE();
  4268. //
  4269. // Reference the file object here so that no special checks need be made
  4270. // in I/O completion to determine whether or not to dereference the file
  4271. // object.
  4272. //
  4273. ObReferenceObject( FileObject );
  4274. //
  4275. // Make a special check here to determine whether this is a synchronous
  4276. // I/O operation. If it is, then wait here until the file is owned by
  4277. // the current thread. If this is not a (serialized) synchronous I/O
  4278. // operation, then initialize the local event.
  4279. //
  4280. if (FileObject->Flags & FO_SYNCHRONOUS_IO) {
  4281. BOOLEAN interrupted;
  4282. if (!IopAcquireFastLock( FileObject )) {
  4283. status = IopAcquireFileObjectLock( FileObject,
  4284. KernelMode,
  4285. (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
  4286. &interrupted );
  4287. if (interrupted) {
  4288. ObDereferenceObject( FileObject );
  4289. return status;
  4290. }
  4291. }
  4292. KeClearEvent( &FileObject->Event );
  4293. synchronousIo = TRUE;
  4294. } else {
  4295. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  4296. synchronousIo = FALSE;
  4297. }
  4298. //
  4299. // Get the address of the target device object.
  4300. //
  4301. deviceObject = IoGetRelatedDeviceObject( FileObject );
  4302. //
  4303. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  4304. // The allocation is performed with an exception handler in case the
  4305. // caller does not have enough quota to allocate the packet.
  4306. //
  4307. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  4308. if (!irp) {
  4309. //
  4310. // An IRP could not be allocated. Cleanup and return an appropriate
  4311. // error status code.
  4312. //
  4313. IopAllocateIrpCleanup( FileObject, (PKEVENT) NULL );
  4314. return STATUS_INSUFFICIENT_RESOURCES;
  4315. }
  4316. irp->Tail.Overlay.OriginalFileObject = FileObject;
  4317. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  4318. irp->RequestorMode = KernelMode;
  4319. //
  4320. // Fill in the service independent parameters in the IRP.
  4321. //
  4322. if (synchronousIo) {
  4323. irp->UserEvent = (PKEVENT) NULL;
  4324. } else {
  4325. irp->UserEvent = &event;
  4326. irp->Flags = IRP_SYNCHRONOUS_API;
  4327. }
  4328. irp->UserIosb = &localIoStatus;
  4329. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  4330. //
  4331. // Get a pointer to the stack location for the first driver. This will be
  4332. // used to pass the original function codes and parameters.
  4333. //
  4334. irpSp = IoGetNextIrpStackLocation( irp );
  4335. irpSp->MajorFunction = FileInformation ?
  4336. IRP_MJ_QUERY_INFORMATION :
  4337. IRP_MJ_QUERY_VOLUME_INFORMATION;
  4338. irpSp->FileObject = FileObject;
  4339. //
  4340. // Set the system buffer address to the address of the caller's buffer and
  4341. // set the flags so that the buffer is not deallocated.
  4342. //
  4343. irp->AssociatedIrp.SystemBuffer = Information;
  4344. irp->Flags |= IRP_BUFFERED_IO;
  4345. //
  4346. // Copy the caller's parameters to the service-specific portion of the
  4347. // IRP.
  4348. //
  4349. if (FileInformation) {
  4350. irpSp->Parameters.QueryFile.Length = Length;
  4351. irpSp->Parameters.QueryFile.FileInformationClass = InformationClass;
  4352. } else {
  4353. irpSp->Parameters.QueryVolume.Length = Length;
  4354. irpSp->Parameters.QueryVolume.FsInformationClass = InformationClass;
  4355. }
  4356. //
  4357. // Insert the packet at the head of the IRP list for the thread.
  4358. //
  4359. IopQueueThreadIrp( irp );
  4360. //
  4361. // Now simply invoke the driver at its dispatch entry with the IRP.
  4362. //
  4363. status = IoCallDriver( deviceObject, irp );
  4364. //
  4365. // If this operation was a synchronous I/O operation, check the return
  4366. // status to determine whether or not to wait on the file object. If
  4367. // the file object is to be waited on, wait for the operation to complete
  4368. // and obtain the final status from the file object itself.
  4369. //
  4370. if (synchronousIo) {
  4371. if (status == STATUS_PENDING) {
  4372. status = KeWaitForSingleObject( &FileObject->Event,
  4373. Executive,
  4374. KernelMode,
  4375. (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
  4376. (PLARGE_INTEGER) NULL );
  4377. if (status == STATUS_ALERTED) {
  4378. IopCancelAlertedRequest( &FileObject->Event, irp );
  4379. }
  4380. status = FileObject->FinalStatus;
  4381. }
  4382. IopReleaseFileObjectLock( FileObject );
  4383. } else {
  4384. //
  4385. // This is a normal synchronous I/O operation, as opposed to a
  4386. // serialized synchronous I/O operation. For this case, wait
  4387. // for the local event and copy the final status information
  4388. // back to the caller.
  4389. //
  4390. if (status == STATUS_PENDING) {
  4391. (VOID) KeWaitForSingleObject( &event,
  4392. Executive,
  4393. KernelMode,
  4394. FALSE,
  4395. (PLARGE_INTEGER) NULL );
  4396. status = localIoStatus.Status;
  4397. }
  4398. }
  4399. *ReturnedLength = (ULONG) localIoStatus.Information;
  4400. return status;
  4401. }
  4402. VOID
  4403. IopRaiseHardError(
  4404. IN PVOID NormalContext,
  4405. IN PVOID SystemArgument1,
  4406. IN PVOID SystemArgument2
  4407. )
  4408. /*++
  4409. Routine Description:
  4410. This routine raises a hard error popup in the context of the current
  4411. thread. The APC was used to get into the context of this thread so that
  4412. the popup would be sent to the appropriate port.
  4413. Arguments:
  4414. NormalContext - Supplies a pointer to the I/O Request Packet (IRP) that
  4415. was initially used to request the operation that has failed.
  4416. SystemArgument1 - Supplies a pointer to the media's volume parameter block.
  4417. See IoRaiseHardError documentation for more information.
  4418. SystemArgument2 - Supplies a pointer to the real device object. See
  4419. IoRaiseHardError documentation for more information.
  4420. Return Value:
  4421. None.
  4422. --*/
  4423. {
  4424. ULONG_PTR parameters[2];
  4425. ULONG numberOfParameters;
  4426. ULONG parameterMask;
  4427. ULONG response;
  4428. NTSTATUS status;
  4429. PIRP irp = (PIRP) NormalContext;
  4430. PVPB vpb = (PVPB) SystemArgument1;
  4431. PDEVICE_OBJECT realDeviceObject = (PDEVICE_OBJECT) SystemArgument2;
  4432. ULONG length = 0;
  4433. POBJECT_NAME_INFORMATION objectName;
  4434. UNICODE_STRING labelName;
  4435. //
  4436. // Determine the name of the device and the volume label of the offending
  4437. // media. Start by determining the size of the DeviceName, and allocate
  4438. // enough storage for both the ObjectName structure and the string
  4439. // because "that's the ways Steve's routine works".
  4440. //
  4441. ObQueryNameString( realDeviceObject, NULL, 0, &length );
  4442. if ((objectName = ExAllocatePool(PagedPool, length)) == NULL) {
  4443. status = STATUS_INSUFFICIENT_RESOURCES;
  4444. } else {
  4445. status = STATUS_SUCCESS;
  4446. }
  4447. if (!NT_SUCCESS( status ) ||
  4448. !NT_SUCCESS( status = ObQueryNameString( realDeviceObject,
  4449. objectName,
  4450. length,
  4451. &response ) )) {
  4452. //
  4453. // Allocation of the pool to put up this popup did not work or
  4454. // something else failed, so there isn't really much that can be
  4455. // done here. Simply return an error back to the user.
  4456. //
  4457. if (objectName) {
  4458. ExFreePool( objectName );
  4459. }
  4460. irp->IoStatus.Status = status;
  4461. irp->IoStatus.Information = 0;
  4462. IoCompleteRequest( irp, IO_DISK_INCREMENT );
  4463. return;
  4464. }
  4465. //
  4466. // The volume label has a max size of 32 characters (Unicode). Convert
  4467. // it to a Unicode string for output in the popup message.
  4468. //
  4469. if (vpb != NULL && vpb->Flags & VPB_MOUNTED) {
  4470. labelName.Buffer = &vpb->VolumeLabel[0];
  4471. labelName.Length = vpb->VolumeLabelLength;
  4472. labelName.MaximumLength = MAXIMUM_VOLUME_LABEL_LENGTH;
  4473. } else {
  4474. RtlInitUnicodeString( &labelName, NULL );
  4475. }
  4476. //
  4477. // Different pop-ups have different printf formats. Depending on the
  4478. // specific error value, adjust the parameters.
  4479. //
  4480. switch( irp->IoStatus.Status ) {
  4481. case STATUS_MEDIA_WRITE_PROTECTED:
  4482. case STATUS_WRONG_VOLUME:
  4483. numberOfParameters = 2;
  4484. parameterMask = 3;
  4485. parameters[0] = (ULONG_PTR) &labelName;
  4486. parameters[1] = (ULONG_PTR) &objectName->Name;
  4487. break;
  4488. case STATUS_DEVICE_NOT_READY:
  4489. case STATUS_IO_TIMEOUT:
  4490. case STATUS_NO_MEDIA_IN_DEVICE:
  4491. case STATUS_UNRECOGNIZED_MEDIA:
  4492. numberOfParameters = 1;
  4493. parameterMask = 1;
  4494. parameters[0] = (ULONG_PTR) &objectName->Name;
  4495. parameters[1] = 0;
  4496. break;
  4497. default:
  4498. numberOfParameters = 0;
  4499. parameterMask = 0;
  4500. }
  4501. //
  4502. // Simply raise the hard error.
  4503. //
  4504. if (ExReadyForErrors) {
  4505. status = ExRaiseHardError( irp->IoStatus.Status,
  4506. numberOfParameters,
  4507. parameterMask,
  4508. parameters,
  4509. OptionCancelTryContinue,
  4510. &response );
  4511. } else {
  4512. status = STATUS_UNSUCCESSFUL;
  4513. response = ResponseReturnToCaller;
  4514. }
  4515. //
  4516. // Free any pool or other resources that were allocated to output the
  4517. // popup.
  4518. //
  4519. ExFreePool( objectName );
  4520. //
  4521. // If there was a problem, or the user didn't want to retry, just
  4522. // complete the request. Otherwise simply call the driver entry
  4523. // point and retry the IRP as if it had never been tried before.
  4524. //
  4525. if (!NT_SUCCESS( status ) || response != ResponseTryAgain) {
  4526. //
  4527. // Before completing the request, make one last check. If this was
  4528. // a mount request, and the reason for the failure was t/o, no media,
  4529. // or unrecognized media, then set the Information field of the status
  4530. // block to indicate whether or not an abort was performed.
  4531. //
  4532. if (response == ResponseCancel) {
  4533. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( irp );
  4534. if (irpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  4535. irpSp->MinorFunction == IRP_MN_MOUNT_VOLUME) {
  4536. irp->IoStatus.Information = IOP_ABORT;
  4537. } else {
  4538. irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
  4539. }
  4540. }
  4541. //
  4542. // An error was incurred, so zero out the information field before
  4543. // completing the request if this was an input operation. Otherwise,
  4544. // IopCompleteRequest will try to copy to the user's buffer.
  4545. //
  4546. if (irp->Flags & IRP_INPUT_OPERATION) {
  4547. irp->IoStatus.Information = 0;
  4548. }
  4549. IoCompleteRequest( irp, IO_DISK_INCREMENT );
  4550. } else {
  4551. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( irp );
  4552. PDEVICE_OBJECT fsDeviceObject = irpSp->DeviceObject;
  4553. PDRIVER_OBJECT driverObject = fsDeviceObject->DriverObject;
  4554. //
  4555. // Retry the request from the top.
  4556. //
  4557. driverObject->MajorFunction[irpSp->MajorFunction]( fsDeviceObject,
  4558. irp );
  4559. }
  4560. }
  4561. VOID
  4562. IopRaiseInformationalHardError(
  4563. IN PVOID NormalContext,
  4564. IN PVOID SystemArgument1,
  4565. IN PVOID SystemArgument2
  4566. )
  4567. /*++
  4568. Routine Description:
  4569. This routine performs the actual pop-up. It will called from either the
  4570. hard-error thread, or a APC routine in a user thread after exiting the
  4571. file system.
  4572. Arguments:
  4573. NormalContext - Contains the information for the pop-up
  4574. SystemArgument1 - not used.
  4575. SystemArgument1 - not used.
  4576. Return Value:
  4577. None.
  4578. --*/
  4579. {
  4580. ULONG parameterPresent;
  4581. ULONG_PTR errorParameter;
  4582. ULONG errorResponse;
  4583. PIOP_HARD_ERROR_PACKET hardErrorPacket;
  4584. UNREFERENCED_PARAMETER( SystemArgument1 );
  4585. UNREFERENCED_PARAMETER( SystemArgument2 );
  4586. hardErrorPacket = (PIOP_HARD_ERROR_PACKET) NormalContext;
  4587. //
  4588. // Simply raise the hard error if the system is ready to accept one.
  4589. //
  4590. errorParameter = (ULONG_PTR) &hardErrorPacket->String;
  4591. parameterPresent = (hardErrorPacket->String.Buffer != NULL);
  4592. if (ExReadyForErrors) {
  4593. (VOID) ExRaiseHardError( hardErrorPacket->ErrorStatus,
  4594. parameterPresent,
  4595. parameterPresent,
  4596. parameterPresent ? &errorParameter : NULL,
  4597. OptionOkNoWait,
  4598. &errorResponse );
  4599. }
  4600. //
  4601. // Now free the packet and the buffer, if one was specified.
  4602. //
  4603. if (hardErrorPacket->String.Buffer) {
  4604. ExFreePool( hardErrorPacket->String.Buffer );
  4605. }
  4606. ExFreePool( hardErrorPacket );
  4607. InterlockedDecrement(&IopHardError.NumPendingApcPopups);
  4608. }
  4609. VOID
  4610. IopReadyDeviceObjects(
  4611. IN PDRIVER_OBJECT DriverObject
  4612. )
  4613. /*++
  4614. Routine Description:
  4615. This routine is invoked to mark all of the device objects owned by the
  4616. specified driver as having been fully initialized and therefore ready
  4617. for access by other drivers/clients.
  4618. Arguments:
  4619. DriverObject - Supplies a pointer to the driver object for the driver
  4620. whose devices are to be marked as being "ready".
  4621. Return Value:
  4622. None.
  4623. --*/
  4624. {
  4625. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  4626. PAGED_CODE();
  4627. //
  4628. // Loop through all of the driver's device objects, clearing the
  4629. // DO_DEVICE_INITIALIZING flag.
  4630. //
  4631. DriverObject->Flags |= DRVO_INITIALIZED;
  4632. while (deviceObject) {
  4633. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  4634. deviceObject = deviceObject->NextDevice;
  4635. }
  4636. }
  4637. NTSTATUS
  4638. IopResurrectDriver(
  4639. PDRIVER_OBJECT DriverObject
  4640. )
  4641. /*++
  4642. Routine Description:
  4643. This routine is invoked to clear unload pending flag on all of the device
  4644. objects owned by the specified driver, if the unload routine has not run.
  4645. This allows the driver to come back to life after a pending unload.
  4646. Arguments:
  4647. DriverObject - Supplies a pointer to the driver object for the driver
  4648. whose devices are to be cleared.
  4649. Return Value:
  4650. Status - Returns success if the driver's unload routine has not run;
  4651. otherwise STATUS_IMAGE_ALREADY_LOADED is returned.
  4652. --*/
  4653. {
  4654. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  4655. KIRQL irql;
  4656. //
  4657. // Acquire the I/O spinlock that protects the device list and
  4658. // driver flags.
  4659. //
  4660. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  4661. if (DriverObject->Flags & DRVO_UNLOAD_INVOKED || !deviceObject ||
  4662. !(deviceObject->DeviceObjectExtension->ExtensionFlags & DOE_UNLOAD_PENDING)) {
  4663. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  4664. return STATUS_IMAGE_ALREADY_LOADED;
  4665. }
  4666. //
  4667. // Loop through all of the driver's device objects, clearing the
  4668. // DOE_UNLOAD_PENDING flag.
  4669. //
  4670. while (deviceObject) {
  4671. deviceObject->DeviceObjectExtension->ExtensionFlags &= ~DOE_UNLOAD_PENDING;
  4672. deviceObject = deviceObject->NextDevice;
  4673. }
  4674. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  4675. return STATUS_SUCCESS;
  4676. }
  4677. VOID
  4678. IopMarshalIds(
  4679. OUT PTRACKING_BUFFER TrackingBuffer,
  4680. IN PFILE_VOLUMEID_WITH_TYPE TargetVolumeId,
  4681. IN PFILE_OBJECTID_BUFFER TargetObjectId,
  4682. IN PFILE_TRACKING_INFORMATION TrackingInfo
  4683. )
  4684. /*++
  4685. Routine Description:
  4686. This routine marshals the TargetVolumeId and TargetObjectId
  4687. into the supplied TrackingBuffer in a standard remotable format.
  4688. It also clears the DestinationFile handle to NULL, and sets the
  4689. ObjectInformationLength to the size of the marshalled data.
  4690. Arguments:
  4691. TrackingBuffer - The buffer to receive the marshalled parameters.
  4692. TargetVolumeId - The volume id to marshal.
  4693. TargetObjectId - The object id to marshal.
  4694. TrackingInfo - The additional tracking information to marshal.
  4695. --*/
  4696. {
  4697. ULONG ObjectInformationLength = 0;
  4698. TrackingBuffer->TrackingInformation.DestinationFile = (HANDLE) NULL;
  4699. RtlZeroMemory( &TrackingBuffer->TrackingInformation.ObjectInformation[ ObjectInformationLength ],
  4700. sizeof(TargetVolumeId->Type) );
  4701. RtlCopyMemory( &TrackingBuffer->TrackingInformation.ObjectInformation[ ObjectInformationLength ],
  4702. &TargetVolumeId->Type,
  4703. sizeof(TargetVolumeId->Type) );
  4704. ObjectInformationLength += sizeof(TargetVolumeId->Type);
  4705. RtlCopyMemory( &TrackingBuffer->TrackingInformation.ObjectInformation[ ObjectInformationLength ],
  4706. &TargetVolumeId->VolumeId[0],
  4707. sizeof(TargetVolumeId->VolumeId) );
  4708. ObjectInformationLength += sizeof(TargetVolumeId->VolumeId);
  4709. RtlCopyMemory( &TrackingBuffer->TrackingInformation.ObjectInformation[ ObjectInformationLength ],
  4710. &TargetObjectId->ObjectId[0],
  4711. sizeof(TargetObjectId->ObjectId) );
  4712. ObjectInformationLength += sizeof(TargetObjectId->ObjectId);
  4713. RtlCopyMemory( &TrackingBuffer->TrackingInformation.ObjectInformation[ ObjectInformationLength ],
  4714. &TrackingInfo->ObjectInformation[0],
  4715. TrackingInfo->ObjectInformationLength );
  4716. ObjectInformationLength += TrackingInfo->ObjectInformationLength;
  4717. TrackingBuffer->TrackingInformation.ObjectInformationLength = ObjectInformationLength;
  4718. }
  4719. VOID
  4720. IopUnMarshalIds(
  4721. IN FILE_TRACKING_INFORMATION * TrackingInformation,
  4722. OUT FILE_VOLUMEID_WITH_TYPE * TargetVolumeId,
  4723. OUT GUID * TargetObjectId,
  4724. OUT GUID * TargetMachineId
  4725. )
  4726. /*++
  4727. Routine Description:
  4728. This routine unmarshals the TargetVolumeId and TargetObjectId
  4729. from the supplied TrackingInformation from a standard remotable format.
  4730. Arguments:
  4731. TrackingInformation - The buffer containing the marshalled parameters.
  4732. TargetVolumeId - Buffer to receive the volume id.
  4733. TargetObjectId - Buffer to receive the object id.
  4734. TargetMachineId - Buffer to receieve the machine id.
  4735. --*/
  4736. {
  4737. ULONG ObjectInformationLength = 0;
  4738. RtlCopyMemory( &TargetVolumeId->Type,
  4739. &TrackingInformation->ObjectInformation[ ObjectInformationLength ],
  4740. sizeof(TargetVolumeId->Type) );
  4741. ObjectInformationLength += sizeof(TargetVolumeId->Type);
  4742. RtlCopyMemory( &TargetVolumeId->VolumeId[0],
  4743. &TrackingInformation->ObjectInformation[ ObjectInformationLength ],
  4744. sizeof(TargetVolumeId->VolumeId) );
  4745. ObjectInformationLength += sizeof(TargetVolumeId->VolumeId);
  4746. RtlCopyMemory( TargetObjectId,
  4747. &TrackingInformation->ObjectInformation[ ObjectInformationLength ],
  4748. sizeof(*TargetObjectId) );
  4749. ObjectInformationLength += sizeof(*TargetObjectId);
  4750. if( TrackingInformation->ObjectInformationLength > ObjectInformationLength ) {
  4751. RtlCopyMemory( TargetMachineId,
  4752. &TrackingInformation->ObjectInformation[ ObjectInformationLength ],
  4753. min( sizeof(*TargetMachineId), TrackingInformation->ObjectInformationLength - ObjectInformationLength) );
  4754. // ObjectInformationLength += sizeof(GUID);
  4755. }
  4756. }
  4757. NTSTATUS
  4758. IopSendMessageToTrackService(
  4759. IN PFILE_VOLUMEID_WITH_TYPE SourceVolumeId,
  4760. IN PFILE_OBJECTID_BUFFER SourceObjectId,
  4761. IN PFILE_TRACKING_INFORMATION TargetObjectInformation
  4762. )
  4763. /*++
  4764. Routine Description:
  4765. This routine is invoked to send a message to the user-mode link tracking
  4766. service to inform it that a file has been moved so that it can track it
  4767. by its object ID.
  4768. Arguments:
  4769. SourceVolumeId - Volume ID of the source file.
  4770. SourceObjectId - Object ID of the source file.
  4771. TargetObjectInformation - Volume ID, object ID of the target file.
  4772. Return Value:
  4773. The final function value is the final completion status of the operation.
  4774. --*/
  4775. {
  4776. typedef struct _LINK_TRACKING_MESSAGE {
  4777. NTSTATUS Status;
  4778. ULONG Request;
  4779. FILE_VOLUMEID_WITH_TYPE SourceVolumeId; // src vol type & id
  4780. FILE_OBJECTID_BUFFER SourceObjectId; // src obj id & birth info
  4781. FILE_VOLUMEID_WITH_TYPE TargetVolumeId; // tgt vol type & id
  4782. GUID TargetObjectId; // tgt obj id
  4783. GUID TargetMachineId;
  4784. } LINK_TRACKING_MESSAGE, *PLINK_TRACKING_MESSAGE;
  4785. typedef struct _LINK_TRACKING_RESPONSE {
  4786. NTSTATUS Status;
  4787. } LINK_TRACKING_RESPONSE, *PLINK_TRACKING_RESPONSE;
  4788. PPORT_MESSAGE portMessage;
  4789. PPORT_MESSAGE portReplyMessage;
  4790. CHAR portReply[ 256 ];
  4791. PLINK_TRACKING_MESSAGE requestMessage;
  4792. PLINK_TRACKING_RESPONSE replyMessage;
  4793. LINK_TRACKING_PACKET ltp;
  4794. NTSTATUS status;
  4795. ULONG loopCount = 0;
  4796. KPROCESSOR_MODE PreviousMode;
  4797. PAGED_CODE();
  4798. PreviousMode = KeGetPreviousMode();
  4799. //
  4800. // Begin by determining whether or not the LPC port to the link tracking
  4801. // service has been opened. If not, then attempt to open it now.
  4802. //
  4803. retry:
  4804. if (!IopLinkTrackingServiceObject) {
  4805. //
  4806. // The port has not yet been opened. Check to see whether or not
  4807. // the service has been started. If not, then get out now as there
  4808. // will be no port if the service is not running.
  4809. //
  4810. if (!KeReadStateEvent( IopLinkTrackingServiceEvent )) {
  4811. return STATUS_NO_TRACKING_SERVICE;
  4812. }
  4813. for (;; ) {
  4814. status = KeWaitForSingleObject(&IopLinkTrackingPortObject,
  4815. Executive,
  4816. PreviousMode,
  4817. FALSE,
  4818. (PLARGE_INTEGER) NULL );
  4819. if ((status == STATUS_USER_APC) || (status == STATUS_ALERTED)) {
  4820. return status;
  4821. }
  4822. //
  4823. // There is no referenced object pointer to the
  4824. // link tracking port so open it.
  4825. //
  4826. if (!IopLinkTrackingServiceObject) {
  4827. ExInitializeWorkItem(
  4828. &IopLinkTrackingPacket.WorkQueueItem,
  4829. IopConnectLinkTrackingPort,
  4830. &IopLinkTrackingPacket);
  4831. (VOID)KeResetEvent(&IopLinkTrackingPacket.Event);
  4832. ExQueueWorkItem( &IopLinkTrackingPacket.WorkQueueItem,
  4833. DelayedWorkQueue );
  4834. status = KeWaitForSingleObject(
  4835. &IopLinkTrackingPacket.Event,
  4836. Executive,
  4837. PreviousMode,
  4838. FALSE,
  4839. (PLARGE_INTEGER) NULL );
  4840. if ((status == STATUS_USER_APC) || (status == STATUS_ALERTED)) {
  4841. NOTHING;
  4842. } else if (!NT_SUCCESS( IopLinkTrackingPacket.FinalStatus )) {
  4843. status = IopLinkTrackingPacket.FinalStatus;
  4844. }
  4845. KeSetEvent(&IopLinkTrackingPortObject,
  4846. 0,
  4847. FALSE);
  4848. if (status == STATUS_SUCCESS) {
  4849. break;
  4850. } else {
  4851. return status;
  4852. }
  4853. } else {
  4854. //
  4855. // The connection is established.
  4856. //
  4857. KeSetEvent(&IopLinkTrackingPortObject,
  4858. 0,
  4859. FALSE);
  4860. break;
  4861. }
  4862. }
  4863. }
  4864. //
  4865. // Form a message from the input parameters and send it to the caller.
  4866. //
  4867. portMessage = ExAllocatePool( PagedPool,
  4868. sizeof( LINK_TRACKING_MESSAGE ) +
  4869. sizeof( PORT_MESSAGE ) );
  4870. if (!portMessage) {
  4871. return STATUS_INSUFFICIENT_RESOURCES;
  4872. }
  4873. requestMessage = (PLINK_TRACKING_MESSAGE) (portMessage + 1);
  4874. RtlZeroMemory( requestMessage, sizeof(*requestMessage) );
  4875. requestMessage->Status = STATUS_SUCCESS;
  4876. requestMessage->Request = 0;
  4877. RtlCopyMemory( &requestMessage->SourceVolumeId,
  4878. SourceVolumeId,
  4879. sizeof( FILE_VOLUMEID_WITH_TYPE ) );
  4880. RtlCopyMemory( &requestMessage->SourceObjectId,
  4881. SourceObjectId,
  4882. sizeof( FILE_OBJECTID_BUFFER ) );
  4883. IopUnMarshalIds( TargetObjectInformation,
  4884. &requestMessage->TargetVolumeId,
  4885. &requestMessage->TargetObjectId,
  4886. &requestMessage->TargetMachineId);
  4887. portMessage->u1.s1.TotalLength = (USHORT) (sizeof( PORT_MESSAGE ) +
  4888. sizeof( LINK_TRACKING_MESSAGE ));
  4889. portMessage->u1.s1.DataLength = (USHORT) sizeof( LINK_TRACKING_MESSAGE );
  4890. portMessage->u2.ZeroInit = 0;
  4891. status = LpcRequestWaitReplyPort( IopLinkTrackingServiceObject,
  4892. portMessage,
  4893. (PPORT_MESSAGE) &portReply[0] );
  4894. if (!NT_SUCCESS( status )) {
  4895. if (status == STATUS_PORT_DISCONNECTED) {
  4896. status = KeWaitForSingleObject(&IopLinkTrackingPortObject,
  4897. Executive,
  4898. PreviousMode,
  4899. FALSE,
  4900. (PLARGE_INTEGER) NULL );
  4901. ObDereferenceObject( IopLinkTrackingServiceObject );
  4902. IopLinkTrackingServiceObject = NULL;
  4903. KeSetEvent(&IopLinkTrackingPortObject,
  4904. 0,
  4905. FALSE);
  4906. if (!loopCount) {
  4907. loopCount += 1;
  4908. goto retry;
  4909. }
  4910. }
  4911. }
  4912. if (NT_SUCCESS( status )) {
  4913. portReplyMessage = (PPORT_MESSAGE) &portReply[0];
  4914. replyMessage = (PLINK_TRACKING_RESPONSE) (portReplyMessage + 1);
  4915. status = replyMessage->Status;
  4916. }
  4917. return status;
  4918. }
  4919. NTSTATUS
  4920. IopSetEaOrQuotaInformationFile(
  4921. IN HANDLE FileHandle,
  4922. OUT PIO_STATUS_BLOCK IoStatusBlock,
  4923. IN PVOID Buffer,
  4924. IN ULONG Length,
  4925. IN BOOLEAN SetEa
  4926. )
  4927. /*++
  4928. Routine Description:
  4929. This routine is invoked by the NtSetEa[Quota]InformationFile system services
  4930. to either modify the EAs on a file or the quota entries on a volume. All of
  4931. the specified entries in the buffer are made to the file or volume.
  4932. Arguments:
  4933. FileHandle - Supplies a handle to the file/volume for which the entries are
  4934. to be applied.
  4935. IoStatusBlock - Address of the caller's I/O status block.
  4936. Buffer - Supplies a buffer containing the entries to be added/modified.
  4937. Length - Supplies the length, in bytes, of the buffer.
  4938. SetEa - A BOOLEAN that indicates whether to change the EAs on a file or
  4939. the quota entries on the volume.
  4940. Return Value:
  4941. The status returned is the final completion status of the operation.
  4942. --*/
  4943. {
  4944. PIRP irp;
  4945. NTSTATUS status;
  4946. PFILE_OBJECT fileObject;
  4947. PDEVICE_OBJECT deviceObject;
  4948. PKEVENT event = (PKEVENT) NULL;
  4949. KPROCESSOR_MODE requestorMode;
  4950. PIO_STACK_LOCATION irpSp;
  4951. IO_STATUS_BLOCK localIoStatus;
  4952. BOOLEAN synchronousIo;
  4953. PETHREAD CurrentThread;
  4954. PAGED_CODE();
  4955. //
  4956. // Get the previous mode; i.e., the mode of the caller.
  4957. //
  4958. CurrentThread = PsGetCurrentThread ();
  4959. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  4960. if (requestorMode != KernelMode) {
  4961. //
  4962. // The caller's access mode is user, so probe each of the arguments
  4963. // and capture them as necessary. If any failures occur, the condition
  4964. // handler will be invoked to handle them. It will simply cleanup and
  4965. // return an access violation status code back to the system service
  4966. // dispatcher.
  4967. //
  4968. try {
  4969. //
  4970. // The IoStatusBlock parameter must be writeable by the caller.
  4971. //
  4972. ProbeForWriteIoStatus( IoStatusBlock);
  4973. //
  4974. // The Buffer parameter must be readable by the caller.
  4975. //
  4976. ProbeForRead( Buffer, Length, sizeof( ULONG ) );
  4977. } except(EXCEPTION_EXECUTE_HANDLER) {
  4978. //
  4979. // An exception was incurred while probing the caller's parameters.
  4980. // Cleanup and return an appropriate error status code.
  4981. //
  4982. return GetExceptionCode();
  4983. }
  4984. }
  4985. //
  4986. // There were no blatant errors so far, so reference the file object so
  4987. // the target device object can be found. Note that if the handle does
  4988. // not refer to a file object, or if the caller does not have the required
  4989. // access to the file, then it will fail.
  4990. //
  4991. status = ObReferenceObjectByHandle( FileHandle,
  4992. SetEa ? FILE_WRITE_EA : FILE_WRITE_DATA,
  4993. IoFileObjectType,
  4994. requestorMode,
  4995. (PVOID *) &fileObject,
  4996. NULL );
  4997. if (!NT_SUCCESS( status )) {
  4998. return status;
  4999. }
  5000. //
  5001. // Make a special check here to determine whether this is a synchronous
  5002. // I/O operation. If it is, then wait here until the file is owned by
  5003. // the current thread. If this is not a (serialized) synchronous I/O
  5004. // operation, then allocate and initialize the local event.
  5005. //
  5006. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  5007. BOOLEAN interrupted;
  5008. if (!IopAcquireFastLock( fileObject )) {
  5009. status = IopAcquireFileObjectLock( fileObject,
  5010. requestorMode,
  5011. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  5012. &interrupted );
  5013. if (interrupted) {
  5014. ObDereferenceObject( fileObject );
  5015. return status;
  5016. }
  5017. }
  5018. synchronousIo = TRUE;
  5019. } else {
  5020. //
  5021. // This is a synchronous API being invoked for a file that is opened
  5022. // for asynchronous I/O. This means that this system service is
  5023. // to synchronize the completion of the operation before returning
  5024. // to the caller. A local event is used to do this.
  5025. //
  5026. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  5027. if (!event) {
  5028. ObDereferenceObject( fileObject );
  5029. return STATUS_INSUFFICIENT_RESOURCES;
  5030. }
  5031. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  5032. synchronousIo = FALSE;
  5033. }
  5034. //
  5035. // Set the file object to the Not-Signaled state.
  5036. //
  5037. KeClearEvent( &fileObject->Event );
  5038. //
  5039. // Get the address of the target device object.
  5040. //
  5041. deviceObject = IoGetRelatedDeviceObject( fileObject );
  5042. //
  5043. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  5044. // The allocation is performed with an exception handler in case the
  5045. // caller does not have enough quota to allocate the packet.
  5046. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  5047. if (!irp) {
  5048. //
  5049. // An IRP could not be allocated. Cleanup and return an appropriate
  5050. // error status code.
  5051. //
  5052. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  5053. ExFreePool( event );
  5054. }
  5055. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  5056. return STATUS_INSUFFICIENT_RESOURCES;
  5057. }
  5058. irp->Tail.Overlay.OriginalFileObject = fileObject;
  5059. irp->Tail.Overlay.Thread = CurrentThread;
  5060. irp->RequestorMode = requestorMode;
  5061. //
  5062. // Fill in the service independent parameters in the IRP.
  5063. //
  5064. if (synchronousIo) {
  5065. irp->UserEvent = (PKEVENT) NULL;
  5066. irp->UserIosb = IoStatusBlock;
  5067. } else {
  5068. irp->UserEvent = event;
  5069. irp->UserIosb = &localIoStatus;
  5070. irp->Flags = IRP_SYNCHRONOUS_API;
  5071. }
  5072. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  5073. //
  5074. // Get a pointer to the stack location for the first driver. This will be
  5075. // used to pass the original function codes and parameters.
  5076. //
  5077. irpSp = IoGetNextIrpStackLocation( irp );
  5078. irpSp->MajorFunction = SetEa ? IRP_MJ_SET_EA : IRP_MJ_SET_QUOTA;
  5079. irpSp->FileObject = fileObject;
  5080. //
  5081. // Now determine whether this driver expects to have data buffered to it
  5082. // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO
  5083. // flag in the device object. if the flag is set, then a system buffer is
  5084. // allocated and driver's data is copied to it. If the DO_DIRECT_IO flag
  5085. // is set in the device object, then a Memory Descriptor List (MDL) is
  5086. // allocated and the caller's buffer is locked down using it. Finally, if
  5087. // the driver specifies neither of the flags, then simply pass the address
  5088. // and length of the buffer and allow the driver to perform all of the
  5089. // checking and buffering if any is required.
  5090. //
  5091. if (deviceObject->Flags & DO_BUFFERED_IO) {
  5092. PVOID systemBuffer;
  5093. ULONG errorOffset;
  5094. //
  5095. // The driver wishes the caller's buffer to be copied into an
  5096. // intermediary buffer. Allocate the system buffer and specify
  5097. // that it should be deallocated on completion. Also check to
  5098. // ensure that the caller's EA list or quota list is valid. All
  5099. // of this is performed within an exception handler that will perform
  5100. // cleanup if the operation fails.
  5101. //
  5102. try {
  5103. //
  5104. // Allocate the intermediary system buffer and charge the caller
  5105. // quota for its allocation. Copy the caller's buffer into the
  5106. // system buffer and check to ensure that it is valid.
  5107. //
  5108. systemBuffer = ExAllocatePoolWithQuota( NonPagedPool, Length );
  5109. irp->AssociatedIrp.SystemBuffer = systemBuffer;
  5110. RtlCopyMemory( systemBuffer, Buffer, Length );
  5111. if (SetEa) {
  5112. status = IoCheckEaBufferValidity( systemBuffer,
  5113. Length,
  5114. &errorOffset );
  5115. } else {
  5116. status = IoCheckQuotaBufferValidity( systemBuffer,
  5117. Length,
  5118. &errorOffset );
  5119. }
  5120. if (!NT_SUCCESS( status )) {
  5121. IoStatusBlock->Status = status;
  5122. IoStatusBlock->Information = errorOffset;
  5123. ExRaiseStatus( status );
  5124. }
  5125. } except(EXCEPTION_EXECUTE_HANDLER) {
  5126. //
  5127. // An exception was incurred while allocating the buffer, copying
  5128. // the caller's data into it, or walking the buffer. Determine
  5129. // what happened, cleanup, and return an appropriate error status
  5130. // code.
  5131. //
  5132. IopExceptionCleanup( fileObject,
  5133. irp,
  5134. (PKEVENT) NULL,
  5135. event );
  5136. return GetExceptionCode();
  5137. }
  5138. //
  5139. // Set the flags so that the completion code knows to deallocate the
  5140. // buffer.
  5141. //
  5142. irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  5143. } else if (deviceObject->Flags & DO_DIRECT_IO) {
  5144. PMDL mdl;
  5145. //
  5146. // This is a direct I/O operation. Allocate an MDL and invoke the
  5147. // memory management routine to lock the buffer into memory. This is
  5148. // done using an exception handler that will perform cleanup if the
  5149. // operation fails.
  5150. //
  5151. mdl = (PMDL) NULL;
  5152. try {
  5153. //
  5154. // Allocate an MDL, charging quota for it, and hang it off of the
  5155. // IRP. Probe and lock the pages associated with the caller's
  5156. // buffer for read access and fill in the MDL with the PFNs of those
  5157. // pages.
  5158. //
  5159. mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );
  5160. if (!mdl) {
  5161. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  5162. }
  5163. IopProbeAndLockPages( mdl, requestorMode, IoReadAccess, deviceObject, irpSp->MajorFunction);
  5164. } except(EXCEPTION_EXECUTE_HANDLER) {
  5165. //
  5166. // An exception was incurred while either probing the caller's
  5167. // buffer or allocating the MDL. Determine what actually happened,
  5168. // clean everything up, and return an appropriate error status code.
  5169. //
  5170. IopExceptionCleanup( fileObject,
  5171. irp,
  5172. (PKEVENT) NULL,
  5173. event );
  5174. return GetExceptionCode();
  5175. }
  5176. } else {
  5177. //
  5178. // Pass the address of the user's buffer so the driver has access to
  5179. // it. It is now the driver's responsibility to do everything.
  5180. //
  5181. irp->UserBuffer = Buffer;
  5182. }
  5183. //
  5184. // Copy the caller's parameters to the service-specific portion of the
  5185. // IRP.
  5186. //
  5187. if (SetEa) {
  5188. irpSp->Parameters.SetEa.Length = Length;
  5189. } else {
  5190. irpSp->Parameters.SetQuota.Length = Length;
  5191. }
  5192. //
  5193. // Queue the packet, call the driver, and synchronize appropriately with
  5194. // I/O completion.
  5195. //
  5196. status = IopSynchronousServiceTail( deviceObject,
  5197. irp,
  5198. fileObject,
  5199. FALSE,
  5200. requestorMode,
  5201. synchronousIo,
  5202. OtherTransfer );
  5203. //
  5204. // If the file for this operation was not opened for synchronous I/O, then
  5205. // synchronization of completion of the I/O operation has not yet occurred
  5206. // since the allocated event must be used for synchronous APIs on files
  5207. // opened for asynchronous I/O. Synchronize the completion of the I/O
  5208. // operation now.
  5209. //
  5210. if (!synchronousIo) {
  5211. status = IopSynchronousApiServiceTail( status,
  5212. event,
  5213. irp,
  5214. requestorMode,
  5215. &localIoStatus,
  5216. IoStatusBlock );
  5217. }
  5218. return status;
  5219. }
  5220. NTSTATUS
  5221. IopSetRemoteLink(
  5222. IN PFILE_OBJECT FileObject,
  5223. IN PFILE_OBJECT DestinationFileObject OPTIONAL,
  5224. IN PFILE_TRACKING_INFORMATION FileInformation OPTIONAL
  5225. )
  5226. /*++
  5227. Routine Description:
  5228. This routine is invoked to remote an NtSetInformationFile API call via an
  5229. FSCTL to the Redirector. The call will cause the remote system to perform
  5230. the service call to track the link for a file which was just moved.
  5231. Arguments:
  5232. FileObject - Supplies the file object for the file that was moved.
  5233. DestinationFileObject - Optionally supplies the file object for the new
  5234. destination location for the file.
  5235. FileInformation - Optionally supplies the volume and file object IDs of
  5236. the target file.
  5237. Return Value:
  5238. The final function value is the final completion status of the operation.
  5239. --*/
  5240. {
  5241. REMOTE_LINK_BUFFER remoteBuffer;
  5242. IO_STATUS_BLOCK ioStatus;
  5243. NTSTATUS status;
  5244. PIRP irp;
  5245. KEVENT event;
  5246. PIO_STACK_LOCATION irpSp;
  5247. PDEVICE_OBJECT deviceObject;
  5248. ULONG length = 0;
  5249. PAGED_CODE();
  5250. //
  5251. // Initialize the event structure to synchronize completion of the I/O
  5252. // request.
  5253. //
  5254. KeInitializeEvent( &event,
  5255. NotificationEvent,
  5256. FALSE );
  5257. //
  5258. // Build an I/O Request Packet to be sent to the file system driver to get
  5259. // the volume ID.
  5260. //
  5261. deviceObject = IoGetRelatedDeviceObject( FileObject );
  5262. irp = IoBuildDeviceIoControlRequest( FSCTL_LMR_SET_LINK_TRACKING_INFORMATION,
  5263. deviceObject,
  5264. NULL,
  5265. 0,
  5266. NULL,
  5267. 0,
  5268. FALSE,
  5269. &event,
  5270. &ioStatus );
  5271. if (!irp) {
  5272. return STATUS_INSUFFICIENT_RESOURCES;
  5273. }
  5274. //
  5275. // Initialize the remote link buffer according to the input information.
  5276. //
  5277. if (DestinationFileObject) {
  5278. // The FileObject and DestinationFileObject are on the same machine
  5279. remoteBuffer.TrackingInformation.TargetFileObject = DestinationFileObject;
  5280. if (FileInformation) {
  5281. // Copy the ObjectInformation from the FileInformation buffer into
  5282. // the TargetLinkTrackingInformationBuffer. Set 'length' to include
  5283. // this buffer.
  5284. remoteBuffer.TrackingInformation.TargetLinkTrackingInformationLength
  5285. = length = FileInformation->ObjectInformationLength;
  5286. RtlCopyMemory( &remoteBuffer.TrackingInformation.TargetLinkTrackingInformationBuffer,
  5287. FileInformation->ObjectInformation,
  5288. length );
  5289. } else {
  5290. // We don't have any extra FileInformation.
  5291. remoteBuffer.TrackingInformation.TargetLinkTrackingInformationLength = 0;
  5292. }
  5293. // Increment the length to include the size of the non-optional fields in
  5294. // REMOTE_LINK_TRACKING_INFORMATION.
  5295. length += sizeof( PFILE_OBJECT ) + sizeof( ULONG );
  5296. } else {
  5297. // There's no DestinationFileObject, so all the necessary information is in the
  5298. // FileInformation structure.
  5299. length = FileInformation->ObjectInformationLength + sizeof( HANDLE ) + sizeof( ULONG );
  5300. RtlCopyMemory( &remoteBuffer.TrackingInformation,
  5301. FileInformation,
  5302. length );
  5303. remoteBuffer.TrackingInformation.TargetFileObject = NULL;
  5304. }
  5305. //
  5306. // Fill in the remainder of the IRP to retrieve the object ID for the
  5307. // file.
  5308. //
  5309. irp->Flags |= IRP_SYNCHRONOUS_API;
  5310. irp->AssociatedIrp.SystemBuffer = &remoteBuffer;
  5311. irp->Tail.Overlay.OriginalFileObject = FileObject;
  5312. irpSp = IoGetNextIrpStackLocation( irp );
  5313. irpSp->FileObject = FileObject;
  5314. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  5315. irpSp->MinorFunction = IRP_MN_KERNEL_CALL;
  5316. irpSp->Parameters.FileSystemControl.InputBufferLength = length;
  5317. //
  5318. // Take out another reference to the file object to guarantee that it does
  5319. // not get deleted.
  5320. //
  5321. ObReferenceObject( FileObject );
  5322. //
  5323. // Call the driver to get the request.
  5324. //
  5325. status = IoCallDriver( deviceObject, irp );
  5326. //
  5327. // Synchronize completion of the request.
  5328. //
  5329. if (status == STATUS_PENDING) {
  5330. status = KeWaitForSingleObject( &event,
  5331. Executive,
  5332. KernelMode,
  5333. FALSE,
  5334. (PLARGE_INTEGER) NULL );
  5335. status = ioStatus.Status;
  5336. }
  5337. return status;
  5338. }
  5339. VOID
  5340. IopStartApcHardError(
  5341. IN PVOID StartContext
  5342. )
  5343. /*++
  5344. Routine Description:
  5345. This function is invoked in an ExWorker thread when we need to do a
  5346. hard error pop-up, but the Irp's originating thread is at APC level,
  5347. ie. IoPageRead. It starts a thread to hold the pop-up.
  5348. Arguments:
  5349. StartContext - Startup context, contains a IOP_APC_HARD_ERROR_PACKET.
  5350. Return Value:
  5351. None.
  5352. --*/
  5353. {
  5354. HANDLE thread;
  5355. NTSTATUS status;
  5356. //
  5357. // Create the hard error pop-up thread. If for whatever reason we
  5358. // can't do this then just complete the Irp with the error.
  5359. //
  5360. status = PsCreateSystemThread( &thread,
  5361. 0,
  5362. (POBJECT_ATTRIBUTES)NULL,
  5363. (HANDLE)0,
  5364. (PCLIENT_ID)NULL,
  5365. IopApcHardError,
  5366. StartContext );
  5367. if ( !NT_SUCCESS( status ) ) {
  5368. IoCompleteRequest( ((PIOP_APC_HARD_ERROR_PACKET)StartContext)->Irp,
  5369. IO_DISK_INCREMENT );
  5370. ExFreePool( StartContext );
  5371. return;
  5372. }
  5373. //
  5374. // Close thread handle
  5375. //
  5376. ZwClose(thread);
  5377. }
  5378. NTSTATUS
  5379. IopSynchronousApiServiceTail(
  5380. IN NTSTATUS ReturnedStatus,
  5381. IN PKEVENT Event,
  5382. IN PIRP Irp,
  5383. IN KPROCESSOR_MODE RequestorMode,
  5384. IN PIO_STATUS_BLOCK LocalIoStatus,
  5385. OUT PIO_STATUS_BLOCK IoStatusBlock
  5386. )
  5387. /*++
  5388. Routine Description:
  5389. This routine is invoked when a synchronous API is invoked for a file
  5390. that has been opened for asynchronous I/O. This function synchronizes
  5391. the completion of the I/O operation on the file.
  5392. Arguments:
  5393. ReturnedStatus - Supplies the status that was returned from the call to
  5394. IoCallDriver.
  5395. Event - Address of the allocated kernel event to be used for synchronization
  5396. of the I/O operation.
  5397. Irp - Address of the I/O Request Packet submitted to the driver.
  5398. RequestorMode - Processor mode of the caller when the operation was
  5399. requested.
  5400. LocalIoStatus - Address of the I/O status block used to capture the final
  5401. status by the service itself.
  5402. IoStatusBlock - Address of the I/O status block supplied by the caller of
  5403. the system service.
  5404. Return Value:
  5405. The function value is the final status of the operation.
  5406. --*/
  5407. {
  5408. NTSTATUS status;
  5409. PAGED_CODE();
  5410. //
  5411. // This is a normal synchronous I/O operation, as opposed to a
  5412. // serialized synchronous I/O operation. For this case, wait for
  5413. // the local event and copy the final status information back to
  5414. // the caller.
  5415. //
  5416. status = ReturnedStatus;
  5417. if (status == STATUS_PENDING) {
  5418. status = KeWaitForSingleObject( Event,
  5419. Executive,
  5420. RequestorMode,
  5421. FALSE,
  5422. (PLARGE_INTEGER) NULL );
  5423. if (status == STATUS_USER_APC) {
  5424. //
  5425. // The wait request has ended either because the thread was
  5426. // alerted or an APC was queued to this thread, because of
  5427. // thread rundown or CTRL/C processing. In either case, try
  5428. // to bail out of this I/O request carefully so that the IRP
  5429. // completes before this routine exists or the event will not
  5430. // be around to set to the Signaled state.
  5431. //
  5432. IopCancelAlertedRequest( Event, Irp );
  5433. }
  5434. status = LocalIoStatus->Status;
  5435. }
  5436. try {
  5437. *IoStatusBlock = *LocalIoStatus;
  5438. } except(EXCEPTION_EXECUTE_HANDLER) {
  5439. //
  5440. // An exception occurred attempting to write the caller's I/O
  5441. // status block. Simply change the final status of the operation
  5442. // to the exception code.
  5443. //
  5444. status = GetExceptionCode();
  5445. }
  5446. ExFreePool( Event );
  5447. return status;
  5448. }
  5449. NTSTATUS
  5450. IopSynchronousServiceTail(
  5451. IN PDEVICE_OBJECT DeviceObject,
  5452. IN PIRP Irp,
  5453. IN PFILE_OBJECT FileObject,
  5454. IN BOOLEAN DeferredIoCompletion,
  5455. IN KPROCESSOR_MODE RequestorMode,
  5456. IN BOOLEAN SynchronousIo,
  5457. IN TRANSFER_TYPE TransferType
  5458. )
  5459. /*++
  5460. Routine Description:
  5461. This routine is invoked to complete the operation of a system service.
  5462. It queues the IRP to the thread's queue, updates the transfer count,
  5463. calls the driver, and finally synchronizes completion of the I/O.
  5464. Arguments:
  5465. DeviceObject - Device on which the I/O is to occur.
  5466. Irp - I/O Request Packet representing the I/O operation.
  5467. FileObject - File object for this open instantiation.
  5468. DeferredIoCompletion - Indicates whether deferred completion is possible.
  5469. RequestorMode - Mode in which request was made.
  5470. SynchronousIo - Indicates whether the operation is to be synchronous.
  5471. TransferType - Type of transfer being performed: read, write, or other.
  5472. Return Value:
  5473. The function value is the final status of the operation.
  5474. --*/
  5475. {
  5476. NTSTATUS status;
  5477. PAGED_CODE();
  5478. //
  5479. // Insert the packet at the head of the IRP list for the thread.
  5480. //
  5481. IopQueueThreadIrp( Irp );
  5482. //
  5483. // Update the operation count statistic for the current process.
  5484. //
  5485. switch( TransferType ) {
  5486. case ReadTransfer:
  5487. IopUpdateReadOperationCount();
  5488. break;
  5489. case WriteTransfer:
  5490. IopUpdateWriteOperationCount();
  5491. break;
  5492. case OtherTransfer:
  5493. IopUpdateOtherOperationCount();
  5494. break;
  5495. }
  5496. //
  5497. // Now simply invoke the driver at its dispatch entry with the IRP.
  5498. //
  5499. status = IoCallDriver( DeviceObject, Irp );
  5500. //
  5501. // If deferred I/O completion is possible, check for pending returned
  5502. // from the driver. If the driver did not return pending, then the
  5503. // packet has not actually been completed yet, so complete it here.
  5504. //
  5505. if (DeferredIoCompletion) {
  5506. if (status != STATUS_PENDING) {
  5507. //
  5508. // The I/O operation was completed without returning a status of
  5509. // pending. This means that at this point, the IRP has not been
  5510. // fully completed. Complete it now.
  5511. //
  5512. PKNORMAL_ROUTINE normalRoutine;
  5513. PVOID normalContext;
  5514. KIRQL irql;
  5515. ASSERT( !Irp->PendingReturned );
  5516. KeRaiseIrql( APC_LEVEL, &irql );
  5517. IopCompleteRequest( &Irp->Tail.Apc,
  5518. &normalRoutine,
  5519. &normalContext,
  5520. (PVOID *) &FileObject,
  5521. &normalContext );
  5522. KeLowerIrql( irql );
  5523. }
  5524. }
  5525. //
  5526. // If this operation was a synchronous I/O operation, check the return
  5527. // status to determine whether or not to wait on the file object. If
  5528. // the file object is to be waited on, wait for the operation to complete
  5529. // and obtain the final status from the file object itself.
  5530. //
  5531. if (SynchronousIo) {
  5532. if (status == STATUS_PENDING) {
  5533. status = KeWaitForSingleObject( &FileObject->Event,
  5534. Executive,
  5535. RequestorMode,
  5536. (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
  5537. (PLARGE_INTEGER) NULL );
  5538. if (status == STATUS_ALERTED || status == STATUS_USER_APC) {
  5539. //
  5540. // The wait request has ended either because the thread was alerted
  5541. // or an APC was queued to this thread, because of thread rundown or
  5542. // CTRL/C processing. In either case, try to bail out of this I/O
  5543. // request carefully so that the IRP completes before this routine
  5544. // exists so that synchronization with the file object will remain
  5545. // intact.
  5546. //
  5547. IopCancelAlertedRequest( &FileObject->Event, Irp );
  5548. }
  5549. status = FileObject->FinalStatus;
  5550. }
  5551. IopReleaseFileObjectLock( FileObject );
  5552. }
  5553. return status;
  5554. }
  5555. VOID
  5556. IopTimerDispatch(
  5557. IN PKDPC Dpc,
  5558. IN PVOID DeferredContext,
  5559. IN PVOID SystemArgument1,
  5560. IN PVOID SystemArgument2
  5561. )
  5562. /*++
  5563. Routine Description:
  5564. This routine scans the I/O system timer database and invokes each driver
  5565. that has enabled a timer in the list, once every second.
  5566. Arguments:
  5567. Dpc - Supplies a pointer to a control object of type DPC.
  5568. DeferredContext - Optional deferred context; not used.
  5569. SystemArgument1 - Optional argument 1; not used.
  5570. SystemArgument2 - Optional argument 2; not used.
  5571. Return Value:
  5572. None.
  5573. --*/
  5574. {
  5575. PLIST_ENTRY timerEntry;
  5576. PIO_TIMER timer;
  5577. KIRQL irql;
  5578. ULONG i;
  5579. UNREFERENCED_PARAMETER( Dpc );
  5580. UNREFERENCED_PARAMETER( DeferredContext );
  5581. UNREFERENCED_PARAMETER( SystemArgument1 );
  5582. UNREFERENCED_PARAMETER( SystemArgument2 );
  5583. //
  5584. // Check to see whether or not there are any timers in the queue that
  5585. // have been enabled. If so, then walk the list and invoke all of the
  5586. // drivers' routines. Note that if the counter changes, which it can
  5587. // because the spin lock is not owned, then a timer routine may be
  5588. // missed. However, this is acceptable, since the driver inserting the
  5589. // entry could be context switched away from, etc. Therefore, this is
  5590. // not a critical resource for the most part.
  5591. //
  5592. if (IopTimerCount) {
  5593. //
  5594. // There is at least one timer entry in the queue that is enabled.
  5595. // Walk the queue and invoke each specified timer routine.
  5596. //
  5597. ExAcquireSpinLock( &IopTimerLock, &irql );
  5598. i = IopTimerCount;
  5599. timerEntry = IopTimerQueueHead.Flink;
  5600. //
  5601. // For each entry found that is enabled, invoke the driver's routine
  5602. // with its specified context parameter. The local count is used
  5603. // to abort the queue traversal when there are more entries in the
  5604. // queue, but they are not enabled.
  5605. //
  5606. for (timerEntry = IopTimerQueueHead.Flink;
  5607. (timerEntry != &IopTimerQueueHead) && i;
  5608. timerEntry = timerEntry->Flink ) {
  5609. timer = CONTAINING_RECORD( timerEntry, IO_TIMER, TimerList );
  5610. if (timer->TimerFlag) {
  5611. timer->TimerRoutine( timer->DeviceObject, timer->Context );
  5612. i--;
  5613. }
  5614. }
  5615. ExReleaseSpinLock( &IopTimerLock, irql );
  5616. }
  5617. }
  5618. NTSTATUS
  5619. IopTrackLink(
  5620. IN PFILE_OBJECT FileObject,
  5621. IN OUT PIO_STATUS_BLOCK IoStatusBlock,
  5622. IN PFILE_TRACKING_INFORMATION FileInformation,
  5623. IN ULONG Length,
  5624. IN PKEVENT Event,
  5625. IN KPROCESSOR_MODE RequestorMode
  5626. )
  5627. /*++
  5628. Routine Description:
  5629. This routine is invoked to track a link. It tracks the source file's Object
  5630. ID to the target file so that links to the source will follow to the new
  5631. location of the target.
  5632. Arguments:
  5633. FileObject - Supplies a pointer to the referenced source file object.
  5634. IoStatusBlock - Pointer to the caller's I/O status block.
  5635. FileInformation - A buffer containing the parameters for the move that was
  5636. performed.
  5637. Length - Specifies the length of the FileInformation buffer.
  5638. Event - An event to be set to the Signaled state once the operation has been
  5639. performed, provided it was successful.
  5640. RequestorMode - Requestor mode of the caller.
  5641. N.B. - Note that the presence of an event indicates that the source file was
  5642. opened for asynchronous I/O, otherwise it was opened for synchronous I/O.
  5643. Return Value:
  5644. The status returned is the final completion status of the operation.
  5645. --*/
  5646. {
  5647. PFILE_TRACKING_INFORMATION trackingInfo = NULL;
  5648. PFILE_OBJECT dstFileObject = NULL;
  5649. FILE_VOLUMEID_WITH_TYPE SourceVolumeId;
  5650. FILE_OBJECTID_BUFFER SourceObjectId;
  5651. FILE_OBJECTID_BUFFER NormalizedObjectId;
  5652. FILE_OBJECTID_BUFFER CrossVolumeObjectId;
  5653. FILE_VOLUMEID_WITH_TYPE TargetVolumeId;
  5654. FILE_OBJECTID_BUFFER TargetObjectId;
  5655. TRACKING_BUFFER trackingBuffer;
  5656. NTSTATUS status;
  5657. PAGED_CODE();
  5658. //
  5659. // Begin by capturing the caller's buffer, if required.
  5660. //
  5661. if (RequestorMode != KernelMode) {
  5662. try {
  5663. trackingInfo = ExAllocatePoolWithQuota( PagedPool,
  5664. Length );
  5665. RtlCopyMemory( trackingInfo, FileInformation, Length );
  5666. if (!trackingInfo->DestinationFile ||
  5667. ((Length - FIELD_OFFSET( FILE_TRACKING_INFORMATION, ObjectInformation ))
  5668. < trackingInfo->ObjectInformationLength)) {
  5669. ExFreePool( trackingInfo );
  5670. return STATUS_INVALID_PARAMETER;
  5671. }
  5672. } except(EXCEPTION_EXECUTE_HANDLER) {
  5673. //
  5674. // An exception was incurred while allocating the intermediary
  5675. // system buffer or while copying the caller's data into the
  5676. // buffer. Cleanup and return an appropriate error status code.
  5677. //
  5678. if (trackingInfo) {
  5679. ExFreePool( trackingInfo );
  5680. }
  5681. return GetExceptionCode();
  5682. }
  5683. } else {
  5684. trackingInfo = FileInformation;
  5685. }
  5686. //
  5687. // If a destination file handle was specified, convert it to a pointer to
  5688. // a file object.
  5689. //
  5690. if (trackingInfo->DestinationFile) {
  5691. status = ObReferenceObjectByHandle( trackingInfo->DestinationFile,
  5692. FILE_WRITE_DATA,
  5693. IoFileObjectType,
  5694. RequestorMode,
  5695. (PVOID *) &dstFileObject,
  5696. NULL );
  5697. if (!NT_SUCCESS( status )) {
  5698. if (RequestorMode != KernelMode) {
  5699. ExFreePool( trackingInfo );
  5700. }
  5701. return status;
  5702. }
  5703. }
  5704. try {
  5705. //
  5706. // Determine whether this is a local or a remote link tracking
  5707. // operation.
  5708. //
  5709. if (IsFileLocal( FileObject )) {
  5710. //
  5711. // The source file, i.e., the one being moved, is a file local to
  5712. // this system. Determine the form of the target file and track
  5713. // it accordingly.
  5714. //
  5715. if (trackingInfo->DestinationFile) {
  5716. if (IsFileLocal( dstFileObject )) {
  5717. BOOLEAN IdSetOnTarget = FALSE;
  5718. //
  5719. // The target file is specified as a handle and it is local.
  5720. // Simply perform the query and set locally. Note that if
  5721. // the source file does not have an object ID, then no
  5722. // tracking will be performed, but it will appear as if the
  5723. // operation worked.
  5724. //
  5725. status = IopGetSetObjectId( FileObject,
  5726. &SourceObjectId,
  5727. sizeof( SourceObjectId ),
  5728. FSCTL_GET_OBJECT_ID );
  5729. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  5730. return(STATUS_SUCCESS);
  5731. }
  5732. if (!NT_SUCCESS( status )) {
  5733. return status;
  5734. }
  5735. //
  5736. // If the extended info field is zero then this file
  5737. // has no interesting tracking information.
  5738. //
  5739. if (RtlCompareMemoryUlong(SourceObjectId.BirthObjectId,
  5740. sizeof(SourceObjectId.BirthObjectId),
  5741. 0) == sizeof(SourceObjectId.BirthObjectId)) {
  5742. return (STATUS_SUCCESS);
  5743. }
  5744. //
  5745. // Get the volume ID of the source and destination
  5746. //
  5747. status = IopGetVolumeId( dstFileObject,
  5748. &TargetVolumeId,
  5749. sizeof( TargetVolumeId ) );
  5750. if (!NT_SUCCESS( status )) {
  5751. return status;
  5752. }
  5753. status = IopGetVolumeId( FileObject,
  5754. &SourceVolumeId,
  5755. sizeof( SourceVolumeId ) );
  5756. if (!NT_SUCCESS( status )) {
  5757. return status;
  5758. }
  5759. //
  5760. // Delete the ID from the source now, since the
  5761. // target may be on the same volume. If there's a
  5762. // subsequent error, we'll try to restore it.
  5763. //
  5764. status = IopGetSetObjectId( FileObject,
  5765. NULL,
  5766. 0,
  5767. FSCTL_DELETE_OBJECT_ID );
  5768. if (!NT_SUCCESS( status )) {
  5769. return status;
  5770. }
  5771. //
  5772. // Set the ID on the target. If it's a cross-volume
  5773. // move, set the bit that indicates same.
  5774. //
  5775. CrossVolumeObjectId = TargetObjectId = SourceObjectId;
  5776. if( !RtlEqualMemory( &TargetVolumeId.VolumeId[0],
  5777. &SourceVolumeId.VolumeId[0],
  5778. sizeof(SourceVolumeId.VolumeId) )) {
  5779. CrossVolumeObjectId.BirthVolumeId[0] |= 1;
  5780. }
  5781. status = IopGetSetObjectId( dstFileObject,
  5782. &CrossVolumeObjectId,
  5783. sizeof( CrossVolumeObjectId ),
  5784. FSCTL_SET_OBJECT_ID );
  5785. if( status == STATUS_DUPLICATE_NAME ||
  5786. status == STATUS_OBJECT_NAME_COLLISION ) {
  5787. // This object ID is already in use on the target volume,
  5788. // or the dest file already has an object ID.
  5789. // Get the file's ID (or have NTFS generate a new one).
  5790. status = IopGetSetObjectId( dstFileObject,
  5791. &TargetObjectId,
  5792. sizeof(TargetObjectId),
  5793. FSCTL_CREATE_OR_GET_OBJECT_ID );
  5794. if( NT_SUCCESS(status) ) {
  5795. // Write the birth ID
  5796. status = IopGetSetObjectId( dstFileObject,
  5797. &CrossVolumeObjectId.ExtendedInfo[0],
  5798. sizeof( CrossVolumeObjectId.ExtendedInfo ),
  5799. FSCTL_SET_OBJECT_ID_EXTENDED );
  5800. }
  5801. }
  5802. if( NT_SUCCESS(status) ) {
  5803. IdSetOnTarget = TRUE;
  5804. // If this was a cross-volume move, notify the tracking service.
  5805. if( !RtlEqualMemory( &TargetVolumeId.VolumeId[0],
  5806. &SourceVolumeId.VolumeId[0],
  5807. sizeof(SourceVolumeId.VolumeId) )) {
  5808. IopMarshalIds( &trackingBuffer, &TargetVolumeId, &TargetObjectId, trackingInfo );
  5809. // Bit 0 must be reset before notifying tracking service
  5810. NormalizedObjectId = SourceObjectId;
  5811. NormalizedObjectId.BirthVolumeId[0] &= 0xfe;
  5812. status = IopSendMessageToTrackService( &SourceVolumeId,
  5813. &NormalizedObjectId,
  5814. &trackingBuffer.TrackingInformation );
  5815. }
  5816. }
  5817. //
  5818. // If there was an error after the ObjectID was deleted
  5819. // from the source. Try to restore it before returning.
  5820. //
  5821. if( !NT_SUCCESS(status) ) {
  5822. NTSTATUS statusT = STATUS_SUCCESS;
  5823. if( IdSetOnTarget ) {
  5824. if( RtlEqualMemory( &TargetObjectId.ObjectId,
  5825. &SourceObjectId.ObjectId,
  5826. sizeof(TargetObjectId.ObjectId) )) {
  5827. // This ID was set with FSCTL_SET_OBJECT_ID
  5828. statusT = IopGetSetObjectId( dstFileObject,
  5829. NULL,
  5830. 0,
  5831. FSCTL_DELETE_OBJECT_ID );
  5832. } else {
  5833. // Restore the target's extended data.
  5834. statusT = IopGetSetObjectId( dstFileObject,
  5835. &TargetObjectId.ExtendedInfo[0],
  5836. sizeof(TargetObjectId.ExtendedInfo),
  5837. FSCTL_SET_OBJECT_ID_EXTENDED );
  5838. }
  5839. }
  5840. if( NT_SUCCESS( statusT )) {
  5841. IopGetSetObjectId( FileObject,
  5842. &SourceObjectId,
  5843. sizeof(SourceObjectId),
  5844. FSCTL_SET_OBJECT_ID );
  5845. }
  5846. return status;
  5847. }
  5848. } else { // if (IsFileLocal( dstFileObject ))
  5849. //
  5850. // The source file is local, but the destination file object
  5851. // is remote. For this case query the target file's object
  5852. // ID and notify the link tracking system that the file has
  5853. // been moved across systems.
  5854. //
  5855. //
  5856. // Begin by ensuring that the source file has an object ID
  5857. // already. If not, then just make it appear as if the
  5858. // operation worked.
  5859. //
  5860. status = IopGetSetObjectId( FileObject,
  5861. &SourceObjectId,
  5862. sizeof( SourceObjectId ),
  5863. FSCTL_GET_OBJECT_ID );
  5864. if (!NT_SUCCESS( status )) {
  5865. return STATUS_SUCCESS;
  5866. }
  5867. //
  5868. // If the extended info field is zero then this file
  5869. // has no interesting tracking information.
  5870. //
  5871. if (RtlCompareMemoryUlong(&SourceObjectId.BirthObjectId,
  5872. sizeof(SourceObjectId.BirthObjectId),
  5873. 0) == sizeof(SourceObjectId.BirthObjectId)) {
  5874. return (STATUS_SUCCESS);
  5875. }
  5876. //
  5877. // Query the volume ID of the target.
  5878. //
  5879. status = IopGetSetObjectId( dstFileObject,
  5880. &TargetVolumeId,
  5881. sizeof( FILE_VOLUMEID_WITH_TYPE ),
  5882. FSCTL_LMR_GET_LINK_TRACKING_INFORMATION );
  5883. if (!NT_SUCCESS( status )) {
  5884. return status;
  5885. }
  5886. //
  5887. // Query the object ID of the target.
  5888. //
  5889. status = IopGetSetObjectId( dstFileObject,
  5890. &TargetObjectId,
  5891. sizeof( TargetObjectId ),
  5892. FSCTL_CREATE_OR_GET_OBJECT_ID );
  5893. if (!NT_SUCCESS( status )) {
  5894. return status;
  5895. }
  5896. //
  5897. // Notify the tracking system of the move.
  5898. //
  5899. IopMarshalIds( &trackingBuffer, &TargetVolumeId, &TargetObjectId, trackingInfo );
  5900. status = IopTrackLink( FileObject,
  5901. IoStatusBlock,
  5902. &trackingBuffer.TrackingInformation,
  5903. FIELD_OFFSET( FILE_TRACKING_INFORMATION,
  5904. ObjectInformation ) +
  5905. trackingBuffer.TrackingInformation.ObjectInformationLength,
  5906. Event,
  5907. KernelMode );
  5908. if (!NT_SUCCESS( status )) {
  5909. return status;
  5910. }
  5911. //
  5912. // Delete the ID from the source
  5913. //
  5914. status = IopGetSetObjectId( FileObject,
  5915. NULL,
  5916. 0,
  5917. FSCTL_DELETE_OBJECT_ID );
  5918. if( !NT_SUCCESS( status )) {
  5919. return status;
  5920. }
  5921. //
  5922. // Set the Birth ID on the target, turning on the bit
  5923. // that indicates that this file has been involved in a cross-
  5924. // volume move.
  5925. //
  5926. CrossVolumeObjectId = SourceObjectId;
  5927. CrossVolumeObjectId.BirthVolumeId[0] |= 1;
  5928. status = IopGetSetObjectId( dstFileObject,
  5929. &CrossVolumeObjectId.ExtendedInfo[0],
  5930. sizeof( CrossVolumeObjectId.ExtendedInfo ),
  5931. FSCTL_SET_OBJECT_ID_EXTENDED );
  5932. if (!NT_SUCCESS( status )) {
  5933. // Try to restore the source
  5934. IopGetSetObjectId( FileObject,
  5935. &SourceObjectId,
  5936. sizeof(SourceObjectId),
  5937. FSCTL_SET_OBJECT_ID );
  5938. return status;
  5939. }
  5940. } // if (IsFileLocal( dstFileObject ))
  5941. } else { // if (trackingInfo->DestinationFile)
  5942. //
  5943. // A destination file handle was not specified. Simply query
  5944. // the source file's object ID and call the link tracking code.
  5945. // Note that the function input buffer contains the volume ID
  5946. // and file object ID of the target. Note also that it is
  5947. // assumed that the source file has an object ID.
  5948. //
  5949. status = IopGetVolumeId( FileObject,
  5950. &SourceVolumeId,
  5951. sizeof( SourceVolumeId ) );
  5952. if (!NT_SUCCESS( status )) {
  5953. return status;
  5954. }
  5955. status = IopGetSetObjectId( FileObject,
  5956. &SourceObjectId,
  5957. sizeof( SourceObjectId ),
  5958. FSCTL_GET_OBJECT_ID );
  5959. if (!NT_SUCCESS( status )) {
  5960. return status;
  5961. }
  5962. //
  5963. // If the extended info field is zero then this file
  5964. // has no interesting tracking information.
  5965. //
  5966. if (RtlCompareMemoryUlong(SourceObjectId.BirthObjectId,
  5967. sizeof(SourceObjectId.BirthObjectId),
  5968. 0) == sizeof(SourceObjectId.BirthObjectId)) {
  5969. return (STATUS_SUCCESS);
  5970. }
  5971. //
  5972. // Inform the user-mode link tracking service that the file
  5973. // has been moved.
  5974. //
  5975. NormalizedObjectId = SourceObjectId;
  5976. NormalizedObjectId.BirthVolumeId[0] &= 0xfe;
  5977. status = IopSendMessageToTrackService( &SourceVolumeId,
  5978. &NormalizedObjectId,
  5979. FileInformation );
  5980. if (!NT_SUCCESS( status )) {
  5981. return status;
  5982. }
  5983. } // if (trackingInfo->DestinationFile) ... else
  5984. } else { // if (IsFileLocal( FileObject ))
  5985. //
  5986. // The source file is remote. For this case, remote the operation
  5987. // to the system on which the source file is located. Begin by
  5988. // ensuring that the source file actually has an object ID. If
  5989. // not, then get out now since there is nothing to be done.
  5990. //
  5991. status = IopGetSetObjectId( FileObject,
  5992. &SourceObjectId,
  5993. sizeof( SourceObjectId ),
  5994. FSCTL_GET_OBJECT_ID );
  5995. if (status == STATUS_OBJECT_NAME_NOT_FOUND)
  5996. {
  5997. return STATUS_SUCCESS;
  5998. }
  5999. if (!NT_SUCCESS( status )) {
  6000. return status;
  6001. }
  6002. //
  6003. // If the extended info field is zero then this file
  6004. // has no interesting tracking information.
  6005. //
  6006. if (RtlCompareMemoryUlong(SourceObjectId.BirthObjectId,
  6007. sizeof(SourceObjectId.BirthObjectId),
  6008. 0) == sizeof(SourceObjectId.BirthObjectId)) {
  6009. return (STATUS_SUCCESS);
  6010. }
  6011. if (trackingInfo->DestinationFile) {
  6012. //
  6013. // A handle was specified for the destination file. Determine
  6014. // whether it is local or remote. If remote and both handles
  6015. // refer to the same machine, then ship the entire API to that
  6016. // machine and have it perform the operation.
  6017. //
  6018. // Otherwise, query the target file's object ID, and then redo
  6019. // the operation. This will cause the API to be remoted to the
  6020. // machine where the source file resides.
  6021. //
  6022. if (IsFileLocal( dstFileObject )) {
  6023. //
  6024. // The source is remote and the destination is local, so
  6025. // query the object ID of the target and recursively track
  6026. // the link from the source file's remote node.
  6027. //
  6028. status = IopGetVolumeId( dstFileObject,
  6029. &TargetVolumeId,
  6030. sizeof( TargetVolumeId ) );
  6031. if (!NT_SUCCESS( status )) {
  6032. return status;
  6033. }
  6034. status = IopGetSetObjectId( dstFileObject,
  6035. &TargetObjectId,
  6036. sizeof( TargetObjectId ),
  6037. FSCTL_CREATE_OR_GET_OBJECT_ID );
  6038. if (!NT_SUCCESS( status )) {
  6039. return status;
  6040. }
  6041. //
  6042. // Notify the tracking system of the move.
  6043. //
  6044. IopMarshalIds( &trackingBuffer, &TargetVolumeId, &TargetObjectId, trackingInfo );
  6045. status = IopTrackLink( FileObject,
  6046. IoStatusBlock,
  6047. &trackingBuffer.TrackingInformation,
  6048. FIELD_OFFSET( FILE_TRACKING_INFORMATION,
  6049. ObjectInformation ) +
  6050. trackingBuffer.TrackingInformation.ObjectInformationLength,
  6051. Event,
  6052. KernelMode );
  6053. if( !NT_SUCCESS(status) ) {
  6054. return status;
  6055. }
  6056. //
  6057. // Delete the ID from the source
  6058. //
  6059. status = IopGetSetObjectId( FileObject,
  6060. NULL,
  6061. 0,
  6062. FSCTL_DELETE_OBJECT_ID );
  6063. if( !NT_SUCCESS( status )) {
  6064. return status;
  6065. }
  6066. //
  6067. // Set the birth ID on the target, also turning on the bit
  6068. // that indicates that this file has moved across volumes.
  6069. //
  6070. CrossVolumeObjectId = SourceObjectId;
  6071. CrossVolumeObjectId.BirthVolumeId[0] |= 1;
  6072. status = IopGetSetObjectId( dstFileObject,
  6073. &CrossVolumeObjectId.ExtendedInfo[0],
  6074. sizeof( CrossVolumeObjectId.ExtendedInfo ),
  6075. FSCTL_SET_OBJECT_ID_EXTENDED );
  6076. if( !NT_SUCCESS( status )) {
  6077. IopGetSetObjectId( FileObject,
  6078. &SourceObjectId,
  6079. sizeof(SourceObjectId),
  6080. FSCTL_SET_OBJECT_ID );
  6081. return status;
  6082. }
  6083. } // if (IsFileLocal( dstFileObject ))
  6084. else if (!IopIsSameMachine( FileObject, trackingInfo->DestinationFile)) {
  6085. //
  6086. // The source and the target are remote from each other and from
  6087. // this machine. Query the object ID of the target and recursively
  6088. // track the link from the source file's remote node.
  6089. //
  6090. //
  6091. // Query the volume ID of the target.
  6092. //
  6093. status = IopGetSetObjectId( dstFileObject,
  6094. &TargetVolumeId,
  6095. sizeof( FILE_VOLUMEID_WITH_TYPE ),
  6096. FSCTL_LMR_GET_LINK_TRACKING_INFORMATION );
  6097. if (!NT_SUCCESS( status )) {
  6098. return status;
  6099. }
  6100. //
  6101. // Query the object ID of the target.
  6102. //
  6103. status = IopGetSetObjectId( dstFileObject,
  6104. &TargetObjectId,
  6105. sizeof( TargetObjectId ),
  6106. FSCTL_CREATE_OR_GET_OBJECT_ID );
  6107. if( !NT_SUCCESS( status )) {
  6108. return status;
  6109. }
  6110. //
  6111. // Notify the tracking system of the move.
  6112. //
  6113. IopMarshalIds( &trackingBuffer, &TargetVolumeId, &TargetObjectId, trackingInfo );
  6114. status = IopTrackLink( FileObject,
  6115. IoStatusBlock,
  6116. &trackingBuffer.TrackingInformation,
  6117. FIELD_OFFSET( FILE_TRACKING_INFORMATION,
  6118. ObjectInformation ) +
  6119. trackingBuffer.TrackingInformation.ObjectInformationLength,
  6120. Event,
  6121. KernelMode );
  6122. if( !NT_SUCCESS( status )) {
  6123. return status;
  6124. }
  6125. //
  6126. // Set the birth ID on the target, turning on the bit that indicates
  6127. // that this file has moved across volumes.
  6128. //
  6129. CrossVolumeObjectId = SourceObjectId;
  6130. CrossVolumeObjectId.BirthVolumeId[0] |= 1;
  6131. status = IopGetSetObjectId( dstFileObject,
  6132. &CrossVolumeObjectId.ExtendedInfo[0],
  6133. sizeof( CrossVolumeObjectId.ExtendedInfo ),
  6134. FSCTL_SET_OBJECT_ID_EXTENDED );
  6135. if( !NT_SUCCESS( status )) {
  6136. IopGetSetObjectId( FileObject,
  6137. &SourceObjectId,
  6138. sizeof(SourceObjectId),
  6139. FSCTL_SET_OBJECT_ID );
  6140. return status;
  6141. }
  6142. } else { // else if (!IopIsSameMachine( FileObject, trackingInfo->DestinationFile))
  6143. //
  6144. // Both the source and the target are remote and they're
  6145. // both on the same remote machine. For this case, remote
  6146. // the entire API using the file object pointers.
  6147. //
  6148. status = IopSetRemoteLink( FileObject, dstFileObject, trackingInfo );
  6149. } // else if (!IopIsSameMachine( FileObject, trackingInfo->DestinationFile)) ... else
  6150. } else { // if (trackingInfo->DestinationFile)
  6151. //
  6152. // The source file is remote and the object ID of the target is
  6153. // contained w/in the tracking buffer. Simply remote the API
  6154. // to the remote machine using the source file object pointer
  6155. // and the object ID of the target in the buffer.
  6156. //
  6157. status = IopSetRemoteLink( FileObject, NULL, FileInformation );
  6158. } // if (trackingInfo->DestinationFile) ... else
  6159. } // if (IsFileLocal( FileObject )) ... else
  6160. } finally {
  6161. //
  6162. // Ensure that everything has been cleaned up.
  6163. //
  6164. if (RequestorMode != KernelMode && trackingInfo) {
  6165. ExFreePool( trackingInfo );
  6166. }
  6167. if (dstFileObject ) {
  6168. ObDereferenceObject( dstFileObject );
  6169. }
  6170. KeSetEvent( Event, 0, FALSE );
  6171. }
  6172. return status;
  6173. }
  6174. VOID
  6175. IopUserCompletion(
  6176. IN PKAPC Apc,
  6177. IN PKNORMAL_ROUTINE *NormalRoutine,
  6178. IN PVOID *NormalContext,
  6179. IN PVOID *SystemArgument1,
  6180. IN PVOID *SystemArgument2
  6181. )
  6182. /*++
  6183. Routine Description:
  6184. This routine is invoked in the final processing of an IRP. Everything has
  6185. been completed except that the caller's APC routine must be invoked. The
  6186. system will do this as soon as this routine exits. The only processing
  6187. remaining to be completed by the I/O system is to free the I/O Request
  6188. Packet itself.
  6189. Arguments:
  6190. Apc - Supplies a pointer to kernel APC structure.
  6191. NormalRoutine - Supplies a pointer to a pointer to the normal function
  6192. that was specified when the APC was initialied.
  6193. NormalContext - Supplies a pointer to a pointer to an arbitrary data
  6194. structure that was specified when the APC was initialized.
  6195. SystemArgument1, SystemArgument2 - Supplies a set of two pointers to
  6196. two arguments that contain untyped data.
  6197. Return Value:
  6198. None.
  6199. Note:
  6200. If no other processing is ever needed, and the APC can be placed at the
  6201. beginning of the IRP, then this routine could be replaced by simply
  6202. specifying the address of the pool deallocation routine in the APC instead
  6203. of the address of this routine.
  6204. Caution:
  6205. This routine is also invoked as a general purpose rundown routine for APCs.
  6206. Should this code ever need to directly access any of the other parameters
  6207. other than Apc, this routine will need to be split into two separate
  6208. routines. The rundown routine should perform exactly the following code's
  6209. functionality.
  6210. --*/
  6211. {
  6212. UNREFERENCED_PARAMETER( NormalRoutine );
  6213. UNREFERENCED_PARAMETER( NormalContext );
  6214. UNREFERENCED_PARAMETER( SystemArgument1 );
  6215. UNREFERENCED_PARAMETER( SystemArgument2 );
  6216. PAGED_CODE();
  6217. //
  6218. // Free the packet.
  6219. //
  6220. IoFreeIrp( CONTAINING_RECORD( Apc, IRP, Tail.Apc ) );
  6221. }
  6222. VOID
  6223. IopUserRundown(
  6224. IN PKAPC Apc
  6225. )
  6226. /*++
  6227. Routine Description:
  6228. This routine is invoked during thread termination as the rundown routine
  6229. for it simply calls IopUserCompletion.
  6230. Arguments:
  6231. Apc - Supplies a pointer to kernel APC structure.
  6232. Return Value:
  6233. None.
  6234. --*/
  6235. {
  6236. PAGED_CODE();
  6237. //
  6238. // Free the packet.
  6239. //
  6240. IoFreeIrp( CONTAINING_RECORD( Apc, IRP, Tail.Apc ) );
  6241. }
  6242. NTSTATUS
  6243. IopXxxControlFile(
  6244. IN HANDLE FileHandle,
  6245. IN HANDLE Event OPTIONAL,
  6246. IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  6247. IN PVOID ApcContext OPTIONAL,
  6248. OUT PIO_STATUS_BLOCK IoStatusBlock,
  6249. IN ULONG IoControlCode,
  6250. IN PVOID InputBuffer OPTIONAL,
  6251. IN ULONG InputBufferLength,
  6252. OUT PVOID OutputBuffer OPTIONAL,
  6253. IN ULONG OutputBufferLength,
  6254. IN BOOLEAN DeviceIoControl
  6255. )
  6256. /*++
  6257. Routine Description:
  6258. This service builds descriptors or MDLs for the supplied buffer(s) and
  6259. passes the untyped data to the driver associated with the file handle.
  6260. handle. It is up to the driver to check the input data and function
  6261. IoControlCode for validity, as well as to make the appropriate access
  6262. checks.
  6263. Arguments:
  6264. FileHandle - Supplies a handle to the file on which the service is being
  6265. performed.
  6266. Event - Supplies an optional event to be set to the Signaled state when
  6267. the service is complete.
  6268. ApcRoutine - Supplies an optional APC routine to be executed when the
  6269. service is complete.
  6270. ApcContext - Supplies a context parameter to be passed to the ApcRoutine,
  6271. if an ApcRoutine was specified.
  6272. IoStatusBlock - Address of the caller's I/O status block.
  6273. IoControlCode - Subfunction code to determine exactly what operation is
  6274. being performed.
  6275. InputBuffer - Optionally supplies an input buffer to be passed to the
  6276. driver. Whether or not the buffer is actually optional is dependent
  6277. on the IoControlCode.
  6278. InputBufferLength - Length of the InputBuffer in bytes.
  6279. OutputBuffer - Optionally supplies an output buffer to receive information
  6280. from the driver. Whether or not the buffer is actually optional is
  6281. dependent on the IoControlCode.
  6282. OutputBufferLength - Length of the OutputBuffer in bytes.
  6283. DeviceIoControl - Determines whether this is a Device or File System
  6284. Control function.
  6285. Return Value:
  6286. The status returned is success if the control operation was properly
  6287. queued to the I/O system. Once the operation completes, the status
  6288. can be determined by examining the Status field of the I/O status block.
  6289. --*/
  6290. {
  6291. PIRP irp;
  6292. NTSTATUS status;
  6293. PFILE_OBJECT fileObject;
  6294. PDEVICE_OBJECT deviceObject;
  6295. PKEVENT eventObject = (PKEVENT) NULL;
  6296. PIO_STACK_LOCATION irpSp;
  6297. ULONG method;
  6298. OBJECT_HANDLE_INFORMATION handleInformation;
  6299. BOOLEAN synchronousIo;
  6300. IO_STATUS_BLOCK localIoStatus;
  6301. PFAST_IO_DISPATCH fastIoDispatch;
  6302. POOL_TYPE poolType;
  6303. PULONG majorFunction;
  6304. KPROCESSOR_MODE requestorMode;
  6305. PETHREAD CurrentThread;
  6306. PAGED_CODE();
  6307. //
  6308. // Get the method that the buffers are being passed by.
  6309. //
  6310. method = IoControlCode & 3;
  6311. //
  6312. // Check the caller's parameters based on the mode of the caller.
  6313. //
  6314. CurrentThread = PsGetCurrentThread ();
  6315. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  6316. if (requestorMode != KernelMode) {
  6317. //
  6318. // The caller's access mode is not kernel so probe each of the arguments
  6319. // and capture them as necessary. If any failures occur, the condition
  6320. // handler will be invoked to handle them. It will simply cleanup and
  6321. // return an access violation status code back to the system service
  6322. // dispatcher.
  6323. //
  6324. try {
  6325. //
  6326. // The IoStatusBlock parameter must be writeable by the caller.
  6327. //
  6328. ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine);
  6329. //
  6330. // The output buffer can be used in any one of the following three ways,
  6331. // if it is specified:
  6332. //
  6333. // 0) It can be a normal, buffered output buffer.
  6334. //
  6335. // 1) It can be a DMA input buffer.
  6336. //
  6337. // 2) It can be a DMA output buffer.
  6338. //
  6339. // Which way the buffer is to be used it based on the low-order two bits
  6340. // of the IoControlCode.
  6341. //
  6342. // If the method is 0 we probe the output buffer for write access.
  6343. // If the method is not 3 we probe the input buffer for read access.
  6344. //
  6345. if (method == METHOD_BUFFERED) {
  6346. if (ARGUMENT_PRESENT( OutputBuffer )) {
  6347. ProbeForWrite( OutputBuffer,
  6348. OutputBufferLength,
  6349. sizeof( UCHAR ) );
  6350. } else {
  6351. OutputBufferLength = 0;
  6352. }
  6353. }
  6354. if (method != METHOD_NEITHER) {
  6355. if (ARGUMENT_PRESENT( InputBuffer )) {
  6356. ProbeForRead( InputBuffer,
  6357. InputBufferLength,
  6358. sizeof( UCHAR ) );
  6359. } else {
  6360. InputBufferLength = 0;
  6361. }
  6362. }
  6363. } except(EXCEPTION_EXECUTE_HANDLER) {
  6364. //
  6365. // An exception was incurred while attempting to probe or write
  6366. // one of the caller's parameters. Simply return an appropriate
  6367. // error status code.
  6368. //
  6369. return GetExceptionCode();
  6370. }
  6371. }
  6372. //
  6373. // There were no blatant errors so far, so reference the file object so
  6374. // the target device object can be found. Note that if the handle does
  6375. // not refer to a file object, or if the caller does not have the required
  6376. // access to the file, then it will fail.
  6377. //
  6378. status = ObReferenceObjectByHandle( FileHandle,
  6379. 0L,
  6380. IoFileObjectType,
  6381. requestorMode,
  6382. (PVOID *) &fileObject,
  6383. &handleInformation );
  6384. if (!NT_SUCCESS( status )) {
  6385. return status;
  6386. }
  6387. //
  6388. // If this file has an I/O completion port associated w/it, then ensure
  6389. // that the caller did not supply an APC routine, as the two are mutually
  6390. // exclusive methods for I/O completion notification.
  6391. //
  6392. if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
  6393. ObDereferenceObject( fileObject );
  6394. return STATUS_INVALID_PARAMETER;
  6395. }
  6396. //
  6397. // Now check the access type for this control code to ensure that the
  6398. // caller has the appropriate access to this file object to perform the
  6399. // operation.
  6400. //
  6401. if (requestorMode != KernelMode) {
  6402. ULONG accessMode = (IoControlCode >> 14) & 3;
  6403. if (accessMode != FILE_ANY_ACCESS) {
  6404. //
  6405. // This I/O control requires that the caller have read, write,
  6406. // or read/write access to the object. If this is not the case,
  6407. // then cleanup and return an appropriate error status code.
  6408. //
  6409. if (SeComputeGrantedAccesses( handleInformation.GrantedAccess, accessMode ) != accessMode ) {
  6410. ObDereferenceObject( fileObject );
  6411. return STATUS_ACCESS_DENIED;
  6412. }
  6413. }
  6414. }
  6415. //
  6416. // Get the address of the event object and set the event to the Not-
  6417. // Signaled state, if an event was specified. Note here, too, that if
  6418. // the handle does not refer to an event, or if the event cannot be
  6419. // written, then the reference will fail.
  6420. //
  6421. if (ARGUMENT_PRESENT( Event )) {
  6422. status = ObReferenceObjectByHandle( Event,
  6423. EVENT_MODIFY_STATE,
  6424. ExEventObjectType,
  6425. requestorMode,
  6426. (PVOID *) &eventObject,
  6427. NULL );
  6428. if (!NT_SUCCESS( status )) {
  6429. ObDereferenceObject( fileObject );
  6430. return status;
  6431. } else {
  6432. KeClearEvent( eventObject );
  6433. }
  6434. }
  6435. //
  6436. // Make a special check here to determine whether this is a synchronous
  6437. // I/O operation. If it is, then wait here until the file is owned by
  6438. // the current thread.
  6439. //
  6440. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  6441. BOOLEAN interrupted;
  6442. if (!IopAcquireFastLock( fileObject )) {
  6443. status = IopAcquireFileObjectLock( fileObject,
  6444. requestorMode,
  6445. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  6446. &interrupted );
  6447. if (interrupted) {
  6448. if (eventObject) {
  6449. ObDereferenceObject( eventObject );
  6450. }
  6451. ObDereferenceObject( fileObject );
  6452. return status;
  6453. }
  6454. }
  6455. synchronousIo = TRUE;
  6456. } else {
  6457. synchronousIo = FALSE;
  6458. }
  6459. //
  6460. // Get the address of the target device object. If this file represents
  6461. // a device that was opened directly, then simply use the device or its
  6462. // attached device(s) directly.
  6463. //
  6464. if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  6465. deviceObject = IoGetRelatedDeviceObject( fileObject );
  6466. } else {
  6467. deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
  6468. }
  6469. if (DeviceIoControl) {
  6470. //
  6471. // Also get the address of the Fast I/O dispatch structure.
  6472. //
  6473. fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  6474. //
  6475. // Turbo device control support. If the device has a fast I/O entry
  6476. // point for DeviceIoControlFile, call the entry point and give it a
  6477. // chance to try to complete the request. Note if FastIoDeviceControl
  6478. // returns FALSE or we get an I/O error, we simply fall through and
  6479. // go the "long way" and create an Irp.
  6480. //
  6481. if (fastIoDispatch && fastIoDispatch->FastIoDeviceControl) {
  6482. //
  6483. // Before we actually call the fast I/O routine in the driver,
  6484. // we must probe OutputBuffer if the method is METHOD_IN_DIRECT or METHOD_OUT_DIRECT.
  6485. //
  6486. if (requestorMode != KernelMode && ARGUMENT_PRESENT(OutputBuffer)) {
  6487. try {
  6488. if (method == METHOD_IN_DIRECT) {
  6489. ProbeForRead( OutputBuffer,
  6490. OutputBufferLength,
  6491. sizeof( UCHAR ) );
  6492. } else if (method == METHOD_OUT_DIRECT) {
  6493. ProbeForWrite( OutputBuffer,
  6494. OutputBufferLength,
  6495. sizeof( UCHAR ) );
  6496. }
  6497. } except(EXCEPTION_EXECUTE_HANDLER) {
  6498. //
  6499. // An exception was incurred while attempting to probe
  6500. // the output buffer. Clean up and return an
  6501. // appropriate error status code.
  6502. //
  6503. if (synchronousIo) {
  6504. IopReleaseFileObjectLock( fileObject );
  6505. }
  6506. if (eventObject) {
  6507. ObDereferenceObject( eventObject );
  6508. }
  6509. ObDereferenceObject( fileObject );
  6510. return GetExceptionCode();
  6511. }
  6512. }
  6513. //
  6514. // If we are dismounting a volume, increment the shared count. This
  6515. // allows user-space applications to efficiently test for validity
  6516. // of current directory handles.
  6517. //
  6518. if (IoControlCode == FSCTL_DISMOUNT_VOLUME) {
  6519. InterlockedIncrement( (PLONG) &SharedUserData->DismountCount );
  6520. }
  6521. //
  6522. // Call the driver's fast I/O routine.
  6523. //
  6524. if (fastIoDispatch->FastIoDeviceControl( fileObject,
  6525. TRUE,
  6526. InputBuffer,
  6527. InputBufferLength,
  6528. OutputBuffer,
  6529. OutputBufferLength,
  6530. IoControlCode,
  6531. &localIoStatus,
  6532. deviceObject )) {
  6533. //
  6534. // The driver successfully performed the I/O in it's
  6535. // fast device control routine. Carefully return the
  6536. // I/O status.
  6537. //
  6538. try {
  6539. #if defined(_WIN64)
  6540. //
  6541. // If this is a32-bit thread, and the IO request is
  6542. // asynchronous, then the IOSB is 32-bit. Wow64 always sends
  6543. // the 32-bit IOSB when the I/O is asynchronous.
  6544. //
  6545. if (IopIsIosb32(ApcRoutine)) {
  6546. PIO_STATUS_BLOCK32 UserIosb32 = (PIO_STATUS_BLOCK32)IoStatusBlock;
  6547. UserIosb32->Information = (ULONG)localIoStatus.Information;
  6548. UserIosb32->Status = (NTSTATUS)localIoStatus.Status;
  6549. } else {
  6550. *IoStatusBlock = localIoStatus;
  6551. }
  6552. #else
  6553. *IoStatusBlock = localIoStatus;
  6554. #endif
  6555. } except( EXCEPTION_EXECUTE_HANDLER ) {
  6556. localIoStatus.Status = GetExceptionCode();
  6557. localIoStatus.Information = 0;
  6558. }
  6559. //
  6560. // If an event was specified, set it.
  6561. //
  6562. if (ARGUMENT_PRESENT( Event )) {
  6563. KeSetEvent( eventObject, 0, FALSE );
  6564. ObDereferenceObject( eventObject );
  6565. }
  6566. //
  6567. // Note that the file object event need not be set to the
  6568. // Signaled state, as it is already set. Release the
  6569. // file object lock, if necessary.
  6570. //
  6571. if (synchronousIo) {
  6572. IopReleaseFileObjectLock( fileObject );
  6573. }
  6574. //
  6575. // If this file object has a completion port associated with it
  6576. // and this request has a non-NULL APC context then a completion
  6577. // message needs to be queued.
  6578. //
  6579. if (fileObject->CompletionContext && ARGUMENT_PRESENT( ApcContext )) {
  6580. if (!NT_SUCCESS(IoSetIoCompletion( fileObject->CompletionContext->Port,
  6581. fileObject->CompletionContext->Key,
  6582. ApcContext,
  6583. localIoStatus.Status,
  6584. localIoStatus.Information,
  6585. TRUE ))) {
  6586. localIoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  6587. }
  6588. }
  6589. //
  6590. // Cleanup and return.
  6591. //
  6592. ObDereferenceObject( fileObject );
  6593. return localIoStatus.Status;
  6594. }
  6595. }
  6596. }
  6597. //
  6598. // Set the file object to the Not-Signaled state.
  6599. //
  6600. KeClearEvent( &fileObject->Event );
  6601. //
  6602. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  6603. irp = IopAllocateIrp( deviceObject->StackSize, TRUE );
  6604. if (!irp) {
  6605. //
  6606. // An IRP could not be allocated. Cleanup and return an appropriate
  6607. // error status code.
  6608. //
  6609. IopAllocateIrpCleanup( fileObject, eventObject );
  6610. return STATUS_INSUFFICIENT_RESOURCES;
  6611. }
  6612. irp->Tail.Overlay.OriginalFileObject = fileObject;
  6613. irp->Tail.Overlay.Thread = CurrentThread;
  6614. irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
  6615. irp->RequestorMode = requestorMode;
  6616. irp->PendingReturned = FALSE;
  6617. irp->Cancel = FALSE;
  6618. irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
  6619. //
  6620. // Fill in the service independent parameters in the IRP.
  6621. //
  6622. irp->UserEvent = eventObject;
  6623. irp->UserIosb = IoStatusBlock;
  6624. irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
  6625. irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
  6626. //
  6627. // Get a pointer to the stack location for the first driver. This will be
  6628. // used to pass the original function codes and parameters. Note that
  6629. // setting the major function here also sets:
  6630. //
  6631. // MinorFunction = 0;
  6632. // Flags = 0;
  6633. // Control = 0;
  6634. //
  6635. irpSp = IoGetNextIrpStackLocation( irp );
  6636. majorFunction = (PULONG) (&irpSp->MajorFunction);
  6637. *majorFunction = DeviceIoControl ? IRP_MJ_DEVICE_CONTROL : IRP_MJ_FILE_SYSTEM_CONTROL;
  6638. irpSp->FileObject = fileObject;
  6639. //
  6640. // Copy the caller's parameters to the service-specific portion of the
  6641. // IRP for those parameters that are the same for all three methods.
  6642. //
  6643. irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  6644. irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  6645. irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  6646. //
  6647. // Set the pool type based on the type of function being performed.
  6648. //
  6649. poolType = DeviceIoControl ? NonPagedPoolCacheAligned : NonPagedPool;
  6650. //
  6651. // Based on the method that the buffer are being passed, either allocate
  6652. // buffers or build MDLs. Note that in some cases no probing has taken
  6653. // place so the exception handler must catch access violations.
  6654. //
  6655. irp->MdlAddress = (PMDL) NULL;
  6656. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  6657. switch ( method ) {
  6658. case METHOD_BUFFERED:
  6659. //
  6660. // For this case, allocate a buffer that is large enough to contain
  6661. // both the input and the output buffers. Copy the input buffer to
  6662. // the allocated buffer and set the appropriate IRP fields.
  6663. //
  6664. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) NULL;
  6665. try {
  6666. if (InputBufferLength || OutputBufferLength) {
  6667. irp->AssociatedIrp.SystemBuffer =
  6668. ExAllocatePoolWithQuota( poolType,
  6669. (InputBufferLength > OutputBufferLength) ? InputBufferLength : OutputBufferLength );
  6670. if (ARGUMENT_PRESENT( InputBuffer )) {
  6671. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
  6672. InputBuffer,
  6673. InputBufferLength );
  6674. }
  6675. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  6676. irp->UserBuffer = OutputBuffer;
  6677. if (ARGUMENT_PRESENT( OutputBuffer )) {
  6678. irp->Flags |= IRP_INPUT_OPERATION;
  6679. }
  6680. } else {
  6681. irp->Flags = 0;
  6682. irp->UserBuffer = (PVOID) NULL;
  6683. }
  6684. } except(EXCEPTION_EXECUTE_HANDLER) {
  6685. //
  6686. // An exception was incurred while either allocating the
  6687. // the system buffer or moving the caller's data. Determine
  6688. // what actually happened, cleanup accordingly, and return
  6689. // an appropriate error status code.
  6690. //
  6691. IopExceptionCleanup( fileObject,
  6692. irp,
  6693. eventObject,
  6694. (PKEVENT) NULL );
  6695. return GetExceptionCode();
  6696. }
  6697. break;
  6698. case METHOD_IN_DIRECT:
  6699. case METHOD_OUT_DIRECT:
  6700. //
  6701. // For these two cases, allocate a buffer that is large enough to
  6702. // contain the input buffer, if any, and copy the information to
  6703. // the allocated buffer. Then build an MDL for either read or write
  6704. // access, depending on the method, for the output buffer. Note
  6705. // that the buffer length parameters have been jammed to zero for
  6706. // users if the buffer parameter was not passed. (Kernel callers
  6707. // should be calling the service correctly in the first place.)
  6708. //
  6709. // Note also that it doesn't make a whole lot of sense to specify
  6710. // either method #1 or #2 if the IOCTL does not require the caller
  6711. // to specify an output buffer.
  6712. //
  6713. irp->Flags = 0;
  6714. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) NULL;
  6715. try {
  6716. if (InputBufferLength && ARGUMENT_PRESENT( InputBuffer )) {
  6717. irp->AssociatedIrp.SystemBuffer =
  6718. ExAllocatePoolWithQuota( poolType,
  6719. InputBufferLength );
  6720. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
  6721. InputBuffer,
  6722. InputBufferLength );
  6723. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  6724. }
  6725. if (OutputBufferLength != 0) {
  6726. irp->MdlAddress = IoAllocateMdl( OutputBuffer,
  6727. OutputBufferLength,
  6728. FALSE,
  6729. TRUE,
  6730. irp );
  6731. if (irp->MdlAddress == NULL) {
  6732. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  6733. }
  6734. IopProbeAndLockPages( irp->MdlAddress,
  6735. requestorMode,
  6736. (LOCK_OPERATION) ((method == 1) ? IoReadAccess : IoWriteAccess),
  6737. deviceObject,
  6738. *majorFunction);
  6739. }
  6740. } except(EXCEPTION_EXECUTE_HANDLER) {
  6741. //
  6742. // An exception was incurred while either allocating the
  6743. // system buffer, copying the caller's data, allocating the
  6744. // MDL, or probing and locking the caller's buffer. Determine
  6745. // what actually happened, cleanup accordingly, and return
  6746. // an appropriate error status code.
  6747. //
  6748. IopExceptionCleanup( fileObject,
  6749. irp,
  6750. eventObject,
  6751. (PKEVENT) NULL );
  6752. return GetExceptionCode();
  6753. }
  6754. break;
  6755. case METHOD_NEITHER:
  6756. //
  6757. // For this case, do nothing. Everything is up to the driver.
  6758. // Simply give the driver a copy of the caller's parameters and
  6759. // let the driver do everything itself.
  6760. //
  6761. irp->Flags = 0;
  6762. irp->UserBuffer = OutputBuffer;
  6763. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
  6764. }
  6765. //
  6766. // Pass the read/write access granted bits down to the driver. This allows drivers to check
  6767. // access for ioctls that were mistakenly defined as FILE_ANY_ACCESS and cannot be redefined for
  6768. // compatibility reasons.
  6769. //
  6770. irpSp->Flags |= SeComputeGrantedAccesses( handleInformation.GrantedAccess, FILE_READ_DATA ) ? SL_READ_ACCESS_GRANTED : 0;
  6771. irpSp->Flags |= SeComputeGrantedAccesses( handleInformation.GrantedAccess, FILE_WRITE_DATA ) ? SL_WRITE_ACCESS_GRANTED : 0;
  6772. //
  6773. // Defer I/O completion for FSCTL requests, but not for IOCTL requests,
  6774. // since file systems set pending properly but device driver do not.
  6775. //
  6776. if (!DeviceIoControl) {
  6777. irp->Flags |= IRP_DEFER_IO_COMPLETION;
  6778. }
  6779. //
  6780. // If we are dismounting a volume, increment the shared count. This
  6781. // allows user-space applications to efficiently test for validity
  6782. // of current directory handles.
  6783. //
  6784. if (IoControlCode == FSCTL_DISMOUNT_VOLUME) {
  6785. InterlockedIncrement( (PLONG) &SharedUserData->DismountCount );
  6786. }
  6787. //
  6788. // Queue the packet, call the driver, and synchronize appropriately with
  6789. // I/O completion.
  6790. //
  6791. return IopSynchronousServiceTail( deviceObject,
  6792. irp,
  6793. fileObject,
  6794. (BOOLEAN)!DeviceIoControl,
  6795. requestorMode,
  6796. synchronousIo,
  6797. OtherTransfer );
  6798. }
  6799. NTSTATUS
  6800. IopLookupBusStringFromID (
  6801. IN HANDLE KeyHandle,
  6802. IN INTERFACE_TYPE InterfaceType,
  6803. OUT PWCHAR Buffer,
  6804. IN ULONG Length,
  6805. OUT PULONG BusFlags OPTIONAL
  6806. )
  6807. /*++
  6808. Routine Description:
  6809. Translates INTERFACE_TYPE to its corresponding WCHAR[] string.
  6810. Arguments:
  6811. KeyHandle - Supplies a handle to the opened registry key,
  6812. HKLM\System\CurrentControlSet\Control\SystemResources\BusValues.
  6813. InterfaceType - Supplies the interface type for which a descriptive
  6814. name is to be retrieved.
  6815. Buffer - Supplies a pointer to a unicode character buffer that will
  6816. receive the bus name. Since this buffer is used in an
  6817. intermediate step to retrieve a KEY_VALUE_FULL_INFORMATION structure,
  6818. it must be large enough to contain this structure (including the
  6819. longest value name & data length under KeyHandle).
  6820. Length - Supplies the length, in bytes, of the Buffer.
  6821. BusFlags - Optionally receives the flags specified in the second
  6822. DWORD of the matching REG_BINARY value.
  6823. Return Value:
  6824. The function value is the final status of the operation.
  6825. --*/
  6826. {
  6827. NTSTATUS status;
  6828. ULONG Index, junk, i, j;
  6829. PULONG pl;
  6830. PKEY_VALUE_FULL_INFORMATION KeyInformation;
  6831. WCHAR c;
  6832. PAGED_CODE();
  6833. Index = 0;
  6834. KeyInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
  6835. for (; ;) {
  6836. status = ZwEnumerateValueKey (
  6837. KeyHandle,
  6838. Index++,
  6839. KeyValueFullInformation,
  6840. Buffer,
  6841. Length,
  6842. &junk
  6843. );
  6844. if (!NT_SUCCESS (status)) {
  6845. return status;
  6846. }
  6847. if (KeyInformation->Type != REG_BINARY) {
  6848. continue;
  6849. }
  6850. pl = (PULONG) ((PUCHAR) KeyInformation + KeyInformation->DataOffset);
  6851. if ((ULONG) InterfaceType != pl[0]) {
  6852. continue;
  6853. }
  6854. //
  6855. // Found a match - move the name to the start of the buffer
  6856. //
  6857. if(ARGUMENT_PRESENT(BusFlags)) {
  6858. *BusFlags = pl[1];
  6859. }
  6860. j = KeyInformation->NameLength / sizeof (WCHAR);
  6861. for (i=0; i < j; i++) {
  6862. c = KeyInformation->Name[i];
  6863. Buffer[i] = c;
  6864. }
  6865. Buffer[i] = 0;
  6866. return STATUS_SUCCESS;
  6867. }
  6868. }
  6869. BOOLEAN
  6870. IopSafebootDriverLoad(
  6871. PUNICODE_STRING DriverId
  6872. )
  6873. /*++
  6874. Routine Description:
  6875. Checks to see if a driver or service is included
  6876. in the current safeboot registry section.
  6877. Arguments:
  6878. DriverId - Specifies which driver is to be validated.
  6879. The string should contain a driver executable name
  6880. like foo.sys or a GUID for a pnp driver class.
  6881. Return Value:
  6882. TRUE - driver/service is in the registry
  6883. FALSE - driver/service is NOT in the registry
  6884. --*/
  6885. {
  6886. NTSTATUS status;
  6887. HANDLE hSafeBoot,hGuid;
  6888. UNICODE_STRING safeBootKey;
  6889. UNICODE_STRING SafeBootTypeString;
  6890. //
  6891. // set the first part of the registry key name
  6892. //
  6893. switch (InitSafeBootMode) {
  6894. case SAFEBOOT_MINIMAL:
  6895. RtlInitUnicodeString(&SafeBootTypeString,SAFEBOOT_MINIMAL_STR_W);
  6896. break;
  6897. case SAFEBOOT_NETWORK:
  6898. RtlInitUnicodeString(&SafeBootTypeString,SAFEBOOT_NETWORK_STR_W);
  6899. break;
  6900. case SAFEBOOT_DSREPAIR:
  6901. return TRUE;
  6902. default:
  6903. KdPrint(("SAFEBOOT: invalid safeboot option = %d\n",InitSafeBootMode));
  6904. return FALSE;
  6905. }
  6906. safeBootKey.Length = 0;
  6907. safeBootKey.MaximumLength = DriverId->Length + SafeBootTypeString.Length + (4*sizeof(WCHAR));
  6908. safeBootKey.Buffer = (PWCHAR)ExAllocatePool(PagedPool,safeBootKey.MaximumLength);
  6909. if (!safeBootKey.Buffer) {
  6910. KdPrint(("SAFEBOOT: could not allocate pool\n"));
  6911. return FALSE;
  6912. }
  6913. RtlCopyUnicodeString(&safeBootKey,&SafeBootTypeString);
  6914. status = RtlAppendUnicodeToString(&safeBootKey,L"\\");
  6915. if (!NT_SUCCESS(status)) {
  6916. ExFreePool (safeBootKey.Buffer);
  6917. KdPrint(("SAFEBOOT: could not create registry key string = %x\n",status));
  6918. return FALSE;
  6919. }
  6920. status = RtlAppendUnicodeStringToString(&safeBootKey,DriverId);
  6921. if (!NT_SUCCESS(status)) {
  6922. ExFreePool (safeBootKey.Buffer);
  6923. KdPrint(("SAFEBOOT: could not create registry key string = %x\n",status));
  6924. return FALSE;
  6925. }
  6926. status = IopOpenRegistryKey (
  6927. &hSafeBoot,
  6928. NULL,
  6929. &CmRegistryMachineSystemCurrentControlSetControlSafeBoot,
  6930. KEY_ALL_ACCESS,
  6931. FALSE
  6932. );
  6933. if (NT_SUCCESS(status)) {
  6934. status = IopOpenRegistryKey (
  6935. &hGuid,
  6936. hSafeBoot,
  6937. &safeBootKey,
  6938. KEY_ALL_ACCESS,
  6939. FALSE
  6940. );
  6941. NtClose(hSafeBoot);
  6942. if (NT_SUCCESS(status)) {
  6943. NtClose(hGuid);
  6944. ExFreePool(safeBootKey.Buffer);
  6945. return TRUE;
  6946. }
  6947. }
  6948. ExFreePool(safeBootKey.Buffer);
  6949. return FALSE;
  6950. }
  6951. #ifdef ALLOC_DATA_PRAGMA
  6952. #pragma data_seg("PAGEDATA")
  6953. #endif
  6954. static PBOOT_LOG_RECORD BootLogRecord;
  6955. #ifdef ALLOC_DATA_PRAGMA
  6956. #pragma data_seg()
  6957. #endif
  6958. VOID
  6959. IopInitializeBootLogging(
  6960. PLOADER_PARAMETER_BLOCK LoaderBlock,
  6961. PCHAR HeaderString
  6962. )
  6963. /*++
  6964. Routine Description:
  6965. Initializes strings for boot logging.
  6966. Arguments:
  6967. LoaderBlock - the loader parameter block
  6968. Return Value:
  6969. VOID
  6970. --*/
  6971. {
  6972. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  6973. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  6974. ULONG MsgId = 0;
  6975. ANSI_STRING AnsiString;
  6976. NTSTATUS Status;
  6977. PLIST_ENTRY nextEntry;
  6978. PKLDR_DATA_TABLE_ENTRY driverEntry;
  6979. PAGED_CODE();
  6980. if (BootLogRecord != NULL) {
  6981. return;
  6982. }
  6983. BootLogRecord = (PBOOT_LOG_RECORD) ExAllocatePool(NonPagedPool, sizeof(BOOT_LOG_RECORD));
  6984. if (BootLogRecord == NULL) {
  6985. return;
  6986. }
  6987. RtlZeroMemory(BootLogRecord, sizeof(BOOT_LOG_RECORD));
  6988. ExInitializeResourceLite(&BootLogRecord->Resource);
  6989. //
  6990. // No need to do KeEnterCriticalRegion as this is called
  6991. // from system process only.
  6992. //
  6993. ExAcquireResourceExclusiveLite(&BootLogRecord->Resource, TRUE);
  6994. DataTableEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
  6995. KLDR_DATA_TABLE_ENTRY,
  6996. InLoadOrderLinks);
  6997. Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0, BOOTLOG_LOADED, &MessageEntry);
  6998. if (NT_SUCCESS( Status )) {
  6999. AnsiString.Buffer = MessageEntry->Text;
  7000. AnsiString.Length = (USHORT)strlen(MessageEntry->Text);
  7001. AnsiString.MaximumLength = AnsiString.Length + 1;
  7002. RtlAnsiStringToUnicodeString(&BootLogRecord->LoadedString, &AnsiString, TRUE);
  7003. // whack the crlf at the end of the string
  7004. if (BootLogRecord->LoadedString.Length > 2 * sizeof(WCHAR)) {
  7005. BootLogRecord->LoadedString.Length -= 2 * sizeof(WCHAR);
  7006. BootLogRecord->LoadedString.Buffer[BootLogRecord->LoadedString.Length / sizeof(WCHAR)] = UNICODE_NULL;
  7007. }
  7008. }
  7009. Status = RtlFindMessage (DataTableEntry->DllBase, 11, 0, BOOTLOG_NOT_LOADED, &MessageEntry);
  7010. if (NT_SUCCESS( Status )) {
  7011. AnsiString.Buffer = MessageEntry->Text;
  7012. AnsiString.Length = (USHORT)strlen(MessageEntry->Text);
  7013. AnsiString.MaximumLength = AnsiString.Length + 1;
  7014. RtlAnsiStringToUnicodeString(&BootLogRecord->NotLoadedString, &AnsiString, TRUE);
  7015. // whack the crlf at the end of the string
  7016. if (BootLogRecord->NotLoadedString.Length > 2 * sizeof(WCHAR)) {
  7017. BootLogRecord->NotLoadedString.Length -= 2 * sizeof(WCHAR);
  7018. BootLogRecord->NotLoadedString.Buffer[BootLogRecord->NotLoadedString.Length / sizeof(WCHAR)] = UNICODE_NULL;
  7019. }
  7020. }
  7021. // The header string (copied from DebugString in Phase1Initialization) appears to have a leading null byte
  7022. HeaderString++;
  7023. RtlCreateUnicodeStringFromAsciiz(&BootLogRecord->HeaderString, HeaderString);
  7024. // Log the drivers loaded by the boot loader
  7025. ExAcquireResourceSharedLite( &PsLoadedModuleResource, TRUE );
  7026. nextEntry = PsLoadedModuleList.Flink;
  7027. while (nextEntry != &PsLoadedModuleList) {
  7028. //
  7029. // Look at the next boot driver in the list.
  7030. //
  7031. driverEntry = CONTAINING_RECORD( nextEntry,
  7032. KLDR_DATA_TABLE_ENTRY,
  7033. InLoadOrderLinks );
  7034. IopBootLog(&driverEntry->FullDllName, TRUE);
  7035. nextEntry = nextEntry->Flink;
  7036. }
  7037. ExReleaseResourceLite( &PsLoadedModuleResource );
  7038. ExReleaseResourceLite(&BootLogRecord->Resource);
  7039. }
  7040. VOID
  7041. IopBootLog(
  7042. PUNICODE_STRING LogEntry,
  7043. BOOLEAN Loaded
  7044. )
  7045. /*++
  7046. Routine Description:
  7047. Create and write out a log entry. Before NtInitializeRegistry is called, log entries are spooled
  7048. into the registry. When NtInitalizeRegistry is called by the session manager, the
  7049. log file is created if necessary and truncated. Log entries in the registry are
  7050. then copied into the log file and the registry entries are deleted.
  7051. Arguments:
  7052. LogEntry - the text to log.
  7053. Loaded - indicates whether to prepend the "Loaded" string or the "Not Loaded" string.
  7054. Return Value:
  7055. VOID
  7056. --*/
  7057. {
  7058. WCHAR NameBuffer[BOOTLOG_STRSIZE];
  7059. UNICODE_STRING KeyName;
  7060. UNICODE_STRING ValueName;
  7061. UNICODE_STRING CrLf;
  7062. UNICODE_STRING Space;
  7063. NTSTATUS Status;
  7064. WCHAR MessageBuffer[BOOTLOG_STRSIZE];
  7065. UNICODE_STRING MessageString = {
  7066. 0,
  7067. BOOTLOG_STRSIZE,
  7068. &MessageBuffer[0]
  7069. };
  7070. PAGED_CODE();
  7071. if (BootLogRecord == NULL) {
  7072. return;
  7073. }
  7074. //
  7075. // No need to do KeEnterCriticalRegion as this is called
  7076. // from system process only.
  7077. //
  7078. ExAcquireResourceExclusiveLite(&BootLogRecord->Resource, TRUE);
  7079. if (Loaded) {
  7080. RtlCopyUnicodeString(&MessageString, &BootLogRecord->LoadedString);
  7081. } else {
  7082. RtlCopyUnicodeString(&MessageString, &BootLogRecord->NotLoadedString);
  7083. }
  7084. // add a space after the message prefix
  7085. RtlInitUnicodeString(&Space, L" ");
  7086. RtlAppendUnicodeStringToString(&MessageString, &Space);
  7087. RtlAppendUnicodeStringToString(&MessageString, LogEntry);
  7088. // add a CR LF
  7089. RtlInitUnicodeString(&CrLf, L"\r\n");
  7090. RtlAppendUnicodeStringToString(&MessageString, &CrLf);
  7091. swprintf(NameBuffer, L"%d", BootLogRecord->NextKey++);
  7092. RtlCreateUnicodeString(&KeyName, NameBuffer);
  7093. RtlInitUnicodeString(&ValueName, L"");
  7094. if (!BootLogRecord->FileLogging) {
  7095. HANDLE hLogKey, hBootKey;
  7096. Status = IopOpenRegistryKey (
  7097. &hBootKey,
  7098. NULL,
  7099. &CmRegistryMachineSystemCurrentControlSetControlBootLog,
  7100. KEY_ALL_ACCESS,
  7101. TRUE
  7102. );
  7103. if (NT_SUCCESS(Status)) {
  7104. Status = IopOpenRegistryKey (
  7105. &hLogKey,
  7106. hBootKey,
  7107. &KeyName,
  7108. KEY_ALL_ACCESS,
  7109. TRUE
  7110. );
  7111. if (NT_SUCCESS(Status)) {
  7112. Status = IopSetRegistryStringValue(
  7113. hLogKey,
  7114. &ValueName,
  7115. &MessageString
  7116. );
  7117. ZwClose(hLogKey);
  7118. }
  7119. ZwClose(hBootKey);
  7120. }
  7121. } else {
  7122. IopBootLogToFile( &MessageString );
  7123. }
  7124. RtlFreeUnicodeString(&KeyName);
  7125. ExReleaseResourceLite(&BootLogRecord->Resource);
  7126. }
  7127. VOID
  7128. IopCopyBootLogRegistryToFile(
  7129. VOID
  7130. )
  7131. /*++
  7132. Routine Description:
  7133. Copy the text in the registry entries into the log file and delete the registry entries. Set the
  7134. flag that indicates direct logging to the log file.
  7135. Arguments:
  7136. NONE
  7137. Return Value:
  7138. VOID
  7139. --*/
  7140. {
  7141. UNICODE_STRING KeyName;
  7142. WCHAR NameBuffer[BOOTLOG_STRSIZE];
  7143. NTSTATUS Status;
  7144. HANDLE hLogKey, hBootKey;
  7145. ULONG Index;
  7146. PKEY_VALUE_FULL_INFORMATION Information;
  7147. LARGE_INTEGER LocalTime;
  7148. TIME_FIELDS TimeFields;
  7149. CHAR AnsiTimeBuffer[256];
  7150. ANSI_STRING AnsiTimeString;
  7151. UNICODE_STRING UnicodeTimeString;
  7152. UNICODE_STRING LogString;
  7153. PKTHREAD CurrentThread;
  7154. PAGED_CODE();
  7155. if (BootLogRecord == NULL) {
  7156. return;
  7157. }
  7158. CurrentThread = KeGetCurrentThread ();
  7159. KeEnterCriticalRegionThread(CurrentThread);
  7160. ExAcquireResourceExclusiveLite(&BootLogRecord->Resource, TRUE);
  7161. IopBootLogToFile(&BootLogRecord->HeaderString);
  7162. ExSystemTimeToLocalTime(&KeBootTime, &LocalTime);
  7163. RtlTimeToTimeFields(&LocalTime, &TimeFields);
  7164. sprintf(
  7165. AnsiTimeBuffer,
  7166. "%2d %2d %4d %02d:%02d:%02d.%03d\r\n",
  7167. TimeFields.Month,
  7168. TimeFields.Day,
  7169. TimeFields.Year,
  7170. TimeFields.Hour,
  7171. TimeFields.Minute,
  7172. TimeFields.Second,
  7173. TimeFields.Milliseconds
  7174. );
  7175. RtlInitAnsiString(&AnsiTimeString, AnsiTimeBuffer);
  7176. RtlAnsiStringToUnicodeString(&UnicodeTimeString, &AnsiTimeString, TRUE);
  7177. IopBootLogToFile(&UnicodeTimeString);
  7178. RtlFreeUnicodeString(&UnicodeTimeString);
  7179. //
  7180. // Read all of the strings in the registry and write them to the log file.
  7181. // Delete the registry keys when done.
  7182. //
  7183. Status = IopOpenRegistryKey (
  7184. &hBootKey,
  7185. NULL,
  7186. &CmRegistryMachineSystemCurrentControlSetControlBootLog,
  7187. KEY_ALL_ACCESS,
  7188. FALSE
  7189. );
  7190. if (NT_SUCCESS(Status)) {
  7191. for (Index = 0; Index < BootLogRecord->NextKey; Index++) {
  7192. swprintf(NameBuffer, L"%d", Index);
  7193. RtlCreateUnicodeString(&KeyName, NameBuffer);
  7194. Status = IopOpenRegistryKey (
  7195. &hLogKey,
  7196. hBootKey,
  7197. &KeyName,
  7198. KEY_ALL_ACCESS,
  7199. FALSE
  7200. );
  7201. if (NT_SUCCESS(Status)) {
  7202. Status = IopGetRegistryValue(
  7203. hLogKey,
  7204. L"",
  7205. &Information
  7206. );
  7207. if (NT_SUCCESS(Status)){
  7208. RtlInitUnicodeString(&LogString, (PWSTR) ((PUCHAR)Information + Information->DataOffset));
  7209. IopBootLogToFile(&LogString);
  7210. }
  7211. ExFreePool(Information);
  7212. ZwDeleteKey(hLogKey);
  7213. ZwClose(hLogKey);
  7214. }
  7215. }
  7216. ZwDeleteKey(hBootKey);
  7217. ZwClose(hBootKey);
  7218. //
  7219. // Write directly to the file from now on.
  7220. //
  7221. BootLogRecord->FileLogging = TRUE;
  7222. }
  7223. ExReleaseResourceLite(&BootLogRecord->Resource);
  7224. KeLeaveCriticalRegionThread(CurrentThread);
  7225. }
  7226. NTSTATUS
  7227. IopBootLogToFile(
  7228. PUNICODE_STRING String
  7229. )
  7230. /*++
  7231. Routine Description:
  7232. Write the buffer into the log file.
  7233. Arguments:
  7234. Buffer - pointer to the string to write out.
  7235. Length - number of bytes to write
  7236. Return Value:
  7237. The function status is the final status of the operation.
  7238. --*/
  7239. {
  7240. OBJECT_ATTRIBUTES ObjA;
  7241. NTSTATUS Status;
  7242. IO_STATUS_BLOCK IoStatusBlock;
  7243. HANDLE FileHandle;
  7244. WCHAR UnicodeHeader = 0xfeff;
  7245. PKTHREAD CurrentThread;
  7246. PAGED_CODE();
  7247. if (BootLogRecord == NULL) {
  7248. return STATUS_SUCCESS;
  7249. }
  7250. CurrentThread = KeGetCurrentThread ();
  7251. KeEnterCriticalRegionThread(CurrentThread);
  7252. ExAcquireResourceExclusiveLite(&BootLogRecord->Resource, TRUE);
  7253. if (BootLogRecord->LogFileName.Buffer == NULL) {
  7254. RtlInitUnicodeString(&BootLogRecord->LogFileName, L"\\SystemRoot\\ntbtlog.txt");
  7255. }
  7256. InitializeObjectAttributes(&ObjA, &BootLogRecord->LogFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  7257. Status = ZwCreateFile(&FileHandle,
  7258. GENERIC_WRITE,
  7259. &ObjA,
  7260. &IoStatusBlock,
  7261. NULL,
  7262. FILE_ATTRIBUTE_NORMAL,
  7263. FILE_SHARE_READ,
  7264. FILE_OPEN_IF,
  7265. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY,
  7266. NULL,
  7267. 0
  7268. );
  7269. if (NT_SUCCESS(Status)) {
  7270. //
  7271. // If the file is created for the first time, write the header.
  7272. //
  7273. if (IoStatusBlock.Information == FILE_CREATED) {
  7274. Status = ZwWriteFile(
  7275. FileHandle,
  7276. NULL,
  7277. NULL,
  7278. NULL,
  7279. &IoStatusBlock,
  7280. (PVOID) &UnicodeHeader,
  7281. sizeof(WCHAR),
  7282. NULL,
  7283. NULL
  7284. );
  7285. }
  7286. if (NT_SUCCESS(Status)) {
  7287. LARGE_INTEGER EndOfFile;
  7288. EndOfFile.HighPart = 0xffffffff;
  7289. EndOfFile.LowPart = FILE_WRITE_TO_END_OF_FILE;
  7290. Status = ZwWriteFile(
  7291. FileHandle,
  7292. NULL,
  7293. NULL,
  7294. NULL,
  7295. &IoStatusBlock,
  7296. (PVOID) String->Buffer,
  7297. String->Length,
  7298. &EndOfFile,
  7299. NULL
  7300. );
  7301. }
  7302. ZwClose(FileHandle);
  7303. }
  7304. ExReleaseResourceLite(&BootLogRecord->Resource);
  7305. KeLeaveCriticalRegionThread(CurrentThread);
  7306. return Status;
  7307. }
  7308. PLIST_ENTRY
  7309. FASTCALL
  7310. IopInterlockedInsertHeadList (
  7311. IN PLIST_ENTRY ListHead,
  7312. IN PLIST_ENTRY ListEntry
  7313. )
  7314. /*++
  7315. Routine Description:
  7316. This function inserts an entry at the head of a list using the I/O
  7317. database lock for synchronization.
  7318. Arguments:
  7319. Listhead - Supplies a pointer to the list head.
  7320. ListEntry - Supplies a pointer to the list entry.
  7321. Return Value:
  7322. If the list was previously empty, then NULL is returned as the function
  7323. value. Otherwise, a pointer to the previous first entry in the list is
  7324. returned as the function value.
  7325. --*/
  7326. {
  7327. PLIST_ENTRY entry;
  7328. KIRQL irql;
  7329. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  7330. entry = ListHead->Flink;
  7331. if ( entry == ListHead ) {
  7332. entry = NULL;
  7333. }
  7334. InsertHeadList( ListHead, ListEntry );
  7335. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7336. return entry;
  7337. }
  7338. PLIST_ENTRY
  7339. FASTCALL
  7340. IopInterlockedInsertTailList (
  7341. IN PLIST_ENTRY ListHead,
  7342. IN PLIST_ENTRY ListEntry
  7343. )
  7344. /*++
  7345. Routine Description:
  7346. This function inserts an entry at the tail of a list using the I/O
  7347. database lock for synchronization.
  7348. Arguments:
  7349. Listhead - Supplies a pointer to the list head.
  7350. ListEntry - Supplies a pointer to the list entry.
  7351. Return Value:
  7352. If the list was previously empty, then NULL is returned as the function
  7353. value. Otherwise, a pointer to the previous last entry in the list is
  7354. returned as the function value.
  7355. --*/
  7356. {
  7357. PLIST_ENTRY entry;
  7358. KIRQL irql;
  7359. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  7360. entry = ListHead->Blink;
  7361. if ( entry == ListHead) {
  7362. entry = NULL;
  7363. }
  7364. InsertTailList( ListHead, ListEntry );
  7365. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7366. return entry;
  7367. }
  7368. PLIST_ENTRY
  7369. FASTCALL
  7370. IopInterlockedRemoveHeadList (
  7371. IN PLIST_ENTRY ListHead
  7372. )
  7373. /*++
  7374. Routine Description:
  7375. This function removes the first entry form a list using the I/O database
  7376. lock for synchronization.
  7377. Arguments:
  7378. Listhead - Supplies a pointer to the list head.
  7379. Return Value:
  7380. If the list is empty, then NULL is returned as the function value.
  7381. Otherwise, a pointer to the first entry in the list is returned as
  7382. the function value.
  7383. --*/
  7384. {
  7385. PLIST_ENTRY entry;
  7386. KIRQL irql;
  7387. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  7388. entry = ListHead->Flink;
  7389. if ( entry != ListHead ) {
  7390. RemoveEntryList( entry );
  7391. } else {
  7392. entry = NULL;
  7393. }
  7394. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7395. return entry;
  7396. }
  7397. ULONG
  7398. FASTCALL
  7399. IopInterlockedDecrementUlong (
  7400. IN KSPIN_LOCK_QUEUE_NUMBER Number,
  7401. IN OUT PULONG Addend
  7402. )
  7403. /*++
  7404. Routine Description:
  7405. This function decrements the specified value using a queued spin lock
  7406. for synchronization.
  7407. Arguments:
  7408. Number - Supplies the number of the queued spin lock.
  7409. Addend - Supplies a pointer to the variable to be decremented.
  7410. Return Value:
  7411. The value of the variable before the decrement is applied.
  7412. --*/
  7413. {
  7414. KIRQL irql;
  7415. ULONG value;
  7416. irql = KeAcquireQueuedSpinLock( Number );
  7417. value = *Addend;
  7418. *Addend -= 1;
  7419. KeReleaseQueuedSpinLock( Number, irql );
  7420. return value;
  7421. }
  7422. ULONG
  7423. FASTCALL
  7424. IopInterlockedIncrementUlong (
  7425. IN KSPIN_LOCK_QUEUE_NUMBER Number,
  7426. IN OUT PULONG Addend
  7427. )
  7428. /*++
  7429. Routine Description:
  7430. This function increments the specified value using a queued spin lock
  7431. for synchronization.
  7432. Arguments:
  7433. Number - Supplies the number of the queued spin lock.
  7434. Addend - Supplies a pointer to the variable to be incremented.
  7435. Return Value:
  7436. The value of the variable before the increment is applied.
  7437. --*/
  7438. {
  7439. KIRQL irql;
  7440. ULONG value;
  7441. irql = KeAcquireQueuedSpinLock( Number );
  7442. value = *Addend;
  7443. *Addend += 1;
  7444. KeReleaseQueuedSpinLock( Number, irql );
  7445. return value;
  7446. }
  7447. BOOLEAN
  7448. IopCallBootDriverReinitializationRoutines(
  7449. VOID
  7450. )
  7451. /*++
  7452. Routine Description:
  7453. This routine processes the boot driver reinitialization list. It calls each
  7454. entry and then removes it from the list.
  7455. Arguments:
  7456. NONE
  7457. Returns:
  7458. TRUE if any entries were processed.
  7459. --*/
  7460. {
  7461. PLIST_ENTRY entry;
  7462. PREINIT_PACKET reinitEntry;
  7463. BOOLEAN routinesFound = FALSE;
  7464. //
  7465. // Walk the list reinitialization list in case this driver, or
  7466. // some other driver, has requested to be invoked at a re-
  7467. // initialization entry point.
  7468. //
  7469. while (entry = IopInterlockedRemoveHeadList( &IopBootDriverReinitializeQueueHead )) {
  7470. routinesFound = TRUE;
  7471. reinitEntry = CONTAINING_RECORD( entry, REINIT_PACKET, ListEntry );
  7472. reinitEntry->DriverObject->DriverExtension->Count++;
  7473. reinitEntry->DriverObject->Flags &= ~DRVO_BOOTREINIT_REGISTERED;
  7474. reinitEntry->DriverReinitializationRoutine( reinitEntry->DriverObject,
  7475. reinitEntry->Context,
  7476. reinitEntry->DriverObject->DriverExtension->Count );
  7477. ExFreePool( reinitEntry );
  7478. }
  7479. return routinesFound;
  7480. }
  7481. BOOLEAN
  7482. IopCallDriverReinitializationRoutines(
  7483. VOID
  7484. )
  7485. /*++
  7486. Routine Description:
  7487. This routine processes the driver reinitialization list. It calls each
  7488. entry and then removes it from the list.
  7489. Arguments:
  7490. NONE
  7491. Returns:
  7492. TRUE if any entries were processed.
  7493. --*/
  7494. {
  7495. PLIST_ENTRY entry;
  7496. PREINIT_PACKET reinitEntry;
  7497. BOOLEAN routinesFound = FALSE;
  7498. PAGED_CODE();
  7499. //
  7500. // Walk the list reinitialization list in case this driver, or
  7501. // some other driver, has requested to be invoked at a re-
  7502. // initialization entry point.
  7503. //
  7504. while (entry = IopInterlockedRemoveHeadList( &IopDriverReinitializeQueueHead )) {
  7505. routinesFound = TRUE;
  7506. reinitEntry = CONTAINING_RECORD( entry, REINIT_PACKET, ListEntry );
  7507. reinitEntry->DriverObject->DriverExtension->Count++;
  7508. reinitEntry->DriverObject->Flags &= ~DRVO_REINIT_REGISTERED;
  7509. reinitEntry->DriverReinitializationRoutine( reinitEntry->DriverObject,
  7510. reinitEntry->Context,
  7511. reinitEntry->DriverObject->DriverExtension->Count );
  7512. ExFreePool( reinitEntry );
  7513. }
  7514. return routinesFound;
  7515. }
  7516. PDRIVER_OBJECT
  7517. IopReferenceDriverObjectByName (
  7518. IN PUNICODE_STRING DriverName
  7519. )
  7520. /*++
  7521. Routine Description:
  7522. This routine references a driver object by a given driver name.
  7523. Arguments:
  7524. DriverName - supplies a pointer to the name of the driver whose driver object is
  7525. to be referenced.
  7526. Returns:
  7527. A pointer to a DRIVER_OBJECT if succeeds. Otherwise, a NULL value.
  7528. --*/
  7529. {
  7530. OBJECT_ATTRIBUTES objectAttributes;
  7531. HANDLE driverHandle;
  7532. NTSTATUS status;
  7533. PDRIVER_OBJECT driverObject;
  7534. //
  7535. // Make sure the driver name is valid.
  7536. //
  7537. if (DriverName->Length == 0) {
  7538. return NULL;
  7539. }
  7540. InitializeObjectAttributes(&objectAttributes,
  7541. DriverName,
  7542. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  7543. NULL,
  7544. NULL
  7545. );
  7546. status = ObOpenObjectByName(&objectAttributes,
  7547. IoDriverObjectType,
  7548. KernelMode,
  7549. NULL,
  7550. FILE_READ_ATTRIBUTES,
  7551. NULL,
  7552. &driverHandle
  7553. );
  7554. if (NT_SUCCESS(status)) {
  7555. //
  7556. // Now reference the driver object.
  7557. //
  7558. status = ObReferenceObjectByHandle(driverHandle,
  7559. 0,
  7560. IoDriverObjectType,
  7561. KernelMode,
  7562. &driverObject,
  7563. NULL
  7564. );
  7565. NtClose(driverHandle);
  7566. }
  7567. if (NT_SUCCESS(status)) {
  7568. return driverObject;
  7569. } else {
  7570. return NULL;
  7571. }
  7572. }
  7573. PIRP
  7574. IopAllocateReserveIrp(
  7575. IN CCHAR StackSize
  7576. )
  7577. /*++
  7578. Routine Description:
  7579. This routine allocates a reserve IRP for paging reads.
  7580. Arguments:
  7581. StackSize - IRP stack size.
  7582. Return Value:
  7583. The function value is an IRP.
  7584. --*/
  7585. {
  7586. PIOP_RESERVE_IRP_ALLOCATOR allocator = &IopReserveIrpAllocator;
  7587. if (StackSize > allocator->ReserveIrpStackSize) {
  7588. return NULL;
  7589. }
  7590. while (InterlockedExchange(&allocator->IrpAllocated, 1) == 1) {
  7591. (VOID)KeWaitForSingleObject(&allocator->Event,
  7592. Executive,
  7593. KernelMode,
  7594. FALSE,
  7595. (PLARGE_INTEGER)0);
  7596. }
  7597. IoInitializeIrp(allocator->ReserveIrp, IoSizeOfIrp(StackSize), StackSize);
  7598. return (allocator->ReserveIrp);
  7599. }
  7600. VOID
  7601. IopFreeReserveIrp(
  7602. IN PIRP Irp,
  7603. IN CCHAR PriorityBoost
  7604. )
  7605. /*++
  7606. Routine Description:
  7607. This routine frees a reserve IRP
  7608. Arguments:
  7609. IRP - IRP to be freed.
  7610. Return Value:
  7611. None
  7612. --*/
  7613. {
  7614. InterlockedExchange(&IopReserveIrpAllocator.IrpAllocated, 0);
  7615. KeSetEvent(&IopReserveIrpAllocator.Event, PriorityBoost, FALSE);
  7616. }
  7617. NTSTATUS
  7618. IopGetBasicInformationFile(
  7619. IN PFILE_OBJECT FileObject,
  7620. IN PFILE_BASIC_INFORMATION BasicInformationBuffer
  7621. )
  7622. /*++
  7623. Routine Description:
  7624. This routine gets the basic information of a fileobject.
  7625. Arguments:
  7626. FileObject - Fileobject for which the information is needed.
  7627. BasicInformationBuffer - Buffer of type FILE_BASIC_INFORMATION
  7628. Return Value:
  7629. NTSTATUS
  7630. --*/
  7631. {
  7632. NTSTATUS status;
  7633. PDEVICE_OBJECT deviceObject;
  7634. IO_STATUS_BLOCK localIoStatus;
  7635. PFAST_IO_DISPATCH fastIoDispatch;
  7636. ULONG lengthNeeded;
  7637. BOOLEAN queryResult;
  7638. PAGED_CODE();
  7639. deviceObject = IoGetRelatedDeviceObject( FileObject );
  7640. fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
  7641. if (fastIoDispatch && fastIoDispatch->FastIoQueryBasicInfo) {
  7642. queryResult = fastIoDispatch->FastIoQueryBasicInfo( FileObject,
  7643. (FileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE,
  7644. BasicInformationBuffer,
  7645. &localIoStatus,
  7646. deviceObject );
  7647. if (queryResult) {
  7648. return (localIoStatus.Status);
  7649. }
  7650. }
  7651. //
  7652. // Use the special API because the fileobject may be synchronous.
  7653. //
  7654. status = IopGetFileInformation(FileObject,
  7655. sizeof(FILE_BASIC_INFORMATION),
  7656. FileBasicInformation,
  7657. BasicInformationBuffer,
  7658. &lengthNeeded);
  7659. return status;
  7660. }
  7661. PVPB
  7662. IopMountInitializeVpb(
  7663. IN PDEVICE_OBJECT DeviceObject,
  7664. IN PDEVICE_OBJECT AttachedDevice,
  7665. IN ULONG RawMountOnly
  7666. )
  7667. /*++
  7668. Routine Description:
  7669. This routine initializes the mounted volume VPB holding the VPB lock.
  7670. Arguments:
  7671. DeviceObject - Disk device object
  7672. AttachedDevice - Top of FS stack.
  7673. RawMountOnly - Only allow raw mounts
  7674. Return Value:
  7675. none.
  7676. --*/
  7677. {
  7678. KIRQL irql;
  7679. PVPB vpb;
  7680. IoAcquireVpbSpinLock(&irql);
  7681. vpb = DeviceObject->Vpb;
  7682. vpb->Flags = VPB_MOUNTED;
  7683. //
  7684. // We explicitly propagate VPB_RAW_MOUNT as the previous
  7685. // statement that has been there for a long time in NT
  7686. // could be clearing other flags which should be cleared.
  7687. //
  7688. if (RawMountOnly) {
  7689. vpb->Flags |= VPB_RAW_MOUNT;
  7690. }
  7691. vpb->DeviceObject->StackSize = (UCHAR) (AttachedDevice->StackSize + 1);
  7692. //
  7693. // Set the reverse Vpb pointer in the filesystem device object's VPB.
  7694. //
  7695. vpb->DeviceObject->DeviceObjectExtension->Vpb = vpb;
  7696. vpb->ReferenceCount += 1;
  7697. IoReleaseVpbSpinLock(irql);
  7698. return vpb;
  7699. }
  7700. BOOLEAN
  7701. IopVerifyDeviceObjectOnStack(
  7702. IN PDEVICE_OBJECT BaseDeviceObject,
  7703. IN PDEVICE_OBJECT TopDeviceObject
  7704. )
  7705. /*++
  7706. Routine Description:
  7707. This routine checks if a device object is on a device stack.
  7708. Arguments:
  7709. BaseDeviceObject - Lowest device object on the stack.
  7710. TopDeviceObject - Device which is to be tested.
  7711. Return Value:
  7712. Returns TRUE if TopDeviceObject is on stack.
  7713. --*/
  7714. {
  7715. KIRQL irql;
  7716. PDEVICE_OBJECT currentDeviceObject;
  7717. //
  7718. // Loop through all of the device object's attached to the specified
  7719. // device. When the last device object is found that is not attached
  7720. // to, return it.
  7721. //
  7722. ASSERT( BaseDeviceObject != NULL);
  7723. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  7724. currentDeviceObject = BaseDeviceObject;
  7725. do {
  7726. if (currentDeviceObject == TopDeviceObject) {
  7727. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7728. return TRUE;
  7729. }
  7730. currentDeviceObject = currentDeviceObject->AttachedDevice;
  7731. } while (currentDeviceObject);
  7732. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7733. return FALSE;
  7734. }
  7735. BOOLEAN
  7736. IopVerifyDiskSignature(
  7737. IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout,
  7738. IN PARC_DISK_SIGNATURE LoaderDiskBlock,
  7739. OUT PULONG DiskSignature
  7740. )
  7741. /*++
  7742. Routine Description:
  7743. This routine verifies disk signature that is present in the loader block
  7744. and that retrieved by the storage drivers.
  7745. Arguments:
  7746. DriveLayout - Informtion obtained from the storage stack.
  7747. LoaderDiskBlock - Signature info from loader
  7748. SectorBuffer - Buffer containing sector 0 on the disk.
  7749. DiskSignature - If successful contains disk signature.
  7750. Return Value:
  7751. Returns TRUE if signature matches.
  7752. --*/
  7753. {
  7754. ULONG diskSignature;
  7755. if (!LoaderDiskBlock->ValidPartitionTable) {
  7756. return FALSE;
  7757. }
  7758. //
  7759. // Save off the signature in local variable if
  7760. // its a MBR disk
  7761. //
  7762. if (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) {
  7763. diskSignature = DriveLayout->Mbr.Signature;
  7764. if (LoaderDiskBlock->Signature == diskSignature) {
  7765. if (DiskSignature) {
  7766. *DiskSignature = diskSignature;
  7767. }
  7768. return TRUE;
  7769. }
  7770. }
  7771. //
  7772. // Get hold of the signature from MBR if its GPT disk
  7773. //
  7774. if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) {
  7775. if (!LoaderDiskBlock->IsGpt) {
  7776. return FALSE;
  7777. }
  7778. if (!RtlEqualMemory(LoaderDiskBlock->GptSignature, &DriveLayout->Gpt.DiskId, sizeof(GUID))) {
  7779. return FALSE;
  7780. }
  7781. if (DiskSignature) {
  7782. *DiskSignature = 0;
  7783. }
  7784. return TRUE;
  7785. }
  7786. return FALSE;
  7787. }
  7788. NTSTATUS
  7789. IopGetDriverPathInformation(
  7790. IN PFILE_OBJECT FileObject,
  7791. IN PFILE_FS_DRIVER_PATH_INFORMATION FsDpInfo,
  7792. IN ULONG Length
  7793. )
  7794. /*++
  7795. Routine Description:
  7796. This routine returns true if a driver specified by name is present in the IO path
  7797. for the fileobject.
  7798. Arguments:
  7799. FileObject - FileObject to which IO is issued.
  7800. FsDpInfo - Info that contains driver name.
  7801. Return Value:
  7802. NTSTATUS
  7803. --*/
  7804. {
  7805. UNICODE_STRING driverString;
  7806. PDRIVER_OBJECT driverObject;
  7807. NTSTATUS status;
  7808. KIRQL irql;
  7809. if ((ULONG) (Length - FIELD_OFFSET( FILE_FS_DRIVER_PATH_INFORMATION, DriverName[0] )) < FsDpInfo->DriverNameLength) {
  7810. return STATUS_INVALID_PARAMETER;
  7811. }
  7812. driverString.Buffer = FsDpInfo->DriverName;
  7813. driverString.Length = (USHORT)FsDpInfo->DriverNameLength;
  7814. driverString.MaximumLength = (USHORT)FsDpInfo->DriverNameLength;
  7815. status = ObReferenceObjectByName(&driverString,
  7816. OBJ_CASE_INSENSITIVE,
  7817. NULL, // access state
  7818. 0, // access mask
  7819. IoDriverObjectType,
  7820. KernelMode,
  7821. NULL, // parse context
  7822. &driverObject);
  7823. if (!NT_SUCCESS(status)) {
  7824. return status;
  7825. }
  7826. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  7827. if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) {
  7828. //
  7829. // Check the disk filesystem stack.
  7830. //
  7831. if (IopVerifyDriverObjectOnStack(FileObject->Vpb->DeviceObject, driverObject)) {
  7832. FsDpInfo->DriverInPath = TRUE;
  7833. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7834. ObDereferenceObject(driverObject);
  7835. return STATUS_SUCCESS;
  7836. }
  7837. }
  7838. //
  7839. // Check the storage stack or non disk filesystem stack.
  7840. //
  7841. FsDpInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->DeviceObject, driverObject);
  7842. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  7843. ObDereferenceObject(driverObject);
  7844. return STATUS_SUCCESS;
  7845. }
  7846. BOOLEAN
  7847. IopVerifyDriverObjectOnStack(
  7848. IN PDEVICE_OBJECT DeviceObject,
  7849. IN PDRIVER_OBJECT DriverObject
  7850. )
  7851. /*++
  7852. Routine Description:
  7853. This routine returns true if a driver specified by driverObject is present in the IO path
  7854. for the deviceobject.
  7855. Arguments:
  7856. DeviceObject - DeviceObject to which IO is issued.
  7857. Driverobject - DriverObject to be checked.
  7858. Return Value:
  7859. TRUE if the driverObject is in the IO path
  7860. --*/
  7861. {
  7862. PDEVICE_OBJECT currentDeviceObject;
  7863. currentDeviceObject = IopGetDeviceAttachmentBase(DeviceObject);
  7864. while (currentDeviceObject) {
  7865. if (currentDeviceObject->DriverObject == DriverObject) {
  7866. return TRUE;
  7867. }
  7868. currentDeviceObject = currentDeviceObject->AttachedDevice;
  7869. }
  7870. return FALSE;
  7871. }
  7872. VOID
  7873. IopIncrementDeviceObjectHandleCount(
  7874. IN PDEVICE_OBJECT DeviceObject
  7875. )
  7876. {
  7877. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  7878. &DeviceObject->ReferenceCount );
  7879. }
  7880. VOID
  7881. IopDecrementDeviceObjectHandleCount(
  7882. IN PDEVICE_OBJECT DeviceObject
  7883. )
  7884. {
  7885. IopDecrementDeviceObjectRef(DeviceObject, FALSE, FALSE);
  7886. }
  7887. NTSTATUS
  7888. IopInitializeIrpStackProfiler(
  7889. VOID
  7890. )
  7891. /*++
  7892. Routine Description:
  7893. This routine initializes the Irp stack profiler.
  7894. Arguments:
  7895. Return Value:
  7896. NTSTATUS
  7897. --*/
  7898. {
  7899. LARGE_INTEGER dueTime;
  7900. LONG i;
  7901. RtlZeroMemory(IopIrpStackProfiler.Profile, MAX_LOOKASIDE_IRP_STACK_COUNT * sizeof(ULONG));
  7902. KeInitializeTimer(&IopIrpStackProfiler.Timer);
  7903. KeInitializeDpc(&IopIrpStackProfiler.Dpc, IopIrpStackProfilerTimer, &IopIrpStackProfiler);
  7904. dueTime.QuadPart = - IOP_PROFILE_TIME_PERIOD * 10 * 1000 * 1000; // 1 Minute with a recurring period of a minute
  7905. IopIrpStackProfiler.TriggerCount = 0;
  7906. KeSetTimerEx(&IopIrpStackProfiler.Timer, dueTime, IOP_PROFILE_TIME_PERIOD * 1000, &IopIrpStackProfiler.Dpc);
  7907. return STATUS_SUCCESS;
  7908. }
  7909. VOID
  7910. IopIrpStackProfilerTimer(
  7911. IN struct _KDPC *Dpc,
  7912. IN PVOID DeferredContext,
  7913. IN PVOID SystemArgument1,
  7914. IN PVOID SystemArgument2
  7915. )
  7916. /*++
  7917. Routine Description:
  7918. This routine is the timer DPC routine.
  7919. Arguments:
  7920. DeferredContext - Pointer to the profiler structure.
  7921. Return Value:
  7922. None
  7923. --*/
  7924. {
  7925. PIOP_IRP_STACK_PROFILER profiler = DeferredContext;
  7926. LONG i;
  7927. ULONG totalIrpsCounted;
  7928. //
  7929. // If profile stack count is now enabled, we wait for ProfileDuration * 60 secs to stop
  7930. // it. Once stopped, IopProcessIrpStackProfiler will tally the counts and find the top two
  7931. // stack counts.
  7932. //
  7933. if (profiler->Flags & IOP_PROFILE_STACK_COUNT) {
  7934. totalIrpsCounted = 0;
  7935. for (i = 0; i < MAX_LOOKASIDE_IRP_STACK_COUNT; i++) {
  7936. totalIrpsCounted += profiler->Profile[i];
  7937. }
  7938. if (totalIrpsCounted > NUM_SAMPLE_IRPS) {
  7939. profiler->Flags &= ~IOP_PROFILE_STACK_COUNT; // Stop the profiling.
  7940. IopProcessIrpStackProfiler();
  7941. }
  7942. return;
  7943. }
  7944. //
  7945. // Every IOP_PROFILE_TRIGGER_INTERVAL * 60 seconds we turn on the profiling
  7946. //
  7947. profiler->TriggerCount++;
  7948. if ((profiler->TriggerCount % IOP_PROFILE_TRIGGER_INTERVAL) == 0) {
  7949. profiler->Flags |= IOP_PROFILE_STACK_COUNT; // Enable profiling
  7950. }
  7951. }
  7952. VOID
  7953. IopProcessIrpStackProfiler(
  7954. VOID
  7955. )
  7956. /*++
  7957. Routine Description:
  7958. This routine profiles and resets the per-processor counters. It sets the variables
  7959. IopLargeIrpStackLocations and IopSmallIrpStackLocations with the values learned from
  7960. counters.
  7961. Arguments:
  7962. None
  7963. Return Value:
  7964. None
  7965. --*/
  7966. {
  7967. PIOP_IRP_STACK_PROFILER profiler = &IopIrpStackProfiler;
  7968. LONG i, j;
  7969. LONG bucket = 0;
  7970. LONG stackCount = 0;
  7971. LONG numRequests;
  7972. numRequests = 0;
  7973. for (i = BASE_STACK_COUNT; i < MAX_LOOKASIDE_IRP_STACK_COUNT; i++) {
  7974. numRequests += profiler->Profile[i];
  7975. profiler->Profile[i] = 0;
  7976. if (numRequests > bucket) {
  7977. stackCount = i;
  7978. bucket = numRequests;
  7979. }
  7980. numRequests = 0;
  7981. }
  7982. //
  7983. // If the top allocation is less than the minimum threshold do nothing.
  7984. //
  7985. if (bucket < MIN_IRP_THRESHOLD) {
  7986. return;
  7987. }
  7988. //
  7989. // Update the global variables. This should cause IoAllocateIrp to start using the new IRPs
  7990. // right away.
  7991. //
  7992. if (IopLargeIrpStackLocations != stackCount) {
  7993. IopLargeIrpStackLocations = stackCount;
  7994. }
  7995. }