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.

14850 lines
416 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. iosubs.c
  5. Abstract:
  6. This module contains the subroutines for the I/O system.
  7. Author:
  8. Darryl E. Havens (darrylh) 16-Apr-1989
  9. Nar Ganapathy (narg) 1-Jan-1999
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. //
  16. // This is the overall system device configuration record.
  17. //
  18. #ifdef ALLOC_DATA_PRAGMA
  19. #pragma data_seg("PAGEDATA")
  20. #endif
  21. static CONFIGURATION_INFORMATION ConfigurationInformation = {
  22. 0, // DiskCount
  23. 0, // FloppyCount
  24. 0, // CdRomCount
  25. 0, // TapeCount
  26. 0, // ScsiPortCount
  27. 0, // SerialCount
  28. 0, // ParallelCount
  29. FALSE, // Primary ATDISK IO address claimed
  30. FALSE, // Secondary ATDISK IO address claimed
  31. sizeof(CONFIGURATION_INFORMATION), // Version
  32. 0 // MediumChangerCount
  33. };
  34. #ifdef ALLOC_DATA_PRAGMA
  35. #pragma data_seg()
  36. #endif
  37. //
  38. // This value may be overridden by the registry.
  39. //
  40. LOGICAL IoCountOperations = TRUE;
  41. LONG IoPageReadIrpAllocationFailure;
  42. #ifdef ALLOC_PRAGMA
  43. NTSTATUS
  44. IopDeleteSessionSymLinks(
  45. IN PUNICODE_STRING LinkName
  46. );
  47. #pragma alloc_text(PAGE, IoAttachDevice)
  48. #pragma alloc_text(PAGE, IoCancelThreadIo)
  49. #pragma alloc_text(PAGE, IoCheckDesiredAccess)
  50. #pragma alloc_text(PAGE, IoCheckEaBufferValidity)
  51. #pragma alloc_text(PAGE, IoCheckFunctionAccess)
  52. #pragma alloc_text(PAGE, IoCheckQuotaBufferValidity)
  53. #pragma alloc_text(PAGE, IoCheckShareAccess)
  54. #pragma alloc_text(PAGE, IoConnectInterrupt)
  55. #pragma alloc_text(PAGE, IoCreateController)
  56. #pragma alloc_text(PAGE, IoCreateDevice)
  57. #pragma alloc_text(PAGE, IoCreateDriver)
  58. #pragma alloc_text(PAGE, IoCreateFile)
  59. #pragma alloc_text(PAGE, IopCreateFile)
  60. #pragma alloc_text(PAGE, IoCreateNotificationEvent)
  61. #pragma alloc_text(PAGE, IoCreateStreamFileObject)
  62. #pragma alloc_text(PAGE, IoCreateStreamFileObjectLite)
  63. #pragma alloc_text(PAGE, IoCreateSymbolicLink)
  64. #pragma alloc_text(PAGE, IoCreateSynchronizationEvent)
  65. #pragma alloc_text(PAGE, IoCreateUnprotectedSymbolicLink)
  66. #pragma alloc_text(PAGE, IoDeleteController)
  67. #pragma alloc_text(PAGE, IoDeleteDriver)
  68. #pragma alloc_text(PAGE, IoDeleteSymbolicLink)
  69. #pragma alloc_text(PAGE, IopDeleteSessionSymLinks)
  70. #pragma alloc_text(PAGE, IoDisconnectInterrupt)
  71. #pragma alloc_text(PAGE, IoEnqueueIrp)
  72. #pragma alloc_text(PAGE, IoGetFileObjectGenericMapping)
  73. #pragma alloc_text(PAGE, IoFastQueryNetworkAttributes)
  74. #pragma alloc_text(PAGE, IoGetConfigurationInformation)
  75. #pragma alloc_text(PAGE, IoGetDeviceObjectPointer)
  76. #pragma alloc_text(PAGE, IoInitializeTimer)
  77. #pragma alloc_text(PAGE, IoIsValidNameGraftingBuffer)
  78. #pragma alloc_text(PAGE, IopDoNameTransmogrify)
  79. #pragma alloc_text(PAGE, IoQueryFileDosDeviceName)
  80. #pragma alloc_text(PAGE, IoQueryFileInformation)
  81. #pragma alloc_text(PAGE, IoQueryVolumeInformation)
  82. #pragma alloc_text(PAGE, IoRegisterBootDriverReinitialization)
  83. #pragma alloc_text(PAGE, IoRegisterDriverReinitialization)
  84. #pragma alloc_text(PAGE, IoRegisterFileSystem)
  85. #pragma alloc_text(PAGE, IoRegisterFsRegistrationChange)
  86. #pragma alloc_text(PAGE, IoRegisterLastChanceShutdownNotification)
  87. #pragma alloc_text(PAGE, IoRegisterShutdownNotification)
  88. #pragma alloc_text(PAGE, IoRemoveShareAccess)
  89. #pragma alloc_text(PAGE, IoSetInformation)
  90. #pragma alloc_text(PAGE, IoSetShareAccess)
  91. #pragma alloc_text(PAGE, IoUnregisterFileSystem)
  92. #pragma alloc_text(PAGE, IoUnregisterFsRegistrationChange)
  93. #pragma alloc_text(PAGE, IoUpdateShareAccess)
  94. #pragma alloc_text(PAGE, IoVerifyVolume)
  95. #pragma alloc_text(PAGE, IoGetBootDiskInformation)
  96. #pragma alloc_text(PAGE, IopCreateDefaultDeviceSecurityDescriptor)
  97. #pragma alloc_text(PAGE, IopCreateVpb)
  98. #pragma alloc_text(PAGE, IoCancelFileOpen)
  99. #pragma alloc_text(PAGE, IopNotifyAlreadyRegisteredFileSystems)
  100. #pragma alloc_text(PAGE, IoCreateFileSpecifyDeviceObjectHint)
  101. #pragma alloc_text(PAGELK, IoShutdownSystem)
  102. #pragma alloc_text(PAGELK, IoUnregisterShutdownNotification)
  103. #endif
  104. VOID
  105. IoAcquireCancelSpinLock(
  106. OUT PKIRQL Irql
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is invoked to acquire the cancel spin lock. This spin lock
  111. must be acquired before setting the address of a cancel routine in an
  112. IRP.
  113. Arguments:
  114. Irql - Address of a variable to receive the old IRQL.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. //
  120. // Simply acquire the cancel spin lock and return.
  121. //
  122. *Irql = KeAcquireQueuedSpinLock( LockQueueIoCancelLock );
  123. }
  124. VOID
  125. IoAcquireVpbSpinLock(
  126. OUT PKIRQL Irql
  127. )
  128. /*++
  129. Routine Description:
  130. This routine is invoked to acquire the Volume Parameter Block (VPB) spin
  131. lock. This spin lock must be acquired before accessing the mount flag,
  132. reference count, and device object fields of a VPB.
  133. Arguments:
  134. Irql - Address of a variable to receive the old IRQL.
  135. Return Value:
  136. None.
  137. --*/
  138. {
  139. //
  140. // Simply acquire the IopLoadFileSystemDriverVPB spin lock and return.
  141. //
  142. *Irql = KeAcquireQueuedSpinLock( LockQueueIoVpbLock );
  143. return;
  144. }
  145. NTSTATUS
  146. IoAllocateAdapterChannel(
  147. IN PADAPTER_OBJECT AdapterObject,
  148. IN PDEVICE_OBJECT DeviceObject,
  149. IN ULONG NumberOfMapRegisters,
  150. IN PDRIVER_CONTROL ExecutionRoutine,
  151. IN PVOID Context
  152. )
  153. /*++
  154. Routine Description:
  155. This routine allocates the adapter channel specified by the adapter object.
  156. This is accomplished by calling HalAllocateAdapterChannel which does all of
  157. the work.
  158. Arguments:
  159. AdapterObject - Pointer to the adapter control object to allocate to the
  160. driver.
  161. DeviceObject - Pointer to the driver's device object that represents the
  162. device allocating the adapter.
  163. NumberOfMapRegisters - The number of map registers that are to be allocated
  164. from the channel, if any.
  165. ExecutionRoutine - The address of the driver's execution routine that is
  166. invoked once the adapter channel (and possibly map registers) have been
  167. allocated.
  168. Context - An untyped longword context parameter passed to the driver's
  169. execution routine.
  170. Return Value:
  171. Returns STATUS_SUCESS unless too many map registers are requested.
  172. Notes:
  173. Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
  174. --*/
  175. {
  176. #if !defined(NO_LEGACY_DRIVERS)
  177. PWAIT_CONTEXT_BLOCK wcb;
  178. wcb = &DeviceObject->Queue.Wcb;
  179. wcb->DeviceObject = DeviceObject;
  180. wcb->CurrentIrp = DeviceObject->CurrentIrp;
  181. wcb->DeviceContext = Context;
  182. return( HalAllocateAdapterChannel( AdapterObject,
  183. wcb,
  184. NumberOfMapRegisters,
  185. ExecutionRoutine ) );
  186. #else
  187. return( (*((PDMA_ADAPTER)AdapterObject)->DmaOperations->
  188. AllocateAdapterChannel)( (PDMA_ADAPTER)AdapterObject,
  189. DeviceObject,
  190. NumberOfMapRegisters,
  191. ExecutionRoutine,
  192. Context) );
  193. #endif // NO_LEGACY_DRIVERS
  194. }
  195. VOID
  196. IoAllocateController(
  197. IN PCONTROLLER_OBJECT ControllerObject,
  198. IN PDEVICE_OBJECT DeviceObject,
  199. IN PDRIVER_CONTROL ExecutionRoutine,
  200. IN PVOID Context
  201. )
  202. /*++
  203. Routine Description:
  204. This routine allocates the controller specified by the controller object.
  205. This is accomplished by placing the device object of the driver that wants
  206. to allocate the controller on the controller's queue. If the queue is
  207. already "busy", then the controller has already been allocated, so the
  208. device object is simply placed onto the queue and waits until the controller
  209. becomes free.
  210. Once the controller becomes free (or if it already is), then the driver's
  211. execution routine is invoked.
  212. Arguments:
  213. ControllerObject - Pointer to the controller object to allocate to the
  214. driver.
  215. DeviceObject - Pointer to the driver's device object that represents the
  216. device allocating the controller.
  217. ExecutionRoutine - The address of the driver's execution routine that is
  218. invoked once the controller has been allocated.
  219. Context - An untyped longword context parameter passed to the driver's
  220. execution routine.
  221. Return Value:
  222. None.
  223. Notes:
  224. Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
  225. --*/
  226. {
  227. IO_ALLOCATION_ACTION action;
  228. //
  229. // Initialize the device object's wait context block in case this device
  230. // must wait before being able to allocate the controller.
  231. //
  232. DeviceObject->Queue.Wcb.DeviceRoutine = ExecutionRoutine;
  233. DeviceObject->Queue.Wcb.DeviceContext = Context;
  234. //
  235. // Allocate the controller object for this particular device. If the
  236. // controller cannot be allocated because it has already been allocated
  237. // to another device, then return to the caller now; otherwise,
  238. // continue.
  239. //
  240. if (!KeInsertDeviceQueue( &ControllerObject->DeviceWaitQueue,
  241. &DeviceObject->Queue.Wcb.WaitQueueEntry )) {
  242. //
  243. // The controller was not busy so it has been allocated. Simply
  244. // invoke the driver's execution routine now.
  245. //
  246. action = ExecutionRoutine( DeviceObject,
  247. DeviceObject->CurrentIrp,
  248. 0,
  249. Context );
  250. //
  251. // If the driver would like to have the controller deallocated,
  252. // then deallocate it now.
  253. //
  254. if (action == DeallocateObject) {
  255. IoFreeController( ControllerObject );
  256. }
  257. }
  258. }
  259. NTSTATUS
  260. IoAllocateDriverObjectExtension(
  261. IN PDRIVER_OBJECT DriverObject,
  262. IN PVOID ClientIdentificationAddress,
  263. IN ULONG DriverObjectExtensionSize,
  264. OUT PVOID *DriverObjectExtension
  265. )
  266. /*++
  267. Routine Description:
  268. This routine allocates per driver storage for helper or class drivers
  269. which may support several different mini-drivers. The storage is tagged
  270. with a client identification address which is used to retrieve a pointer
  271. to the storage. The client id must be unique.
  272. The allocated storage is freed when the driver object is deleted.
  273. Arguments:
  274. DriverObject - The driver object to which the extension is to be
  275. associated.
  276. ClientIdentificationAddress - Unique identifier used to retrieve the
  277. extension.
  278. DriverObjectExtensionSize - Specifies the size in bytes of the extension.
  279. DriverObjectExtension - Returns a pointer to the allocated extension.
  280. Return Value:
  281. Returns the status of the operation. Failure cases are
  282. STATUS_INSUFFICIENT_RESOURCES and STATUS_OBJECT_NAME_COLLISION.
  283. --*/
  284. {
  285. KIRQL irql;
  286. BOOLEAN inserted = FALSE;
  287. PIO_CLIENT_EXTENSION extension;
  288. PIO_CLIENT_EXTENSION newExtension;
  289. *DriverObjectExtension = NULL;
  290. newExtension = ExAllocatePoolWithTag( NonPagedPool,
  291. DriverObjectExtensionSize +
  292. sizeof( IO_CLIENT_EXTENSION ),
  293. 'virD');
  294. if (newExtension == NULL) {
  295. return(STATUS_INSUFFICIENT_RESOURCES);
  296. }
  297. RtlZeroMemory( newExtension,
  298. DriverObjectExtensionSize +
  299. sizeof( IO_CLIENT_EXTENSION )
  300. );
  301. newExtension->ClientIdentificationAddress = ClientIdentificationAddress;
  302. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  303. extension = DriverObject->DriverExtension->ClientDriverExtension;
  304. while (extension != NULL) {
  305. if (extension->ClientIdentificationAddress == ClientIdentificationAddress) {
  306. break;
  307. }
  308. extension = extension->NextExtension;
  309. }
  310. if (extension == NULL) {
  311. //
  312. // The client id does not exist. Insert the new extension in the
  313. // list.
  314. //
  315. newExtension->NextExtension =
  316. DriverObject->DriverExtension->ClientDriverExtension;
  317. DriverObject->DriverExtension->ClientDriverExtension = newExtension;
  318. inserted = TRUE;
  319. }
  320. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  321. if (!inserted) {
  322. ExFreePool( newExtension );
  323. return(STATUS_OBJECT_NAME_COLLISION);
  324. }
  325. //
  326. // Return a pointer to the client's data area.
  327. //
  328. *DriverObjectExtension = newExtension + 1;
  329. return(STATUS_SUCCESS);
  330. }
  331. PVOID
  332. IoAllocateErrorLogEntry(
  333. IN PVOID IoObject,
  334. IN UCHAR EntrySize
  335. )
  336. /*++
  337. Routine Description:
  338. This routine allocates and initializes an error log entry buffer and returns
  339. a pointer to the data entry portion of the buffer.
  340. Arguments:
  341. IoObject - Pointer to driver's device object or driver object.
  342. EntrySize - Size of entry to be allocated, in bytes. The maximum size is
  343. specified by ERROR_LOG_MAXIMUM_SIZE.
  344. Return Value:
  345. Pointer to the body of the allocated error log entry, or NULL, if there are
  346. no free entries in the system.
  347. Note:
  348. This routine assumes that the caller wants an error log entry within the
  349. bounds of the maximum size.
  350. --*/
  351. {
  352. PDEVICE_OBJECT deviceObject;
  353. PDRIVER_OBJECT driverObject;
  354. //
  355. // Make sure that a I/O object pointer was passed in.
  356. //
  357. if (IoObject == NULL) {
  358. return(NULL);
  359. }
  360. //
  361. // Assume for a moment this is a device object.
  362. //
  363. deviceObject = IoObject;
  364. //
  365. // Determine if this is a driver object or device object or if we
  366. // are allocating a generic error log entry. This is determined
  367. // from the Type field of the object passed in.
  368. //
  369. if (deviceObject->Type == IO_TYPE_DEVICE) {
  370. driverObject = deviceObject->DriverObject;
  371. } else if (deviceObject->Type == IO_TYPE_DRIVER) {
  372. driverObject = (PDRIVER_OBJECT) IoObject;
  373. deviceObject = NULL;
  374. } else {
  375. return(NULL);
  376. }
  377. return (IopAllocateErrorLogEntry(
  378. deviceObject,
  379. driverObject,
  380. EntrySize));
  381. }
  382. PVOID
  383. IoAllocateGenericErrorLogEntry(
  384. IN UCHAR EntrySize
  385. )
  386. /*++
  387. Routine Description:
  388. This routine allocates and initializes an error log entry buffer and returns
  389. a pointer to the data entry portion of the buffer. It's expected to be
  390. called from inside the kernel where there may not be a driver object
  391. or a device object.
  392. Arguments:
  393. EntrySize - Size of entry to be allocated, in bytes. The maximum size is
  394. specified by ERROR_LOG_MAXIMUM_SIZE.
  395. Return Value:
  396. Pointer to the body of the allocated error log entry, or NULL, if there are
  397. no free entries in the system.
  398. Note:
  399. This routine assumes that the caller wants an error log entry within the
  400. bounds of the maximum size.
  401. --*/
  402. {
  403. return(IopAllocateErrorLogEntry(NULL, NULL, EntrySize));
  404. }
  405. PVOID
  406. IopAllocateErrorLogEntry(
  407. IN PDEVICE_OBJECT deviceObject,
  408. IN PDRIVER_OBJECT driverObject,
  409. IN UCHAR EntrySize
  410. )
  411. {
  412. PERROR_LOG_ENTRY elEntry;
  413. PVOID returnValue;
  414. ULONG size;
  415. ULONG oldSize;
  416. //
  417. // Make sure the packet is large enough but not too large.
  418. //
  419. if (EntrySize < sizeof(IO_ERROR_LOG_PACKET) ||
  420. EntrySize > ERROR_LOG_MAXIMUM_SIZE) {
  421. return(NULL);
  422. }
  423. //
  424. // Round entry size to a PVOID size boundary.
  425. //
  426. EntrySize = (UCHAR) ((EntrySize + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1));
  427. //
  428. // Calculate the size of the entry needed.
  429. //
  430. size = sizeof(ERROR_LOG_ENTRY) + EntrySize;
  431. //
  432. // Make sure that there are not too many outstanding packets.
  433. //
  434. oldSize = InterlockedExchangeAdd(&IopErrorLogAllocation, size);
  435. if (oldSize > IOP_MAXIMUM_LOG_ALLOCATION) {
  436. //
  437. // Fail the request.
  438. //
  439. InterlockedExchangeAdd(&IopErrorLogAllocation, -(LONG)size);
  440. return(NULL);
  441. }
  442. //
  443. // Allocate the packet.
  444. //
  445. elEntry = ExAllocatePoolWithTag( NonPagedPool, size, 'rEoI' );
  446. if (elEntry == NULL) {
  447. //
  448. // Drop the allocation and return.
  449. //
  450. InterlockedExchangeAdd(&IopErrorLogAllocation, -(LONG)size);
  451. return(NULL);
  452. }
  453. //
  454. // Reference the device object and driver object. So they don't
  455. // go away before the name gets pulled out.
  456. //
  457. if (deviceObject != NULL) {
  458. ObReferenceObject( deviceObject );
  459. }
  460. if (driverObject != NULL) {
  461. ObReferenceObject( driverObject );
  462. }
  463. //
  464. // Initialize the fields.
  465. //
  466. RtlZeroMemory(elEntry, size);
  467. elEntry->Type = IO_TYPE_ERROR_LOG;
  468. elEntry->Size = (USHORT) size;
  469. elEntry->DeviceObject = deviceObject;
  470. elEntry->DriverObject = driverObject;
  471. returnValue = elEntry+1;
  472. return returnValue;
  473. }
  474. VOID
  475. IoFreeErrorLogEntry(
  476. IN PVOID ElEntry
  477. )
  478. /*++
  479. Routine Description:
  480. This routine frees an entry allocated using IoAllocateErrorLogEntry. Its used to
  481. free an entry if its not used to actually write an errorlog entry.
  482. Arguments:
  483. ElEntry - Pointer to the entry that was allocated by IoAllocateErrorLogEntry.
  484. Return Value:
  485. --*/
  486. {
  487. PERROR_LOG_ENTRY entry;
  488. //
  489. // Get the address of the error log entry header,
  490. //
  491. entry = ((PERROR_LOG_ENTRY) ElEntry) - 1;
  492. //
  493. // Drop the reference counts.
  494. //
  495. if (entry->DeviceObject != NULL) {
  496. ObDereferenceObject (entry->DeviceObject);
  497. }
  498. if (entry->DriverObject != NULL) {
  499. ObDereferenceObject (entry->DriverObject);
  500. }
  501. InterlockedExchangeAdd( &IopErrorLogAllocation,
  502. -((LONG) (entry->Size )));
  503. ExFreePool (entry);
  504. return;
  505. }
  506. PIRP
  507. IoAllocateIrp(
  508. IN CCHAR StackSize,
  509. IN BOOLEAN ChargeQuota
  510. )
  511. {
  512. return (pIoAllocateIrp(StackSize, ChargeQuota));
  513. }
  514. PIRP
  515. IopAllocateIrpPrivate(
  516. IN CCHAR StackSize,
  517. IN BOOLEAN ChargeQuota
  518. )
  519. /*++
  520. Routine Description:
  521. This routine allocates an I/O Request Packet from the system nonpaged pool.
  522. The packet will be allocated to contain StackSize stack locations. The IRP
  523. will also be initialized.
  524. Arguments:
  525. StackSize - Specifies the maximum number of stack locations required.
  526. ChargeQuota - Specifies whether quota should be charged against thread.
  527. Return Value:
  528. The function value is the address of the allocated/initialized IRP,
  529. or NULL if one could not be allocated.
  530. --*/
  531. {
  532. USHORT allocateSize;
  533. UCHAR fixedSize;
  534. PIRP irp;
  535. UCHAR lookasideAllocation;
  536. PGENERAL_LOOKASIDE lookasideList;
  537. PP_NPAGED_LOOKASIDE_NUMBER number;
  538. USHORT packetSize;
  539. PKPRCB prcb;
  540. //
  541. // If the size of the packet required is less than or equal to those on
  542. // the lookaside lists, then attempt to allocate the packet from the
  543. // lookaside lists.
  544. //
  545. if (IopIrpProfileStackCountEnabled()) {
  546. IopProfileIrpStackCount(StackSize);
  547. }
  548. irp = NULL;
  549. fixedSize = 0;
  550. packetSize = IoSizeOfIrp(StackSize);
  551. allocateSize = packetSize;
  552. prcb = KeGetCurrentPrcb();
  553. if ((StackSize <= (CCHAR)IopLargeIrpStackLocations) &&
  554. ((ChargeQuota == FALSE) || (prcb->LookasideIrpFloat > 0))) {
  555. fixedSize = IRP_ALLOCATED_FIXED_SIZE;
  556. number = LookasideSmallIrpList;
  557. if (StackSize != 1) {
  558. allocateSize = IoSizeOfIrp((CCHAR)IopLargeIrpStackLocations);
  559. number = LookasideLargeIrpList;
  560. }
  561. lookasideList = prcb->PPLookasideList[number].P;
  562. lookasideList->TotalAllocates += 1;
  563. irp = (PIRP)InterlockedPopEntrySList(&lookasideList->ListHead);
  564. if (irp == NULL) {
  565. lookasideList->AllocateMisses += 1;
  566. lookasideList = prcb->PPLookasideList[number].L;
  567. lookasideList->TotalAllocates += 1;
  568. irp = (PIRP)InterlockedPopEntrySList(&lookasideList->ListHead);
  569. }
  570. }
  571. //
  572. // See if this IRP is a stale entry. If so just free it.
  573. // This can happen if we decided to change the lookaside list size.
  574. // We need to get the size of the IRP from the information field as the size field
  575. // is overlayed with single list entry.
  576. //
  577. if (IopIrpAutoSizingEnabled() && irp ) {
  578. if (irp->IoStatus.Information < packetSize) {
  579. lookasideList->TotalFrees += 1;
  580. ExFreePool(irp);
  581. irp = NULL;
  582. } else {
  583. //
  584. // Update allocateSize to the correct value.
  585. //
  586. allocateSize = (USHORT)irp->IoStatus.Information;
  587. }
  588. }
  589. //
  590. // If an IRP was not allocated from the lookaside list, then allocate
  591. // the packet from nonpaged pool and charge quota if requested.
  592. //
  593. lookasideAllocation = 0;
  594. if (!irp) {
  595. if (fixedSize != 0) {
  596. lookasideList->AllocateMisses += 1;
  597. }
  598. //
  599. // There are no free packets on the lookaside list, or the packet is
  600. // too large to be allocated from one of the lists, so it must be
  601. // allocated from nonpaged pool. If quota is to be charged, charge it
  602. // against the current process. Otherwise, allocate the pool normally.
  603. //
  604. if (ChargeQuota) {
  605. try {
  606. irp = ExAllocatePoolWithQuotaTag(NonPagedPool, allocateSize,' prI');
  607. } except(EXCEPTION_EXECUTE_HANDLER) {
  608. NOTHING;
  609. }
  610. } else {
  611. //
  612. // Attempt to allocate the pool from non-paged pool. If this
  613. // fails, and the caller's previous mode was kernel then allocate
  614. // the pool as must succeed.
  615. //
  616. irp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
  617. }
  618. if (!irp) {
  619. return NULL;
  620. }
  621. } else {
  622. if (ChargeQuota != FALSE) {
  623. lookasideAllocation = IRP_LOOKASIDE_ALLOCATION;
  624. InterlockedDecrement( &prcb->LookasideIrpFloat );
  625. }
  626. ChargeQuota = FALSE;
  627. }
  628. //
  629. // Initialize the packet.
  630. // Note that irp->Size may not be equal to IoSizeOfIrp(StackSize)
  631. //
  632. IopInitializeIrp(irp, allocateSize, StackSize);
  633. irp->AllocationFlags = (fixedSize | lookasideAllocation);
  634. if (ChargeQuota) {
  635. irp->AllocationFlags |= IRP_QUOTA_CHARGED;
  636. }
  637. return irp;
  638. }
  639. PMDL
  640. IoAllocateMdl(
  641. IN PVOID VirtualAddress,
  642. IN ULONG Length,
  643. IN BOOLEAN SecondaryBuffer,
  644. IN BOOLEAN ChargeQuota,
  645. IN OUT PIRP Irp OPTIONAL
  646. )
  647. /*++
  648. Routine Description:
  649. This routine allocates a Memory Descriptor List (MDL) large enough to map
  650. the buffer specified by the VirtualAddress and Length parameters. If the
  651. routine is given a pointer to an Irp, then it will chain the MDL to the
  652. IRP in the appropriate way.
  653. If this routine is not given a pointer to an Irp it is up to the caller to
  654. set the MDL address in the IRP that the MDL is being allocated for.
  655. Note that the header information of the MDL will also be initialized.
  656. Arguments:
  657. VirtualAddress - Starting virtual address of the buffer to be mapped.
  658. Length - Length, in bytes, of the buffer to be mapped.
  659. SecondaryBuffer - Indicates whether this is a chained buffer.
  660. ChargeQuota - Indicates whether quota should be charged if MDL allocated.
  661. N.B. This parameter is ignored.
  662. Irp - Optional pointer to IRP that MDL is being allocated for.
  663. Return Value:
  664. A pointer to the allocated MDL, or NULL if one could not be allocated.
  665. Note that if no MDL could be allocated because there was not enough quota,
  666. then it is up to the caller to catch the raised exception.
  667. --*/
  668. {
  669. ULONG allocateSize;
  670. USHORT fixedSize;
  671. PMDL mdl;
  672. ULONG size;
  673. PMDL tmpMdlPtr;
  674. ASSERT(Length);
  675. //
  676. // If the requested length is greater than 2Gb, then we're not going
  677. // to be able to map the memory, so fail the request.
  678. //
  679. if (Length & 0x80000000) {
  680. return NULL;
  681. }
  682. //
  683. // Allocate an MDL from the lookaside list or pool as appropriate.
  684. //
  685. mdl = NULL;
  686. fixedSize = 0;
  687. size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);
  688. if (size > IOP_FIXED_SIZE_MDL_PFNS) {
  689. allocateSize = sizeof(MDL) + (sizeof(PFN_NUMBER) * size);
  690. if (allocateSize > MAXUSHORT) {
  691. return NULL;
  692. }
  693. } else {
  694. fixedSize = MDL_ALLOCATED_FIXED_SIZE;
  695. allocateSize = sizeof(MDL) + (sizeof(PFN_NUMBER) * IOP_FIXED_SIZE_MDL_PFNS);
  696. mdl = (PMDL)ExAllocateFromPPLookasideList(LookasideMdlList);
  697. }
  698. if (!mdl) {
  699. mdl = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' ldM');
  700. if (!mdl) {
  701. return NULL;
  702. }
  703. }
  704. //
  705. // Now fill in the header of the MDL.
  706. //
  707. MmInitializeMdl(mdl, VirtualAddress, Length);
  708. mdl->MdlFlags |= (fixedSize);
  709. //
  710. // Finally, if an IRP was specified, store the address of the MDL
  711. // based on whether or not this is a secondary buffer.
  712. //
  713. if (Irp) {
  714. if (!SecondaryBuffer) {
  715. Irp->MdlAddress = mdl;
  716. } else {
  717. tmpMdlPtr = Irp->MdlAddress;
  718. while (tmpMdlPtr->Next != NULL) {
  719. tmpMdlPtr = tmpMdlPtr->Next;
  720. }
  721. tmpMdlPtr->Next = mdl;
  722. }
  723. }
  724. return mdl;
  725. }
  726. NTSTATUS
  727. IoAsynchronousPageWrite(
  728. IN PFILE_OBJECT FileObject,
  729. IN PMDL MemoryDescriptorList,
  730. IN PLARGE_INTEGER StartingOffset,
  731. IN PIO_APC_ROUTINE ApcRoutine,
  732. IN PVOID ApcContext,
  733. OUT PIO_STATUS_BLOCK IoStatusBlock,
  734. OUT PIRP *Irp OPTIONAL
  735. )
  736. /*++
  737. Routine Description:
  738. This routine provides a special, fast interface for the Modified Page Writer
  739. (MPW) to write pages to the disk quickly and with very little overhead. All
  740. of the special handling for this request is recognized by setting the
  741. IRP_PAGING_IO flag in the IRP flags word.
  742. Arguments:
  743. FileObject - A pointer to a referenced file object describing which file
  744. the write should be performed on.
  745. MemoryDescriptorList - An MDL which describes the physical pages that the
  746. pages should be written to the disk. All of the pages have been locked
  747. in memory. The MDL also describes the length of the write operation.
  748. StartingOffset - Pointer to the offset in the file from which the write
  749. should take place.
  750. ApcRoutine - The address of a kernel APC routine which should be executed
  751. after the write operation has completed.
  752. ApcContext - A context parameter which should be supplied to the kernel APC
  753. routine when it executes.
  754. IoStatusBlock - A pointer to the I/O status block in which the final status
  755. and information should be stored.
  756. Irp - If specified, allows the caller to squirrel away a pointer to the Irp.
  757. Return Value:
  758. The function value is the final status of the queue request to the I/O
  759. system subcomponents.
  760. --*/
  761. {
  762. PIRP irp;
  763. PIO_STACK_LOCATION irpSp;
  764. PDEVICE_OBJECT deviceObject;
  765. NTSTATUS status;
  766. //
  767. // Increment performance counters
  768. //
  769. if (CcIsFileCached(FileObject)) {
  770. CcDataFlushes += 1;
  771. CcDataPages += (MemoryDescriptorList->ByteCount + PAGE_SIZE - 1) >> PAGE_SHIFT;
  772. }
  773. //
  774. // Begin by getting a pointer to the device object that the file resides
  775. // on.
  776. //
  777. deviceObject = IoGetRelatedDeviceObject( FileObject );
  778. //
  779. // Allocate an I/O Request Packet (IRP) for this out-page operation.
  780. //
  781. irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
  782. if (!irp) {
  783. return STATUS_INSUFFICIENT_RESOURCES;
  784. }
  785. //
  786. // If specified, let the caller know what Irp is responsible for this
  787. // transfer. While this is mainly for debugging purposes, it is
  788. // absolutely essential to debug certain types of problems, and is
  789. // very cheap, thus is included in the FREE build as well.
  790. //
  791. if (ARGUMENT_PRESENT(Irp)) {
  792. *Irp = irp;
  793. }
  794. //
  795. // Get a pointer to the first stack location in the packet. This location
  796. // will be used to pass the function codes and parameters to the first
  797. // driver.
  798. //
  799. irpSp = IoGetNextIrpStackLocation( irp );
  800. //
  801. // Fill in the IRP according to this request.
  802. //
  803. irp->MdlAddress = MemoryDescriptorList;
  804. irp->Flags = IRP_PAGING_IO | IRP_NOCACHE;
  805. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  806. irp->Tail.Overlay.OriginalFileObject = FileObject;
  807. irp->UserBuffer = (PVOID) ((PCHAR) MemoryDescriptorList->StartVa + MemoryDescriptorList->ByteOffset);
  808. irp->RequestorMode = KernelMode;
  809. irp->UserIosb = IoStatusBlock;
  810. irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
  811. irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
  812. //
  813. // Fill in the normal write parameters.
  814. //
  815. irpSp->MajorFunction = IRP_MJ_WRITE;
  816. irpSp->Parameters.Write.Length = MemoryDescriptorList->ByteCount;
  817. irpSp->Parameters.Write.ByteOffset = *StartingOffset;
  818. irpSp->FileObject = FileObject;
  819. //
  820. // Queue the packet to the appropriate driver based on whether or not there
  821. // is a VPB associated with the device.
  822. //
  823. status = IoCallDriver( deviceObject, irp );
  824. if (NT_ERROR( status )) {
  825. IoStatusBlock->Status = status;
  826. IoStatusBlock->Information = 0;
  827. ApcRoutine( ApcContext, IoStatusBlock, 0 );
  828. status = STATUS_PENDING;
  829. }
  830. return status;
  831. }
  832. NTSTATUS
  833. IoAttachDevice(
  834. IN PDEVICE_OBJECT SourceDevice,
  835. IN PUNICODE_STRING TargetDevice,
  836. OUT PDEVICE_OBJECT *AttachedDevice
  837. )
  838. /*++
  839. Routine Description:
  840. This routine "attaches" a device to another device. That is, it associates
  841. the source device to a target device which enables the I/O system to ensure
  842. that the target device a) exists, and b) cannot be unloaded until the source
  843. device has detached. Also, requests bound for the target device are given
  844. to the source device first, where applicable.
  845. Arguments:
  846. SourceDevice - Pointer to device object to be attached to the target.
  847. TargetDevice - Supplies the name of the target device to which the attach
  848. is to occur.
  849. AttachedDevice - Returns a pointer to the device to which the attach
  850. occurred. This is the device object that the source driver should
  851. use to communicate with the target driver.
  852. Return Value:
  853. The function value is the final status of the operation.
  854. --*/
  855. {
  856. NTSTATUS status;
  857. PDEVICE_OBJECT targetDevice;
  858. PFILE_OBJECT fileObject;
  859. OBJECT_ATTRIBUTES objectAttributes;
  860. HANDLE fileHandle;
  861. IO_STATUS_BLOCK ioStatus;
  862. PAGED_CODE();
  863. //
  864. // Attempt to open the target device for attach access. This ensures that
  865. // the device itself will be opened, with all of the special considerations
  866. // thereof.
  867. //
  868. InitializeObjectAttributes( &objectAttributes,
  869. TargetDevice,
  870. OBJ_KERNEL_HANDLE,
  871. (HANDLE) NULL,
  872. (PSECURITY_DESCRIPTOR) NULL );
  873. status = ZwOpenFile( &fileHandle,
  874. FILE_READ_ATTRIBUTES,
  875. &objectAttributes,
  876. &ioStatus,
  877. 0,
  878. FILE_NON_DIRECTORY_FILE | IO_ATTACH_DEVICE_API );
  879. if (NT_SUCCESS( status )) {
  880. //
  881. // The open operation was successful. Dereference the file handle
  882. // and obtain a pointer to the device object for the handle.
  883. //
  884. status = ObReferenceObjectByHandle( fileHandle,
  885. 0,
  886. IoFileObjectType,
  887. KernelMode,
  888. (PVOID *) &fileObject,
  889. NULL );
  890. if (NT_SUCCESS( status )) {
  891. //
  892. // Get a pointer to the device object for this file, and close
  893. // the handle.
  894. //
  895. targetDevice = IoGetRelatedDeviceObject( fileObject );
  896. (VOID) ZwClose( fileHandle );
  897. } else {
  898. return status;
  899. }
  900. } else {
  901. return status;
  902. }
  903. //
  904. // Set the attached device pointer so that the driver being attached to
  905. // cannot unload until the detach occurs, and so that attempts to open the
  906. // device object go through the attached driver. Note that the reference
  907. // count is not incremented since exclusive drivers can only be opened once
  908. // and this would count as an open. At that point, both device objects
  909. // would become useless.
  910. //
  911. status = IoAttachDeviceToDeviceStackSafe( SourceDevice, targetDevice, AttachedDevice );
  912. //
  913. // Finally, dereference the file object. This decrements the reference
  914. // count for the target device so that when the detach occurs the device
  915. // can go away if necessary.
  916. //
  917. ObDereferenceObject( fileObject );
  918. //
  919. // Return the final status of the operation.
  920. //
  921. return status;
  922. }
  923. NTSTATUS
  924. IoAttachDeviceByPointer(
  925. IN PDEVICE_OBJECT SourceDevice,
  926. IN PDEVICE_OBJECT TargetDevice
  927. )
  928. /*++
  929. Routine Description:
  930. This routine attaches the source device object to the target device
  931. object.
  932. Arguments:
  933. SourceDevice - Specifies the device object that is to be attached to
  934. the target device.
  935. TargetDevice - Specifies the device object to which the attachment is
  936. to take place.
  937. Return Value:
  938. The function value is the final status of the attach operation.
  939. Note:
  940. THIS FUNCTION IS OBSOLETE!!! see IoAttachDeviceToDeviceStack
  941. --*/
  942. {
  943. PDEVICE_OBJECT deviceObject;
  944. NTSTATUS status;
  945. //
  946. // Get a pointer to the topmost device object in the stack of devices,
  947. // beginning with the TargetDevice.
  948. //
  949. deviceObject = IoAttachDeviceToDeviceStack( SourceDevice, TargetDevice );
  950. if( deviceObject == NULL ){
  951. status = STATUS_NO_SUCH_DEVICE;
  952. } else {
  953. status = STATUS_SUCCESS;
  954. }
  955. return status;
  956. }
  957. PDEVICE_OBJECT
  958. IoAttachDeviceToDeviceStack(
  959. IN PDEVICE_OBJECT SourceDevice,
  960. IN PDEVICE_OBJECT TargetDevice
  961. )
  962. /*++
  963. Routine Description:
  964. This routine attaches the source device object to the target device
  965. object and returns a pointer to the actual device attached to, if
  966. successful.
  967. Arguments:
  968. SourceDevice - Specifies the device object that is to be attached to
  969. the target device.
  970. TargetDevice - Specifies the device object to which the attachment is
  971. to occur.
  972. Return Value:
  973. If successful, this function returns a pointer to the device object to
  974. which the attachment actually occurred.
  975. If unsuccessful, this function returns NULL. (This could happen if the
  976. device currently at the top of the attachment chain is being unloaded,
  977. deleted or initialized.)
  978. --*/
  979. {
  980. return (IopAttachDeviceToDeviceStackSafe(SourceDevice, TargetDevice, NULL));
  981. }
  982. NTSTATUS
  983. IoAttachDeviceToDeviceStackSafe(
  984. IN PDEVICE_OBJECT SourceDevice,
  985. IN PDEVICE_OBJECT TargetDevice,
  986. IN OUT PDEVICE_OBJECT *AttachedToDeviceObject
  987. )
  988. /*++
  989. Routine Description:
  990. This routine attaches the source device object to the target device
  991. object.
  992. Arguments:
  993. SourceDevice - Specifies the device object that is to be attached to
  994. the target device.
  995. TargetDevice - Specifies the device object to which the attachment is
  996. to occur.
  997. AttachedToDeviceObject - Specifies a pointer where the attached to device object
  998. is stored. Its updated while holding the database lock so that when a filter gets an IRP
  999. its attached to device object field is updated correctly.
  1000. Return Value:
  1001. None.
  1002. --*/
  1003. {
  1004. if (IopAttachDeviceToDeviceStackSafe(SourceDevice, TargetDevice, AttachedToDeviceObject) == NULL)
  1005. return STATUS_NO_SUCH_DEVICE;
  1006. else
  1007. return STATUS_SUCCESS;
  1008. }
  1009. PDEVICE_OBJECT
  1010. IopAttachDeviceToDeviceStackSafe(
  1011. IN PDEVICE_OBJECT SourceDevice,
  1012. IN PDEVICE_OBJECT TargetDevice,
  1013. OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. This routine attaches the source device object to the target device
  1018. object and returns a pointer to the actual device attached to, if
  1019. successful.
  1020. Arguments:
  1021. SourceDevice - Specifies the device object that is to be attached to
  1022. the target device.
  1023. TargetDevice - Specifies the device object to which the attachment is
  1024. to occur.
  1025. AttachedToDeviceObject - Specifies a pointer where the attached to device object
  1026. is stored. Its updated while holding the database lock so that when a filter gets an IRP
  1027. its attached to device object field is updated correctly.
  1028. Return Value:
  1029. If successful, this function returns a pointer to the device object to
  1030. which the attachment actually occurred.
  1031. If unsuccessful, this function returns NULL. (This could happen if the
  1032. device currently at the top of the attachment chain is being unloaded,
  1033. deleted or initialized.)
  1034. --*/
  1035. {
  1036. PDEVICE_OBJECT deviceObject;
  1037. PDEVOBJ_EXTENSION sourceExtension;
  1038. KIRQL irql;
  1039. //
  1040. // Retrieve a pointer to the source device object's extension outside
  1041. // of the IopDatabaseLock, since it isn't protected by that.
  1042. //
  1043. sourceExtension = SourceDevice->DeviceObjectExtension;
  1044. //
  1045. // Get a pointer to the topmost device object in the stack of devices,
  1046. // beginning with the TargetDevice, and attach to it.
  1047. //
  1048. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  1049. //
  1050. // Tell the Special IRP code the stack has changed. Code that will reexamine
  1051. // the stack takes the database lock, so we can place the call here. This
  1052. // also allows us to assert correct behavoir *before* the stack is built up.
  1053. //
  1054. IOV_ATTACH_DEVICE_TO_DEVICE_STACK(SourceDevice, TargetDevice);
  1055. deviceObject = IoGetAttachedDevice( TargetDevice );
  1056. //
  1057. // Make sure that the SourceDevice object isn't already attached to
  1058. // something else, this is now illegal.
  1059. //
  1060. ASSERT( sourceExtension->AttachedTo == NULL );
  1061. //
  1062. // Now attach to the device, provided that it is not being unloaded,
  1063. // deleted or initializing.
  1064. //
  1065. if (deviceObject->Flags & DO_DEVICE_INITIALIZING ||
  1066. deviceObject->DeviceObjectExtension->ExtensionFlags &
  1067. (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED)) {
  1068. //
  1069. // The device currently at the top of the attachment chain is being
  1070. // unloaded, deleted or initialized.
  1071. //
  1072. deviceObject = (PDEVICE_OBJECT) NULL;
  1073. } else {
  1074. //
  1075. // Perform the attachment. First update the device previously at the
  1076. // top of the attachment chain.
  1077. //
  1078. deviceObject->AttachedDevice = SourceDevice;
  1079. deviceObject->Spare1++;
  1080. //
  1081. // Now update the new top-of-attachment-chain.
  1082. //
  1083. SourceDevice->StackSize = (UCHAR) (deviceObject->StackSize + 1);
  1084. SourceDevice->AlignmentRequirement = deviceObject->AlignmentRequirement;
  1085. SourceDevice->SectorSize = deviceObject->SectorSize;
  1086. if (deviceObject->DeviceObjectExtension->ExtensionFlags & DOE_START_PENDING) {
  1087. SourceDevice->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING;
  1088. }
  1089. //
  1090. // Attachment chain is doubly-linked.
  1091. //
  1092. sourceExtension->AttachedTo = deviceObject;
  1093. }
  1094. //
  1095. // Atomically update this field inside the lock.
  1096. // The caller has to ensure that this location is in non-paged pool.
  1097. // This is required so that a filesystem filter can attach to a device and before it
  1098. // gets an IRP it can update its lower device object pointer.
  1099. //
  1100. if (AttachedToDeviceObject) {
  1101. *AttachedToDeviceObject = deviceObject;
  1102. }
  1103. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  1104. return deviceObject;
  1105. }
  1106. PIRP
  1107. IoBuildAsynchronousFsdRequest(
  1108. IN ULONG MajorFunction,
  1109. IN PDEVICE_OBJECT DeviceObject,
  1110. IN OUT PVOID Buffer OPTIONAL,
  1111. IN ULONG Length OPTIONAL,
  1112. IN PLARGE_INTEGER StartingOffset OPTIONAL,
  1113. IN PIO_STATUS_BLOCK IoStatusBlock OPTIONAL
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This routine builds an I/O Request Packet (IRP) suitable for a File System
  1118. Driver (FSD) to use in requesting an I/O operation from a device driver.
  1119. The request must be one of the following request codes:
  1120. IRP_MJ_READ
  1121. IRP_MJ_WRITE
  1122. IRP_MJ_FLUSH_BUFFERS
  1123. IRP_MJ_SHUTDOWN
  1124. IRP_MJ_POWER
  1125. This routine provides a simple, fast interface to the device driver w/o
  1126. having to put the knowledge of how to build an IRP into all of the FSDs
  1127. (and device drivers) in the system.
  1128. Arguments:
  1129. MajorFunction - Function to be performed; see previous list.
  1130. DeviceObject - Pointer to device object on which the I/O will be performed.
  1131. Buffer - Pointer to buffer to get data from or write data into. This
  1132. parameter is required for read/write, but not for flush or shutdown
  1133. functions.
  1134. Length - Length of buffer in bytes. This parameter is required for
  1135. read/write, but not for flush or shutdown functions.
  1136. StartingOffset - Pointer to the offset on the disk to read/write from/to.
  1137. This parameter is required for read/write, but not for flush or
  1138. shutdown functions.
  1139. IoStatusBlock - Pointer to the I/O status block for completion status
  1140. information. This parameter is optional since most asynchronous FSD
  1141. requests will be synchronized by using completion routines, and so the
  1142. I/O status block will not be written.
  1143. Return Value:
  1144. The function value is a pointer to the IRP representing the specified
  1145. request.
  1146. --*/
  1147. {
  1148. PIRP irp;
  1149. PIO_STACK_LOCATION irpSp;
  1150. //
  1151. // Begin by allocating the IRP for this request. Do not charge quota to
  1152. // the current process for this IRP.
  1153. //
  1154. irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
  1155. if (!irp) {
  1156. return irp;
  1157. }
  1158. //
  1159. // Set current thread for IoSetHardErrorOrVerifyDevice.
  1160. //
  1161. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1162. //
  1163. // Get a pointer to the stack location of the first driver which will be
  1164. // invoked. This is where the function codes and the parameters are set.
  1165. //
  1166. irpSp = IoGetNextIrpStackLocation( irp );
  1167. //
  1168. // Set the major function code.
  1169. //
  1170. irpSp->MajorFunction = (UCHAR) MajorFunction;
  1171. if (MajorFunction != IRP_MJ_FLUSH_BUFFERS &&
  1172. MajorFunction != IRP_MJ_SHUTDOWN &&
  1173. MajorFunction != IRP_MJ_PNP &&
  1174. MajorFunction != IRP_MJ_POWER) {
  1175. //
  1176. // Now allocate a buffer or lock the pages of the caller's buffer into
  1177. // memory based on whether the target device performs direct or buffered
  1178. // I/O operations.
  1179. //
  1180. if (DeviceObject->Flags & DO_BUFFERED_IO) {
  1181. //
  1182. // The target device supports buffered I/O operations. Allocate a
  1183. // system buffer and, if this is a write, fill it in. Otherwise,
  1184. // the copy will be done into the caller's buffer in the completion
  1185. // code. Also note that the system buffer should be deallocated on
  1186. // completion. Also, set the parameters based on whether this is a
  1187. // read or a write operation.
  1188. //
  1189. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1190. Length,
  1191. ' oI' );
  1192. if (irp->AssociatedIrp.SystemBuffer == NULL) {
  1193. IoFreeIrp( irp );
  1194. return (PIRP) NULL;
  1195. }
  1196. if (MajorFunction == IRP_MJ_WRITE) {
  1197. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, Buffer, Length );
  1198. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  1199. } else {
  1200. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
  1201. irp->UserBuffer = Buffer;
  1202. }
  1203. } else if (DeviceObject->Flags & DO_DIRECT_IO) {
  1204. //
  1205. // The target device supports direct I/O operations. Allocate
  1206. // an MDL large enough to map the buffer and lock the pages into
  1207. // memory.
  1208. //
  1209. irp->MdlAddress = IoAllocateMdl( Buffer,
  1210. Length,
  1211. FALSE,
  1212. FALSE,
  1213. (PIRP) NULL );
  1214. if (irp->MdlAddress == NULL) {
  1215. IoFreeIrp( irp );
  1216. return (PIRP) NULL;
  1217. }
  1218. try {
  1219. MmProbeAndLockPages( irp->MdlAddress,
  1220. KernelMode,
  1221. (LOCK_OPERATION) (MajorFunction == IRP_MJ_READ ? IoWriteAccess : IoReadAccess) );
  1222. } except(EXCEPTION_EXECUTE_HANDLER) {
  1223. if (irp->MdlAddress != NULL) {
  1224. IoFreeMdl( irp->MdlAddress );
  1225. }
  1226. IoFreeIrp( irp );
  1227. return (PIRP) NULL;
  1228. }
  1229. } else {
  1230. //
  1231. // The operation is neither buffered nor direct. Simply pass the
  1232. // address of the buffer in the packet to the driver.
  1233. //
  1234. irp->UserBuffer = Buffer;
  1235. }
  1236. //
  1237. // Set the parameters according to whether this is a read or a write
  1238. // operation. Notice that these parameters must be set even if the
  1239. // driver has not specified buffered or direct I/O.
  1240. //
  1241. if (MajorFunction == IRP_MJ_WRITE) {
  1242. irpSp->Parameters.Write.Length = Length;
  1243. irpSp->Parameters.Write.ByteOffset = *StartingOffset;
  1244. } else {
  1245. irpSp->Parameters.Read.Length = Length;
  1246. irpSp->Parameters.Read.ByteOffset = *StartingOffset;
  1247. }
  1248. }
  1249. //
  1250. // Finally, set the address of the I/O status block and return a pointer
  1251. // to the IRP.
  1252. //
  1253. irp->UserIosb = IoStatusBlock;
  1254. return irp;
  1255. }
  1256. PIRP
  1257. IoBuildDeviceIoControlRequest(
  1258. IN ULONG IoControlCode,
  1259. IN PDEVICE_OBJECT DeviceObject,
  1260. IN PVOID InputBuffer OPTIONAL,
  1261. IN ULONG InputBufferLength,
  1262. OUT PVOID OutputBuffer OPTIONAL,
  1263. IN ULONG OutputBufferLength,
  1264. IN BOOLEAN InternalDeviceIoControl,
  1265. IN PKEVENT Event,
  1266. OUT PIO_STATUS_BLOCK IoStatusBlock
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. This routine builds an I/O Request Packet (IRP) that can be used to
  1271. perform a synchronous internal or normal device I/O control function.
  1272. Arguments:
  1273. IoControlCode - Specifies the device I/O control code that is to be
  1274. performed by the target device driver.
  1275. DeviceObject - Specifies the target device on which the I/O control
  1276. function is to be performed.
  1277. InputBuffer - Optional pointer to an input buffer that is to be passed
  1278. to the device driver.
  1279. InputBufferLength - Length of the InputBuffer in bytes. If the Input-
  1280. Buffer parameter is not passed, this parameter must be zero.
  1281. OutputBuffer - Optional pointer to an output buffer that is to be passed
  1282. to the device driver.
  1283. OutputBufferLength - Length of the OutputBuffer in bytes. If the
  1284. OutputBuffer parameter is not passed, this parameter must be zero.
  1285. InternalDeviceIoControl - A BOOLEAN parameter that specifies whether
  1286. the packet that gets generated should have a major function code
  1287. of IRP_MJ_INTERNAL_DEVICE_CONTROL (the parameter is TRUE), or
  1288. IRP_MJ_DEVICE_CONTROL (the parameter is FALSE).
  1289. Event - Supplies a pointer to a kernel event that is to be set to the
  1290. Signaled state when the I/O operation is complete. Note that the
  1291. Event must already be set to the Not-Signaled state.
  1292. IoStatusBlock - Supplies a pointer to an I/O status block that is to
  1293. be filled in with the final status of the operation once it
  1294. completes.
  1295. Return Value:
  1296. The function value is a pointer to the generated IRP suitable for calling
  1297. the target device driver.
  1298. --*/
  1299. {
  1300. PIRP irp;
  1301. PIO_STACK_LOCATION irpSp;
  1302. ULONG method;
  1303. //
  1304. // Begin by allocating the IRP for this request. Do not charge quota to
  1305. // the current process for this IRP.
  1306. //
  1307. irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
  1308. if (!irp) {
  1309. return irp;
  1310. }
  1311. //
  1312. // Get a pointer to the stack location of the first driver which will be
  1313. // invoked. This is where the function codes and the parameters are set.
  1314. //
  1315. irpSp = IoGetNextIrpStackLocation( irp );
  1316. //
  1317. // Set the major function code based on the type of device I/O control
  1318. // function the caller has specified.
  1319. //
  1320. if (InternalDeviceIoControl) {
  1321. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1322. } else {
  1323. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1324. }
  1325. //
  1326. // Copy the caller's parameters to the service-specific portion of the
  1327. // IRP for those parameters that are the same for all four methods.
  1328. //
  1329. irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  1330. irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  1331. irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  1332. //
  1333. // Get the method bits from the I/O control code to determine how the
  1334. // buffers are to be passed to the driver.
  1335. //
  1336. method = IoControlCode & 3;
  1337. //
  1338. // Based on the method that the buffers are being passed, either allocate
  1339. // buffers or build MDLs or do nothing.
  1340. //
  1341. switch ( method ) {
  1342. case METHOD_BUFFERED:
  1343. //
  1344. // For this case, allocate a buffer that is large enough to contain
  1345. // both the input and the output buffers. Copy the input buffer
  1346. // to the allocated buffer and set the appropriate IRP fields.
  1347. //
  1348. if (InputBufferLength != 0 || OutputBufferLength != 0) {
  1349. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1350. InputBufferLength > OutputBufferLength ? InputBufferLength : OutputBufferLength,
  1351. ' oI' );
  1352. if (irp->AssociatedIrp.SystemBuffer == NULL) {
  1353. IoFreeIrp( irp );
  1354. return (PIRP) NULL;
  1355. }
  1356. if (ARGUMENT_PRESENT( InputBuffer )) {
  1357. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
  1358. InputBuffer,
  1359. InputBufferLength );
  1360. }
  1361. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  1362. irp->UserBuffer = OutputBuffer;
  1363. if (ARGUMENT_PRESENT( OutputBuffer )) {
  1364. irp->Flags |= IRP_INPUT_OPERATION;
  1365. }
  1366. } else {
  1367. irp->Flags = 0;
  1368. irp->UserBuffer = (PVOID) NULL;
  1369. }
  1370. break;
  1371. case METHOD_IN_DIRECT:
  1372. case METHOD_OUT_DIRECT:
  1373. //
  1374. // For these two cases, allocate a buffer that is large enough to
  1375. // contain the input buffer, if any, and copy the information to
  1376. // the allocated buffer. Then build an MDL for either read or write
  1377. // access, depending on the method, for the output buffer. Note
  1378. // that an output buffer must have been specified.
  1379. //
  1380. if (ARGUMENT_PRESENT( InputBuffer )) {
  1381. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1382. InputBufferLength,
  1383. ' oI' );
  1384. if (irp->AssociatedIrp.SystemBuffer == NULL) {
  1385. IoFreeIrp( irp );
  1386. return (PIRP) NULL;
  1387. }
  1388. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
  1389. InputBuffer,
  1390. InputBufferLength );
  1391. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  1392. } else {
  1393. irp->Flags = 0;
  1394. }
  1395. if (ARGUMENT_PRESENT( OutputBuffer )) {
  1396. irp->MdlAddress = IoAllocateMdl( OutputBuffer,
  1397. OutputBufferLength,
  1398. FALSE,
  1399. FALSE,
  1400. (PIRP) NULL );
  1401. if (irp->MdlAddress == NULL) {
  1402. if (ARGUMENT_PRESENT( InputBuffer )) {
  1403. ExFreePool( irp->AssociatedIrp.SystemBuffer );
  1404. }
  1405. IoFreeIrp( irp );
  1406. return (PIRP) NULL;
  1407. }
  1408. try {
  1409. MmProbeAndLockPages( irp->MdlAddress,
  1410. KernelMode,
  1411. (LOCK_OPERATION) ((method == 1) ? IoReadAccess : IoWriteAccess) );
  1412. } except (EXCEPTION_EXECUTE_HANDLER) {
  1413. if (irp->MdlAddress != NULL) {
  1414. IoFreeMdl( irp->MdlAddress );
  1415. }
  1416. if (ARGUMENT_PRESENT( InputBuffer )) {
  1417. ExFreePool( irp->AssociatedIrp.SystemBuffer );
  1418. }
  1419. IoFreeIrp( irp );
  1420. return (PIRP) NULL;
  1421. }
  1422. }
  1423. break;
  1424. case METHOD_NEITHER:
  1425. //
  1426. // For this case, do nothing. Everything is up to the driver.
  1427. // Simply give the driver a copy of the caller's parameters and
  1428. // let the driver do everything itself.
  1429. //
  1430. irp->UserBuffer = OutputBuffer;
  1431. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
  1432. }
  1433. //
  1434. // Finally, set the address of the I/O status block and the address of
  1435. // the kernel event object. Note that I/O completion will not attempt
  1436. // to dereference the event since there is no file object associated
  1437. // with this operation.
  1438. //
  1439. irp->UserIosb = IoStatusBlock;
  1440. irp->UserEvent = Event;
  1441. //
  1442. // Also set the address of the current thread in the packet so the
  1443. // completion code will have a context to execute in. The IRP also
  1444. // needs to be queued to the thread since the caller is going to set
  1445. // the file object pointer.
  1446. //
  1447. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1448. IopQueueThreadIrp( irp );
  1449. //
  1450. // Simply return a pointer to the packet.
  1451. //
  1452. return irp;
  1453. }
  1454. VOID
  1455. IoBuildPartialMdl(
  1456. IN PMDL SourceMdl,
  1457. IN OUT PMDL TargetMdl,
  1458. IN PVOID VirtualAddress,
  1459. IN ULONG Length
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. This routine maps a portion of a buffer as described by an MDL. The
  1464. portion of the buffer to be mapped is specified via a virtual address
  1465. and an optional length. If the length is not supplied, then the
  1466. remainder of the buffer is mapped.
  1467. Arguments:
  1468. SourceMdl - MDL for the current buffer.
  1469. TargetMdl - MDL to map the specified portion of the buffer.
  1470. VirtualAddress - Base of the buffer to begin mapping.
  1471. Length - Length of buffer to be mapped; if zero, remainder.
  1472. Return Value:
  1473. None.
  1474. Notes:
  1475. This routine assumes that the target MDL is large enough to map the
  1476. desired portion of the buffer. If the target is not large enough
  1477. then an exception will be raised.
  1478. It is also assumed that the remaining length of the buffer to be mapped
  1479. is non-zero.
  1480. --*/
  1481. {
  1482. ULONG_PTR baseVa;
  1483. ULONG offset;
  1484. ULONG newLength;
  1485. ULONG pageOffset;
  1486. PPFN_NUMBER basePointer;
  1487. PPFN_NUMBER copyPointer;
  1488. //
  1489. // Calculate the base address of the buffer that the source Mdl maps.
  1490. // Then, determine the length of the buffer to be mapped, if not
  1491. // specified.
  1492. //
  1493. baseVa = (ULONG_PTR) MmGetMdlBaseVa( SourceMdl );
  1494. offset = (ULONG) ((ULONG_PTR)VirtualAddress - baseVa) - MmGetMdlByteOffset(SourceMdl);
  1495. if (Length == 0) {
  1496. newLength = MmGetMdlByteCount( SourceMdl ) - offset;
  1497. } else {
  1498. newLength = Length;
  1499. //if (newLength > (MmGetMdlByteCount(SourceMdl) - offset)) {
  1500. // KeBugCheck( TARGET_MDL_TOO_SMALL );
  1501. //}
  1502. }
  1503. //
  1504. // Initialize the target MDL header. Note that the original size of
  1505. // the MDL structure itself is left unchanged.
  1506. //
  1507. //ASSERT ((SourceMdl->MdlFlags & MDL_PARTIAL) == 0);
  1508. TargetMdl->Process = SourceMdl->Process;
  1509. TargetMdl->StartVa = (PVOID) PAGE_ALIGN( VirtualAddress );
  1510. pageOffset = ((ULONG)((ULONG_PTR) TargetMdl->StartVa - (ULONG_PTR) SourceMdl->StartVa)) >> PAGE_SHIFT;
  1511. TargetMdl->ByteCount = newLength;
  1512. TargetMdl->ByteOffset = BYTE_OFFSET( VirtualAddress );
  1513. newLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES( VirtualAddress, newLength );
  1514. if (((TargetMdl->Size - sizeof( MDL )) / sizeof (PFN_NUMBER)) < newLength ) {
  1515. KeBugCheck( TARGET_MDL_TOO_SMALL );
  1516. }
  1517. //
  1518. // Set the MdlFlags in the target MDL. Clear all flags but
  1519. // carry across the allocation information, page read and the
  1520. // system mapped info.
  1521. //
  1522. TargetMdl->MdlFlags &= (MDL_ALLOCATED_FIXED_SIZE | MDL_ALLOCATED_MUST_SUCCEED);
  1523. TargetMdl->MdlFlags |= SourceMdl->MdlFlags & (MDL_SOURCE_IS_NONPAGED_POOL |
  1524. MDL_MAPPED_TO_SYSTEM_VA |
  1525. MDL_IO_PAGE_READ);
  1526. TargetMdl->MdlFlags |= MDL_PARTIAL;
  1527. #if DBG
  1528. if (TargetMdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
  1529. TargetMdl->MdlFlags |= MDL_PARENT_MAPPED_SYSTEM_VA;
  1530. }
  1531. #endif //DBG
  1532. //
  1533. // Preserved the mapped system address.
  1534. //
  1535. TargetMdl->MappedSystemVa = (PUCHAR)SourceMdl->MappedSystemVa + offset;
  1536. //
  1537. // Determine the base address of the first PFN in the source MDL that
  1538. // needs to be copied to the target. Then, copy as many PFNs as are
  1539. // needed.
  1540. //
  1541. basePointer = MmGetMdlPfnArray(SourceMdl);
  1542. basePointer += pageOffset;
  1543. copyPointer = MmGetMdlPfnArray(TargetMdl);
  1544. while (newLength > 0) {
  1545. *copyPointer = *basePointer;
  1546. copyPointer++;
  1547. basePointer++;
  1548. newLength--;
  1549. }
  1550. }
  1551. PIRP
  1552. IoBuildSynchronousFsdRequest(
  1553. IN ULONG MajorFunction,
  1554. IN PDEVICE_OBJECT DeviceObject,
  1555. IN OUT PVOID Buffer OPTIONAL,
  1556. IN ULONG Length OPTIONAL,
  1557. IN PLARGE_INTEGER StartingOffset OPTIONAL,
  1558. IN PKEVENT Event,
  1559. OUT PIO_STATUS_BLOCK IoStatusBlock
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. This routine builds an I/O Request Packet (IRP) suitable for a File System
  1564. Driver (FSD) to use in requesting an I/O operation from a device driver.
  1565. The request must be one of the following request codes:
  1566. IRP_MJ_READ
  1567. IRP_MJ_WRITE
  1568. IRP_MJ_FLUSH_BUFFERS
  1569. IRP_MJ_SHUTDOWN
  1570. This routine provides a simple, fast interface to the device driver w/o
  1571. having to put the knowledge of how to build an IRP into all of the FSDs
  1572. (and device drivers) in the system.
  1573. The IRP created by this function causes the I/O system to complete the
  1574. request by setting the specified event to the Signaled state.
  1575. Arguments:
  1576. MajorFunction - Function to be performed; see previous list.
  1577. DeviceObject - Pointer to device object on which the I/O will be performed.
  1578. Buffer - Pointer to buffer to get data from or write data into. This
  1579. parameter is required for read/write, but not for flush or shutdown
  1580. functions.
  1581. Length - Length of buffer in bytes. This parameter is required for
  1582. read/write, but not for flush or shutdown functions.
  1583. StartingOffset - Pointer to the offset on the disk to read/write from/to.
  1584. This parameter is required for read/write, but not for flush or
  1585. shutdown functions.
  1586. Event - Pointer to a kernel event structure for synchronization. The event
  1587. will be set to the Signaled state when the I/O has completed.
  1588. IoStatusBlock - Pointer to I/O status block for completion status info.
  1589. Return Value:
  1590. The function value is a pointer to the IRP representing the specified
  1591. request.
  1592. --*/
  1593. {
  1594. PIRP irp;
  1595. //
  1596. // Do all of the real work in real IRP build routine.
  1597. //
  1598. irp = IoBuildAsynchronousFsdRequest( MajorFunction,
  1599. DeviceObject,
  1600. Buffer,
  1601. Length,
  1602. StartingOffset,
  1603. IoStatusBlock );
  1604. if (irp == NULL) {
  1605. return irp;
  1606. }
  1607. //
  1608. // Now fill in the event to the completion code will do the right thing.
  1609. // Notice that because there is no FileObject, the I/O completion code
  1610. // will not attempt to dereference the event.
  1611. //
  1612. irp->UserEvent = Event;
  1613. //
  1614. // There will be a file object associated w/this packet, so it must be
  1615. // queued to the thread.
  1616. //
  1617. IopQueueThreadIrp( irp );
  1618. return irp;
  1619. }
  1620. NTSTATUS
  1621. FASTCALL
  1622. IopfCallDriver(
  1623. IN PDEVICE_OBJECT DeviceObject,
  1624. IN OUT PIRP Irp
  1625. )
  1626. /*++
  1627. Routine Description:
  1628. This routine is invoked to pass an I/O Request Packet (IRP) to another
  1629. driver at its dispatch routine.
  1630. Arguments:
  1631. DeviceObject - Pointer to device object to which the IRP should be passed.
  1632. Irp - Pointer to IRP for request.
  1633. Return Value:
  1634. Return status from driver's dispatch routine.
  1635. --*/
  1636. {
  1637. PIO_STACK_LOCATION irpSp;
  1638. PDRIVER_OBJECT driverObject;
  1639. NTSTATUS status;
  1640. //
  1641. // Ensure that this is really an I/O Request Packet.
  1642. //
  1643. ASSERT( Irp->Type == IO_TYPE_IRP );
  1644. //
  1645. // Update the IRP stack to point to the next location.
  1646. //
  1647. Irp->CurrentLocation--;
  1648. if (Irp->CurrentLocation <= 0) {
  1649. KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0, 0 );
  1650. }
  1651. irpSp = IoGetNextIrpStackLocation( Irp );
  1652. Irp->Tail.Overlay.CurrentStackLocation = irpSp;
  1653. //
  1654. // Save a pointer to the device object for this request so that it can
  1655. // be used later in completion.
  1656. //
  1657. irpSp->DeviceObject = DeviceObject;
  1658. //
  1659. // Invoke the driver at its dispatch routine entry point.
  1660. //
  1661. driverObject = DeviceObject->DriverObject;
  1662. //
  1663. // Prevent the driver from unloading.
  1664. //
  1665. status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
  1666. Irp );
  1667. return status;
  1668. }
  1669. NTSTATUS
  1670. FASTCALL
  1671. IofCallDriver(
  1672. IN PDEVICE_OBJECT DeviceObject,
  1673. IN OUT PIRP Irp
  1674. )
  1675. {
  1676. //
  1677. // This routine will either jump immediately to IopfCallDriver, or rather
  1678. // IovCallDriver.
  1679. //
  1680. return pIofCallDriver(DeviceObject, Irp);
  1681. }
  1682. BOOLEAN
  1683. IoCancelIrp(
  1684. IN PIRP Irp
  1685. )
  1686. /*++
  1687. Routine Description:
  1688. This routine is invoked to cancel an individual I/O Request Packet.
  1689. It acquires the cancel spin lock, sets the cancel flag in the IRP, and
  1690. then invokes the cancel routine specified by the appropriate field in
  1691. the IRP, if a routine was specified. It is expected that the cancel
  1692. routine will relaease the cancel spinlock. If there is no cancel routine,
  1693. then the cancel spin lock is released.
  1694. Arguments:
  1695. Irp - Supplies a pointer to the IRP to be cancelled.
  1696. Return Value:
  1697. The function value is TRUE if the IRP was in a cancelable state (it
  1698. had a cancel routine), else FALSE is returned.
  1699. Notes:
  1700. It is assumed that the caller has taken the necessary action to ensure
  1701. that the packet cannot be fully completed before invoking this routine.
  1702. --*/
  1703. {
  1704. PDRIVER_CANCEL cancelRoutine;
  1705. KIRQL irql;
  1706. BOOLEAN returnValue;
  1707. ASSERT( Irp->Type == IO_TYPE_IRP );
  1708. if (IopVerifierOn) {
  1709. if (IOV_CANCEL_IRP(Irp, &returnValue)) {
  1710. return returnValue;
  1711. }
  1712. }
  1713. //
  1714. // Acquire the cancel spin lock.
  1715. //
  1716. IoAcquireCancelSpinLock( &irql );
  1717. //
  1718. // Set the cancel flag in the IRP.
  1719. //
  1720. Irp->Cancel = TRUE;
  1721. //
  1722. // Obtain the address of the cancel routine, and if one was specified,
  1723. // invoke it.
  1724. //
  1725. cancelRoutine = (PDRIVER_CANCEL) InterlockedExchangePointer( (PVOID *) &Irp->CancelRoutine,
  1726. NULL );
  1727. if (cancelRoutine) {
  1728. if (Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1)) {
  1729. KeBugCheckEx( CANCEL_STATE_IN_COMPLETED_IRP, (ULONG_PTR) Irp, 0, 0, 0 );
  1730. }
  1731. Irp->CancelIrql = irql;
  1732. cancelRoutine( Irp->Tail.Overlay.CurrentStackLocation->DeviceObject,
  1733. Irp );
  1734. //
  1735. // The cancel spinlock should have been released by the cancel routine.
  1736. //
  1737. return(TRUE);
  1738. } else {
  1739. //
  1740. // There was no cancel routine, so release the cancel spinlock and
  1741. // return indicating the Irp was not currently cancelable.
  1742. //
  1743. IoReleaseCancelSpinLock( irql );
  1744. return(FALSE);
  1745. }
  1746. }
  1747. VOID
  1748. IoCancelThreadIo(
  1749. IN PETHREAD Thread
  1750. )
  1751. /*++
  1752. Routine Description:
  1753. This routine cancels all of the I/O operations for the specified thread.
  1754. This is accomplished by walking the list of IRPs in the thread IRP list
  1755. and canceling each one individually. No other I/O operations can be
  1756. started for the thread since this routine has control of the thread itself.
  1757. Arguments:
  1758. Tcb - Pointer to the Thread Control Block for the thread.
  1759. Return Value:
  1760. None.
  1761. --*/
  1762. {
  1763. PLIST_ENTRY header;
  1764. PLIST_ENTRY entry;
  1765. KIRQL irql;
  1766. PETHREAD thread;
  1767. PIRP irp;
  1768. ULONG count;
  1769. LARGE_INTEGER interval;
  1770. PAGED_CODE();
  1771. DBG_UNREFERENCED_PARAMETER( Thread );
  1772. thread = PsGetCurrentThread();
  1773. //
  1774. // Raise the IRQL so that the IrpList cannot be modified by a completion
  1775. // APC.
  1776. //
  1777. KeRaiseIrql( APC_LEVEL, &irql );
  1778. header = &thread->IrpList;
  1779. entry = thread->IrpList.Flink;
  1780. //
  1781. // Walk the list of pending IRPs, canceling each of them.
  1782. //
  1783. while (header != entry) {
  1784. irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
  1785. IoCancelIrp( irp );
  1786. entry = entry->Flink;
  1787. }
  1788. //
  1789. // Wait for the requests to complete. Note that waiting may eventually
  1790. // timeout, in which case more work must be done.
  1791. //
  1792. count = 0;
  1793. interval.QuadPart = -10 * 1000 * 100;
  1794. while (!IsListEmpty( &Thread->IrpList )) {
  1795. //
  1796. // Lower the IRQL so that the thread APC can fire which will complete
  1797. // the requests. Delay execution for a time and let the request
  1798. // finish. The delay time is 100ms.
  1799. //
  1800. KeLowerIrql( irql );
  1801. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  1802. if (count++ > 3000) {
  1803. //
  1804. // This I/O request has timed out, as it has not been completed
  1805. // for a full 5 minutes. Attempt to remove the packet's association
  1806. // with this thread. Note that by not resetting the count, the
  1807. // next time through the loop the next packet, if there is one,
  1808. // which has also timed out, will be dealt with, although it
  1809. // will be given another 100ms to complete.
  1810. //
  1811. IopDisassociateThreadIrp();
  1812. }
  1813. KeRaiseIrql( APC_LEVEL, &irql );
  1814. }
  1815. KeLowerIrql( irql );
  1816. }
  1817. NTSTATUS
  1818. IoCheckDesiredAccess(
  1819. IN OUT PACCESS_MASK DesiredAccess,
  1820. IN ACCESS_MASK GrantedAccess
  1821. )
  1822. /*++
  1823. Routine Description:
  1824. This routine is invoked to determine whether or not the granted access
  1825. to a file allows the access specified by a desired access.
  1826. Arguments:
  1827. DesiredAccess - Pointer to a variable containing the access desired to
  1828. the file.
  1829. GrantedAccess - Access currently granted to the file.
  1830. Return Value:
  1831. The final status of the access check is the function value. If the
  1832. accessor has the access to the file, then STATUS_SUCCESS is returned;
  1833. otherwise, STATUS_ACCESS_DENIED is returned.
  1834. Also, the DesiredAccess is returned with no generic mapping.
  1835. --*/
  1836. {
  1837. PAGED_CODE();
  1838. //
  1839. // Convert the desired access to a non-generic access mask.
  1840. //
  1841. RtlMapGenericMask( DesiredAccess,
  1842. &IoFileObjectType->TypeInfo.GenericMapping );
  1843. //
  1844. // Determine whether the desired access to the file is allowed, given
  1845. // the current granted access.
  1846. //
  1847. if (!SeComputeDeniedAccesses( GrantedAccess, *DesiredAccess )) {
  1848. return STATUS_SUCCESS;
  1849. } else {
  1850. return STATUS_ACCESS_DENIED;
  1851. }
  1852. }
  1853. NTSTATUS
  1854. IoCheckEaBufferValidity(
  1855. IN PFILE_FULL_EA_INFORMATION EaBuffer,
  1856. IN ULONG EaLength,
  1857. OUT PULONG ErrorOffset
  1858. )
  1859. /*++
  1860. Routine Description:
  1861. This routine checks the validity of the specified EA buffer to guarantee
  1862. that its format is proper, no fields hang over, that it is not recursive,
  1863. etc.
  1864. Arguments:
  1865. EaBuffer - Pointer to the buffer containing the EAs to be checked.
  1866. EaLength - Specifies the length of EaBuffer.
  1867. ErrorOffset - A variable to receive the offset of the offending entry
  1868. in the EA buffer if an error is incurred. This variable is only
  1869. valid if an error occurs.
  1870. Return Value:
  1871. The function value is STATUS_SUCCESS if the EA buffer contains a valid,
  1872. properly formed list, otherwise STATUS_EA_LIST_INCONSISTENT.
  1873. --*/
  1874. #define ALIGN_LONG( Address ) ( (ULONG) ((Address + 3) & ~3) )
  1875. #define GET_OFFSET_LENGTH( CurrentEa, EaBase ) ( \
  1876. (ULONG) ((PCHAR) CurrentEa - (PCHAR) EaBase) )
  1877. {
  1878. LONG tempLength;
  1879. ULONG entrySize;
  1880. PFILE_FULL_EA_INFORMATION eas;
  1881. PAGED_CODE();
  1882. //
  1883. // Walk the buffer and ensure that its format is valid. That is, ensure
  1884. // that it does not walk off the end of the buffer, is not recursive,
  1885. // etc.
  1886. //
  1887. eas = EaBuffer;
  1888. tempLength = EaLength;
  1889. for (;;) {
  1890. //
  1891. // Get the size of the current entry in the buffer. The minimum
  1892. // size of the entry is the fixed size part of the structure plus
  1893. // the length of the name, a single termination character byte which
  1894. // must be present (a 0), plus the length of the value. If this
  1895. // is not the last entry, then there will also be pad bytes to get
  1896. // to the next longword boundary.
  1897. //
  1898. //
  1899. // Start by checking that the fixed size lies within the stated length.
  1900. //
  1901. if (tempLength < FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0])) {
  1902. *ErrorOffset = GET_OFFSET_LENGTH( eas, EaBuffer );
  1903. return STATUS_EA_LIST_INCONSISTENT;
  1904. }
  1905. entrySize = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  1906. eas->EaNameLength + 1 + eas->EaValueLength;
  1907. //
  1908. // Confirm that the full length lies within the stated buffer length.
  1909. //
  1910. if ((ULONG) tempLength < entrySize) {
  1911. *ErrorOffset = GET_OFFSET_LENGTH( eas, EaBuffer );
  1912. return STATUS_EA_LIST_INCONSISTENT;
  1913. }
  1914. //
  1915. // Confirm that there is a NULL terminator after the name.
  1916. //
  1917. if (eas->EaName[eas->EaNameLength] != '\0') {
  1918. *ErrorOffset = GET_OFFSET_LENGTH( eas, EaBuffer );
  1919. return STATUS_EA_LIST_INCONSISTENT;
  1920. }
  1921. if (eas->NextEntryOffset) {
  1922. //
  1923. // There is another entry in the buffer and it must be longword
  1924. // aligned. Ensure that the offset indicates that it is. If it
  1925. // isn't, return invalid parameter.
  1926. //
  1927. if (ALIGN_LONG( entrySize ) != eas->NextEntryOffset ||
  1928. (LONG) eas->NextEntryOffset < 0) {
  1929. *ErrorOffset = GET_OFFSET_LENGTH( eas, EaBuffer );
  1930. return STATUS_EA_LIST_INCONSISTENT;
  1931. } else {
  1932. //
  1933. // There is another entry in the buffer, so account for the
  1934. // size of the current entry in the length and get a pointer
  1935. // to the next entry.
  1936. //
  1937. tempLength -= eas->NextEntryOffset;
  1938. if (tempLength < 0) {
  1939. *ErrorOffset = GET_OFFSET_LENGTH( eas, EaBuffer );
  1940. return STATUS_EA_LIST_INCONSISTENT;
  1941. }
  1942. eas = (PFILE_FULL_EA_INFORMATION) ((PCHAR) eas + eas->NextEntryOffset);
  1943. }
  1944. } else {
  1945. //
  1946. // There are no other entries in the buffer. Simply account for
  1947. // the overall buffer length according to the size of the current
  1948. // entry and exit the loop.
  1949. //
  1950. tempLength -= entrySize;
  1951. break;
  1952. }
  1953. }
  1954. //
  1955. // All of the entries in the buffer have been processed. Check to see
  1956. // whether the overall buffer length went negative. If so, return an
  1957. // error.
  1958. //
  1959. if (tempLength < 0) {
  1960. *ErrorOffset = GET_OFFSET_LENGTH( eas, EaBuffer );
  1961. return STATUS_EA_LIST_INCONSISTENT;
  1962. }
  1963. return STATUS_SUCCESS;
  1964. }
  1965. NTSTATUS
  1966. IoCheckFunctionAccess(
  1967. IN ACCESS_MASK GrantedAccess,
  1968. IN UCHAR MajorFunction,
  1969. IN UCHAR MinorFunction,
  1970. IN ULONG IoControlCode,
  1971. IN PVOID Arg1 OPTIONAL,
  1972. IN PVOID Arg2 OPTIONAL
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. This routine checks the parameters and access for the function and
  1977. parameters specified by the input parameters against the current access
  1978. to the file as described by the GrantedAccess mask parameter. If the
  1979. caller has the access to the file, then a successful status code is
  1980. returned. Otherwise, an error status code is returned as the function
  1981. value.
  1982. Arguments:
  1983. GrantedAccess - Access granted to the file for the caller.
  1984. MajorFunction - Major function code for the operation being performed.
  1985. MinorFunction - Minor function code for the operation being performed.
  1986. IoControlCode - I/O function control code for a device or file system I/O
  1987. code. Used only for those two function types.
  1988. Arg1 - Optional argument that depends on the major function. Its
  1989. FileInformationClass if the major function code indicates a query or set
  1990. file information function is being performed. It points to Security Info
  1991. if major function code is IRP_MJ_*_SECURITY.
  1992. Arg2 - Optional second argument that depends on the major function. Currently its
  1993. FsInformationClass.This parameter MUST be supplied if the major function
  1994. code indicates that a query or set file system information function is
  1995. being performed.
  1996. Return Value:
  1997. The final status of the access check is the function value. If the
  1998. accessor has the access to the file, then STATUS_SUCCESS is returned;
  1999. otherwise, STATUS_ACCESS_DENIED is returned.
  2000. Note:
  2001. The GrantedAccess mask may not contain any generic mappings. That is,
  2002. the IoCheckDesiredAccess function must have been previously invoked to
  2003. return a full mask.
  2004. --*/
  2005. {
  2006. NTSTATUS status = STATUS_SUCCESS;
  2007. PFILE_INFORMATION_CLASS FileInformationClass;
  2008. PFS_INFORMATION_CLASS FsInformationClass;
  2009. SECURITY_INFORMATION SecurityInformation;
  2010. ACCESS_MASK DesiredAccess;
  2011. UNREFERENCED_PARAMETER( MinorFunction );
  2012. PAGED_CODE();
  2013. //
  2014. // Determine the major function being performed. If the function code
  2015. // is invalid, then return an error.
  2016. //
  2017. FileInformationClass = (PFILE_INFORMATION_CLASS)Arg1;
  2018. FsInformationClass = (PFS_INFORMATION_CLASS)Arg2;
  2019. switch( MajorFunction ) {
  2020. case IRP_MJ_CREATE:
  2021. case IRP_MJ_CLOSE:
  2022. break;
  2023. case IRP_MJ_READ:
  2024. if (SeComputeDeniedAccesses( GrantedAccess, FILE_READ_DATA )) {
  2025. status = STATUS_ACCESS_DENIED;
  2026. }
  2027. break;
  2028. case IRP_MJ_WRITE:
  2029. if (!SeComputeGrantedAccesses( GrantedAccess, FILE_WRITE_DATA | FILE_APPEND_DATA )) {
  2030. status = STATUS_ACCESS_DENIED;
  2031. }
  2032. break;
  2033. case IRP_MJ_QUERY_INFORMATION:
  2034. if (IopQueryOperationAccess[*FileInformationClass] != 0) {
  2035. if (SeComputeDeniedAccesses( GrantedAccess, IopQueryOperationAccess[*FileInformationClass] )) {
  2036. status = STATUS_ACCESS_DENIED;
  2037. }
  2038. }
  2039. break;
  2040. case IRP_MJ_SET_INFORMATION:
  2041. if (IopSetOperationAccess[*FileInformationClass] != 0) {
  2042. if (SeComputeDeniedAccesses( GrantedAccess, IopSetOperationAccess[*FileInformationClass] )) {
  2043. status = STATUS_ACCESS_DENIED;
  2044. }
  2045. }
  2046. break;
  2047. case IRP_MJ_QUERY_EA:
  2048. if (SeComputeDeniedAccesses( GrantedAccess, FILE_READ_EA )) {
  2049. status = STATUS_ACCESS_DENIED;
  2050. }
  2051. break;
  2052. case IRP_MJ_SET_EA:
  2053. if (SeComputeDeniedAccesses( GrantedAccess, FILE_WRITE_EA )) {
  2054. status = STATUS_ACCESS_DENIED;
  2055. }
  2056. break;
  2057. case IRP_MJ_FLUSH_BUFFERS:
  2058. if (SeComputeDeniedAccesses( GrantedAccess, FILE_WRITE_DATA )) {
  2059. status = STATUS_ACCESS_DENIED;
  2060. }
  2061. break;
  2062. case IRP_MJ_QUERY_VOLUME_INFORMATION:
  2063. if (SeComputeDeniedAccesses( GrantedAccess, IopQueryFsOperationAccess[*FsInformationClass] )) {
  2064. status = STATUS_ACCESS_DENIED;
  2065. }
  2066. break;
  2067. case IRP_MJ_SET_VOLUME_INFORMATION:
  2068. if (SeComputeDeniedAccesses( GrantedAccess, IopSetFsOperationAccess[*FsInformationClass] )) {
  2069. status = STATUS_ACCESS_DENIED;
  2070. }
  2071. break;
  2072. case IRP_MJ_DIRECTORY_CONTROL:
  2073. if (SeComputeDeniedAccesses( GrantedAccess, FILE_LIST_DIRECTORY )) {
  2074. status = STATUS_ACCESS_DENIED;
  2075. }
  2076. break;
  2077. case IRP_MJ_FILE_SYSTEM_CONTROL:
  2078. case IRP_MJ_DEVICE_CONTROL:
  2079. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  2080. {
  2081. ULONG accessMode = (IoControlCode >> 14) & 3;
  2082. if (accessMode != FILE_ANY_ACCESS) {
  2083. //
  2084. // This I/O control requires that the caller have read, write,
  2085. // or read/write access to the object. If this is not the case,
  2086. // then cleanup and return an appropriate error status code.
  2087. //
  2088. if (!(SeComputeGrantedAccesses( GrantedAccess, accessMode ))) {
  2089. status = STATUS_ACCESS_DENIED;
  2090. }
  2091. }
  2092. }
  2093. break;
  2094. case IRP_MJ_LOCK_CONTROL:
  2095. if (!SeComputeGrantedAccesses( GrantedAccess, FILE_READ_DATA | FILE_WRITE_DATA )) {
  2096. status = STATUS_ACCESS_DENIED;
  2097. }
  2098. break;
  2099. case IRP_MJ_SET_SECURITY:
  2100. SecurityInformation = *((PSECURITY_INFORMATION)Arg1);
  2101. SeSetSecurityAccessMask(SecurityInformation, &DesiredAccess);
  2102. if (SeComputeDeniedAccesses( GrantedAccess, DesiredAccess )) {
  2103. status = STATUS_ACCESS_DENIED;
  2104. }
  2105. break;
  2106. case IRP_MJ_QUERY_SECURITY:
  2107. SecurityInformation = *((PSECURITY_INFORMATION)Arg1);
  2108. SeQuerySecurityAccessMask(SecurityInformation, &DesiredAccess);
  2109. if (SeComputeDeniedAccesses( GrantedAccess, DesiredAccess )) {
  2110. status = STATUS_ACCESS_DENIED;
  2111. }
  2112. break;
  2113. default:
  2114. status = STATUS_INVALID_DEVICE_REQUEST;
  2115. }
  2116. return status;
  2117. }
  2118. NTKERNELAPI
  2119. NTSTATUS
  2120. IoCheckQuerySetFileInformation(
  2121. IN FILE_INFORMATION_CLASS FileInformationClass,
  2122. IN ULONG Length,
  2123. IN BOOLEAN SetOperation
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. This routine checks the validity of the parameters for either a query or a
  2128. set file information operation. It is used primarily by network servers
  2129. running in kernel mode since no such parameter validity checking is done
  2130. in the normal path.
  2131. Arguments:
  2132. FileInformationClass - Specifies the information class to check checked.
  2133. Length - Specifies the length of the buffer supplied.
  2134. SetOperation - Specifies that the operation was a set file information as
  2135. opposed to a query operation.
  2136. Return Value:
  2137. The function value is STATUS_SUCCESS if the parameters were valid,
  2138. otherwise an appropriate error is returned.
  2139. --*/
  2140. {
  2141. const CHAR* operationLength;
  2142. //
  2143. // The file information class itself must be w/in the valid range of file
  2144. // information classes, otherwise this is an invalid information class.
  2145. //
  2146. if ((ULONG) FileInformationClass >= FileMaximumInformation) {
  2147. return STATUS_INVALID_INFO_CLASS;
  2148. }
  2149. //
  2150. // Determine whether this is a query or a set operation and act accordingly.
  2151. //
  2152. operationLength = SetOperation ? IopSetOperationLength : IopQueryOperationLength;
  2153. if (!operationLength[FileInformationClass]) {
  2154. return STATUS_INVALID_INFO_CLASS;
  2155. }
  2156. if (Length < (ULONG) operationLength[FileInformationClass]) {
  2157. return STATUS_INFO_LENGTH_MISMATCH;
  2158. }
  2159. return STATUS_SUCCESS;
  2160. }
  2161. NTKERNELAPI
  2162. NTSTATUS
  2163. IoCheckQuerySetVolumeInformation(
  2164. IN FS_INFORMATION_CLASS FsInformationClass,
  2165. IN ULONG Length,
  2166. IN BOOLEAN SetOperation
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. This routine checks the validity of the parameters for either a query or a
  2171. set volume information operation. It is used primarily by network servers
  2172. running in kernel mode since no such parameter validity checking is done
  2173. in the normal path.
  2174. Arguments:
  2175. FsInformationClass - Specifies the information class to check.
  2176. Length - Specifies the length of the buffer supplied.
  2177. SetOperation - Specifies that the operation was a set volume information as
  2178. opposed to a query operation.
  2179. Return Value:
  2180. The function value is STATUS_SUCCESS if the parameters were valid,
  2181. otherwise an appropriate error is returned.
  2182. --*/
  2183. {
  2184. const CHAR* operationLength;
  2185. operationLength = SetOperation ? IopSetFsOperationLength : IopQueryFsOperationLength;
  2186. //
  2187. // The volume information class itself must be w/in the valid range of file
  2188. // information classes, otherwise this is an invalid information class.
  2189. //
  2190. if ((ULONG) FsInformationClass >= FileFsMaximumInformation ||
  2191. operationLength[ FsInformationClass ] == 0 ) {
  2192. return STATUS_INVALID_INFO_CLASS;
  2193. }
  2194. if (Length < (ULONG) operationLength[FsInformationClass]) {
  2195. return STATUS_INFO_LENGTH_MISMATCH;
  2196. }
  2197. return STATUS_SUCCESS;
  2198. }
  2199. NTSTATUS
  2200. IoCheckQuotaBufferValidity(
  2201. IN PFILE_QUOTA_INFORMATION QuotaBuffer,
  2202. IN ULONG QuotaLength,
  2203. OUT PULONG ErrorOffset
  2204. )
  2205. /*++
  2206. Routine Description:
  2207. This routine checks the validity of the specified quota buffer to guarantee
  2208. that its format is proper, no fields hang over, that it is not recursive,
  2209. etc.
  2210. Arguments:
  2211. QuotaBuffer - Pointer to the buffer containing the quota entries to be
  2212. checked.
  2213. QuotaLength - Specifies the length of the QuotaBuffer.
  2214. ErrorOffset - A variable to receive the offset of the offending entry in
  2215. the quota buffer if an error is incurred. This variable is only valid
  2216. if an error occurs.
  2217. Return Value:
  2218. The function value is STATUS_SUCCESS if the quota buffer contains a valid,
  2219. properly formed list, otherwise STATUS_QUOTA_LIST_INCONSISTENT.
  2220. --*/
  2221. #if defined(_X86_)
  2222. #define REQUIRED_QUOTA_ALIGNMENT sizeof( ULONG )
  2223. #else
  2224. #define REQUIRED_QUOTA_ALIGNMENT sizeof( ULONGLONG )
  2225. #endif
  2226. #define ALIGN_QUAD( Address ) ( (ULONG) ((Address + 7) & ~7) )
  2227. #define GET_OFFSET_LENGTH( CurrentEntry, QuotaBase ) (\
  2228. (ULONG) ((PCHAR) CurrentEntry - (PCHAR) QuotaBase) )
  2229. {
  2230. LONG tempLength;
  2231. ULONG entrySize;
  2232. PFILE_QUOTA_INFORMATION quotas;
  2233. PAGED_CODE();
  2234. //
  2235. // Walk the buffer and ensure that its format is valid. That is, ensure
  2236. // that it does not walk off the end of the buffer, is not recursive,
  2237. // etc.
  2238. //
  2239. quotas = QuotaBuffer;
  2240. tempLength = QuotaLength;
  2241. //
  2242. // Ensure the buffer has the correct alignment.
  2243. //
  2244. if ((ULONG_PTR) quotas & (REQUIRED_QUOTA_ALIGNMENT - 1)) {
  2245. *ErrorOffset = 0;
  2246. return STATUS_DATATYPE_MISALIGNMENT;
  2247. }
  2248. for (;;) {
  2249. ULONG sidLength;
  2250. //
  2251. // Get the size of the current entry in the buffer. The minimum size
  2252. // of the entry is the fixed size part of the structure plus the actual
  2253. // length of the SID. If this is not the last entry, then there will
  2254. // also be pad bytes to get to the next longword boundary. Likewise,
  2255. // ensure that the SID itself is valid.
  2256. //
  2257. if (tempLength < FIELD_OFFSET( FILE_QUOTA_INFORMATION, Sid ) ||
  2258. !RtlValidSid( &quotas->Sid )) {
  2259. goto error_exit;
  2260. }
  2261. sidLength = RtlLengthSid( (&quotas->Sid) );
  2262. entrySize = FIELD_OFFSET( FILE_QUOTA_INFORMATION, Sid ) + sidLength;
  2263. //
  2264. // Confirm that the full length lies within the stated buffer length.
  2265. //
  2266. if ((ULONG) tempLength < entrySize ||
  2267. quotas->SidLength != sidLength) {
  2268. goto error_exit;
  2269. }
  2270. if (quotas->NextEntryOffset) {
  2271. //
  2272. // There is another entry in the buffer and it must be longword
  2273. // aligned. Ensure that the offset indicates that it is. If it
  2274. // is not, return error status code.
  2275. //
  2276. if (entrySize > quotas->NextEntryOffset ||
  2277. quotas->NextEntryOffset & (REQUIRED_QUOTA_ALIGNMENT - 1) ||
  2278. (LONG) quotas->NextEntryOffset < 0) {
  2279. goto error_exit;
  2280. } else {
  2281. //
  2282. // There is another entry in the buffer, so account for the size
  2283. // of the current entry in the length and get a pointer to the
  2284. // next entry.
  2285. //
  2286. tempLength -= quotas->NextEntryOffset;
  2287. if (tempLength < 0) {
  2288. goto error_exit;
  2289. }
  2290. quotas = (PFILE_QUOTA_INFORMATION) ((PCHAR) quotas + quotas->NextEntryOffset);
  2291. }
  2292. } else {
  2293. //
  2294. // There are no more entries in the buffer. Simply account for the
  2295. // overall buffer length according to the size of the current
  2296. // entry and exit the loop.
  2297. //
  2298. tempLength -= entrySize;
  2299. break;
  2300. }
  2301. }
  2302. //
  2303. // All of the entries in the buffer have been processed. Check to see
  2304. // whether the overall buffer length went negative. If so, return an
  2305. // error.
  2306. //
  2307. if (tempLength < 0) {
  2308. goto error_exit;
  2309. }
  2310. return STATUS_SUCCESS;
  2311. error_exit:
  2312. *ErrorOffset = GET_OFFSET_LENGTH( quotas, QuotaBuffer );
  2313. return STATUS_QUOTA_LIST_INCONSISTENT;
  2314. }
  2315. NTSTATUS
  2316. IoCheckShareAccess(
  2317. IN ACCESS_MASK DesiredAccess,
  2318. IN ULONG DesiredShareAccess,
  2319. IN OUT PFILE_OBJECT FileObject,
  2320. IN OUT PSHARE_ACCESS ShareAccess,
  2321. IN BOOLEAN Update
  2322. )
  2323. /*++
  2324. Routine Description:
  2325. This routine is invoked to determine whether or not a new accessor to
  2326. a file actually has shared access to it. The check is made according
  2327. to:
  2328. 1) How the file is currently opened.
  2329. 2) What types of shared accesses are currently specified.
  2330. 3) The desired and shared accesses that the new open is requesting.
  2331. If the open should succeed, then the access information about how the
  2332. file is currently opened is updated, according to the Update parameter.
  2333. Arguments:
  2334. DesiredAccess - Desired access of current open request.
  2335. DesiredShareAccess - Shared access requested by current open request.
  2336. FileObject - Pointer to the file object of the current open request.
  2337. ShareAccess - Pointer to the share access structure that describes how
  2338. the file is currently being accessed.
  2339. Update - Specifies whether or not the share access information for the
  2340. file is to be updated.
  2341. Return Value:
  2342. The final status of the access check is the function value. If the
  2343. accessor has access to the file, STATUS_SUCCESS is returned. Otherwise,
  2344. STATUS_SHARING_VIOLATION is returned.
  2345. Note:
  2346. Note that the ShareAccess parameter must be locked against other accesses
  2347. from other threads while this routine is executing. Otherwise the counts
  2348. will be out-of-synch.
  2349. --*/
  2350. {
  2351. ULONG ocount;
  2352. PAGED_CODE();
  2353. //
  2354. // Set the access type in the file object for the current accessor.
  2355. // Note that reading and writing attributes are not included in the
  2356. // access check.
  2357. //
  2358. FileObject->ReadAccess = (BOOLEAN) ((DesiredAccess & (FILE_EXECUTE
  2359. | FILE_READ_DATA)) != 0);
  2360. FileObject->WriteAccess = (BOOLEAN) ((DesiredAccess & (FILE_WRITE_DATA
  2361. | FILE_APPEND_DATA)) != 0);
  2362. FileObject->DeleteAccess = (BOOLEAN) ((DesiredAccess & DELETE) != 0);
  2363. //
  2364. // There is no more work to do unless the user specified one of the
  2365. // sharing modes above.
  2366. //
  2367. if (FileObject->ReadAccess ||
  2368. FileObject->WriteAccess ||
  2369. FileObject->DeleteAccess) {
  2370. FileObject->SharedRead = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_READ) != 0);
  2371. FileObject->SharedWrite = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_WRITE) != 0);
  2372. FileObject->SharedDelete = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_DELETE) != 0);
  2373. //
  2374. // If this is a special filter fileobject ignore share access check if necessary.
  2375. //
  2376. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  2377. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  2378. if (fileObjectExtension->FileObjectExtensionFlags & FO_EXTENSION_IGNORE_SHARE_ACCESS_CHECK) {
  2379. return STATUS_SUCCESS;
  2380. }
  2381. }
  2382. //
  2383. // Now check to see whether or not the desired accesses are compatible
  2384. // with the way that the file is currently open.
  2385. //
  2386. ocount = ShareAccess->OpenCount;
  2387. if ( (FileObject->ReadAccess && (ShareAccess->SharedRead < ocount))
  2388. ||
  2389. (FileObject->WriteAccess && (ShareAccess->SharedWrite < ocount))
  2390. ||
  2391. (FileObject->DeleteAccess && (ShareAccess->SharedDelete < ocount))
  2392. ||
  2393. ((ShareAccess->Readers != 0) && !FileObject->SharedRead)
  2394. ||
  2395. ((ShareAccess->Writers != 0) && !FileObject->SharedWrite)
  2396. ||
  2397. ((ShareAccess->Deleters != 0) && !FileObject->SharedDelete)
  2398. ) {
  2399. //
  2400. // The check failed. Simply return to the caller indicating that the
  2401. // current open cannot access the file.
  2402. //
  2403. return STATUS_SHARING_VIOLATION;
  2404. //
  2405. // The check was successful. Update the counter information in the
  2406. // shared access structure for this open request if the caller
  2407. // specified that it should be updated.
  2408. //
  2409. } else if (Update) {
  2410. ShareAccess->OpenCount++;
  2411. ShareAccess->Readers += FileObject->ReadAccess;
  2412. ShareAccess->Writers += FileObject->WriteAccess;
  2413. ShareAccess->Deleters += FileObject->DeleteAccess;
  2414. ShareAccess->SharedRead += FileObject->SharedRead;
  2415. ShareAccess->SharedWrite += FileObject->SharedWrite;
  2416. ShareAccess->SharedDelete += FileObject->SharedDelete;
  2417. }
  2418. }
  2419. return STATUS_SUCCESS;
  2420. }
  2421. VOID
  2422. FASTCALL
  2423. IofCompleteRequest(
  2424. IN PIRP Irp,
  2425. IN CCHAR PriorityBoost
  2426. )
  2427. {
  2428. //
  2429. // This routine will either jump immediately to IopfCompleteRequest, or
  2430. // rather IovCompleteRequest.
  2431. //
  2432. pIofCompleteRequest(Irp, PriorityBoost);
  2433. }
  2434. VOID
  2435. FASTCALL
  2436. IopfCompleteRequest(
  2437. IN PIRP Irp,
  2438. IN CCHAR PriorityBoost
  2439. )
  2440. /*++
  2441. Routine Description:
  2442. This routine is invoked to complete an I/O request. It is invoked by the
  2443. driver in its DPC routine to perform the final completion of the IRP. The
  2444. functions performed by this routine are as follows.
  2445. 1. A check is made to determine whether the packet's stack locations
  2446. have been exhausted. If not, then the stack location pointer is set
  2447. to the next location and if there is a routine to be invoked, then
  2448. it will be invoked. This continues until there are either no more
  2449. routines which are interested or the packet runs out of stack.
  2450. If a routine is invoked to complete the packet for a specific driver
  2451. which needs to perform work a lot of work or the work needs to be
  2452. performed in the context of another process, then the routine will
  2453. return an alternate success code of STATUS_MORE_PROCESSING_REQUIRED.
  2454. This indicates that this completion routine should simply return to
  2455. its caller because the operation will be "completed" by this routine
  2456. again sometime in the future.
  2457. 2. A check is made to determine whether this IRP is an associated IRP.
  2458. If it is, then the count on the master IRP is decremented. If the
  2459. count for the master becomes zero, then the master IRP will be
  2460. completed according to the steps below taken for a normal IRP being
  2461. completed. If the count is still non-zero, then this IRP (the one
  2462. being completed) will simply be deallocated.
  2463. 3. If this is paging I/O or a close operation, then simply write the
  2464. I/O status block and set the event to the signaled state, and
  2465. dereference the event. If this is paging I/O, deallocate the IRP
  2466. as well.
  2467. 4. Unlock the pages, if any, specified by the MDL by calling
  2468. MmUnlockPages.
  2469. 5. A check is made to determine whether or not completion of the
  2470. request can be deferred until later. If it can be, then this
  2471. routine simply exits and leaves it up to the originator of the
  2472. request to fully complete the IRP. By not initializing and queueing
  2473. the special kernel APC to the calling thread (which is the current
  2474. thread by definition), a lot of interrupt and queueing processing
  2475. can be avoided.
  2476. 6. The final rundown routine is invoked to queue the request packet to
  2477. the target (requesting) thread as a special kernel mode APC.
  2478. Arguments:
  2479. Irp - Pointer to the I/O Request Packet to complete.
  2480. PriorityBoost - Supplies the amount of priority boost that is to be given
  2481. to the target thread when the special kernel APC is queued.
  2482. Return Value:
  2483. None.
  2484. --*/
  2485. #define ZeroIrpStackLocation( IrpSp ) { \
  2486. (IrpSp)->MinorFunction = 0; \
  2487. (IrpSp)->Flags = 0; \
  2488. (IrpSp)->Control = 0 ; \
  2489. (IrpSp)->Parameters.Others.Argument1 = 0; \
  2490. (IrpSp)->Parameters.Others.Argument2 = 0; \
  2491. (IrpSp)->Parameters.Others.Argument3 = 0; \
  2492. (IrpSp)->Parameters.Others.Argument4 = 0; \
  2493. (IrpSp)->FileObject = (PFILE_OBJECT) NULL; }
  2494. {
  2495. PIRP masterIrp;
  2496. NTSTATUS status;
  2497. PIO_STACK_LOCATION stackPointer;
  2498. PMDL mdl;
  2499. PETHREAD thread;
  2500. PFILE_OBJECT fileObject;
  2501. KIRQL irql;
  2502. PVOID saveAuxiliaryPointer = NULL;
  2503. //
  2504. // Begin by ensuring that this packet has not already been completed
  2505. // by someone.
  2506. //
  2507. if (Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1) ||
  2508. Irp->Type != IO_TYPE_IRP) {
  2509. KeBugCheckEx( MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR) Irp, __LINE__, 0, 0 );
  2510. }
  2511. //
  2512. // Ensure that the packet being completed really is still an IRP.
  2513. //
  2514. ASSERT( Irp->Type == IO_TYPE_IRP );
  2515. //
  2516. // Ensure that no one believes that this request is still in a cancelable
  2517. // state.
  2518. //
  2519. ASSERT( !Irp->CancelRoutine );
  2520. //
  2521. // Ensure that the packet is not being completed with a thoroughly
  2522. // confusing status code. Actually completing a packet with a pending
  2523. // status probably means that someone forgot to set the real status in
  2524. // the packet.
  2525. //
  2526. ASSERT( Irp->IoStatus.Status != STATUS_PENDING );
  2527. //
  2528. // Ensure that the packet is not being completed with a minus one. This
  2529. // is apparently a common problem in some drivers, and has no meaning
  2530. // as a status code.
  2531. //
  2532. ASSERT( Irp->IoStatus.Status != 0xffffffff );
  2533. //
  2534. // Now check to see whether this is the last driver that needs to be
  2535. // invoked for this packet. If not, then bump the stack and check to
  2536. // see whether the driver wishes to see the completion. As each stack
  2537. // location is examined, invoke any routine which needs to be invoked.
  2538. // If the routine returns STATUS_MORE_PROCESSING_REQUIRED, then stop the
  2539. // processing of this packet.
  2540. //
  2541. for (stackPointer = IoGetCurrentIrpStackLocation( Irp ),
  2542. Irp->CurrentLocation++,
  2543. Irp->Tail.Overlay.CurrentStackLocation++;
  2544. Irp->CurrentLocation <= (CCHAR) (Irp->StackCount + 1);
  2545. stackPointer++,
  2546. Irp->CurrentLocation++,
  2547. Irp->Tail.Overlay.CurrentStackLocation++) {
  2548. //
  2549. // A stack location was located. Check to see whether or not it
  2550. // has a completion routine and if so, whether or not it should be
  2551. // invoked.
  2552. //
  2553. // Begin by saving the pending returned flag in the current stack
  2554. // location in the fixed part of the IRP.
  2555. //
  2556. Irp->PendingReturned = stackPointer->Control & SL_PENDING_RETURNED;
  2557. if ( (NT_SUCCESS( Irp->IoStatus.Status ) &&
  2558. stackPointer->Control & SL_INVOKE_ON_SUCCESS) ||
  2559. (!NT_SUCCESS( Irp->IoStatus.Status ) &&
  2560. stackPointer->Control & SL_INVOKE_ON_ERROR) ||
  2561. (Irp->Cancel &&
  2562. stackPointer->Control & SL_INVOKE_ON_CANCEL)
  2563. ) {
  2564. //
  2565. // This driver has specified a completion routine. Invoke the
  2566. // routine passing it a pointer to its device object and the
  2567. // IRP that is being completed.
  2568. //
  2569. ZeroIrpStackLocation( stackPointer );
  2570. status = stackPointer->CompletionRoutine( (PDEVICE_OBJECT) (Irp->CurrentLocation == (CCHAR) (Irp->StackCount + 1) ?
  2571. (PDEVICE_OBJECT) NULL :
  2572. IoGetCurrentIrpStackLocation( Irp )->DeviceObject),
  2573. Irp,
  2574. stackPointer->Context );
  2575. if (status == STATUS_MORE_PROCESSING_REQUIRED) {
  2576. //
  2577. // Note: Notice that if the driver has returned the above
  2578. // status value, it may have already DEALLOCATED the
  2579. // packet! Therefore, do NOT touch any part of the
  2580. // IRP in the following code.
  2581. //
  2582. return;
  2583. }
  2584. } else {
  2585. if (Irp->PendingReturned && Irp->CurrentLocation <= Irp->StackCount) {
  2586. IoMarkIrpPending( Irp );
  2587. }
  2588. ZeroIrpStackLocation( stackPointer );
  2589. }
  2590. }
  2591. //
  2592. // Check to see whether this is an associated IRP. If so, then decrement
  2593. // the count in the master IRP. If the count is decremented to zero,
  2594. // then complete the master packet as well.
  2595. //
  2596. if (Irp->Flags & IRP_ASSOCIATED_IRP) {
  2597. ULONG count;
  2598. masterIrp = Irp->AssociatedIrp.MasterIrp;
  2599. //
  2600. // After this decrement master IRP cannot be touched except if count == 1.
  2601. //
  2602. count = IopInterlockedDecrementUlong( LockQueueIoDatabaseLock,
  2603. &masterIrp->AssociatedIrp.IrpCount );
  2604. //
  2605. // Deallocate this packet and any MDLs that are associated with it
  2606. // by either doing direct deallocations if they were allocated from
  2607. // a zone or by queueing the packet to a thread to perform the
  2608. // deallocation.
  2609. //
  2610. // Also, check the count of the master IRP to determine whether or not
  2611. // the count has gone to zero. If not, then simply get out of here.
  2612. // Otherwise, complete the master packet.
  2613. //
  2614. IopFreeIrpAndMdls( Irp );
  2615. if (count == 1) {
  2616. IoCompleteRequest( masterIrp, PriorityBoost );
  2617. }
  2618. return;
  2619. }
  2620. //
  2621. // Check to see if we have a name junction. If so set the stage to
  2622. // transmogrify the reparse point data in IopCompleteRequest.
  2623. //
  2624. if ((Irp->IoStatus.Status == STATUS_REPARSE ) &&
  2625. (Irp->IoStatus.Information > IO_REPARSE_TAG_RESERVED_RANGE)) {
  2626. if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) {
  2627. //
  2628. // For name junctions, we save the pointer to the auxiliary
  2629. // buffer and use it below.
  2630. //
  2631. ASSERT( Irp->Tail.Overlay.AuxiliaryBuffer != NULL );
  2632. saveAuxiliaryPointer = (PVOID) Irp->Tail.Overlay.AuxiliaryBuffer;
  2633. //
  2634. // We NULL the entry to avoid its de-allocation at this time.
  2635. // This buffer get deallocated in IopDoNameTransmogrify
  2636. //
  2637. Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  2638. } else {
  2639. //
  2640. // Fail the request. A driver needed to act on this IRP prior
  2641. // to getting to this point.
  2642. //
  2643. Irp->IoStatus.Status = STATUS_IO_REPARSE_TAG_NOT_HANDLED;
  2644. }
  2645. }
  2646. //
  2647. // Check the auxiliary buffer pointer in the packet and if a buffer was
  2648. // allocated, deallocate it now. Note that this buffer must be freed
  2649. // here since the pointer is overlayed with the APC that will be used
  2650. // to get to the requesting thread's context.
  2651. //
  2652. if (Irp->Tail.Overlay.AuxiliaryBuffer) {
  2653. ExFreePool( Irp->Tail.Overlay.AuxiliaryBuffer );
  2654. Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  2655. }
  2656. //
  2657. // Check to see if this is paging I/O or a close operation. If either,
  2658. // then special processing must be performed. The reasons that special
  2659. // processing must be performed is different based on the type of
  2660. // operation being performed. The biggest reasons for special processing
  2661. // on paging operations are that using a special kernel APC for an in-
  2662. // page operation cannot work since the special kernel APC can incur
  2663. // another pagefault. Likewise, all paging I/O uses MDLs that belong
  2664. // to the memory manager, not the I/O system.
  2665. //
  2666. // Close operations are special because the close may have been invoked
  2667. // because of a special kernel APC (some IRP was completed which caused
  2668. // the reference count on the object to become zero while in the I/O
  2669. // system's special kernel APC routine). Therefore, a special kernel APC
  2670. // cannot be used since it cannot execute until the close APC finishes.
  2671. //
  2672. // The special steps are as follows for a synchronous paging operation
  2673. // and close are:
  2674. //
  2675. // 1. Copy the I/O status block (it is in SVAS, nonpaged).
  2676. // 2. Signal the event
  2677. // 3. If paging I/O, deallocate the IRP
  2678. //
  2679. // The special steps taken for asynchronous paging operations (out-pages)
  2680. // are as follows:
  2681. //
  2682. // 1. Initialize a special kernel APC just for page writes.
  2683. // 1. Queue the special kernel APC.
  2684. //
  2685. // It should also be noted that the logic for completing a Mount request
  2686. // operation is exactly the same as a Page Read. No assumptions should be
  2687. // made here about this being a Page Read operation w/o carefully checking
  2688. // to ensure that they are also true for a Mount. That is:
  2689. //
  2690. // IRP_PAGING_IO and IRP_MOUNT_COMPLETION
  2691. //
  2692. // are the same flag in the IRP.
  2693. //
  2694. // Also note that the last time the IRP is touched for a close operation
  2695. // must be just before the event is set to the signaled state. Once this
  2696. // occurs, the IRP can be deallocated by the thread waiting for the event.
  2697. //
  2698. //
  2699. // IRP_CLOSE_OPERATION and IRP_SET_USER_EVENT are the same flags. They both indicate
  2700. // that only the user event field should be set and no APC should be queued. Unfortunately
  2701. // IRP_CLOSE_OPERATION is used by some drivers to do exactly this so it cannot be renamed.
  2702. //
  2703. //
  2704. if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION |IRP_SET_USER_EVENT)) {
  2705. if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION |IRP_SET_USER_EVENT)) {
  2706. ULONG flags;
  2707. flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO|IRP_PAGING_IO);
  2708. *Irp->UserIosb = Irp->IoStatus;
  2709. (VOID) KeSetEvent( Irp->UserEvent, PriorityBoost, FALSE );
  2710. if (flags) {
  2711. if (IopIsReserveIrp(Irp)) {
  2712. IopFreeReserveIrp(Irp, PriorityBoost);
  2713. } else {
  2714. IoFreeIrp( Irp );
  2715. }
  2716. }
  2717. } else {
  2718. thread = Irp->Tail.Overlay.Thread;
  2719. KeInitializeApc( &Irp->Tail.Apc,
  2720. &thread->Tcb,
  2721. Irp->ApcEnvironment,
  2722. IopCompletePageWrite,
  2723. (PKRUNDOWN_ROUTINE) NULL,
  2724. (PKNORMAL_ROUTINE) NULL,
  2725. KernelMode,
  2726. (PVOID) NULL );
  2727. (VOID) KeInsertQueueApc( &Irp->Tail.Apc,
  2728. (PVOID) NULL,
  2729. (PVOID) NULL,
  2730. PriorityBoost );
  2731. }
  2732. return;
  2733. }
  2734. //
  2735. // Check to see whether any pages need to be unlocked.
  2736. //
  2737. if (Irp->MdlAddress != NULL) {
  2738. //
  2739. // Unlock any pages that may be described by MDLs.
  2740. //
  2741. mdl = Irp->MdlAddress;
  2742. while (mdl != NULL) {
  2743. MmUnlockPages( mdl );
  2744. mdl = mdl->Next;
  2745. }
  2746. }
  2747. //
  2748. // Make a final check here to determine whether or not this is a
  2749. // synchronous I/O operation that is being completed in the context
  2750. // of the original requestor. If so, then an optimal path through
  2751. // I/O completion can be taken.
  2752. //
  2753. if (Irp->Flags & IRP_DEFER_IO_COMPLETION && !Irp->PendingReturned) {
  2754. if ((Irp->IoStatus.Status == STATUS_REPARSE ) &&
  2755. (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)) {
  2756. //
  2757. // For name junctions we reinstate the address of the appropriate
  2758. // buffer. It is freed in parse.c
  2759. //
  2760. Irp->Tail.Overlay.AuxiliaryBuffer = saveAuxiliaryPointer;
  2761. }
  2762. return;
  2763. }
  2764. //
  2765. // Finally, initialize the IRP as an APC structure and queue the special
  2766. // kernel APC to the target thread.
  2767. //
  2768. thread = Irp->Tail.Overlay.Thread;
  2769. fileObject = Irp->Tail.Overlay.OriginalFileObject;
  2770. if (!Irp->Cancel) {
  2771. KeInitializeApc( &Irp->Tail.Apc,
  2772. &thread->Tcb,
  2773. Irp->ApcEnvironment,
  2774. IopCompleteRequest,
  2775. IopAbortRequest,
  2776. (PKNORMAL_ROUTINE) NULL,
  2777. KernelMode,
  2778. (PVOID) NULL );
  2779. (VOID) KeInsertQueueApc( &Irp->Tail.Apc,
  2780. fileObject,
  2781. (PVOID) saveAuxiliaryPointer,
  2782. PriorityBoost );
  2783. } else {
  2784. //
  2785. // This request has been cancelled. Ensure that access to the thread
  2786. // is synchronized, otherwise it may go away while attempting to get
  2787. // through the remainder of completion for this request. This happens
  2788. // when the thread times out waiting for the request to be completed
  2789. // once it has been cancelled.
  2790. //
  2791. // Note that it is safe to capture the thread pointer above, w/o having
  2792. // the lock because the cancel flag was not set at that point, and
  2793. // the code that disassociates IRPs must set the flag before looking to
  2794. // see whether or not the packet has been completed, and this packet
  2795. // will appear to be completed because it no longer belongs to a driver.
  2796. //
  2797. irql = KeAcquireQueuedSpinLock( LockQueueIoCompletionLock );
  2798. thread = Irp->Tail.Overlay.Thread;
  2799. if (thread) {
  2800. KeInitializeApc( &Irp->Tail.Apc,
  2801. &thread->Tcb,
  2802. Irp->ApcEnvironment,
  2803. IopCompleteRequest,
  2804. IopAbortRequest,
  2805. (PKNORMAL_ROUTINE) NULL,
  2806. KernelMode,
  2807. (PVOID) NULL );
  2808. (VOID) KeInsertQueueApc( &Irp->Tail.Apc,
  2809. fileObject,
  2810. (PVOID) saveAuxiliaryPointer,
  2811. PriorityBoost );
  2812. KeReleaseQueuedSpinLock( LockQueueIoCompletionLock, irql );
  2813. } else {
  2814. //
  2815. // This request has been aborted from completing in the caller's
  2816. // thread. This can only occur if the packet was cancelled, and
  2817. // the driver did not complete the request, so it was timed out.
  2818. // Attempt to drop things on the floor, since the originating thread
  2819. // has probably exited at this point.
  2820. //
  2821. KeReleaseQueuedSpinLock( LockQueueIoCompletionLock, irql );
  2822. ASSERT( Irp->Cancel );
  2823. //
  2824. // Drop the IRP on the floor.
  2825. //
  2826. IopDropIrp( Irp, fileObject );
  2827. }
  2828. }
  2829. }
  2830. NTSTATUS
  2831. IoConnectInterrupt(
  2832. OUT PKINTERRUPT *InterruptObject,
  2833. IN PKSERVICE_ROUTINE ServiceRoutine,
  2834. IN PVOID ServiceContext,
  2835. IN PKSPIN_LOCK SpinLock OPTIONAL,
  2836. IN ULONG Vector,
  2837. IN KIRQL Irql,
  2838. IN KIRQL SynchronizeIrql,
  2839. IN KINTERRUPT_MODE InterruptMode,
  2840. IN BOOLEAN ShareVector,
  2841. IN KAFFINITY ProcessorEnableMask,
  2842. IN BOOLEAN FloatingSave
  2843. )
  2844. /*++
  2845. Routine Description:
  2846. This routine allocates, initializes, and connects interrupt objects for
  2847. all of the processors specified in the processor enable mask.
  2848. Arguments:
  2849. InterruptObject - Address of a variable to receive a pointer to the first
  2850. interrupt object allocated and initialized.
  2851. ServiceRoutine - Address of the interrupt service routine (ISR) that should
  2852. be executed when the interrupt occurs.
  2853. ServiceContext - Supplies a pointer to the context information required
  2854. by the ISR.
  2855. SpinLock - Supplies a pointer to a spin lock to be used when synchronizing
  2856. with the ISR.
  2857. Vector - Supplies the vector upon which the interrupt occurs.
  2858. Irql - Supplies the IRQL upon which the interrupt occurs.
  2859. SynchronizeIrql - The request priority that the interrupt should be
  2860. synchronized with.
  2861. InterruptMode - Specifies the interrupt mode of the device.
  2862. ShareVector - Supplies a boolean value that specifies whether the
  2863. vector can be shared with other interrupt objects or not. If FALSE
  2864. then the vector may not be shared, if TRUE it may be.
  2865. Latched.
  2866. ProcessorEnableMask - Specifies a bit-vector for each processor on which
  2867. the interrupt is to be connected. A value of one in the bit position
  2868. cooresponding to the processor number indicates that the interrupt
  2869. should be allowed on that processor. At least one bit must be set.
  2870. FloatingSave - A BOOLEAN that specifies whether or not the machine's
  2871. floating point state should be saved before invoking the ISR.
  2872. Return Value:
  2873. The function value is the final function status. The three status values
  2874. that this routine can itself return are:
  2875. STATUS_SUCCESS - Everything worked successfully.
  2876. STATUS_INVALID_PARAMETER - No processors were specified.
  2877. STATUS_INSUFFICIENT_RESOURCES - There was not enough nonpaged pool.
  2878. --*/
  2879. {
  2880. CCHAR count;
  2881. BOOLEAN builtinUsed;
  2882. PKINTERRUPT interruptObject;
  2883. KAFFINITY processorMask;
  2884. NTSTATUS status;
  2885. PIO_INTERRUPT_STRUCTURE interruptStructure;
  2886. PKSPIN_LOCK spinLock;
  2887. #ifdef INTR_BINDING
  2888. ULONG AssignedProcessor;
  2889. #endif // INTR_BINDING
  2890. PAGED_CODE();
  2891. //
  2892. // Initialize the return pointer and assume success.
  2893. //
  2894. *InterruptObject = (PKINTERRUPT) NULL;
  2895. status = STATUS_SUCCESS;
  2896. //
  2897. // Determine how much memory is to be allocated based on how many
  2898. // processors this system may have and how many bits are set in the
  2899. // processor enable mask.
  2900. //
  2901. processorMask = ProcessorEnableMask & KeActiveProcessors;
  2902. count = 0;
  2903. while (processorMask) {
  2904. if (processorMask & 1) {
  2905. count++;
  2906. }
  2907. processorMask >>= 1;
  2908. }
  2909. //
  2910. // If any interrupt objects are to be allocated and initialized, allocate
  2911. // the memory now.
  2912. //
  2913. if (count) {
  2914. interruptStructure = ExAllocatePoolWithTag( NonPagedPool,
  2915. ((count - 1) * sizeof( KINTERRUPT )) +
  2916. sizeof( IO_INTERRUPT_STRUCTURE ),
  2917. 'nioI' );
  2918. if (interruptStructure == NULL) {
  2919. status = STATUS_INSUFFICIENT_RESOURCES;
  2920. }
  2921. } else {
  2922. status = STATUS_INVALID_PARAMETER;
  2923. }
  2924. //
  2925. // If the caller specified a spin lock to be used for the interrupt object,
  2926. // use it. Otherwise, provide one by using the one in the structure that
  2927. // was just allocated.
  2928. //
  2929. if (ARGUMENT_PRESENT( SpinLock )) {
  2930. spinLock = SpinLock;
  2931. } else {
  2932. spinLock = &interruptStructure->SpinLock;
  2933. }
  2934. //
  2935. // If the pool allocation was successful, initialize and connect the
  2936. // interrupt objects to the appropriate processors.
  2937. //
  2938. if (NT_SUCCESS( status )) {
  2939. //
  2940. // Return the address of the first interrupt object in case an
  2941. // interrupt is pending for the device when it is initially connected
  2942. // and the driver must synchronize its execution with the ISR.
  2943. //
  2944. *InterruptObject = &interruptStructure->InterruptObject;
  2945. //
  2946. // Begin by getting a pointer to the start of the memory to be used
  2947. // for interrupt objects other than the builtin object.
  2948. //
  2949. interruptObject = (PKINTERRUPT) (interruptStructure + 1);
  2950. builtinUsed = FALSE;
  2951. processorMask = ProcessorEnableMask & KeActiveProcessors;
  2952. //
  2953. // Now zero the interrupt structure itself so that if something goes
  2954. // wrong it can be backed out.
  2955. //
  2956. RtlZeroMemory( interruptStructure, sizeof( IO_INTERRUPT_STRUCTURE ) );
  2957. //
  2958. // For each entry in the processor enable mask that is set, connect
  2959. // and initialize an interrupt object. The first bit that is set
  2960. // uses the builtin interrupt object, and all others use the pointers
  2961. // that follow it.
  2962. //
  2963. for (count = 0; processorMask; count++, processorMask >>= 1) {
  2964. if (processorMask & 1) {
  2965. KeInitializeInterrupt( builtinUsed ?
  2966. interruptObject :
  2967. &interruptStructure->InterruptObject,
  2968. ServiceRoutine,
  2969. ServiceContext,
  2970. spinLock,
  2971. Vector,
  2972. Irql,
  2973. SynchronizeIrql,
  2974. InterruptMode,
  2975. ShareVector,
  2976. count,
  2977. FloatingSave );
  2978. if (!KeConnectInterrupt( builtinUsed ?
  2979. interruptObject :
  2980. &interruptStructure->InterruptObject )) {
  2981. //
  2982. // An error occurred while attempting to connect the
  2983. // interrupt. This means that the driver either specified
  2984. // the wrong type of interrupt mode, or attempted to connect
  2985. // to some processor that didn't exist, or whatever. In
  2986. // any case, the problem turns out to be an invalid
  2987. // parameter was specified. Simply back everything out
  2988. // and return an error status.
  2989. //
  2990. // Note that if the builtin entry was used, then the entire
  2991. // structure needs to be walked as there are entries that
  2992. // were successfully connected. Otherwise, the first
  2993. // attempt to connect failed, so simply free everything
  2994. // in-line.
  2995. //
  2996. if (builtinUsed) {
  2997. IoDisconnectInterrupt( &interruptStructure->InterruptObject );
  2998. } else {
  2999. ExFreePool( interruptStructure );
  3000. }
  3001. status = STATUS_INVALID_PARAMETER;
  3002. break;
  3003. }
  3004. //
  3005. // If the builtin entry has been used, then the interrupt
  3006. // object just connected was one of the pointers, so fill
  3007. // it in with the address of the memory actually used.
  3008. //
  3009. if (builtinUsed) {
  3010. interruptStructure->InterruptArray[count] = interruptObject++;
  3011. } else {
  3012. //
  3013. // Otherwise, the builtin entry was used, so indicate
  3014. // that it is no longer valid to use and start using
  3015. // the pointers instead.
  3016. //
  3017. builtinUsed = TRUE;
  3018. }
  3019. }
  3020. }
  3021. }
  3022. //
  3023. // Finally, reset the address of the interrupt object if the function
  3024. // failed and return the final status of the operation.
  3025. //
  3026. if (!NT_SUCCESS( status )) {
  3027. *InterruptObject = (PKINTERRUPT) NULL;
  3028. }
  3029. return status;
  3030. }
  3031. PCONTROLLER_OBJECT
  3032. IoCreateController(
  3033. IN ULONG Size
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. This routine creates a controller object that can be used to synchronize
  3038. access to a physical device controller from two or more devices.
  3039. Arguments:
  3040. Size - Size of the adapter extension in bytes.
  3041. Return Value:
  3042. A pointer to the controller object that was created or a NULL pointer.
  3043. --*/
  3044. {
  3045. OBJECT_ATTRIBUTES objectAttributes;
  3046. PCONTROLLER_OBJECT controllerObject;
  3047. HANDLE handle;
  3048. NTSTATUS status;
  3049. PAGED_CODE();
  3050. //
  3051. // Initialize the object attributes structure in preparation for creating
  3052. // the controller object.
  3053. //
  3054. InitializeObjectAttributes( &objectAttributes,
  3055. (PUNICODE_STRING) NULL,
  3056. 0,
  3057. (HANDLE) NULL,
  3058. (PSECURITY_DESCRIPTOR) NULL );
  3059. //
  3060. // Create the controller object itself.
  3061. //
  3062. status = ObCreateObject( KernelMode,
  3063. IoControllerObjectType,
  3064. &objectAttributes,
  3065. KernelMode,
  3066. (PVOID) NULL,
  3067. (ULONG) sizeof( CONTROLLER_OBJECT ) + Size,
  3068. 0,
  3069. 0,
  3070. (PVOID *) &controllerObject );
  3071. if (NT_SUCCESS( status )) {
  3072. //
  3073. // Insert the controller object into the table.
  3074. //
  3075. status = ObInsertObject( controllerObject,
  3076. NULL,
  3077. FILE_READ_DATA | FILE_WRITE_DATA,
  3078. 1,
  3079. (PVOID *) &controllerObject,
  3080. &handle );
  3081. //
  3082. // If the insert operation fails, set return value to NULL.
  3083. //
  3084. if (!NT_SUCCESS( status )) {
  3085. controllerObject = (PCONTROLLER_OBJECT) NULL;
  3086. } else {
  3087. //
  3088. // The insert completed successfully. Close the handle so that if
  3089. // the driver is unloaded, the controller object can go away.
  3090. //
  3091. (VOID) NtClose( handle );
  3092. //
  3093. // Zero the memory for the controller object.
  3094. //
  3095. RtlZeroMemory( controllerObject, sizeof( CONTROLLER_OBJECT ) + Size );
  3096. //
  3097. // Set the type and size of this controller object.
  3098. //
  3099. controllerObject->Type = IO_TYPE_CONTROLLER;
  3100. controllerObject->Size = (USHORT) (sizeof( CONTROLLER_OBJECT ) + Size);
  3101. controllerObject->ControllerExtension = (PVOID) (controllerObject + 1);
  3102. //
  3103. // Finally, initialize the controller's device queue.
  3104. //
  3105. KeInitializeDeviceQueue( &controllerObject->DeviceWaitQueue );
  3106. }
  3107. } else {
  3108. controllerObject = (PCONTROLLER_OBJECT) NULL;
  3109. }
  3110. return controllerObject;
  3111. }
  3112. VOID
  3113. IopInsertRemoveDevice(
  3114. IN PDRIVER_OBJECT DriverObject,
  3115. IN PDEVICE_OBJECT DeviceObject,
  3116. IN BOOLEAN Insert
  3117. )
  3118. {
  3119. KIRQL irql;
  3120. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  3121. if (Insert) {
  3122. DeviceObject->NextDevice = DriverObject->DeviceObject;
  3123. DriverObject->DeviceObject = DeviceObject;
  3124. }
  3125. else {
  3126. PDEVICE_OBJECT *prevPoint;
  3127. prevPoint = &DeviceObject->DriverObject->DeviceObject;
  3128. while (*prevPoint != DeviceObject) {
  3129. prevPoint = &(*prevPoint)->NextDevice;
  3130. }
  3131. *prevPoint = DeviceObject->NextDevice;
  3132. }
  3133. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  3134. }
  3135. NTSTATUS
  3136. IopCreateVpb (
  3137. IN PDEVICE_OBJECT DeviceObject
  3138. )
  3139. {
  3140. PVPB Vpb;
  3141. Vpb = ExAllocatePoolWithTag(
  3142. NonPagedPool,
  3143. sizeof( VPB ),
  3144. ' bpV'
  3145. );
  3146. if (!Vpb) {
  3147. return STATUS_INSUFFICIENT_RESOURCES;
  3148. }
  3149. RtlZeroMemory (Vpb, sizeof(VPB));
  3150. Vpb->Type = IO_TYPE_VPB;
  3151. Vpb->Size = sizeof( VPB );
  3152. Vpb->RealDevice = DeviceObject;
  3153. DeviceObject->Vpb = Vpb;
  3154. return STATUS_SUCCESS;
  3155. }
  3156. NTSTATUS
  3157. IoCreateDevice(
  3158. IN PDRIVER_OBJECT DriverObject,
  3159. IN ULONG DeviceExtensionSize,
  3160. IN PUNICODE_STRING DeviceName OPTIONAL,
  3161. IN DEVICE_TYPE DeviceType,
  3162. IN ULONG DeviceCharacteristics,
  3163. IN BOOLEAN Exclusive,
  3164. OUT PDEVICE_OBJECT *DeviceObject
  3165. )
  3166. /*++
  3167. Routine Description:
  3168. This routine creates a device object and links it into the I/O database.
  3169. Arguments:
  3170. DriverObject - A pointer to the driver object for this device.
  3171. DeviceExtensionSize - Size, in bytes, of extension to device object;
  3172. i.e., the size of the driver-specific data for this device object.
  3173. DeviceName - Optional name that should be associated with this device.
  3174. If the DeviceCharacteristics has the FILE_AUTOGENERATED_DEVICE_NAME
  3175. flag set, this parameter is ignored.
  3176. DeviceType - The type of device that the device object should represent.
  3177. DeviceCharacteristics - The characteristics for the device.
  3178. Exclusive - Indicates that the device object should be created with using
  3179. the exclusive object attribute.
  3180. NOTE: This flag should not be used for WDM drivers. Since only the
  3181. PDO is named, it is the only device object in a devnode attachment
  3182. stack that is openable. However, since this device object is created
  3183. by the underlying bus driver (which has no knowledge about what type
  3184. of device this is), there is no way to know whether this flag should
  3185. be set. Therefore, this parameter should always be FALSE for WDM
  3186. drivers. Drivers attached to the PDO (e.g., the function driver) must
  3187. enforce any exclusivity rules.
  3188. DeviceObject - Pointer to the device object pointer we will return.
  3189. Return Value:
  3190. The function value is the final status of the operation.
  3191. --*/
  3192. {
  3193. OBJECT_ATTRIBUTES objectAttributes;
  3194. PDEVICE_OBJECT deviceObject;
  3195. PDEVOBJ_EXTENSION deviceObjectExt;
  3196. HANDLE handle;
  3197. BOOLEAN deviceHasName;
  3198. CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
  3199. PSECURITY_DESCRIPTOR securityDescriptor;
  3200. PACL acl;
  3201. ULONG RoundedSize;
  3202. NTSTATUS status;
  3203. USHORT sectorSize = 0;
  3204. LONG nextUniqueDeviceObjectNumber;
  3205. UNICODE_STRING autoGeneratedDeviceName;
  3206. BOOLEAN retryWithNewName = FALSE;
  3207. WCHAR deviceNameBuffer[17]; // "\Device\xxxxxxxx"
  3208. PAGED_CODE();
  3209. acl = NULL;
  3210. //
  3211. // Enclose the creation of the device object in a do/while, in the rare
  3212. // event where we have to retry because some other driver is using our
  3213. // naming scheme for auto-generated device object names.
  3214. //
  3215. do {
  3216. if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME) {
  3217. //
  3218. // The caller has requested that we automatically generate a device
  3219. // object name. Retrieve the next available number to use for this
  3220. // purpose, and create a name of the form "\Device\<n>", where <n>
  3221. // is the (8 hexadecimal digit) character representation of the unique
  3222. // number we retrieve.
  3223. //
  3224. nextUniqueDeviceObjectNumber = InterlockedIncrement( &IopUniqueDeviceObjectNumber );
  3225. swprintf( deviceNameBuffer, L"\\Device\\%08lx", nextUniqueDeviceObjectNumber );
  3226. if (retryWithNewName) {
  3227. //
  3228. // We've already done this once (hence, the unicode device name string
  3229. // is all set up, as is all the security information). Thus, we can
  3230. // skip down to where we re-attempt the creation of the device object
  3231. // using our new name.
  3232. //
  3233. retryWithNewName = FALSE;
  3234. goto attemptDeviceObjectCreation;
  3235. } else {
  3236. //
  3237. // Set the DeviceName parameter to point to our unicode string, just as
  3238. // if the caller had specified it (note, we explicitly ignore anything
  3239. // the caller passes us for device name if the FILE_AUTOGENERATED_DEVICE_NAME
  3240. // characteristic is specified.
  3241. //
  3242. RtlInitUnicodeString( &autoGeneratedDeviceName, deviceNameBuffer );
  3243. DeviceName = &autoGeneratedDeviceName;
  3244. }
  3245. }
  3246. //
  3247. // Remember whether or not this device was created with a name so that
  3248. // it can be deallocated later.
  3249. //
  3250. deviceHasName = (BOOLEAN) (ARGUMENT_PRESENT( DeviceName ) ? TRUE : FALSE);
  3251. //
  3252. // Detmermine whether or not this device needs to have a security descriptor
  3253. // placed on it that allows read/write access, or whether the system default
  3254. // should be used. Disks, virtual disks, and file systems simply use the
  3255. // system default descriptor. All others allow read/write access.
  3256. //
  3257. // NOTE: This routine assumes that it is in the system's security context.
  3258. // In particular, it assumes that the Default DACL is the system's
  3259. // Default DACL. If this assumption changes in future releases,
  3260. // then use of the Default DACL below should be reviewed for
  3261. // appropriateness.
  3262. //
  3263. //
  3264. // If the device is a pnp device then wait until it registers a device
  3265. // class before doing the default setup.
  3266. //
  3267. securityDescriptor = IopCreateDefaultDeviceSecurityDescriptor(
  3268. DeviceType,
  3269. DeviceCharacteristics,
  3270. deviceHasName,
  3271. localSecurityDescriptor,
  3272. &acl,
  3273. NULL);
  3274. switch ( DeviceType ) {
  3275. case FILE_DEVICE_DISK_FILE_SYSTEM:
  3276. sectorSize = 512;
  3277. break;
  3278. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  3279. sectorSize = 2048;
  3280. break;
  3281. case FILE_DEVICE_DISK:
  3282. case FILE_DEVICE_VIRTUAL_DISK:
  3283. sectorSize = 512;
  3284. break;
  3285. }
  3286. attemptDeviceObjectCreation:
  3287. //
  3288. // Initialize the object attributes structure in preparation for creating
  3289. // device object. Note that the device may be created as an exclusive
  3290. // device so that only one open can be done to it at a time. This saves
  3291. // single user devices from having drivers that implement special code to
  3292. // make sure that only one connection is ever valid at any given time.
  3293. //
  3294. InitializeObjectAttributes( &objectAttributes,
  3295. DeviceName,
  3296. 0,
  3297. (HANDLE) NULL,
  3298. securityDescriptor );
  3299. if (Exclusive) {
  3300. objectAttributes.Attributes |= OBJ_EXCLUSIVE;
  3301. } else {
  3302. objectAttributes.Attributes |= 0;
  3303. }
  3304. if (deviceHasName) {
  3305. objectAttributes.Attributes |= OBJ_PERMANENT;
  3306. }
  3307. //
  3308. // Create the device object itself.
  3309. //
  3310. RoundedSize = (sizeof( DEVICE_OBJECT ) + DeviceExtensionSize)
  3311. % sizeof (LONGLONG);
  3312. if (RoundedSize) {
  3313. RoundedSize = sizeof (LONGLONG) - RoundedSize;
  3314. }
  3315. RoundedSize += DeviceExtensionSize;
  3316. status = ObCreateObject( KernelMode,
  3317. IoDeviceObjectType,
  3318. &objectAttributes,
  3319. KernelMode,
  3320. (PVOID) NULL,
  3321. (ULONG) sizeof( DEVICE_OBJECT ) + sizeof ( DEVOBJ_EXTENSION ) +
  3322. RoundedSize,
  3323. 0,
  3324. 0,
  3325. (PVOID *) &deviceObject );
  3326. if ((status == STATUS_OBJECT_NAME_COLLISION) &&
  3327. (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)) {
  3328. //
  3329. // Some other driver is using our naming scheme, and we've picked a
  3330. // device name already in use. Try again, with a new number.
  3331. //
  3332. retryWithNewName = TRUE;
  3333. }
  3334. } while (retryWithNewName);
  3335. if (!NT_SUCCESS( status )) {
  3336. //
  3337. // Creating the device object was not successful. Clean everything
  3338. // up and indicate that the object was not created.
  3339. //
  3340. deviceObject = (PDEVICE_OBJECT) NULL;
  3341. } else {
  3342. //
  3343. // The device was successfully created. Initialize the object so
  3344. // that it can be inserted into the object table. Begin by zeroing
  3345. // the memory for the device object.
  3346. //
  3347. RtlZeroMemory( deviceObject,
  3348. sizeof( DEVICE_OBJECT ) + sizeof ( DEVOBJ_EXTENSION ) +
  3349. RoundedSize );
  3350. //
  3351. // Fill in deviceObject & deviceObjectExtension cross pointers
  3352. //
  3353. deviceObjectExt = (PDEVOBJ_EXTENSION) (((PCHAR) deviceObject) +
  3354. sizeof (DEVICE_OBJECT) + RoundedSize);
  3355. deviceObjectExt->DeviceObject = deviceObject;
  3356. deviceObject->DeviceObjectExtension = deviceObjectExt;
  3357. //
  3358. // Initialize deviceObjectExt
  3359. // Note: the size of a Device Object Extension is initialized specifically
  3360. // to ZERO so no driver will depend on it.
  3361. //
  3362. deviceObjectExt->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
  3363. deviceObjectExt->Size = 0;
  3364. PoInitializeDeviceObject(deviceObjectExt);
  3365. //
  3366. // Set the type and size of this device object.
  3367. //
  3368. deviceObject->Type = IO_TYPE_DEVICE;
  3369. deviceObject->Size = (USHORT) (sizeof( DEVICE_OBJECT ) + DeviceExtensionSize);
  3370. //
  3371. // Set the device type field in the object so that later code can
  3372. // check the type. Likewise, set the device characteristics.
  3373. //
  3374. deviceObject->DeviceType = DeviceType;
  3375. deviceObject->Characteristics = DeviceCharacteristics;
  3376. //
  3377. // If this device is either a tape or a disk, allocate a Volume
  3378. // Parameter Block (VPB) which indicates that the volume has
  3379. // never been mounted, and set the device object's VPB pointer to
  3380. // it.
  3381. //
  3382. if ((DeviceType == FILE_DEVICE_DISK) ||
  3383. (DeviceType == FILE_DEVICE_TAPE) ||
  3384. (DeviceType == FILE_DEVICE_CD_ROM) ||
  3385. (DeviceType == FILE_DEVICE_VIRTUAL_DISK)) {
  3386. status = IopCreateVpb (deviceObject);
  3387. if (!NT_SUCCESS(status)) {
  3388. ObDereferenceObject(deviceObject);
  3389. if (acl != NULL) {
  3390. ExFreePool( acl );
  3391. }
  3392. *DeviceObject = (PDEVICE_OBJECT)NULL;
  3393. return status;
  3394. }
  3395. KeInitializeEvent( &deviceObject->DeviceLock,
  3396. SynchronizationEvent,
  3397. TRUE );
  3398. }
  3399. //
  3400. // Initialize the remainder of the device object.
  3401. //
  3402. deviceObject->AlignmentRequirement = HalGetDmaAlignmentRequirement() - 1;
  3403. deviceObject->SectorSize = sectorSize;
  3404. deviceObject->Flags = DO_DEVICE_INITIALIZING;
  3405. if (Exclusive) {
  3406. deviceObject->Flags |= DO_EXCLUSIVE;
  3407. }
  3408. if (deviceHasName) {
  3409. deviceObject->Flags |= DO_DEVICE_HAS_NAME;
  3410. }
  3411. if(DeviceExtensionSize) {
  3412. deviceObject->DeviceExtension = deviceObject + 1;
  3413. } else {
  3414. deviceObject->DeviceExtension = NULL;
  3415. }
  3416. deviceObject->StackSize = 1;
  3417. switch ( DeviceType ) {
  3418. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  3419. case FILE_DEVICE_DISK_FILE_SYSTEM:
  3420. case FILE_DEVICE_FILE_SYSTEM:
  3421. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  3422. case FILE_DEVICE_TAPE_FILE_SYSTEM:
  3423. //
  3424. // This device represents a file system of some sort. Simply
  3425. // initialize the queue list head in the device object.
  3426. //
  3427. InitializeListHead( &deviceObject->Queue.ListEntry );
  3428. break;
  3429. default:
  3430. //
  3431. // This is a real device of some sort. Allocate a spin lock
  3432. // and initialize the device queue object in the device object.
  3433. //
  3434. KeInitializeDeviceQueue( &deviceObject->DeviceQueue );
  3435. break;
  3436. }
  3437. //
  3438. // Insert the device object into the table.
  3439. //
  3440. status = ObInsertObject( deviceObject,
  3441. NULL,
  3442. FILE_READ_DATA | FILE_WRITE_DATA,
  3443. 1,
  3444. (PVOID *) &deviceObject,
  3445. &handle );
  3446. if (NT_SUCCESS( status )) {
  3447. //
  3448. // Reference the driver object. When the device object goes
  3449. // away the reference will be removed. This prevents the
  3450. // driver object and driver image from going away while the
  3451. // device object is in the pending delete state.
  3452. //
  3453. ObReferenceObject( DriverObject );
  3454. ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
  3455. //
  3456. // The insert completed successfully. Link the device object
  3457. // and driver objects together. Close the handle so that if
  3458. // the driver is unloaded, the device object can go away.
  3459. //
  3460. deviceObject->DriverObject = DriverObject;
  3461. IopInsertRemoveDevice( DriverObject, deviceObject, TRUE );
  3462. if (deviceObject->Vpb) {
  3463. PoVolumeDevice(deviceObject);
  3464. }
  3465. (VOID) NtClose( handle );
  3466. } else {
  3467. //
  3468. // The insert operation failed. Fortunately it dropped the
  3469. // reference count on the device - since that was the last one
  3470. // all the cleanup should be done for us.
  3471. //
  3472. //
  3473. // indicate that no device object was created.
  3474. //
  3475. deviceObject = (PDEVICE_OBJECT) NULL;
  3476. }
  3477. }
  3478. //
  3479. // Free the DACL if we allocated it...
  3480. //
  3481. if (acl != NULL) {
  3482. ExFreePool( acl );
  3483. }
  3484. *DeviceObject = deviceObject;
  3485. return status;
  3486. }
  3487. NTSTATUS
  3488. IoCreateFile(
  3489. OUT PHANDLE FileHandle,
  3490. IN ACCESS_MASK DesiredAccess,
  3491. IN POBJECT_ATTRIBUTES ObjectAttributes,
  3492. OUT PIO_STATUS_BLOCK IoStatusBlock,
  3493. IN PLARGE_INTEGER AllocationSize OPTIONAL,
  3494. IN ULONG FileAttributes,
  3495. IN ULONG ShareAccess,
  3496. IN ULONG Disposition,
  3497. IN ULONG CreateOptions,
  3498. IN PVOID EaBuffer OPTIONAL,
  3499. IN ULONG EaLength,
  3500. IN CREATE_FILE_TYPE CreateFileType,
  3501. IN PVOID ExtraCreateParameters OPTIONAL,
  3502. IN ULONG Options
  3503. )
  3504. /*++
  3505. Routine Description:
  3506. This is the common routine for both NtCreateFile and NtOpenFile to allow
  3507. a user to create or open a file. This procedure is also used internally
  3508. by kernel mode components, such as the network server, to perform the
  3509. same type of operation, but allows kernel mode code to force checking
  3510. arguments and access to the file, rather than bypassing these checks
  3511. because the code is running in kernel mode.
  3512. Arguments:
  3513. FileHandle - A pointer to a variable to receive the handle to the open
  3514. file.
  3515. DesiredAccess - Supplies the types of access that the caller would like
  3516. to the file.
  3517. ObjectAttributes - Supplies the attributes to be used for the file object
  3518. (name, SECURITY_DESCRIPTOR, etc.)
  3519. IoStatusBlock - Specifies the address of the caller's I/O status block.
  3520. AllocationSize - Initial size that should be allocated to the file.
  3521. This parameter only has an affect if the file is created. Further,
  3522. if not specified, then it is taken to mean zero.
  3523. FileAttributes - Specifies the attributes that should be set on the file,
  3524. if it is created.
  3525. ShareAccess - Supplies the types of share access that the caller would
  3526. like to the file.
  3527. Disposition - Supplies the method for handling the create/open.
  3528. CreateOptions - Caller options for how to perform the create/open.
  3529. EaBuffer - Optionally specifies a set of EAs to be applied to the file
  3530. if it is created.
  3531. EaLength - Supplies the length of the EaBuffer.
  3532. CreateFileType - The type of file to create.
  3533. ExtraCreateParameters - Optionally specifies a pointer to extra create
  3534. parameters. The format of the parameters depends on the value of
  3535. CreateFileType.
  3536. Options - Specifies the options that are to be used during generation
  3537. of the create IRP.
  3538. Return Value:
  3539. The function value is the final status of the create/open operation.
  3540. Warning:
  3541. If a pointer to ExtraCreateParameters is passed the data must be
  3542. readable from kernel mode.
  3543. --*/
  3544. {
  3545. return IopCreateFile(
  3546. FileHandle,
  3547. DesiredAccess,
  3548. ObjectAttributes,
  3549. IoStatusBlock,
  3550. AllocationSize,
  3551. FileAttributes,
  3552. ShareAccess,
  3553. Disposition,
  3554. CreateOptions,
  3555. EaBuffer,
  3556. EaLength,
  3557. CreateFileType,
  3558. ExtraCreateParameters,
  3559. Options,
  3560. 0,
  3561. NULL
  3562. );
  3563. }
  3564. NTSTATUS
  3565. IoCreateFileSpecifyDeviceObjectHint(
  3566. OUT PHANDLE FileHandle,
  3567. IN ACCESS_MASK DesiredAccess,
  3568. IN POBJECT_ATTRIBUTES ObjectAttributes,
  3569. OUT PIO_STATUS_BLOCK IoStatusBlock,
  3570. IN PLARGE_INTEGER AllocationSize OPTIONAL,
  3571. IN ULONG FileAttributes,
  3572. IN ULONG ShareAccess,
  3573. IN ULONG Disposition,
  3574. IN ULONG CreateOptions,
  3575. IN PVOID EaBuffer OPTIONAL,
  3576. IN ULONG EaLength,
  3577. IN CREATE_FILE_TYPE CreateFileType,
  3578. IN PVOID ExtraCreateParameters OPTIONAL,
  3579. IN ULONG Options,
  3580. IN PVOID DeviceObject
  3581. )
  3582. {
  3583. ULONG internalFlags = 0;
  3584. if (DeviceObject != NULL) {
  3585. internalFlags = IOP_CREATE_USE_TOP_DEVICE_OBJECT_HINT;
  3586. }
  3587. if (Options & IO_IGNORE_SHARE_ACCESS_CHECK) {
  3588. internalFlags |= IOP_CREATE_IGNORE_SHARE_ACCESS_CHECK;
  3589. }
  3590. return IopCreateFile(
  3591. FileHandle,
  3592. DesiredAccess,
  3593. ObjectAttributes,
  3594. IoStatusBlock,
  3595. AllocationSize,
  3596. FileAttributes,
  3597. ShareAccess,
  3598. Disposition,
  3599. CreateOptions,
  3600. EaBuffer,
  3601. EaLength,
  3602. CreateFileType,
  3603. ExtraCreateParameters,
  3604. Options|IO_NO_PARAMETER_CHECKING,
  3605. internalFlags,
  3606. DeviceObject
  3607. );
  3608. }
  3609. NTSTATUS
  3610. IopCreateFile(
  3611. OUT PHANDLE FileHandle,
  3612. IN ACCESS_MASK DesiredAccess,
  3613. IN POBJECT_ATTRIBUTES ObjectAttributes,
  3614. OUT PIO_STATUS_BLOCK IoStatusBlock,
  3615. IN PLARGE_INTEGER AllocationSize OPTIONAL,
  3616. IN ULONG FileAttributes,
  3617. IN ULONG ShareAccess,
  3618. IN ULONG Disposition,
  3619. IN ULONG CreateOptions,
  3620. IN PVOID EaBuffer OPTIONAL,
  3621. IN ULONG EaLength,
  3622. IN CREATE_FILE_TYPE CreateFileType,
  3623. IN PVOID ExtraCreateParameters OPTIONAL,
  3624. IN ULONG Options,
  3625. IN ULONG InternalFlags,
  3626. IN PVOID DeviceObject
  3627. )
  3628. /*++
  3629. Routine Description:
  3630. This is the common routine for both NtCreateFile and NtOpenFile to allow
  3631. a user to create or open a file. This procedure is also used internally
  3632. by kernel mode components, such as the network server, to perform the
  3633. same type of operation, but allows kernel mode code to force checking
  3634. arguments and access to the file, rather than bypassing these checks
  3635. because the code is running in kernel mode.
  3636. Arguments:
  3637. FileHandle - A pointer to a variable to receive the handle to the open
  3638. file.
  3639. DesiredAccess - Supplies the types of access that the caller would like
  3640. to the file.
  3641. ObjectAttributes - Supplies the attributes to be used for the file object
  3642. (name, SECURITY_DESCRIPTOR, etc.)
  3643. IoStatusBlock - Specifies the address of the caller's I/O status block.
  3644. AllocationSize - Initial size that should be allocated to the file.
  3645. This parameter only has an affect if the file is created. Further,
  3646. if not specified, then it is taken to mean zero.
  3647. FileAttributes - Specifies the attributes that should be set on the file,
  3648. if it is created.
  3649. ShareAccess - Supplies the types of share access that the caller would
  3650. like to the file.
  3651. Disposition - Supplies the method for handling the create/open.
  3652. CreateOptions - Caller options for how to perform the create/open.
  3653. EaBuffer - Optionally specifies a set of EAs to be applied to the file
  3654. if it is created.
  3655. EaLength - Supplies the length of the EaBuffer.
  3656. CreateFileType - The type of file to create.
  3657. ExtraCreateParameters - Optionally specifies a pointer to extra create
  3658. parameters. The format of the parameters depends on the value of
  3659. CreateFileType.
  3660. Options - Specifies the options that are to be used during generation
  3661. of the create IRP.
  3662. DeviceObject - Specifies which device object to use when issuing the create IRP.
  3663. Return Value:
  3664. The function value is the final status of the create/open operation.
  3665. Warning:
  3666. If a pointer to ExtraCreateParameters is passed the data must be
  3667. readable from kernel mode.
  3668. --*/
  3669. {
  3670. KPROCESSOR_MODE requestorMode;
  3671. NTSTATUS status;
  3672. HANDLE handle;
  3673. POPEN_PACKET openPacket;
  3674. BOOLEAN SuccessfulIoParse;
  3675. LARGE_INTEGER initialAllocationSize;
  3676. PAGED_CODE();
  3677. //
  3678. // Get the previous mode; i.e., the mode of the caller.
  3679. //
  3680. requestorMode = KeGetPreviousMode();
  3681. if (Options & IO_NO_PARAMETER_CHECKING) {
  3682. requestorMode = KernelMode;
  3683. }
  3684. openPacket = ExAllocatePoolWithTag( NonPagedPool,
  3685. sizeof(OPEN_PACKET),
  3686. 'pOoI');
  3687. if (openPacket == NULL) {
  3688. return STATUS_INSUFFICIENT_RESOURCES;
  3689. }
  3690. if (requestorMode != KernelMode || Options & IO_CHECK_CREATE_PARAMETERS) {
  3691. //
  3692. // Check for any invalid parameters.
  3693. //
  3694. if (
  3695. //
  3696. // Check that no invalid file attributes flags were specified.
  3697. //
  3698. // (FileAttributes & ~FILE_ATTRIBUTE_VALID_SET_FLAGS)
  3699. (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
  3700. ||
  3701. //
  3702. // Check that no invalid share access flags were specified.
  3703. //
  3704. (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
  3705. ||
  3706. //
  3707. // Ensure that the disposition value is in range.
  3708. //
  3709. (Disposition > FILE_MAXIMUM_DISPOSITION)
  3710. ||
  3711. //
  3712. // Check that no invalid create options were specified.
  3713. //
  3714. (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
  3715. ||
  3716. //
  3717. // If the caller specified synchronous I/O, then ensure that
  3718. // (s)he also asked for synchronize desired access to the
  3719. // file.
  3720. //
  3721. (CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT) &&
  3722. (!(DesiredAccess & SYNCHRONIZE)))
  3723. ||
  3724. //
  3725. // Also, if the caller specified that the file is to be deleted
  3726. // on close, then ensure that delete is specified as one of the
  3727. // desired accesses requested.
  3728. //
  3729. (CreateOptions & FILE_DELETE_ON_CLOSE &&
  3730. (!(DesiredAccess & DELETE)))
  3731. ||
  3732. //
  3733. // Likewise, ensure that if one of the synchronous I/O modes
  3734. // is specified that the other one is not specified as well.
  3735. //
  3736. ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ==
  3737. (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
  3738. ||
  3739. //
  3740. // If this create or open is for a directory operation, check
  3741. // that all of the other flags, dispositions, and desired
  3742. // access parameters were also specified correctly.
  3743. //
  3744. // These are as follows:
  3745. //
  3746. // o No other flags other than the synchronous I/O flags,
  3747. // write-through, or open by file ID are set.
  3748. //
  3749. // o The disposition value is one of create, open, or
  3750. // open-if.
  3751. //
  3752. // o No non-directory accesses have been specified.
  3753. //
  3754. ((CreateOptions & FILE_DIRECTORY_FILE)
  3755. && !(CreateOptions & FILE_NON_DIRECTORY_FILE)
  3756. && ((CreateOptions & ~(FILE_DIRECTORY_FILE |
  3757. FILE_SYNCHRONOUS_IO_ALERT |
  3758. FILE_SYNCHRONOUS_IO_NONALERT |
  3759. FILE_WRITE_THROUGH |
  3760. FILE_COMPLETE_IF_OPLOCKED |
  3761. FILE_OPEN_FOR_BACKUP_INTENT |
  3762. FILE_DELETE_ON_CLOSE |
  3763. FILE_OPEN_FOR_FREE_SPACE_QUERY |
  3764. FILE_OPEN_BY_FILE_ID |
  3765. FILE_NO_COMPRESSION|
  3766. FILE_OPEN_REPARSE_POINT))
  3767. || ((Disposition != FILE_CREATE)
  3768. && (Disposition != FILE_OPEN)
  3769. && (Disposition != FILE_OPEN_IF))
  3770. )
  3771. )
  3772. ||
  3773. //
  3774. // FILE_COMPLETE_IF_OPLOCK and FILE_RESERVE_OPFILTER are
  3775. // incompatible options.
  3776. //
  3777. ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) &&
  3778. (CreateOptions & FILE_RESERVE_OPFILTER))
  3779. ||
  3780. //
  3781. // Finally, if the no intermediate buffering option was
  3782. // specified, ensure that the caller did not also request
  3783. // append access to the file.
  3784. //
  3785. (CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING &&
  3786. (DesiredAccess & FILE_APPEND_DATA)) ) {
  3787. ExFreePool(openPacket);
  3788. return STATUS_INVALID_PARAMETER;
  3789. }
  3790. //
  3791. // Check the file type specific creation parameters.
  3792. //
  3793. if (CreateFileType == CreateFileTypeNone) {
  3794. NOTHING;
  3795. } else if (CreateFileType == CreateFileTypeNamedPipe) {
  3796. if (!ARGUMENT_PRESENT( ExtraCreateParameters ) ) {
  3797. ExFreePool(openPacket);
  3798. return STATUS_INVALID_PARAMETER;
  3799. } else {
  3800. PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
  3801. NamedPipeCreateParameters = ExtraCreateParameters;
  3802. //
  3803. // Check the parameters for creating a named pipe to
  3804. // ensure that no invalid parameters were passed.
  3805. //
  3806. if (
  3807. //
  3808. // Check the NamedPipeType field to ensure that it
  3809. // is within range.
  3810. //
  3811. (NamedPipeCreateParameters->NamedPipeType >
  3812. FILE_PIPE_MESSAGE_TYPE)
  3813. ||
  3814. //
  3815. // Check the ReadMode field to ensure that it is
  3816. // within range.
  3817. //
  3818. (NamedPipeCreateParameters->ReadMode >
  3819. FILE_PIPE_MESSAGE_MODE)
  3820. ||
  3821. //
  3822. // Check the CompletionMode field to ensure that
  3823. // it is within range.
  3824. //
  3825. (NamedPipeCreateParameters->CompletionMode >
  3826. FILE_PIPE_COMPLETE_OPERATION)
  3827. ||
  3828. //
  3829. // Check the ShareAccess parameter to ensure that
  3830. // it does not specify shared delete access. The
  3831. // Named Pipe File System itself will need to ensure
  3832. // that at least one of SHARE_READ or SHARE_WRITE
  3833. // is specified if the first instance of the pipe
  3834. // is being created.
  3835. //
  3836. (ShareAccess & FILE_SHARE_DELETE)
  3837. ||
  3838. //
  3839. // Check the Disposition parameter to ensure that
  3840. // is does not specify anything other than create,
  3841. // open, or open if.
  3842. //
  3843. (Disposition < FILE_OPEN || Disposition > FILE_OPEN_IF)
  3844. ||
  3845. //
  3846. // Finally, check the CreateOptions parameter to
  3847. // ensure that it does not contain any invalid
  3848. // options for named pipes.
  3849. //
  3850. (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS)) {
  3851. ExFreePool(openPacket);
  3852. return STATUS_INVALID_PARAMETER;
  3853. }
  3854. }
  3855. } else if (CreateFileType == CreateFileTypeMailslot) {
  3856. if (!ARGUMENT_PRESENT( ExtraCreateParameters ) ) {
  3857. ExFreePool(openPacket);
  3858. return STATUS_INVALID_PARAMETER;
  3859. } else {
  3860. PMAILSLOT_CREATE_PARAMETERS mailslotCreateParameters;
  3861. mailslotCreateParameters = ExtraCreateParameters;
  3862. //
  3863. // Check the parameters for creating a mailslot to ensure
  3864. // that no invalid parameters were passed.
  3865. //
  3866. if (
  3867. //
  3868. // Check the ShareAccess parameter to ensure that
  3869. // it does not specify shared delete access.
  3870. //
  3871. (ShareAccess & FILE_SHARE_DELETE)
  3872. ||
  3873. //
  3874. // Check the ShareAccess parameter to ensure that
  3875. // shared write access is specified.
  3876. //
  3877. !(ShareAccess & ~FILE_SHARE_WRITE)
  3878. ||
  3879. //
  3880. // Check the Disposition parameter to ensure that
  3881. // it specifies that the file is to be created.
  3882. //
  3883. (Disposition != FILE_CREATE)
  3884. ||
  3885. //
  3886. // Check the CreateOptions parameter to ensure that
  3887. // it does not contain any options that are invalid
  3888. // for mailslots.
  3889. //
  3890. (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS)) {
  3891. ExFreePool(openPacket);
  3892. return STATUS_INVALID_PARAMETER;
  3893. }
  3894. }
  3895. }
  3896. }
  3897. if (requestorMode != KernelMode) {
  3898. //
  3899. // The caller's access mode is not kernel so probe each of the
  3900. // arguments and capture them as necessary. If any failures occur,
  3901. // the condition handler will be invoked to handle them. It will
  3902. // simply cleanup and return an access violation status code back
  3903. // to the system service dispatcher.
  3904. //
  3905. openPacket->EaBuffer = (PFILE_FULL_EA_INFORMATION) NULL;
  3906. try {
  3907. //
  3908. // The FileHandle parameter must be writeable by the caller.
  3909. // Probe it for a write operation.
  3910. //
  3911. ProbeAndWriteHandle( FileHandle, 0L );
  3912. //
  3913. // The IoStatusBlock parameter must be writeable by the caller.
  3914. //
  3915. ProbeForWriteIoStatus( IoStatusBlock );
  3916. //
  3917. // The AllocationSize parameter must be readable by the caller
  3918. // if it is present. If so, probe and capture it.
  3919. //
  3920. if (ARGUMENT_PRESENT( AllocationSize )) {
  3921. ProbeForReadSmallStructure( AllocationSize,
  3922. sizeof( LARGE_INTEGER ),
  3923. sizeof( ULONG ) );
  3924. initialAllocationSize = *AllocationSize;
  3925. } else {
  3926. initialAllocationSize.QuadPart = 0;
  3927. }
  3928. if (initialAllocationSize.QuadPart < 0) {
  3929. ExRaiseStatus( STATUS_INVALID_PARAMETER );
  3930. }
  3931. } except(EXCEPTION_EXECUTE_HANDLER) {
  3932. //
  3933. // An exception was incurred while attempting to access the
  3934. // caller's parameters. Simply return the reason for the
  3935. // exception as the service status.
  3936. //
  3937. ExFreePool(openPacket);
  3938. return GetExceptionCode();
  3939. }
  3940. //
  3941. // Finally, if an EaBuffer was specified, ensure that it is readable
  3942. // from the caller's mode and capture it.
  3943. //
  3944. if (ARGUMENT_PRESENT( EaBuffer ) && EaLength) {
  3945. ULONG errorOffset;
  3946. try {
  3947. ProbeForRead( EaBuffer, EaLength, sizeof( ULONG ) );
  3948. openPacket->EaBuffer = ExAllocatePoolWithQuotaTag( NonPagedPool,
  3949. EaLength,
  3950. 'aEoI' );
  3951. openPacket->EaLength = EaLength;
  3952. RtlCopyMemory( openPacket->EaBuffer, EaBuffer, EaLength );
  3953. //
  3954. // Walk the buffer and ensure that its format is valid. Note
  3955. // that has been probed.
  3956. //
  3957. status = IoCheckEaBufferValidity( openPacket->EaBuffer,
  3958. EaLength,
  3959. &errorOffset );
  3960. if (!NT_SUCCESS( status )) {
  3961. IoStatusBlock->Status = status;
  3962. IoStatusBlock->Information = errorOffset;
  3963. ExRaiseStatus( status );
  3964. }
  3965. } except(EXCEPTION_EXECUTE_HANDLER) {
  3966. //
  3967. // An exception was incurred while attempting to access the
  3968. // caller's parameters. Check to see whether or not an EA
  3969. // buffer was allocated and deallocate if so.
  3970. //
  3971. if (openPacket->EaBuffer != NULL) {
  3972. ExFreePool( openPacket->EaBuffer );
  3973. }
  3974. ExFreePool(openPacket);
  3975. return GetExceptionCode();
  3976. }
  3977. } else {
  3978. //
  3979. // No EAs were specified.
  3980. //
  3981. openPacket->EaBuffer = (PVOID) NULL;
  3982. openPacket->EaLength = 0L;
  3983. }
  3984. } else {
  3985. //
  3986. // The caller's mode is kernel. Copy the input parameters to their
  3987. // expected locations for later use. Also, put move attach device
  3988. // flag where it belongs.
  3989. //
  3990. if (CreateOptions & IO_ATTACH_DEVICE_API) {
  3991. Options |= IO_ATTACH_DEVICE;
  3992. CreateOptions &= ~IO_ATTACH_DEVICE_API;
  3993. }
  3994. if (ARGUMENT_PRESENT( AllocationSize )) {
  3995. initialAllocationSize = *AllocationSize;
  3996. } else {
  3997. initialAllocationSize.QuadPart = 0;
  3998. }
  3999. if (ARGUMENT_PRESENT( EaBuffer ) && EaLength) {
  4000. ULONG errorOffset;
  4001. openPacket->EaBuffer = ExAllocatePoolWithTag( NonPagedPool,
  4002. EaLength,
  4003. 'aEoI' );
  4004. if (!openPacket->EaBuffer) {
  4005. ExFreePool(openPacket);
  4006. return STATUS_INSUFFICIENT_RESOURCES;
  4007. }
  4008. openPacket->EaLength = EaLength;
  4009. RtlCopyMemory( openPacket->EaBuffer, EaBuffer, EaLength );
  4010. //
  4011. // Walk the buffer and ensure that its format is valid. Note
  4012. // that has been probed.
  4013. //
  4014. status = IoCheckEaBufferValidity( openPacket->EaBuffer,
  4015. EaLength,
  4016. &errorOffset );
  4017. if (!NT_SUCCESS( status )) {
  4018. ExFreePool(openPacket->EaBuffer);
  4019. IoStatusBlock->Status = status;
  4020. IoStatusBlock->Information = errorOffset;
  4021. ExFreePool(openPacket);
  4022. return status;
  4023. }
  4024. } else {
  4025. openPacket->EaBuffer = (PVOID) NULL;
  4026. openPacket->EaLength = 0L;
  4027. }
  4028. }
  4029. //
  4030. // Now fill in an Open Packet (OP) to be used in calling the device object
  4031. // parse routine. This packet will allow information to be passed between
  4032. // this routine and the parse routine so that a common context may be kept.
  4033. // For most services this would be done with an I/O Request Packet (IRP),
  4034. // but this cannot be done here because the number of stack entries which
  4035. // need to be allocated in the IRP is not yet known.
  4036. //
  4037. openPacket->Type = IO_TYPE_OPEN_PACKET;
  4038. openPacket->Size = sizeof( OPEN_PACKET );
  4039. openPacket->ParseCheck = 0L;
  4040. openPacket->AllocationSize = initialAllocationSize;
  4041. openPacket->CreateOptions = CreateOptions;
  4042. openPacket->FileAttributes = (USHORT) FileAttributes;
  4043. openPacket->ShareAccess = (USHORT) ShareAccess;
  4044. openPacket->Disposition = Disposition;
  4045. openPacket->Override = FALSE;
  4046. openPacket->QueryOnly = FALSE;
  4047. openPacket->DeleteOnly = FALSE;
  4048. openPacket->Options = Options;
  4049. openPacket->RelatedFileObject = (PFILE_OBJECT) NULL;
  4050. openPacket->CreateFileType = CreateFileType;
  4051. openPacket->ExtraCreateParameters = ExtraCreateParameters;
  4052. openPacket->TraversedMountPoint = FALSE;
  4053. openPacket->InternalFlags = InternalFlags;
  4054. openPacket->TopDeviceObjectHint = DeviceObject;
  4055. //
  4056. // Assume that the operation is going to be successful.
  4057. //
  4058. openPacket->FinalStatus = STATUS_SUCCESS;
  4059. //
  4060. // Zero the file object field in the OP so the parse routine knows that
  4061. // this is the first time through. For reparse operations it will continue
  4062. // to use the same file object that it allocated the first time.
  4063. //
  4064. openPacket->FileObject = (PFILE_OBJECT) NULL;
  4065. //
  4066. // Update the open count for this process.
  4067. //
  4068. IopUpdateOtherOperationCount();
  4069. //
  4070. // Attempt to open the file object by name. This will yield the handle
  4071. // that the user is to use as his handle to the file in all subsequent
  4072. // calls, if it works.
  4073. //
  4074. // This call performs a whole lot of the work for actually getting every-
  4075. // thing set up for the I/O system. The object manager will take the name
  4076. // of the file and will translate it until it reaches a device object (or
  4077. // it fails). If the former, then it will invoke the parse routine set up
  4078. // by the I/O system for device objects. This routine will actually end
  4079. // up creating the file object, allocating an IRP, filling it in, and then
  4080. // invoking the driver's dispatch routine with the packet.
  4081. //
  4082. status = ObOpenObjectByName( ObjectAttributes,
  4083. (POBJECT_TYPE) NULL,
  4084. requestorMode,
  4085. NULL,
  4086. DesiredAccess,
  4087. openPacket,
  4088. &handle );
  4089. //
  4090. // If an EA buffer was allocated, deallocate it now before attempting to
  4091. // determine whether or not the operation was successful so that it can be
  4092. // done in one place rather than in two places.
  4093. //
  4094. if (openPacket->EaBuffer) {
  4095. ExFreePool( openPacket->EaBuffer );
  4096. }
  4097. //
  4098. // Check the status of the open. If it was not successful, cleanup and
  4099. // get out. Notice that it is also possible, because this code does not
  4100. // explicitly request that a particular type of object (because the Object
  4101. // Manager does not check when a parse routine is present and because the
  4102. // name first refers to a device object and then a file object), a check
  4103. // must be made here to ensure that what was returned was really a file
  4104. // object. The check is to see whether the device object parse routine
  4105. // believes that it successfully returned a pointer to a file object. If
  4106. // it does, then OK; otherwise, something went wrong somewhere.
  4107. //
  4108. SuccessfulIoParse = (BOOLEAN) (openPacket->ParseCheck == OPEN_PACKET_PATTERN);
  4109. if (!NT_SUCCESS( status ) || !SuccessfulIoParse) {
  4110. if (NT_SUCCESS( status )) {
  4111. //
  4112. // The operation was successful as far as the object system is
  4113. // concerned, but the I/O system device parse routine was never
  4114. // successfully completed so this operation has actually completed
  4115. // with an error because of an object mismatch. Therefore, this is
  4116. // the wrong type of object so dereference whatever was actually
  4117. // referenced by closing the handle that was created for it.
  4118. // We have to do a ZwClose as this handle can be a kernel handle if
  4119. // IoCreateFile was called by a driver.
  4120. //
  4121. ZwClose( handle );
  4122. status = STATUS_OBJECT_TYPE_MISMATCH;
  4123. }
  4124. //
  4125. // If the final status according to the device parse routine
  4126. // indicates that the operation was not successful, then use that
  4127. // routine's final status because it is more descriptive than the
  4128. // status which was returned by the object manager.
  4129. //
  4130. if (!NT_SUCCESS( openPacket->FinalStatus )) {
  4131. status = openPacket->FinalStatus;
  4132. if (NT_WARNING( status )) {
  4133. try {
  4134. IoStatusBlock->Status = openPacket->FinalStatus;
  4135. IoStatusBlock->Information = openPacket->Information;
  4136. } except(EXCEPTION_EXECUTE_HANDLER) {
  4137. status = GetExceptionCode();
  4138. }
  4139. }
  4140. } else if (openPacket->FileObject != NULL && !SuccessfulIoParse) {
  4141. //
  4142. // Otherwise, one of two things occurred:
  4143. //
  4144. // 1) The parse routine was invoked at least once and a
  4145. // reparse was performed but the parse routine did not
  4146. // actually complete.
  4147. //
  4148. // 2) The parse routine was successful so everything worked
  4149. // but the object manager incurred an error after the
  4150. // parse routine completed.
  4151. //
  4152. // For case #1, there is an outstanding file object that still
  4153. // exists. This must be cleaned up.
  4154. //
  4155. // For case #2, nothing must be done as the object manager has
  4156. // already dereferenced the file object. Note that this code is
  4157. // not invoked if the parse routine completed with a successful
  4158. // status return (SuccessfulIoParse is TRUE).
  4159. //
  4160. if (openPacket->FileObject->FileName.Length != 0) {
  4161. ExFreePool( openPacket->FileObject->FileName.Buffer );
  4162. }
  4163. openPacket->FileObject->DeviceObject = (PDEVICE_OBJECT) NULL;
  4164. ObDereferenceObject( openPacket->FileObject );
  4165. }
  4166. //
  4167. // When an NTFS file junction or an NTFS directory junction is traversed
  4168. // OBJ_MAX_REPARSE_ATTEMPTS namy times, the object manager gives up and
  4169. // returns the code STATUS_OBJECT_NAME_NOT_FOUND.
  4170. //
  4171. // This can happen in the following cases:
  4172. //
  4173. // 1) One encounters a legal chain of directory junctions that happen
  4174. // to be longer than the value of the above constant.
  4175. //
  4176. // 2) One encounters a self-referential file or directory junction that
  4177. // is, in effect, a tight name cycle.
  4178. //
  4179. // 3) One encounters a name cycle composed of several NTFS junctions.
  4180. //
  4181. // To improve on this return code see if openPacket->Information is
  4182. // the trace of an NTFS name junction.
  4183. //
  4184. if ((status == STATUS_OBJECT_NAME_NOT_FOUND) &&
  4185. (openPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)) {
  4186. status = STATUS_REPARSE_POINT_NOT_RESOLVED;
  4187. }
  4188. } else {
  4189. //
  4190. // At this point, the open/create operation has been successfully
  4191. // completed. There is a handle to the file object, which has been
  4192. // created, and the file object has been signaled.
  4193. //
  4194. // The remaining work to be done is to complete the operation. This is
  4195. // performed as follows:
  4196. //
  4197. // 1. The file object has been signaled, so no work needs to be done
  4198. // for it.
  4199. //
  4200. // 2. The file handle is returned to the user.
  4201. //
  4202. // 3. The I/O status block is written with the final status.
  4203. //
  4204. openPacket->FileObject->Flags |= FO_HANDLE_CREATED;
  4205. ASSERT( openPacket->FileObject->Type == IO_TYPE_FILE );
  4206. try {
  4207. //
  4208. // Return the file handle.
  4209. //
  4210. *FileHandle = handle;
  4211. //
  4212. // Write the I/O status into the caller's buffer.
  4213. //
  4214. IoStatusBlock->Information = openPacket->Information;
  4215. IoStatusBlock->Status = openPacket->FinalStatus;
  4216. status = openPacket->FinalStatus;
  4217. } except(EXCEPTION_EXECUTE_HANDLER) {
  4218. status = GetExceptionCode();
  4219. }
  4220. }
  4221. //
  4222. // If the parse routine successfully created a file object then
  4223. // derefence it here.
  4224. //
  4225. if (SuccessfulIoParse && openPacket->FileObject != NULL) {
  4226. ObDereferenceObject( openPacket->FileObject );
  4227. }
  4228. ExFreePool(openPacket);
  4229. return status;
  4230. }
  4231. PKEVENT
  4232. IoCreateNotificationEvent(
  4233. IN PUNICODE_STRING EventName,
  4234. OUT PHANDLE EventHandle
  4235. )
  4236. /*++
  4237. Routine Description:
  4238. This routine creates a named notification event for use in notifying
  4239. different system components or drivers that an event occurred.
  4240. Arguments:
  4241. EventName - Supplies the full name of the event.
  4242. EventHandle - Supplies a location to return a handle to the event.
  4243. Return Value:
  4244. The function value is a pointer to the created/opened event, or NULL if
  4245. the event could not be created/opened.
  4246. --*/
  4247. {
  4248. OBJECT_ATTRIBUTES objectAttributes;
  4249. NTSTATUS status;
  4250. HANDLE eventHandle;
  4251. PKEVENT eventObject;
  4252. PAGED_CODE();
  4253. //
  4254. // Begin by initializing the object attributes.
  4255. //
  4256. InitializeObjectAttributes( &objectAttributes,
  4257. EventName,
  4258. OBJ_OPENIF,
  4259. (HANDLE) NULL,
  4260. (PSECURITY_DESCRIPTOR) NULL );
  4261. //
  4262. // Now create or open the event.
  4263. //
  4264. status = ZwCreateEvent( &eventHandle,
  4265. EVENT_ALL_ACCESS,
  4266. &objectAttributes,
  4267. NotificationEvent,
  4268. TRUE );
  4269. if (!NT_SUCCESS( status )) {
  4270. return (PKEVENT) NULL;
  4271. }
  4272. //
  4273. // Reference the object by its handle to get a pointer that can be returned
  4274. // to the caller.
  4275. //
  4276. (VOID) ObReferenceObjectByHandle( eventHandle,
  4277. 0,
  4278. ExEventObjectType,
  4279. KernelMode,
  4280. (PVOID *) &eventObject,
  4281. NULL );
  4282. ObDereferenceObject( eventObject );
  4283. //
  4284. // Return the handle and the pointer to the event.
  4285. //
  4286. *EventHandle = eventHandle;
  4287. return eventObject;
  4288. }
  4289. PFILE_OBJECT
  4290. IoCreateStreamFileObject(
  4291. IN PFILE_OBJECT FileObject OPTIONAL,
  4292. IN PDEVICE_OBJECT DeviceObject OPTIONAL
  4293. )
  4294. {
  4295. return (IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL));
  4296. }
  4297. PFILE_OBJECT
  4298. IoCreateStreamFileObjectEx(
  4299. IN PFILE_OBJECT FileObject OPTIONAL,
  4300. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  4301. OUT PHANDLE FileHandle OPTIONAL
  4302. )
  4303. /*++
  4304. Routine Description:
  4305. This routine is invoked to create a new file object that represents an
  4306. alternate data stream for an existing file object. The input file object
  4307. represents the file object that already exists for a file, and the newly
  4308. created stream file object is used to access other parts of the file
  4309. other than the data. Some uses of stream file objects are the EAs or
  4310. the SECURITY_DESCRIPTORs on the file. The stream file object allows
  4311. the file system to cache these parts of the file just as if they were
  4312. an entire to themselves.
  4313. It is also possible to use stream file objects to represent virtual
  4314. volume files. This allows various parts of the on-disk structure to
  4315. be viewed as a virtual file and therefore be cached using the same logic
  4316. in the file system. For this case, the device object pointer is used
  4317. to create the file object.
  4318. Arguments:
  4319. FileObject - Pointer to the file object to which the new stream file
  4320. is related. This pointer is optional.
  4321. DeviceObject - Pointer to the device object on which the stream file
  4322. is to be opened. This pointer is not optional if the FileObject
  4323. pointer is not specified.
  4324. FileHandle - Out parameter for handle if necessary.
  4325. Return Value:
  4326. The function value is a pointer to the newly created stream file object.
  4327. --*/
  4328. {
  4329. PFILE_OBJECT newFileObject;
  4330. OBJECT_ATTRIBUTES objectAttributes;
  4331. HANDLE handle;
  4332. NTSTATUS status;
  4333. PAGED_CODE();
  4334. //
  4335. // Begin by getting the device object from either the file object or
  4336. // the device object parameter.
  4337. //
  4338. if (ARGUMENT_PRESENT( FileObject )) {
  4339. DeviceObject = FileObject->DeviceObject;
  4340. }
  4341. //
  4342. // Increment the reference count for the target device object. Note
  4343. // that no check is made to determine whether or not the device driver
  4344. // is attempting to unload since this is an implicit open of a pseudo-
  4345. // file that is being made, not a real file open request. In essence,
  4346. // no new file is really being opened.
  4347. //
  4348. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  4349. &DeviceObject->ReferenceCount );
  4350. //
  4351. // Initialize the object attributes that will be used to create the file
  4352. // object.
  4353. //
  4354. InitializeObjectAttributes( &objectAttributes,
  4355. (PUNICODE_STRING) NULL,
  4356. OBJ_KERNEL_HANDLE,
  4357. (HANDLE) NULL,
  4358. (PSECURITY_DESCRIPTOR) NULL );
  4359. //
  4360. // Create the new file object.
  4361. //
  4362. status = ObCreateObject( KernelMode,
  4363. IoFileObjectType,
  4364. &objectAttributes,
  4365. KernelMode,
  4366. (PVOID) NULL,
  4367. (ULONG) sizeof( FILE_OBJECT ),
  4368. (ULONG) sizeof( FILE_OBJECT ),
  4369. 0,
  4370. (PVOID *) &newFileObject );
  4371. if (!NT_SUCCESS( status )) {
  4372. IopDecrementDeviceObjectRef( DeviceObject, FALSE, FALSE );
  4373. ExRaiseStatus( status );
  4374. }
  4375. //
  4376. // Initialize the common fields of the file object.
  4377. //
  4378. RtlZeroMemory( newFileObject, sizeof( FILE_OBJECT ) );
  4379. newFileObject->Type = IO_TYPE_FILE;
  4380. newFileObject->Size = sizeof( FILE_OBJECT );
  4381. newFileObject->DeviceObject = DeviceObject;
  4382. newFileObject->Flags = FO_STREAM_FILE;
  4383. KeInitializeEvent( &newFileObject->Event, SynchronizationEvent, FALSE );
  4384. //
  4385. // Insert the device object into the table. Note that this is done w/a
  4386. // pointer bias so that the object cannot go away if some random user
  4387. // application closes the handle before this code is finished w/it.
  4388. //
  4389. status = ObInsertObject( newFileObject,
  4390. NULL,
  4391. FILE_READ_DATA,
  4392. 1,
  4393. (PVOID *) &newFileObject,
  4394. &handle );
  4395. if (!NT_SUCCESS( status )) {
  4396. ExRaiseStatus( status );
  4397. }
  4398. //
  4399. // The insert completed successfully. Update the bookkeeping so that the
  4400. // fact that there is a handle is reflected.
  4401. //
  4402. newFileObject->Flags |= FO_HANDLE_CREATED;
  4403. ASSERT( newFileObject->Type == IO_TYPE_FILE );
  4404. //
  4405. // Synchronize here with the file system to make sure that
  4406. // volumes don't go away while en route to the FS.
  4407. //
  4408. if (DeviceObject->Vpb) {
  4409. IopInterlockedIncrementUlong( LockQueueIoVpbLock,
  4410. &DeviceObject->Vpb->ReferenceCount );
  4411. }
  4412. //
  4413. // Finally, close the handle to the file. and clear the forward cluster
  4414. //
  4415. if (FileHandle == NULL) {
  4416. ObCloseHandle( handle , KernelMode);
  4417. } else {
  4418. *FileHandle = handle;
  4419. //
  4420. // Get rid of the reference in ObInsertObject.
  4421. //
  4422. ObDereferenceObject(newFileObject);
  4423. }
  4424. ASSERT( NT_SUCCESS( status ) );
  4425. return newFileObject;
  4426. }
  4427. PFILE_OBJECT
  4428. IoCreateStreamFileObjectLite(
  4429. IN PFILE_OBJECT FileObject OPTIONAL,
  4430. IN PDEVICE_OBJECT DeviceObject OPTIONAL
  4431. )
  4432. /*++
  4433. Routine Description:
  4434. This routine is invoked to create a new file object that represents an
  4435. alternate data stream for an existing file object. The input file object
  4436. represents the file object that already exists for a file, and the newly
  4437. created stream file object is used to access other parts of the file
  4438. other than the data. Some uses of stream file objects are the EAs or
  4439. the SECURITY_DESCRIPTORs on the file. The stream file object allows
  4440. the file system to cache these parts of the file just as if they were
  4441. an entire to themselves.
  4442. It is also possible to use stream file objects to represent virtual
  4443. volume files. This allows various parts of the on-disk structure to
  4444. be viewed as a virtual file and therefore be cached using the same logic
  4445. in the file system. For this case, the device object pointer is used
  4446. to create the file object.
  4447. This call differs from IoCreateStreamFileObject in that it performs no
  4448. handle management and does not result in a call to the file system
  4449. cleanup entry.
  4450. Arguments:
  4451. FileObject - Pointer to the file object to which the new stream file
  4452. is related. This pointer is optional.
  4453. DeviceObject - Pointer to the device object on which the stream file
  4454. is to be opened. This pointer is not optional if the FileObject
  4455. pointer is not specified.
  4456. Return Value:
  4457. The function value is a pointer to the newly created stream file object.
  4458. --*/
  4459. {
  4460. PFILE_OBJECT newFileObject;
  4461. OBJECT_ATTRIBUTES objectAttributes;
  4462. NTSTATUS status;
  4463. PAGED_CODE();
  4464. //
  4465. // Begin by getting the device object from either the file object or
  4466. // the device object parameter.
  4467. //
  4468. if (ARGUMENT_PRESENT( FileObject )) {
  4469. DeviceObject = FileObject->DeviceObject;
  4470. }
  4471. //
  4472. // if the driver has been marked for an unload or deleted operation, and
  4473. // the reference count goes to zero, then the driver may need to be
  4474. // unloaded or deleted at this point.
  4475. // file that is being made, not a real file open request. In essence,
  4476. // no new file is really being opened.
  4477. //
  4478. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  4479. &DeviceObject->ReferenceCount );
  4480. //
  4481. // Initialize the object attributes that will be used to create the file
  4482. // object.
  4483. //
  4484. InitializeObjectAttributes( &objectAttributes,
  4485. (PUNICODE_STRING) NULL,
  4486. 0,
  4487. (HANDLE) NULL,
  4488. (PSECURITY_DESCRIPTOR) NULL );
  4489. //
  4490. // Create the new file object.
  4491. //
  4492. status = ObCreateObject( KernelMode,
  4493. IoFileObjectType,
  4494. &objectAttributes,
  4495. KernelMode,
  4496. (PVOID) NULL,
  4497. (ULONG) sizeof( FILE_OBJECT ),
  4498. (ULONG) sizeof( FILE_OBJECT ),
  4499. 0,
  4500. (PVOID *) &newFileObject );
  4501. if (!NT_SUCCESS( status )) {
  4502. IopDecrementDeviceObjectRef( DeviceObject, FALSE, FALSE );
  4503. ExRaiseStatus( status );
  4504. }
  4505. //
  4506. // Initialize the common fields of the file object.
  4507. //
  4508. RtlZeroMemory( newFileObject, sizeof( FILE_OBJECT ) );
  4509. newFileObject->Type = IO_TYPE_FILE;
  4510. newFileObject->Size = sizeof( FILE_OBJECT );
  4511. newFileObject->DeviceObject = DeviceObject;
  4512. newFileObject->Flags = FO_STREAM_FILE;
  4513. KeInitializeEvent( &newFileObject->Event, SynchronizationEvent, FALSE );
  4514. //
  4515. // Clean up from the creation.
  4516. //
  4517. ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(newFileObject)->ObjectCreateInfo);
  4518. OBJECT_TO_OBJECT_HEADER(newFileObject)->ObjectCreateInfo = NULL;
  4519. newFileObject->Flags |= FO_HANDLE_CREATED;
  4520. ASSERT( newFileObject->Type == IO_TYPE_FILE );
  4521. //
  4522. // Synchronize here with the file system to make sure that
  4523. // volumes don't go away while en route to the FS.
  4524. //
  4525. if (DeviceObject->Vpb) {
  4526. IopInterlockedIncrementUlong( LockQueueIoVpbLock,
  4527. &DeviceObject->Vpb->ReferenceCount );
  4528. }
  4529. return newFileObject;
  4530. }
  4531. NTSTATUS
  4532. IoCreateSymbolicLink(
  4533. IN PUNICODE_STRING SymbolicLinkName,
  4534. IN PUNICODE_STRING DeviceName
  4535. )
  4536. /*++
  4537. Routine Description:
  4538. This routine is invoked to assign a symbolic link name to a device.
  4539. Arguments:
  4540. SymbolicLinkName - Supplies the symbolic link name as a Unicode string.
  4541. DeviceName - Supplies the name to which the symbolic link name refers.
  4542. Return Value:
  4543. The function value is the final status of the operation.
  4544. --*/
  4545. {
  4546. OBJECT_ATTRIBUTES objectAttributes;
  4547. HANDLE linkHandle;
  4548. NTSTATUS status;
  4549. PAGED_CODE();
  4550. //
  4551. // Begin by initializing the object attributes for the symbolic link.
  4552. //
  4553. InitializeObjectAttributes( &objectAttributes,
  4554. SymbolicLinkName,
  4555. OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
  4556. (HANDLE) NULL,
  4557. SePublicDefaultUnrestrictedSd );
  4558. //
  4559. // Note that the following assignment can fail (because it is not system
  4560. // initialization time and therefore the \ARCname directory does not
  4561. // exist - if this is really a call to IoAssignArcName), but that is fine.
  4562. //
  4563. status = ZwCreateSymbolicLinkObject( &linkHandle,
  4564. SYMBOLIC_LINK_ALL_ACCESS,
  4565. &objectAttributes,
  4566. DeviceName );
  4567. if (NT_SUCCESS( status )) {
  4568. ZwClose( linkHandle );
  4569. }
  4570. return status;
  4571. }
  4572. PKEVENT
  4573. IoCreateSynchronizationEvent(
  4574. IN PUNICODE_STRING EventName,
  4575. OUT PHANDLE EventHandle
  4576. )
  4577. /*++
  4578. Routine Description:
  4579. This routine creates a named synchronization event for use in serialization
  4580. of access to hardware between two otherwise non-related drivers. The event
  4581. is created if it does not already exist, otherwise it is simply opened.
  4582. Arguments:
  4583. EventName - Supplies the full name of the event.
  4584. EventHandle - Supplies a location to return a handle to the event.
  4585. Return Value:
  4586. The function value is a pointer to the created/opened event, or NULL if
  4587. the event could not be created/opened.
  4588. --*/
  4589. {
  4590. OBJECT_ATTRIBUTES objectAttributes;
  4591. NTSTATUS status;
  4592. HANDLE eventHandle;
  4593. PKEVENT eventObject;
  4594. PAGED_CODE();
  4595. //
  4596. // Begin by initializing the object attributes.
  4597. //
  4598. InitializeObjectAttributes( &objectAttributes,
  4599. EventName,
  4600. OBJ_OPENIF,
  4601. (HANDLE) NULL,
  4602. (PSECURITY_DESCRIPTOR) NULL );
  4603. //
  4604. // Now create or open the event.
  4605. //
  4606. status = ZwCreateEvent( &eventHandle,
  4607. EVENT_ALL_ACCESS,
  4608. &objectAttributes,
  4609. SynchronizationEvent,
  4610. TRUE );
  4611. if (!NT_SUCCESS( status )) {
  4612. return (PKEVENT) NULL;
  4613. }
  4614. //
  4615. // Reference the object by its handle to get a pointer that can be returned
  4616. // to the caller.
  4617. //
  4618. (VOID) ObReferenceObjectByHandle( eventHandle,
  4619. 0,
  4620. ExEventObjectType,
  4621. KernelMode,
  4622. (PVOID *) &eventObject,
  4623. NULL );
  4624. ObDereferenceObject( eventObject );
  4625. //
  4626. // Return the handle and the pointer to the event.
  4627. //
  4628. *EventHandle = eventHandle;
  4629. return eventObject;
  4630. }
  4631. NTSTATUS
  4632. IoCreateUnprotectedSymbolicLink(
  4633. IN PUNICODE_STRING SymbolicLinkName,
  4634. IN PUNICODE_STRING DeviceName
  4635. )
  4636. /*++
  4637. Routine Description:
  4638. This routine is invoked to assign an unprotected symbolic link name to
  4639. a device. That is, a symbolic link that can be dynamically reassigned
  4640. without any special authorization.
  4641. NOTE: This routine will NOT over-ride inheritable protection that
  4642. the symbolic link might pick up. It simply prevents the caller's
  4643. default token protection from being assigned.
  4644. Arguments:
  4645. SymbolicLinkName - Supplies the symbolic link name as a Unicode string.
  4646. DeviceName - Supplies the name to which the symbolic link name refers.
  4647. Return Value:
  4648. The function value is the final status of the operation.
  4649. --*/
  4650. {
  4651. OBJECT_ATTRIBUTES objectAttributes;
  4652. HANDLE linkHandle;
  4653. NTSTATUS status;
  4654. SECURITY_DESCRIPTOR securityDescriptor;
  4655. PAGED_CODE();
  4656. //
  4657. // Create a security descriptor that has all access.
  4658. //
  4659. status = RtlCreateSecurityDescriptor( &securityDescriptor,
  4660. SECURITY_DESCRIPTOR_REVISION1 );
  4661. if (!NT_SUCCESS( status )) {
  4662. return status;
  4663. }
  4664. status = RtlSetDaclSecurityDescriptor ( &securityDescriptor,
  4665. TRUE,
  4666. NULL,
  4667. TRUE ); //does not over-ride inheritable protection
  4668. if (!NT_SUCCESS( status )) {
  4669. return status;
  4670. }
  4671. //
  4672. // Initialize the object attributes for the symbolic link.
  4673. //
  4674. InitializeObjectAttributes( &objectAttributes,
  4675. SymbolicLinkName,
  4676. OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
  4677. (HANDLE) NULL,
  4678. &securityDescriptor );
  4679. //
  4680. // Note that the following assignment can fail (because it is not system
  4681. // initialization time and therefore the \ARCname directory does not
  4682. // exist - if this is really a call to IoAssignArcName), but that is fine.
  4683. //
  4684. status = ZwCreateSymbolicLinkObject( &linkHandle,
  4685. SYMBOLIC_LINK_ALL_ACCESS,
  4686. &objectAttributes,
  4687. DeviceName );
  4688. if (NT_SUCCESS( status )) {
  4689. ZwClose( linkHandle );
  4690. }
  4691. return status;
  4692. }
  4693. VOID
  4694. IoDeleteController(
  4695. IN PCONTROLLER_OBJECT ControllerObject
  4696. )
  4697. /*++
  4698. Routine Description:
  4699. This routine deletes the specified controller object from the system
  4700. so that it may no longer be referenced from a driver. It is invoked
  4701. when either the driver is being unloaded from the system, or the driver's
  4702. initialization routine failed to properly initialize the device or a
  4703. fatal driver initialization error was encountered.
  4704. Arguments:
  4705. ControllerObject - Pointer to the controller object that is to be
  4706. deleted.
  4707. Return Value:
  4708. None.
  4709. --*/
  4710. {
  4711. PAGED_CODE();
  4712. //
  4713. // The controller was created as a temporary object, and all of the
  4714. // handles for the object have already been closed. At this point,
  4715. // simply dereferencing the object will cause it to be deleted.
  4716. //
  4717. ObDereferenceObject( ControllerObject );
  4718. }
  4719. VOID
  4720. IopRemoveTimerFromTimerList(
  4721. IN PIO_TIMER timer
  4722. )
  4723. {
  4724. KIRQL irql;
  4725. ExAcquireFastLock( &IopTimerLock, &irql );
  4726. RemoveEntryList( &timer->TimerList );
  4727. if (timer->TimerFlag) {
  4728. IopTimerCount--;
  4729. }
  4730. ExReleaseFastLock( &IopTimerLock, irql );
  4731. }
  4732. VOID
  4733. IoDeleteDevice(
  4734. IN PDEVICE_OBJECT DeviceObject
  4735. )
  4736. /*++
  4737. Routine Description:
  4738. This routine deletes the specified device object from the system so that
  4739. it may no longer be referenced. It is invoked when either the device
  4740. driver is being unloaded from the system, or the driver's initialization
  4741. routine failed to properly initialize the device or a fatal driver
  4742. initialization error was encountered, or when the device is being removed
  4743. from the system.
  4744. Arguments:
  4745. DeviceObject - Pointer to the device object that is to be deleted.
  4746. Return Value:
  4747. None.
  4748. --*/
  4749. {
  4750. KIRQL irql;
  4751. IOV_DELETE_DEVICE(DeviceObject);
  4752. //
  4753. // Check to see whether or not the device has registered a shutdown
  4754. // handler if necessary, and if so, unregister it.
  4755. //
  4756. if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) {
  4757. IoUnregisterShutdownNotification( DeviceObject );
  4758. }
  4759. //
  4760. // Release the pool that was allocated to contain the timer dispatch
  4761. // routine and its associated context if there was one.
  4762. //
  4763. if (DeviceObject->Timer) {
  4764. PIO_TIMER timer;
  4765. timer = DeviceObject->Timer;
  4766. IopRemoveTimerFromTimerList(timer);
  4767. ExFreePool( timer );
  4768. }
  4769. //
  4770. // If this device has a name, then mark the
  4771. // object as temporary so that when it is dereferenced it will be
  4772. // deleted.
  4773. //
  4774. if (DeviceObject->Flags & DO_DEVICE_HAS_NAME) {
  4775. ObMakeTemporaryObject( DeviceObject );
  4776. }
  4777. //
  4778. // PoRunDownDeviceObject will clean up any power management
  4779. // structures attached to the device object.
  4780. //
  4781. PoRunDownDeviceObject(DeviceObject);
  4782. //
  4783. // Mark the device object as deleted.
  4784. //
  4785. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  4786. DeviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_DELETE_PENDING;
  4787. if (!DeviceObject->ReferenceCount) {
  4788. IopCompleteUnloadOrDelete( DeviceObject, FALSE, irql );
  4789. } else {
  4790. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  4791. }
  4792. }
  4793. NTSTATUS
  4794. IopDeleteSessionSymLinks(
  4795. IN PUNICODE_STRING LinkName
  4796. )
  4797. /*++
  4798. Routine Description:
  4799. This routine is called from IoDeleteSymbolic Link. It enumerates all the
  4800. Terminal Server session specific object directories and deletes the specified
  4801. symbolic link from the DosDevices object directory of each sesssion. This
  4802. routine is only called when Terminal Services is enabled.
  4803. Arguments:
  4804. SymbolicLinkName - Provides the Unicode name string to be deassigned.
  4805. Return Values:
  4806. None.
  4807. --*/
  4808. {
  4809. NTSTATUS Status = STATUS_SUCCESS;
  4810. UNICODE_STRING UnicodeString;
  4811. UNICODE_STRING SymbolicLinkName;
  4812. OBJECT_ATTRIBUTES Attributes;
  4813. HANDLE DirectoryHandle;
  4814. HANDLE linkHandle;
  4815. POBJECT_DIRECTORY_INFORMATION DirInfo;
  4816. BOOLEAN RestartScan;
  4817. ULONG Context = 0;
  4818. ULONG ReturnedLength;
  4819. PWCHAR NameBuf;
  4820. PUCHAR DirInfoBuffer;
  4821. ULONG Size;
  4822. WCHAR Prefix[13]; // sizeof L"\\DosDevices\\"
  4823. //
  4824. // Only delete links that start with \DosDevices\
  4825. //
  4826. if (LinkName->Length < (sizeof(L"\\DosDevices\\"))) {
  4827. return STATUS_SUCCESS;
  4828. }
  4829. RtlInitUnicodeString( &UnicodeString, L"\\DosDevices\\" );
  4830. wcsncpy(Prefix,LinkName->Buffer,(sizeof(L"\\DosDevices\\")/sizeof(WCHAR)) - 1);
  4831. RtlInitUnicodeString( &SymbolicLinkName, Prefix);
  4832. if (RtlCompareUnicodeString(&UnicodeString, &SymbolicLinkName,TRUE)) {
  4833. return STATUS_SUCCESS;
  4834. }
  4835. //
  4836. // Open the root Sessions Directory.
  4837. //
  4838. RtlInitUnicodeString( &UnicodeString, L"\\Sessions" );
  4839. InitializeObjectAttributes( &Attributes,
  4840. &UnicodeString,
  4841. OBJ_CASE_INSENSITIVE,
  4842. NULL,
  4843. NULL
  4844. );
  4845. Status = ZwOpenDirectoryObject( &DirectoryHandle,
  4846. DIRECTORY_QUERY,
  4847. &Attributes
  4848. );
  4849. if (NT_SUCCESS( Status )) {
  4850. //
  4851. // Since SessionId is a ULONG , the prefix (\\Sessions\\<SessionId>\\DosDevices)
  4852. // cannot be more that 128 characters in length
  4853. //
  4854. Size = (LinkName->Length + 128) * sizeof(WCHAR);
  4855. NameBuf = (PWCHAR)ExAllocatePoolWithTag(PagedPool, Size, ' oI');
  4856. if (NameBuf == NULL) {
  4857. return STATUS_INSUFFICIENT_RESOURCES;
  4858. }
  4859. SymbolicLinkName.Buffer = (PWSTR)NameBuf;
  4860. SymbolicLinkName.Length = (USHORT)Size;
  4861. SymbolicLinkName.MaximumLength = (USHORT)Size;
  4862. //
  4863. // 4k should be more than enough to query a directory object entry
  4864. //
  4865. Size = 4096;
  4866. DirInfoBuffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool, Size, ' oI');
  4867. if (DirInfoBuffer == NULL) {
  4868. ExFreePool(NameBuf);
  4869. return STATUS_INSUFFICIENT_RESOURCES;
  4870. }
  4871. RestartScan = TRUE;
  4872. DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer;
  4873. while (TRUE) {
  4874. Status = ZwQueryDirectoryObject( DirectoryHandle,
  4875. (PVOID)DirInfo,
  4876. Size,
  4877. TRUE,
  4878. RestartScan,
  4879. &Context,
  4880. &ReturnedLength
  4881. );
  4882. RestartScan = FALSE;
  4883. //
  4884. // Check the status of the operation.
  4885. //
  4886. if (!NT_SUCCESS( Status )) {
  4887. if (Status == STATUS_NO_MORE_ENTRIES) {
  4888. Status = STATUS_SUCCESS;
  4889. }
  4890. break;
  4891. }
  4892. //
  4893. // This generates session specific symbolic link path
  4894. // \Sessions\<id>\DosDevices\<LinkName>
  4895. //
  4896. RtlInitUnicodeString( &UnicodeString, L"\\Sessions\\" );
  4897. RtlCopyUnicodeString( &SymbolicLinkName, &UnicodeString );
  4898. RtlAppendUnicodeStringToString( &SymbolicLinkName, &(DirInfo->Name) );
  4899. RtlAppendUnicodeStringToString( &SymbolicLinkName, LinkName );
  4900. //
  4901. // Begin by initializing the object attributes for the symbolic link.
  4902. //
  4903. InitializeObjectAttributes( &Attributes,
  4904. &SymbolicLinkName,
  4905. OBJ_CASE_INSENSITIVE,
  4906. NULL,
  4907. NULL );
  4908. //
  4909. // Open the symbolic link itself so that it can be marked temporary and
  4910. // closed.
  4911. //
  4912. Status = ZwOpenSymbolicLinkObject( &linkHandle,
  4913. DELETE,
  4914. &Attributes );
  4915. if (NT_SUCCESS( Status )) {
  4916. //
  4917. // The symbolic link was successfully opened. Attempt to make it a
  4918. // temporary object, and then close the handle. This will cause the
  4919. // object to go away.
  4920. //
  4921. Status = ZwMakeTemporaryObject( linkHandle );
  4922. if (NT_SUCCESS( Status )) {
  4923. ZwClose( linkHandle );
  4924. }
  4925. }
  4926. }
  4927. ZwClose(DirectoryHandle);
  4928. ExFreePool(NameBuf);
  4929. ExFreePool(DirInfoBuffer);
  4930. }
  4931. return Status;
  4932. }
  4933. NTSTATUS
  4934. IoDeleteSymbolicLink(
  4935. IN PUNICODE_STRING SymbolicLinkName
  4936. )
  4937. /*++
  4938. Routine Description:
  4939. This routine is invoked to remove a symbolic link from the system. This
  4940. generally occurs whenever a driver that has assigned a symbolic link needs
  4941. to exit. It can also be used when a driver no longer needs to redirect
  4942. a name.
  4943. Arguments:
  4944. SymbolicLinkName - Provides the Unicode name string to be deassigned.
  4945. Return Values:
  4946. None.
  4947. --*/
  4948. {
  4949. OBJECT_ATTRIBUTES objectAttributes;
  4950. HANDLE linkHandle;
  4951. NTSTATUS status;
  4952. PAGED_CODE();
  4953. //
  4954. // Begin by initializing the object attributes for the symbolic link.
  4955. //
  4956. InitializeObjectAttributes( &objectAttributes,
  4957. SymbolicLinkName,
  4958. OBJ_CASE_INSENSITIVE,
  4959. (HANDLE) NULL,
  4960. (PSECURITY_DESCRIPTOR) NULL );
  4961. //
  4962. // Open the symbolic link itself so that it can be marked temporary and
  4963. // closed.
  4964. //
  4965. status = ZwOpenSymbolicLinkObject( &linkHandle,
  4966. DELETE,
  4967. &objectAttributes );
  4968. if (NT_SUCCESS( status )) {
  4969. //
  4970. // The symbolic link was successfully opened. Attempt to make it a
  4971. // temporary object, and then close the handle. This will cause the
  4972. // object to go away.
  4973. //
  4974. status = ZwMakeTemporaryObject( linkHandle );
  4975. if (NT_SUCCESS( status )) {
  4976. ZwClose( linkHandle );
  4977. }
  4978. //
  4979. // When LUID DosDevices are disabled and Terminal Services are
  4980. // enabled, then remove the possible multiple copies of the symbolic
  4981. // link from the DosDevices in the TS sessions
  4982. // When LUID DosDevices are enabled or TS is not enabled, then
  4983. // the symbolic link is not copied and no cleanup is needed.
  4984. //
  4985. if ((ObIsLUIDDeviceMapsEnabled() == 0) &&
  4986. (ExVerifySuite(TerminalServer) == TRUE)) {
  4987. IopDeleteSessionSymLinks( SymbolicLinkName );
  4988. }
  4989. }
  4990. return status;
  4991. }
  4992. VOID
  4993. IoDetachDevice(
  4994. IN OUT PDEVICE_OBJECT TargetDevice
  4995. )
  4996. /*++
  4997. Routine Description:
  4998. This routine detaches the device object which is currently attached to the
  4999. target device.
  5000. Arguments:
  5001. TargetDevice - Pointer to device object to be detached from.
  5002. Return Value:
  5003. None.
  5004. --*/
  5005. {
  5006. KIRQL irql;
  5007. PDEVICE_OBJECT detachingDevice;
  5008. PDEVOBJ_EXTENSION detachingExtension;
  5009. //
  5010. // Detach the device object attached to the target device. This also
  5011. // includes decrementing the reference count for the device. Note that
  5012. // if the driver has been marked for an unload operation, and the
  5013. // reference count goes to zero, then the driver may need to be unloaded
  5014. // at this point.
  5015. //
  5016. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  5017. //
  5018. // Tell the Special IRP code the stack has changed. Code that will reexamine
  5019. // the stack takes the database lock, so we can place the call here. This
  5020. // also allows us to assert correct behavoir *before* the stack is torn
  5021. // down.
  5022. //
  5023. IOV_DETACH_DEVICE(TargetDevice);
  5024. detachingDevice = TargetDevice->AttachedDevice;
  5025. detachingExtension = detachingDevice->DeviceObjectExtension;
  5026. ASSERT( detachingExtension->AttachedTo == TargetDevice );
  5027. //
  5028. // Unlink the device from the doubly-linked attachment chain.
  5029. //
  5030. detachingExtension->AttachedTo = NULL;
  5031. TargetDevice->AttachedDevice = NULL;
  5032. if (TargetDevice->DeviceObjectExtension->ExtensionFlags &
  5033. (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING) &&
  5034. !TargetDevice->ReferenceCount) {
  5035. IopCompleteUnloadOrDelete( TargetDevice, FALSE, irql );
  5036. } else {
  5037. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  5038. }
  5039. }
  5040. VOID
  5041. IoDisconnectInterrupt(
  5042. IN PKINTERRUPT InterruptObject
  5043. )
  5044. /*++
  5045. Routine Description:
  5046. This routine disconnects all of the interrupt objects that were
  5047. initialized and connected by the IoConnectInterrupt routine. Note
  5048. that no interrupt objects directly connected using the kernel
  5049. services may be input to this routine.
  5050. Arguments:
  5051. InterruptObject - Supplies a pointer to the interrupt object allocated
  5052. by the IoConnectInterrupt routine.
  5053. Return Value:
  5054. None.
  5055. --*/
  5056. {
  5057. PIO_INTERRUPT_STRUCTURE interruptStructure;
  5058. ULONG i;
  5059. PAGED_CODE();
  5060. //
  5061. // Obtain a pointer to the builtin interrupt object in the I/O interrupt
  5062. // structure.
  5063. //
  5064. interruptStructure = CONTAINING_RECORD( InterruptObject,
  5065. IO_INTERRUPT_STRUCTURE,
  5066. InterruptObject );
  5067. //
  5068. // The builtin interrupt object is always used, so simply disconnect
  5069. // it.
  5070. //
  5071. KeDisconnectInterrupt( &interruptStructure->InterruptObject );
  5072. //
  5073. // Now loop through each of the interrupt objects pointed to by the
  5074. // structure and disconnect each.
  5075. //
  5076. for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
  5077. if (interruptStructure->InterruptArray[i] != NULL) {
  5078. KeDisconnectInterrupt( interruptStructure->InterruptArray[i] );
  5079. }
  5080. }
  5081. //
  5082. // Finally, deallocate the memory associated with the entire structure.
  5083. //
  5084. ExFreePool( interruptStructure );
  5085. }
  5086. VOID
  5087. IoEnqueueIrp(
  5088. IN PIRP Irp
  5089. )
  5090. /*++
  5091. Routine Description:
  5092. This routine enqueues the specified I/O Request Packet (IRP) to the thread's
  5093. IRP pending queue. The thread that the IRP is queued to is specified by
  5094. the IRP's Thread field.
  5095. Arguments:
  5096. Irp - Supplies a pointer to the IRP to be enqueued.
  5097. Return Value:
  5098. None.
  5099. --*/
  5100. {
  5101. PAGED_CODE();
  5102. //
  5103. // Simply enqueue the IRP to the thread's IRP queue.
  5104. //
  5105. IopQueueThreadIrp( Irp );
  5106. return;
  5107. }
  5108. BOOLEAN
  5109. IoFastQueryNetworkAttributes(
  5110. IN POBJECT_ATTRIBUTES ObjectAttributes,
  5111. IN ACCESS_MASK DesiredAccess,
  5112. IN ULONG OpenOptions,
  5113. OUT PIO_STATUS_BLOCK IoStatus,
  5114. OUT PFILE_NETWORK_OPEN_INFORMATION Buffer
  5115. )
  5116. /*++
  5117. Routine Description:
  5118. This routine attempts to perform a fast I/O call to obtain the network
  5119. attributes for a file. This involves a specialized interface between
  5120. this function and the I/O system's device parse method. This allows the
  5121. parse method to have the file system pseudo-open the file, obtain the
  5122. appropriate attributes for the file, and return them to the caller w/as
  5123. little overhead as possbile from either the Object Manager or the I/O
  5124. system itself.
  5125. Arguments:
  5126. ObjectAttributes - Supplies the attributes to be used for opening the
  5127. file (e.g., the file's name, etc).
  5128. DesiredAccess - Supplies the type(s) of access that the caller would like
  5129. to the file.
  5130. OpenOptions - Supplies standard NtOpenFile open options.
  5131. IoStatus - Supplies a pointer to a variable to receive the final status
  5132. of the operation.
  5133. Buffer - Supplies an output buffer to receive the network attributes for
  5134. the specified file.
  5135. Return Value:
  5136. The final function value indicates whether or not the fast path could
  5137. be taken successfully.
  5138. --*/
  5139. {
  5140. HANDLE handle;
  5141. NTSTATUS status;
  5142. OPEN_PACKET openPacket;
  5143. DUMMY_FILE_OBJECT localFileObject;
  5144. //
  5145. // Build a parse open packet that tells the parse method to open the
  5146. // file and query its network attributes using the fast path, if it
  5147. // exists for this file.
  5148. //
  5149. RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) );
  5150. openPacket.Type = IO_TYPE_OPEN_PACKET;
  5151. openPacket.Size = sizeof( OPEN_PACKET );
  5152. openPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  5153. openPacket.Disposition = FILE_OPEN;
  5154. openPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
  5155. openPacket.Options = IO_FORCE_ACCESS_CHECK;
  5156. openPacket.NetworkInformation = Buffer;
  5157. openPacket.QueryOnly = TRUE;
  5158. openPacket.FullAttributes = TRUE;
  5159. openPacket.LocalFileObject = &localFileObject;
  5160. //
  5161. // Open the object by its name. Because of the special QueryOnly flag set
  5162. // in the open packet, the parse routine will open the file using the fast
  5163. // path open and perform the query, effectively closing it as well.
  5164. //
  5165. status = ObOpenObjectByName( ObjectAttributes,
  5166. (POBJECT_TYPE) NULL,
  5167. KernelMode,
  5168. NULL,
  5169. DesiredAccess,
  5170. &openPacket,
  5171. &handle );
  5172. //
  5173. // The opeation is successful if the parse check field of the open packet
  5174. // indicates that the parse routine was actually invoked, and the final
  5175. // status field of the packet is set to success. The QueryOnly field is
  5176. // set to whether or not the fast path was invoked.
  5177. //
  5178. if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) {
  5179. //
  5180. // The parse routine was not invoked properly so the operation did
  5181. // not work at all.
  5182. //
  5183. IoStatus->Status = status;
  5184. } else {
  5185. //
  5186. // The fast path routine was successfully invoked so return the
  5187. // final status of the operation.
  5188. //
  5189. IoStatus->Status = openPacket.FinalStatus;
  5190. IoStatus->Information = openPacket.Information;
  5191. }
  5192. return TRUE;
  5193. }
  5194. VOID
  5195. IoFreeController(
  5196. IN PCONTROLLER_OBJECT ControllerObject
  5197. )
  5198. /*++
  5199. Routine Description:
  5200. This routine is invoked to deallocate the specified controller object.
  5201. No checks are made to ensure that the controller is really allocated
  5202. to a device object. However, if it is not, then kernel will bugcheck.
  5203. If another device is waiting in the queue to allocate the controller
  5204. object it will be pulled from the queue and its execution routine will
  5205. be invoked.
  5206. Arguments:
  5207. ControllerObject - Pointer to the controller object to be deallocated.
  5208. Return Value:
  5209. None.
  5210. --*/
  5211. {
  5212. PKDEVICE_QUEUE_ENTRY packet;
  5213. PDEVICE_OBJECT deviceObject;
  5214. IO_ALLOCATION_ACTION action;
  5215. //
  5216. // Simply remove the next entry from the controller's device wait queue.
  5217. // If one was successfully removed, invoke its execution routine.
  5218. //
  5219. packet = KeRemoveDeviceQueue( &ControllerObject->DeviceWaitQueue );
  5220. if (packet != NULL) {
  5221. deviceObject = CONTAINING_RECORD( packet,
  5222. DEVICE_OBJECT,
  5223. Queue.Wcb.WaitQueueEntry );
  5224. action = deviceObject->Queue.Wcb.DeviceRoutine( deviceObject,
  5225. deviceObject->CurrentIrp,
  5226. 0,
  5227. deviceObject->Queue.Wcb.DeviceContext );
  5228. //
  5229. // If the execution routine wants the controller to be deallocate
  5230. // now, deallocate it.
  5231. //
  5232. if (action == DeallocateObject) {
  5233. IoFreeController( ControllerObject );
  5234. }
  5235. }
  5236. }
  5237. VOID
  5238. IoFreeIrp(
  5239. IN PIRP Irp
  5240. )
  5241. {
  5242. pIoFreeIrp(Irp);
  5243. }
  5244. VOID
  5245. IopFreeIrp(
  5246. IN PIRP Irp
  5247. )
  5248. /*++
  5249. Routine Description:
  5250. This routine deallocates the specified I/O Request Packet.
  5251. Arguments:
  5252. Irp - I/O Request Packet to deallocate.
  5253. Return Value:
  5254. None.
  5255. --*/
  5256. {
  5257. PGENERAL_LOOKASIDE lookasideList;
  5258. PP_NPAGED_LOOKASIDE_NUMBER number;
  5259. PKPRCB prcb;
  5260. //
  5261. // Ensure that the data structure being freed is really an IRP.
  5262. //
  5263. ASSERT( Irp->Type == IO_TYPE_IRP );
  5264. if (Irp->Type != IO_TYPE_IRP) {
  5265. KeBugCheckEx( MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR) Irp, __LINE__, 0, 0 );
  5266. }
  5267. ASSERT(IsListEmpty(&(Irp)->ThreadListEntry));
  5268. Irp->Type = 0;
  5269. //
  5270. // Ensure that all of the owners of the IRP have at least been notified
  5271. // that the request is going away.
  5272. //
  5273. ASSERT( Irp->CurrentLocation >= Irp->StackCount );
  5274. //
  5275. // Deallocate the IRP.
  5276. //
  5277. prcb = KeGetCurrentPrcb();
  5278. if (Irp->AllocationFlags & IRP_LOOKASIDE_ALLOCATION) {
  5279. Irp->AllocationFlags ^= IRP_LOOKASIDE_ALLOCATION;
  5280. InterlockedIncrement( &prcb->LookasideIrpFloat );
  5281. }
  5282. if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE) ||
  5283. (Irp->AllocationFlags & IRP_ALLOCATED_MUST_SUCCEED)) {
  5284. ExFreePool( Irp );
  5285. } else {
  5286. if (IopIrpAutoSizingEnabled() &&
  5287. (Irp->Size != IoSizeOfIrp(IopLargeIrpStackLocations)) &&
  5288. (Irp->Size != IoSizeOfIrp(1))) {
  5289. ExFreePool( Irp );
  5290. return;
  5291. }
  5292. //
  5293. // Store the size in a different field as this will get overwritten by single list entry.
  5294. //
  5295. Irp->IoStatus.Information = Irp->Size;
  5296. number = LookasideSmallIrpList;
  5297. if (Irp->StackCount != 1) {
  5298. number = LookasideLargeIrpList;
  5299. }
  5300. lookasideList = prcb->PPLookasideList[number].P;
  5301. lookasideList->TotalFrees += 1;
  5302. if (ExQueryDepthSList( &lookasideList->ListHead ) >= lookasideList->Depth) {
  5303. lookasideList->FreeMisses += 1;
  5304. lookasideList = prcb->PPLookasideList[number].L;
  5305. lookasideList->TotalFrees += 1;
  5306. if (ExQueryDepthSList( &lookasideList->ListHead ) >= lookasideList->Depth) {
  5307. lookasideList->FreeMisses += 1;
  5308. ExFreePool( Irp );
  5309. } else {
  5310. if (Irp->AllocationFlags & IRP_QUOTA_CHARGED) {
  5311. Irp->AllocationFlags ^= IRP_QUOTA_CHARGED;
  5312. ExReturnPoolQuota( Irp );
  5313. }
  5314. InterlockedPushEntrySList( &lookasideList->ListHead,
  5315. (PSINGLE_LIST_ENTRY) Irp );
  5316. }
  5317. } else {
  5318. if (Irp->AllocationFlags & IRP_QUOTA_CHARGED) {
  5319. Irp->AllocationFlags ^= IRP_QUOTA_CHARGED;
  5320. ExReturnPoolQuota( Irp );
  5321. }
  5322. InterlockedPushEntrySList( &lookasideList->ListHead,
  5323. (PSINGLE_LIST_ENTRY) Irp );
  5324. }
  5325. }
  5326. return;
  5327. }
  5328. VOID
  5329. IoFreeMdl(
  5330. IN PMDL Mdl
  5331. )
  5332. /*++
  5333. Routine Description:
  5334. This routine frees a Memory Descriptor List (MDL). It only frees the
  5335. specified MDL; any chained MDLs must be freed explicitly through another
  5336. call to this routine.
  5337. Arguments:
  5338. Mdl - Pointer to the Memory Descriptor List to be freed.
  5339. Return Value:
  5340. None.
  5341. --*/
  5342. {
  5343. //
  5344. // Tell memory management that this MDL will be re-used. This will
  5345. // cause MM to unmap any pages that have been mapped for this MDL if
  5346. // it is a partial MDL.
  5347. //
  5348. MmPrepareMdlForReuse(Mdl);
  5349. if (((Mdl->MdlFlags & MDL_ALLOCATED_FIXED_SIZE) == 0) ||
  5350. ((Mdl->MdlFlags & MDL_ALLOCATED_MUST_SUCCEED) != 0)) {
  5351. ExFreePool(Mdl);
  5352. } else {
  5353. ExFreeToPPLookasideList(LookasideMdlList, Mdl);
  5354. }
  5355. }
  5356. PDEVICE_OBJECT
  5357. IoGetAttachedDevice(
  5358. IN PDEVICE_OBJECT DeviceObject
  5359. )
  5360. /*++
  5361. Routine Description:
  5362. This routine returns the highest level device object associated with
  5363. the specified device.
  5364. N.B. Caller must own the IopDatabaseLock. External callers of this
  5365. function must ensure nobody is attaching or detaching from the stack.
  5366. If they cannot, they *must* use IoGetAttachedDeviceReference.
  5367. Arguments:
  5368. DeviceObject - Supplies a pointer to the device for which the attached
  5369. device is to be returned.
  5370. Return Value:
  5371. The function value is the highest level device attached to the specified
  5372. device. If no devices are attached, then the pointer to the device
  5373. object itself is returned.
  5374. --*/
  5375. {
  5376. //
  5377. // Loop through all of the device object's attached to the specified
  5378. // device. When the last device object is found that is not attached
  5379. // to, return it.
  5380. //
  5381. while (DeviceObject->AttachedDevice) {
  5382. DeviceObject = DeviceObject->AttachedDevice;
  5383. }
  5384. return DeviceObject;
  5385. }
  5386. PDEVICE_OBJECT
  5387. IoGetAttachedDeviceReference(
  5388. IN PDEVICE_OBJECT DeviceObject
  5389. )
  5390. /*++
  5391. Routine Description:
  5392. This routine synchronizes with the Io database and returns a refernce
  5393. to the highest level device object associated withthe specified device.
  5394. Arguments:
  5395. DeviceObject - Supplies a pointer to the device for which the attached
  5396. device is to be returned.
  5397. Return Value:
  5398. The function value is a reference to the highest level device attached
  5399. to the specified device. If no devices are attached, then the pointer
  5400. to the device object itself is returned.
  5401. --*/
  5402. {
  5403. KIRQL irql;
  5404. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  5405. DeviceObject = IoGetAttachedDevice (DeviceObject);
  5406. ObReferenceObject (DeviceObject);
  5407. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  5408. return DeviceObject;
  5409. }
  5410. PDEVICE_OBJECT
  5411. IoGetBaseFileSystemDeviceObject(
  5412. IN PFILE_OBJECT FileObject
  5413. )
  5414. /*++
  5415. Routine Description:
  5416. This routine returns the base (lowest-level) file system volume device
  5417. object associated with a file. I.e., it locates the file system w/o
  5418. walking the attached device object list.
  5419. Arguments:
  5420. FileObject - Supplies a pointer to the file object for which the base
  5421. file system device object is to be returned.
  5422. Return Value:
  5423. The function value is the lowest level volume device object associated
  5424. w/the file.
  5425. --*/
  5426. {
  5427. PDEVICE_OBJECT deviceObject;
  5428. //
  5429. // If the file object has a mounted Vpb, use its DeviceObject.
  5430. //
  5431. if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) {
  5432. deviceObject = FileObject->Vpb->DeviceObject;
  5433. //
  5434. // Otherwise, if the real device has a VPB that indicates that it is
  5435. // mounted, then use the file system device object associated with the
  5436. // VPB.
  5437. //
  5438. } else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
  5439. FileObject->DeviceObject->Vpb != NULL &&
  5440. FileObject->DeviceObject->Vpb->DeviceObject != NULL) {
  5441. deviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
  5442. //
  5443. // Otherwise, just return the real device object.
  5444. //
  5445. } else {
  5446. deviceObject = FileObject->DeviceObject;
  5447. }
  5448. ASSERT( deviceObject != NULL );
  5449. //
  5450. // Simply return the resultant file object.
  5451. //
  5452. return deviceObject;
  5453. }
  5454. PCONFIGURATION_INFORMATION
  5455. IoGetConfigurationInformation( VOID )
  5456. /*++
  5457. Routine Description:
  5458. This routine returns a pointer to the system's device configuration
  5459. information structure so that drivers and the system can determine how
  5460. many different types of devices exist in the system.
  5461. Arguments:
  5462. None.
  5463. Return Value:
  5464. The function value is a pointer to the configuration information
  5465. structure.
  5466. --*/
  5467. {
  5468. PAGED_CODE();
  5469. //
  5470. // Simply return a pointer to the built-in configuration information
  5471. // structure.
  5472. //
  5473. return (&ConfigurationInformation);
  5474. }
  5475. PEPROCESS
  5476. IoGetCurrentProcess( VOID )
  5477. /*++
  5478. Routine Description:
  5479. This routine returns a pointer to the current process. It is actually
  5480. a jacket routine for the PS version of the same function since device
  5481. drivers using the ntddk header file cannot see into a thread object.
  5482. Arguments:
  5483. None.
  5484. Return Value:
  5485. The function value is a pointer to the current process.
  5486. Note:
  5487. Note that this function cannot be paged because it is invoked at raised
  5488. IRQL in debug builds, which is the only time that the PAGED_CODE macro
  5489. actually does anything. Therefore, it is impossible to find code that
  5490. invokes this function at raised IRQL in a normal system w/o simply running
  5491. into the "proper conditions". This is too risky to actually page this
  5492. routine, so it is left nonpaged.
  5493. --*/
  5494. {
  5495. //
  5496. // Simply return a pointer to the current process.
  5497. //
  5498. return PsGetCurrentProcess();
  5499. }
  5500. NTSTATUS
  5501. IoGetDeviceObjectPointer(
  5502. IN PUNICODE_STRING ObjectName,
  5503. IN ACCESS_MASK DesiredAccess,
  5504. OUT PFILE_OBJECT *FileObject,
  5505. OUT PDEVICE_OBJECT *DeviceObject
  5506. )
  5507. /*++
  5508. Routine Description:
  5509. This routine returns a pointer to the device object specified by the
  5510. object name. It also returns a pointer to the referenced file object
  5511. that has been opened to the device that ensures that the device cannot
  5512. go away.
  5513. To close access to the device, the caller should dereference the file
  5514. object pointer.
  5515. Arguments:
  5516. ObjectName - Name of the device object for which a pointer is to be
  5517. returned.
  5518. DesiredAccess - Access desired to the target device object.
  5519. FileObject - Supplies the address of a variable to receive a pointer
  5520. to the file object for the device.
  5521. DeviceObject - Supplies the address of a variable to receive a pointer
  5522. to the device object for the specified device.
  5523. Return Value:
  5524. The function value is a referenced pointer to the specified device
  5525. object, if the device exists. Otherwise, NULL is returned.
  5526. --*/
  5527. {
  5528. PFILE_OBJECT fileObject;
  5529. OBJECT_ATTRIBUTES objectAttributes;
  5530. HANDLE fileHandle;
  5531. IO_STATUS_BLOCK ioStatus;
  5532. NTSTATUS status;
  5533. PAGED_CODE();
  5534. //
  5535. // Initialize the object attributes to open the device.
  5536. //
  5537. InitializeObjectAttributes( &objectAttributes,
  5538. ObjectName,
  5539. OBJ_KERNEL_HANDLE,
  5540. (HANDLE) NULL,
  5541. (PSECURITY_DESCRIPTOR) NULL );
  5542. status = ZwOpenFile( &fileHandle,
  5543. DesiredAccess,
  5544. &objectAttributes,
  5545. &ioStatus,
  5546. 0,
  5547. FILE_NON_DIRECTORY_FILE );
  5548. if (NT_SUCCESS( status )) {
  5549. //
  5550. // The open operation was successful. Dereference the file handle
  5551. // and obtain a pointer to the device object for the handle.
  5552. //
  5553. status = ObReferenceObjectByHandle( fileHandle,
  5554. 0,
  5555. IoFileObjectType,
  5556. KernelMode,
  5557. (PVOID *) &fileObject,
  5558. NULL );
  5559. if (NT_SUCCESS( status )) {
  5560. *FileObject = fileObject;
  5561. //
  5562. // Get a pointer to the device object for this file.
  5563. //
  5564. *DeviceObject = IoGetRelatedDeviceObject( fileObject );
  5565. }
  5566. (VOID) ZwClose( fileHandle );
  5567. }
  5568. return status;
  5569. }
  5570. PDEVICE_OBJECT
  5571. IoGetDeviceToVerify(
  5572. IN PETHREAD Thread
  5573. )
  5574. /*++
  5575. Routine Description:
  5576. This routine returns a pointer to the device object that is to be verified.
  5577. The pointer is set in the thread object by a device driver when the disk
  5578. or CD-ROM media appears to have changed since the last access to the device.
  5579. Arguments:
  5580. Thread - Pointer to the thread whose field is to be queried.
  5581. Return Value:
  5582. The function value is a pointer to the device to be verified, or NULL.
  5583. Note:
  5584. This function cannot be made a macro, since fields in the thread object
  5585. move from release to release, so this must remain a full function.
  5586. --*/
  5587. {
  5588. //
  5589. // Simply return the device to be verified.
  5590. //
  5591. return Thread->DeviceToVerify;
  5592. }
  5593. NTKERNELAPI
  5594. PVOID
  5595. IoGetDriverObjectExtension(
  5596. IN PDRIVER_OBJECT DriverObject,
  5597. IN PVOID ClientIdentificationAddress
  5598. )
  5599. /*++
  5600. Routine Description:
  5601. This routine returns a pointer to the client driver object extension.
  5602. This extension was allocated using IoAllocateDriverObjectExtension. If
  5603. an extension with the create Id does not exist for the specified driver
  5604. object then NULL is returned.
  5605. Arguments:
  5606. DriverObject - Pointer to driver object owning the extension.
  5607. ClientIdentificationAddress - Supplies the unique identifier which was
  5608. used to create the extension.
  5609. Return Value:
  5610. The function value is a pointer to the client driver object extension,
  5611. or NULL.
  5612. --*/
  5613. {
  5614. KIRQL irql;
  5615. PIO_CLIENT_EXTENSION extension;
  5616. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  5617. extension = DriverObject->DriverExtension->ClientDriverExtension;
  5618. while (extension != NULL) {
  5619. if (extension->ClientIdentificationAddress == ClientIdentificationAddress) {
  5620. break;
  5621. }
  5622. extension = extension->NextExtension;
  5623. }
  5624. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  5625. if (extension == NULL) {
  5626. return NULL;
  5627. }
  5628. return extension + 1;
  5629. }
  5630. PGENERIC_MAPPING
  5631. IoGetFileObjectGenericMapping(
  5632. VOID
  5633. )
  5634. /*++
  5635. Routine Description:
  5636. This routine returns a pointer to the generic mapping for a file object.
  5637. Arguments:
  5638. None.
  5639. Return Value:
  5640. A pointer to the generic mapping for a file object.
  5641. --*/
  5642. {
  5643. PAGED_CODE()
  5644. //
  5645. // Simply return a pointer to the generic mapping for a file object.
  5646. //
  5647. return (PGENERIC_MAPPING)&IopFileMapping;
  5648. }
  5649. PVOID
  5650. IoGetInitialStack(
  5651. VOID
  5652. )
  5653. /*++
  5654. Routine Description:
  5655. This routine returns the base initial address of the current thread's
  5656. stack.
  5657. Arguments:
  5658. None.
  5659. Return Value:
  5660. The base initial address of the current thread's stack.
  5661. Note:
  5662. This function cannot be made a macro, since fields in the thread object
  5663. move from release to release, so this must remain a full function.
  5664. --*/
  5665. {
  5666. //
  5667. // Simply return the initial stack for this thread.
  5668. //
  5669. return PsGetCurrentThread()->Tcb.InitialStack;
  5670. }
  5671. NTSTATUS
  5672. IoComputeDesiredAccessFileObject(
  5673. IN PFILE_OBJECT FileObject,
  5674. OUT PNTSTATUS DesiredAccess
  5675. )
  5676. /*++
  5677. Routine Description
  5678. This routine is called by ObReferenceFileObjectForWrite (from NtWriteFile)
  5679. to determine which access is desired for the passed file object. The desired
  5680. access differs if the FileObject is a file or a pipe.
  5681. Arguments
  5682. FileObject - the file object to access
  5683. DesiredAccess - the computed access for the object
  5684. Return Value
  5685. STATUS_OBJECT_TYPE_MISMATCH if the object is not of type IoFileObjectType
  5686. STATUS_SUCCESS if successful
  5687. --*/
  5688. {
  5689. POBJECT_HEADER ObjectHeader = NULL;
  5690. NTSTATUS Status = STATUS_SUCCESS;
  5691. *DesiredAccess = 0;
  5692. ObjectHeader = OBJECT_TO_OBJECT_HEADER(FileObject);
  5693. if (ObjectHeader->Type == IoFileObjectType) {
  5694. *DesiredAccess = (!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA;
  5695. Status = STATUS_SUCCESS;
  5696. } else {
  5697. Status = STATUS_OBJECT_TYPE_MISMATCH;
  5698. }
  5699. return Status;
  5700. }
  5701. PDEVICE_OBJECT
  5702. IoGetRelatedDeviceObject(
  5703. IN PFILE_OBJECT FileObject
  5704. )
  5705. /*++
  5706. Routine Description:
  5707. This routine returns a pointer to the actual device object than an I/O
  5708. Request Packet (IRP) should be given to based on the specified file
  5709. object.
  5710. N.B. - Callers of this function must ensure no device object is
  5711. attaching or detaching from this stack for the duration of this call.
  5712. This is because the database lock is *not* held!
  5713. Arguments:
  5714. FileObject - Pointer to the file object representing the open file.
  5715. Return Value:
  5716. The return value is a pointer to the device object for the driver to
  5717. whom the request is to be given.
  5718. --*/
  5719. {
  5720. PDEVICE_OBJECT deviceObject;
  5721. //
  5722. // If the file object was taken out against the mounted file system, it
  5723. // will have a Vpb. Traverse it to get to the DeviceObject. Note that in
  5724. // this case we should never follow FileObject->DeviceObject, as that
  5725. // mapping may be invalid after a forced dismount.
  5726. //
  5727. if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) {
  5728. ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
  5729. deviceObject = FileObject->Vpb->DeviceObject;
  5730. //
  5731. // If a driver opened a disk device using direct device open and
  5732. // later on it uses IoGetRelatedTargetDeviceObject to find the
  5733. // device object it wants to send an IRP then it should not get the
  5734. // filesystem device object. This is so that if the device object is in the
  5735. // process of being mounted then vpb is not stable.
  5736. //
  5737. } else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
  5738. FileObject->DeviceObject->Vpb != NULL &&
  5739. FileObject->DeviceObject->Vpb->DeviceObject != NULL) {
  5740. deviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
  5741. //
  5742. // This is a direct open against the device stack (and there is no mounted
  5743. // file system to strain the IRPs through).
  5744. //
  5745. } else {
  5746. deviceObject = FileObject->DeviceObject;
  5747. }
  5748. ASSERT( deviceObject != NULL );
  5749. //
  5750. // Check to see whether or not the device has any associated devices.
  5751. // If so, return the highest level device; otherwise, return a pointer
  5752. // to the device object itself.
  5753. //
  5754. if (deviceObject->AttachedDevice != NULL) {
  5755. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  5756. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =
  5757. (PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  5758. ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
  5759. if (fileObjectExtension->TopDeviceObjectHint != NULL &&
  5760. IopVerifyDeviceObjectOnStack(deviceObject, fileObjectExtension->TopDeviceObjectHint)) {
  5761. return fileObjectExtension->TopDeviceObjectHint;
  5762. }
  5763. }
  5764. deviceObject = IoGetAttachedDevice( deviceObject );
  5765. }
  5766. return deviceObject;
  5767. }
  5768. ULONG
  5769. IoGetRequestorProcessId(
  5770. IN PIRP Irp
  5771. )
  5772. /*++
  5773. Routine Description:
  5774. This routine returns a 32-bit value that is unique to the process that
  5775. originally requested the specified I/O operation.
  5776. Arguments:
  5777. Irp - Pointer to the I/O Request Packet.
  5778. Return Value:
  5779. The function value is the 32-bit process ID.
  5780. --*/
  5781. {
  5782. PEPROCESS process;
  5783. process = IoGetRequestorProcess( Irp );
  5784. if (process != NULL) {
  5785. //
  5786. // UniqueProcessId is a kernel-mode handle, safe to truncate to ULONG.
  5787. //
  5788. return HandleToUlong( process->UniqueProcessId );
  5789. } else {
  5790. //
  5791. // Return a PID of zero if there is no process associated with the IRP.
  5792. //
  5793. return 0;
  5794. }
  5795. }
  5796. PEPROCESS
  5797. IoGetRequestorProcess(
  5798. IN PIRP Irp
  5799. )
  5800. /*++
  5801. Routine Description:
  5802. This routine returns a pointer to the process that originally
  5803. requested the specified I/O operation.
  5804. Arguments:
  5805. Irp - Pointer to the I/O Request Packet.
  5806. Return Value:
  5807. The function value is a pointer to the original requesting process.
  5808. --*/
  5809. {
  5810. //
  5811. // Return the address of the process that requested the I/O operation.
  5812. //
  5813. if (Irp->Tail.Overlay.Thread) {
  5814. return PsGetCurrentProcessByThread( Irp->Tail.Overlay.Thread );
  5815. } else {
  5816. return NULL;
  5817. }
  5818. }
  5819. PIRP
  5820. IoGetTopLevelIrp(
  5821. VOID
  5822. )
  5823. /*++
  5824. Routine Description:
  5825. This routine returns the contents of the TopLevelIrp field of the current
  5826. thread.
  5827. Arguments:
  5828. None.
  5829. Return Value:
  5830. The final function value is the contents of the TopLevelIrp field.
  5831. Note:
  5832. This function cannot be made a macro, since fields in the thread object
  5833. move from release to release, so this must remain a full function.
  5834. --*/
  5835. {
  5836. //
  5837. // Simply return the TopLevelIrp field of the thread.
  5838. //
  5839. return (PIRP) (PsGetCurrentThread()->TopLevelIrp);
  5840. }
  5841. VOID
  5842. IoInitializeIrp(
  5843. IN OUT PIRP Irp,
  5844. IN USHORT PacketSize,
  5845. IN CCHAR StackSize
  5846. )
  5847. /*++
  5848. Routine Description:
  5849. Initializes an IRP.
  5850. Arguments:
  5851. Irp - a pointer to the IRP to initialize.
  5852. PacketSize - length, in bytes, of the IRP.
  5853. StackSize - Number of stack locations in the IRP.
  5854. Return Value:
  5855. None.
  5856. --*/
  5857. {
  5858. IOV_INITIALIZE_IRP(Irp, PacketSize, StackSize);
  5859. //
  5860. // Begin by zeroing the entire packet.
  5861. //
  5862. RtlZeroMemory( Irp, PacketSize );
  5863. //
  5864. // Initialize the remainder of the packet by setting the appropriate fields
  5865. // and setting up the I/O stack locations in the packet.
  5866. //
  5867. Irp->Type = (CSHORT) IO_TYPE_IRP;
  5868. Irp->Size = (USHORT) PacketSize;
  5869. Irp->StackCount = (CCHAR) StackSize;
  5870. Irp->CurrentLocation = (CCHAR) (StackSize + 1);
  5871. Irp->ApcEnvironment = KeGetCurrentApcEnvironment();
  5872. InitializeListHead (&(Irp)->ThreadListEntry);
  5873. Irp->Tail.Overlay.CurrentStackLocation =
  5874. ((PIO_STACK_LOCATION) ((UCHAR *) (Irp) +
  5875. sizeof( IRP ) +
  5876. ( (StackSize) * sizeof( IO_STACK_LOCATION ))));
  5877. }
  5878. VOID
  5879. IoReuseIrp(
  5880. PIRP Irp,
  5881. NTSTATUS Status)
  5882. /*++
  5883. Routine Description:
  5884. This routine is used by drivers to initialize an already allocated IRP for reuse.
  5885. It does what IoInitializeIrp does but it saves the allocation flags so that we know
  5886. how to free the Irp and take care of quote requirements. Drivers should call IoReuseIrp
  5887. instead of calling IoInitializeIrp to reinitialize an IRP.
  5888. Arguments:
  5889. Irp - Pointer to Irp to be reused
  5890. Status - Status to preinitialize the Iostatus field.
  5891. --*/
  5892. {
  5893. USHORT PacketSize;
  5894. CCHAR StackSize;
  5895. UCHAR AllocationFlags;
  5896. // Did anyone forget to pull their cancel routine?
  5897. ASSERT(Irp->CancelRoutine == NULL) ;
  5898. // We probably don't want thread enqueue'd IRPs to be used
  5899. // ping-pong style as they cannot be dequeue unless they
  5900. // complete entirely. Not really an issue for worker threads,
  5901. // but definitely for operations on application threads.
  5902. ASSERT(IsListEmpty(&Irp->ThreadListEntry)) ;
  5903. AllocationFlags = Irp->AllocationFlags;
  5904. StackSize = Irp->StackCount;
  5905. PacketSize = IoSizeOfIrp(StackSize);
  5906. IopInitializeIrp(Irp, PacketSize, StackSize);
  5907. Irp->AllocationFlags = AllocationFlags;
  5908. Irp->IoStatus.Status = Status;
  5909. }
  5910. NTSTATUS
  5911. IoInitializeTimer(
  5912. IN PDEVICE_OBJECT DeviceObject,
  5913. IN PIO_TIMER_ROUTINE TimerRoutine,
  5914. IN PVOID Context
  5915. )
  5916. /*++
  5917. Routine Description:
  5918. This routine is used by drivers to initialize a timer entry for a device
  5919. object.
  5920. Arguments:
  5921. DeviceObject - Pointer to device object to be used.
  5922. TimerRoutine - Driver routine to be executed when timer expires.
  5923. Context - Context parameter that is passed to the driver routine.
  5924. Return Value:
  5925. The function value indicates whether or not the timer was initialized.
  5926. --*/
  5927. {
  5928. PIO_TIMER timer;
  5929. PAGED_CODE();
  5930. //
  5931. // Begin by getting the address of the timer to be used. If no timer has
  5932. // been allocated, allocate one and initialize it.
  5933. //
  5934. timer = DeviceObject->Timer;
  5935. if (!timer) {
  5936. timer = ExAllocatePoolWithTag( NonPagedPool, sizeof( IO_TIMER ), 'iToI' );
  5937. if (!timer) {
  5938. return STATUS_INSUFFICIENT_RESOURCES;
  5939. }
  5940. //
  5941. // Initialize the timer entry so that it is suitable for being placed
  5942. // into the I/O system's timer queue.
  5943. //
  5944. RtlZeroMemory( timer, sizeof( IO_TIMER ) );
  5945. timer->Type = IO_TYPE_TIMER;
  5946. timer->DeviceObject = DeviceObject;
  5947. DeviceObject->Timer = timer;
  5948. }
  5949. //
  5950. // Set the address of the driver's timer routine and the context parameter
  5951. // passed to it and insert it onto the timer queue. Note that the timer
  5952. // enable flag is not set, so this routine will not actually be invoked
  5953. // yet.
  5954. //
  5955. timer->TimerRoutine = TimerRoutine;
  5956. timer->Context = Context;
  5957. ExInterlockedInsertTailList( &IopTimerQueueHead,
  5958. &timer->TimerList,
  5959. &IopTimerLock );
  5960. return STATUS_SUCCESS;
  5961. }
  5962. BOOLEAN
  5963. IoIsOperationSynchronous(
  5964. IN PIRP Irp
  5965. )
  5966. /*++
  5967. Routine Description:
  5968. This routine determines whether an I/O operation is to be considered
  5969. synchronous or an asynchronous, from the implementors point-of-view.
  5970. Synchronous I/O is defined by how the file was opened, or the API being
  5971. used to perform the operation, or by the type of paging I/O being
  5972. performed, if the operation is paging I/O.
  5973. It is possible for asynchronous paging I/O to occur to a file that was
  5974. opened for synchronous I/O. This occurs when the Modified Page Writer
  5975. is doing I/O to a file that is mapped, when too many modified pages exist
  5976. in the system.
  5977. Arguments:
  5978. Irp - Pointer to the I/O Request Packet (IRP) representing the operation
  5979. to be performed.
  5980. Return Value:
  5981. A value of TRUE is returned if the operation is synchronous, otherwise
  5982. FALSE is returned.
  5983. --*/
  5984. {
  5985. //
  5986. // Determine whether this is a synchronous I/O operation. Synchronous I/O
  5987. // is defined as an operation that is:
  5988. //
  5989. // A file opened for synchronous I/O
  5990. // OR
  5991. // A synchronous API operation
  5992. // OR
  5993. // A synchronous paging I/O operation
  5994. //
  5995. // AND this is NOT an asynchronous paging I/O operation occurring to some
  5996. // file that was opened for either synchronous or asynchronous I/O.
  5997. //
  5998. if ((IoGetCurrentIrpStackLocation( Irp )->FileObject->Flags & FO_SYNCHRONOUS_IO ||
  5999. Irp->Flags & IRP_SYNCHRONOUS_API ||
  6000. Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) &&
  6001. !(Irp->Flags & IRP_PAGING_IO &&
  6002. !(Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO))) {
  6003. return TRUE;
  6004. } else {
  6005. return FALSE;
  6006. }
  6007. }
  6008. BOOLEAN
  6009. IoIsSystemThread(
  6010. IN PETHREAD Thread
  6011. )
  6012. /*++
  6013. Routine Description:
  6014. This routine returns a BOOLEAN indicating whether or not the specified
  6015. thread is a system thread.
  6016. Arguments:
  6017. Thread - Pointer to the thread to be checked.
  6018. Return Value:
  6019. A value of TRUE is returned if the indicated thread is a system thread,
  6020. else FALSE.
  6021. Note:
  6022. This function cannot be made a macro, since fields in the thread object
  6023. move from release to release, so this must remain a full function.
  6024. --*/
  6025. {
  6026. return (BOOLEAN) IS_SYSTEM_THREAD(Thread);
  6027. }
  6028. BOOLEAN
  6029. IoIsValidNameGraftingBuffer(
  6030. IN PIRP Irp,
  6031. IN PREPARSE_DATA_BUFFER ReparseBuffer
  6032. )
  6033. /*++
  6034. Routine Description:
  6035. This routine returns a BOOLEAN indicating whether or not the specified
  6036. buffer is a valid name grafting buffer. All internal validity checks are
  6037. encapsulated in this routine.
  6038. Among the checks performed is whether the name lengths stored within the
  6039. buffer in the private data section are compatible with the total size of
  6040. the buffer that has been passed in.
  6041. Arguments:
  6042. Irp - Pointer to the I/O Request Packet (IRP) representing the operation
  6043. to be performed.
  6044. Buffer - Pointer to a reparse data buffer that is supposed to contain
  6045. a self-consistent set of names to perform name grafting.
  6046. Return Value:
  6047. A value of TRUE is returned if the buffer is correct for name grafting,
  6048. else FALSE.
  6049. Note:
  6050. This function needs to be kept synchronized with the definition of
  6051. REPARSE_DATA_BUFFER.
  6052. --*/
  6053. {
  6054. PIO_STACK_LOCATION thisStackPointer = NULL;
  6055. UNICODE_STRING drivePath;
  6056. PAGED_CODE();
  6057. ASSERT( FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0] ) ==
  6058. FIELD_OFFSET( REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0] ) );
  6059. ASSERT( ReparseBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  6060. //
  6061. // Determine whether we have the correct kind of reparse tag in the buffer.
  6062. //
  6063. if (ReparseBuffer->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
  6064. //
  6065. // The reparse tag is not an NT name grafting tag.
  6066. //
  6067. return FALSE;
  6068. }
  6069. //
  6070. // Determine whether we have enough data for all the length fields.
  6071. //
  6072. if (ReparseBuffer->ReparseDataLength <
  6073. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE)) {
  6074. //
  6075. // The buffer is shorter than the minimum needed to express a pair of valid
  6076. // names.
  6077. //
  6078. return FALSE;
  6079. }
  6080. //
  6081. // Get the address of the current stack location.
  6082. //
  6083. thisStackPointer = IoGetCurrentIrpStackLocation( Irp );
  6084. //
  6085. // Determine whether the data lengths returned are consistent with the buffer in
  6086. // which they are retrieved.
  6087. //
  6088. // This check is meaningful only when the buffer has been allocated. When this routine
  6089. // is used when a name grafting is being set there is no allocated output buffer.
  6090. //
  6091. if ((thisStackPointer->Parameters.FileSystemControl.OutputBufferLength > 0) &&
  6092. (thisStackPointer->Parameters.FileSystemControl.OutputBufferLength <
  6093. (ULONG)(FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) +
  6094. ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength +
  6095. ReparseBuffer->MountPointReparseBuffer.PrintNameLength +
  6096. 2 * sizeof( UNICODE_NULL )))) {
  6097. //
  6098. // The length of the appropriate buffer header, plus the lengths of the substitute
  6099. // and print names are longer than the length of the buffer passed in.
  6100. // Thus, this data is not self-consistent.
  6101. //
  6102. // Note that it is only the I/O subsystem that needs to check for this internal
  6103. // consistency in the buffer as it will do a blind data copy using these lengths
  6104. // when transmogrifying the names. The file system returning the buffer only needs
  6105. // to ascertain that the total syze of the data retrieved does not exceed the size
  6106. // of the output buffer.
  6107. //
  6108. return FALSE;
  6109. }
  6110. //
  6111. // Now we determine whether the names were placed according to the reparse point
  6112. // specification.
  6113. //
  6114. //
  6115. // Determine whether the SubstituteNameOffset is zero.
  6116. //
  6117. if (ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset != 0) {
  6118. //
  6119. // Incorrect offset for the substitute name.
  6120. //
  6121. return FALSE;
  6122. }
  6123. //
  6124. // Determine whether PrintNameOffset is correct.
  6125. //
  6126. if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset !=
  6127. (ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof( UNICODE_NULL )) ) {
  6128. //
  6129. // Incorrect offset for the print name.
  6130. //
  6131. return FALSE;
  6132. }
  6133. //
  6134. // Determine whether ReparseDataLength is correct for name grafting operations.
  6135. // We require a buffer of type REPARSE_DATA_BUFFER.
  6136. //
  6137. if (ReparseBuffer->ReparseDataLength !=
  6138. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE) +
  6139. ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength +
  6140. ReparseBuffer->MountPointReparseBuffer.PrintNameLength +
  6141. 2 * sizeof( UNICODE_NULL )) {
  6142. //
  6143. // Incorrect length of the reparse data.
  6144. //
  6145. return FALSE;
  6146. }
  6147. //
  6148. // Determine that the substitute name is not a UNC name.
  6149. // This assumes that ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset is zero (0).
  6150. //
  6151. {
  6152. //
  6153. // This conditional is a transcription of part of the code of RtlDetermineDosPathNameType_U
  6154. // present in ntos\dll\curdir.c
  6155. //
  6156. // The only two legal names that can begin with \\ are: \\. and \\?
  6157. // All other names that begin with \\ are disallowed.
  6158. //
  6159. if ((ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength > 6) &&
  6160. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') &&
  6161. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[1] == L'\\') &&
  6162. !((ReparseBuffer->MountPointReparseBuffer.PathBuffer[2] == L'.') ||
  6163. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[2] == L'?'))) {
  6164. //
  6165. // The name is not one we want to deal with.
  6166. //
  6167. return FALSE;
  6168. }
  6169. //
  6170. // When RtlDosPathNameToNtPathName_U is used, the UNC names are returned with a prefix
  6171. // of the form \??\UNC\
  6172. //
  6173. if ((ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength > 16) &&
  6174. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') &&
  6175. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[1] == L'?') &&
  6176. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[2] == L'?') &&
  6177. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[3] == L'\\') &&
  6178. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[4] == L'U') &&
  6179. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[5] == L'N') &&
  6180. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[6] == L'C') &&
  6181. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[7] == L'\\')) {
  6182. //
  6183. // The name is not one we want to deal with.
  6184. //
  6185. return FALSE;
  6186. }
  6187. //
  6188. // See whether there is a drive letter that is mapped at the beginning of the name.
  6189. // If the drive letter is C, then the prefix has the form \??\C:
  6190. // Note that we skip the offset 4 on purpose.
  6191. //
  6192. if ((ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength > 12) &&
  6193. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') &&
  6194. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[1] == L'?') &&
  6195. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[2] == L'?') &&
  6196. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[3] == L'\\') &&
  6197. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[5] == L':')) {
  6198. NTSTATUS status;
  6199. UNICODE_STRING linkValue;
  6200. OBJECT_ATTRIBUTES objectAttributes;
  6201. HANDLE linkHandle;
  6202. PWCHAR linkValueBuffer = NULL; // MAX_PATH is 260
  6203. WCHAR pathNameValue[sizeof(L"\\??\\C:\0")];
  6204. RtlCopyMemory( &pathNameValue, L"\\??\\C:\0", sizeof(L"\\??\\C:\0") );
  6205. RtlInitUnicodeString( &drivePath, pathNameValue );
  6206. //
  6207. // Place the appropriate drive letter in the buffer overwriting offset 4.
  6208. //
  6209. drivePath.Buffer[4] = ReparseBuffer->MountPointReparseBuffer.PathBuffer[4];
  6210. InitializeObjectAttributes( &objectAttributes,
  6211. &drivePath,
  6212. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  6213. (HANDLE) NULL,
  6214. (PSECURITY_DESCRIPTOR) NULL );
  6215. status = ZwOpenSymbolicLinkObject( &linkHandle,
  6216. SYMBOLIC_LINK_QUERY,
  6217. &objectAttributes );
  6218. if ( NT_SUCCESS( status ) ) {
  6219. //
  6220. // Now query the link and see if there is a redirection
  6221. //
  6222. linkValueBuffer = ExAllocatePoolWithTag( NonPagedPool,
  6223. 2 * 260,
  6224. ' oI' );
  6225. if ( !linkValueBuffer ) {
  6226. //
  6227. // Insufficient resources. Return FALSE.
  6228. //
  6229. ZwClose( linkHandle );
  6230. return FALSE;
  6231. }
  6232. linkValue.Buffer = linkValueBuffer;
  6233. linkValue.Length = 0;
  6234. linkValue.MaximumLength = (USHORT)(2 * 260);
  6235. status = ZwQuerySymbolicLinkObject( linkHandle,
  6236. &linkValue,
  6237. NULL );
  6238. ZwClose( linkHandle );
  6239. if ( NT_SUCCESS( status ) ) {
  6240. //
  6241. // The link is a re-directed drive when it has the prefix
  6242. // \Device\LanmanRedirector\
  6243. //
  6244. if ((linkValue.Buffer[ 0] == L'\\') &&
  6245. (linkValue.Buffer[ 1] == L'D') &&
  6246. (linkValue.Buffer[ 2] == L'e') &&
  6247. (linkValue.Buffer[ 3] == L'v') &&
  6248. (linkValue.Buffer[ 4] == L'i') &&
  6249. (linkValue.Buffer[ 5] == L'c') &&
  6250. (linkValue.Buffer[ 6] == L'e') &&
  6251. (linkValue.Buffer[ 7] == L'\\') &&
  6252. (linkValue.Buffer[ 8] == L'L') &&
  6253. (linkValue.Buffer[ 9] == L'a') &&
  6254. (linkValue.Buffer[10] == L'n') &&
  6255. (linkValue.Buffer[14] == L'R') &&
  6256. (linkValue.Buffer[15] == L'e') &&
  6257. (linkValue.Buffer[16] == L'd') &&
  6258. (linkValue.Buffer[17] == L'i') &&
  6259. (linkValue.Buffer[18] == L'r') &&
  6260. (linkValue.Buffer[23] == L'r') &
  6261. (linkValue.Buffer[24] == L'\\')) {
  6262. //
  6263. // Free the buffer.
  6264. //
  6265. ExFreePool( linkValueBuffer );
  6266. return FALSE;
  6267. }
  6268. }
  6269. //
  6270. // Free the buffer.
  6271. //
  6272. ExFreePool( linkValueBuffer );
  6273. }
  6274. }
  6275. }
  6276. //
  6277. // Fix for penetration bug. May be relaxed in the future 03/99.
  6278. // Determine that we either have an NT file name or a volume mount point target name.
  6279. //
  6280. // This closes the door of having an arbitrary device name that, with the help of the
  6281. // server, can be used to bypass access checks to the underlying device.
  6282. //
  6283. {
  6284. UNICODE_STRING volumeName;
  6285. if (
  6286. //
  6287. // The shortest valid name is one of the kind \??\C: whose length is 12 when
  6288. // in Unicode. All names used by volume mount points are longer.
  6289. //
  6290. ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength < 12 ) {
  6291. return FALSE;
  6292. }
  6293. //
  6294. // The name has at least 6 Unicode characters.
  6295. //
  6296. // We have verified above that MountPointReparseBuffer.SubstituteNameOffset
  6297. // is zero.
  6298. //
  6299. volumeName.Length =
  6300. volumeName.MaximumLength = ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength;
  6301. volumeName.Buffer = (PWSTR) ReparseBuffer->MountPointReparseBuffer.PathBuffer;
  6302. //
  6303. // When we do not have a name that begins with a drive letter and it is not
  6304. // a valid volume mount point name then we return false.
  6305. //
  6306. if ( !((ReparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') &&
  6307. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[1] == L'?') &&
  6308. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[2] == L'?') &&
  6309. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[3] == L'\\') &&
  6310. //
  6311. // Notice that we skip index 4, where the drive letter is to be.
  6312. //
  6313. (ReparseBuffer->MountPointReparseBuffer.PathBuffer[5] == L':'))
  6314. &&
  6315. !MOUNTMGR_IS_VOLUME_NAME( &volumeName ) ) {
  6316. return FALSE;
  6317. }
  6318. }
  6319. //
  6320. // Otherwise return TRUE.
  6321. //
  6322. return TRUE;
  6323. }
  6324. VOID
  6325. IopDoNameTransmogrify(
  6326. IN PIRP Irp,
  6327. IN PFILE_OBJECT FileObject,
  6328. IN PREPARSE_DATA_BUFFER ReparseBuffer
  6329. )
  6330. /*++
  6331. Routine Description:
  6332. This routine is called to do the name grafting needed for junctions.
  6333. Arguments:
  6334. Irp - Pointer to the I/O Request Packet (IRP) representing the operation
  6335. to be performed.
  6336. FileObject - Pointer to the file object whose name is being affected.
  6337. ReparseBuffer - Pointer to a reparse data buffer that is supposed to contain
  6338. a self-consistent set of names to perform name grafting.
  6339. Return Value:
  6340. No explicit return value. The appropriate fields off the IRP are set.
  6341. Note:
  6342. This function needs to be kept synchronized with the definition of
  6343. REPARSE_DATA_BUFFER.
  6344. --*/
  6345. {
  6346. USHORT pathLength = 0;
  6347. USHORT neededBufferLength = 0;
  6348. PVOID outBuffer = NULL;
  6349. PWSTR pathBuffer = NULL;
  6350. PAGED_CODE();
  6351. //
  6352. // We do the appropriate paste of the new name in the FileName buffer
  6353. // and deallocate the buffer that brought the data from the file system.
  6354. //
  6355. ASSERT( Irp->IoStatus.Status == STATUS_REPARSE );
  6356. ASSERT( Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT );
  6357. ASSERT( Irp->Tail.Overlay.AuxiliaryBuffer != NULL );
  6358. ASSERT( ReparseBuffer != NULL );
  6359. ASSERT( ReparseBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT );
  6360. ASSERT( ReparseBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  6361. ASSERT( ReparseBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE );
  6362. //
  6363. // Determine whether we have enough data for all the length fields.
  6364. //
  6365. // Determine whether the lengths returned are consistent with the maximum
  6366. // buffer. This is the best self-defense check we can do at this time as
  6367. // the stack pointer is already invalid.
  6368. //
  6369. if (ReparseBuffer->ReparseDataLength >=
  6370. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE)) {
  6371. if (MAXIMUM_REPARSE_DATA_BUFFER_SIZE <
  6372. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) +
  6373. ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength +
  6374. ReparseBuffer->MountPointReparseBuffer.PrintNameLength)) {
  6375. Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
  6376. }
  6377. } else {
  6378. Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
  6379. }
  6380. //
  6381. // The value in ReparseBuffer->Reserved is the length of the file
  6382. // name that has still to be parsed.
  6383. //
  6384. //
  6385. // Copy the buffer when it has the appropriate length, else return a null UNICODE name:
  6386. // (1) Do defensive sanity checks on the name lengths returned.
  6387. //
  6388. // We only care to do this if we have no error conditions.
  6389. //
  6390. if (NT_SUCCESS( Irp->IoStatus.Status )) {
  6391. pathBuffer = (PWSTR)((PCHAR)ReparseBuffer->MountPointReparseBuffer.PathBuffer +
  6392. ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset);
  6393. pathLength = ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength;
  6394. }
  6395. //
  6396. // Notice that if the data returned in AuxiliaryBuffer is not long enough then
  6397. // pathLength has value 0 and pathBuffer has value NULL.
  6398. //
  6399. // The value in ReparseBuffer->Reserved is the length of the file name that
  6400. // has still to be parsed.
  6401. //
  6402. // We only care to do this if we have no error conditions.
  6403. //
  6404. if (ReparseBuffer->Reserved < 0) {
  6405. //
  6406. // This is an invalid offset.
  6407. //
  6408. Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
  6409. }
  6410. if (NT_SUCCESS( Irp->IoStatus.Status )) {
  6411. //
  6412. // Check for overflow. (pathLength <= MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
  6413. // so pathLength + sizeof(UNICODE_NULL) cannot overflow.
  6414. //
  6415. if (((USHORT)MAXUSHORT - ReparseBuffer->Reserved ) > (pathLength +(USHORT)sizeof(UNICODE_NULL))) {
  6416. neededBufferLength = pathLength + ReparseBuffer->Reserved + sizeof( UNICODE_NULL );
  6417. //
  6418. // If the out name buffer isn't large enough, allocate a new one.
  6419. //
  6420. if (FileObject->FileName.MaximumLength < neededBufferLength) {
  6421. outBuffer = ExAllocatePoolWithTag( PagedPool,
  6422. neededBufferLength,
  6423. 'cFoI' );
  6424. if (!outBuffer) {
  6425. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  6426. }
  6427. } else {
  6428. outBuffer = FileObject->FileName.Buffer;
  6429. }
  6430. } else {
  6431. Irp->IoStatus.Status = STATUS_NAME_TOO_LONG;
  6432. }
  6433. }
  6434. //
  6435. // Place in the out name buffer the remaining part of the name.
  6436. //
  6437. // We only care to do this if we have no error conditions.
  6438. //
  6439. if (NT_SUCCESS( Irp->IoStatus.Status )) {
  6440. if (ReparseBuffer->Reserved) {
  6441. RtlMoveMemory ( (PCHAR)outBuffer + pathLength,
  6442. (PCHAR)FileObject->FileName.Buffer +
  6443. (FileObject->FileName.Length - ReparseBuffer->Reserved),
  6444. ReparseBuffer->Reserved );
  6445. }
  6446. //
  6447. // Copy into the front of the out name buffer the value of the
  6448. // reparse point.
  6449. //
  6450. if (pathLength) {
  6451. RtlCopyMemory( (PCHAR)outBuffer,
  6452. (PCHAR)pathBuffer,
  6453. pathLength );
  6454. }
  6455. FileObject->FileName.Length = neededBufferLength - sizeof( UNICODE_NULL );
  6456. //
  6457. // Free the old name buffer when needed and update the appropriate values.
  6458. //
  6459. if (outBuffer != FileObject->FileName.Buffer) {
  6460. if (FileObject->FileName.Buffer != NULL) {
  6461. ExFreePool( FileObject->FileName.Buffer );
  6462. }
  6463. FileObject->FileName.Buffer = outBuffer;
  6464. FileObject->FileName.MaximumLength = neededBufferLength;
  6465. ((PWSTR)outBuffer)[ (neededBufferLength / sizeof( WCHAR ))-1 ] = UNICODE_NULL;
  6466. }
  6467. }
  6468. //
  6469. // Free the buffer that came from the file system.
  6470. // NULL the pointer.
  6471. //
  6472. ExFreePool( ReparseBuffer );
  6473. ReparseBuffer = NULL;
  6474. }
  6475. PIRP
  6476. IoMakeAssociatedIrp(
  6477. IN PIRP Irp,
  6478. IN CCHAR StackSize
  6479. )
  6480. /*++
  6481. Routine Description:
  6482. This routine allocates an I/O Request Packet from the system nonpaged pool
  6483. and makes it an associated IRP to the specified IRP. The packet will be
  6484. allocated to contain StackSize stack locations. The IRP iwll also be
  6485. initialized.
  6486. Note that it is up to the caller to have set the number of associated IRPs
  6487. in the master packet before calling this routine for the first time. The
  6488. count should be set in the master packet in: AssociatedIrp.IrpCount.
  6489. Arguments:
  6490. Irp - Pointer to master IRP to be associated with.
  6491. StackSize - Specifies the maximum number of stack locations required.
  6492. Return Value:
  6493. The function value is the address of the associated IRP or NULL, if the
  6494. IRP could be allocated.
  6495. --*/
  6496. {
  6497. USHORT allocateSize;
  6498. UCHAR fixedSize;
  6499. PIRP associatedIrp;
  6500. PGENERAL_LOOKASIDE lookasideList;
  6501. PP_NPAGED_LOOKASIDE_NUMBER number;
  6502. USHORT packetSize;
  6503. PKPRCB prcb;
  6504. //
  6505. // If the size of the packet required is less than or equal to those on
  6506. // the lookaside lists, then attempt to allocate the packet from the
  6507. // lookaside lists.
  6508. //
  6509. associatedIrp = NULL;
  6510. fixedSize = 0;
  6511. packetSize = IoSizeOfIrp(StackSize);
  6512. allocateSize = packetSize;
  6513. if (StackSize <= (CCHAR)IopLargeIrpStackLocations) {
  6514. fixedSize = IRP_ALLOCATED_FIXED_SIZE;
  6515. number = LookasideSmallIrpList;
  6516. if (StackSize != 1) {
  6517. allocateSize = IoSizeOfIrp((CCHAR)IopLargeIrpStackLocations);
  6518. number = LookasideLargeIrpList;
  6519. }
  6520. prcb = KeGetCurrentPrcb();
  6521. lookasideList = prcb->PPLookasideList[number].P;
  6522. lookasideList->TotalAllocates += 1;
  6523. associatedIrp = (PIRP)InterlockedPopEntrySList(&lookasideList->ListHead);
  6524. if (associatedIrp == NULL) {
  6525. lookasideList->AllocateMisses += 1;
  6526. lookasideList = prcb->PPLookasideList[number].L;
  6527. lookasideList->TotalAllocates += 1;
  6528. associatedIrp = (PIRP)InterlockedPopEntrySList(&lookasideList->ListHead);
  6529. }
  6530. }
  6531. //
  6532. // See if this IRP is a stale entry. If so just free it.
  6533. // This can happen if we decided to change the lookaside list size.
  6534. // We need to get the size of the IRP from the information field as the size field
  6535. // is overlayed with single list entry.
  6536. //
  6537. if (IopIrpAutoSizingEnabled() && associatedIrp ) {
  6538. if (associatedIrp->IoStatus.Information < packetSize) {
  6539. lookasideList->TotalFrees += 1;
  6540. ExFreePool(associatedIrp);
  6541. associatedIrp = NULL;
  6542. } else {
  6543. //
  6544. // Update allocateSize to the correct value.
  6545. //
  6546. allocateSize = (USHORT)associatedIrp->IoStatus.Information;
  6547. }
  6548. }
  6549. //
  6550. // If an IRP was not allocated from the lookaside list, then allocate
  6551. // the packet from nonpaged pool.
  6552. //
  6553. if (!associatedIrp) {
  6554. if (fixedSize != 0) {
  6555. lookasideList->AllocateMisses += 1;
  6556. }
  6557. //
  6558. // There are no free packets on the lookaside list, or the packet is
  6559. // too large to be allocated from one of the lists, so it must be
  6560. // allocated from general non-paged pool.
  6561. //
  6562. associatedIrp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
  6563. if (!associatedIrp) {
  6564. return NULL;
  6565. }
  6566. }
  6567. //
  6568. // Initialize the packet.
  6569. //
  6570. IopInitializeIrp(associatedIrp, allocateSize, StackSize);
  6571. associatedIrp->Flags |= IRP_ASSOCIATED_IRP;
  6572. associatedIrp->AllocationFlags |= (fixedSize);
  6573. //
  6574. // Set the thread ID to be that of the master.
  6575. //
  6576. associatedIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
  6577. //
  6578. // Now make the association between this packet and the master.
  6579. //
  6580. associatedIrp->AssociatedIrp.MasterIrp = Irp;
  6581. return associatedIrp;
  6582. }
  6583. NTSTATUS
  6584. IopPageReadInternal(
  6585. IN PFILE_OBJECT FileObject,
  6586. IN PMDL MemoryDescriptorList,
  6587. IN PLARGE_INTEGER StartingOffset,
  6588. IN PKEVENT Event,
  6589. OUT PIO_STATUS_BLOCK IoStatusBlock,
  6590. IN BOOLEAN Async
  6591. )
  6592. /*++
  6593. Routine Description:
  6594. This routine provides a special, fast interface for the Pager to read pages
  6595. in from the disk quickly and with very little overhead. All of the special
  6596. handling for this request is recognized by setting the IRP_PAGING_IO flag
  6597. in the IRP flags word. In-page operations are detected by using the IRP
  6598. flag IRP_INPUT_OPERATION.
  6599. Arguments:
  6600. FileObject - A pointer to a referenced file object describing which file
  6601. the read should be performed from.
  6602. MemoryDescriptorList - An MDL which describes the physical pages that the
  6603. pages should be read into from the disk. All of the pages have been
  6604. locked in memory. The MDL also describes the length of the read
  6605. operation.
  6606. StartingOffset - Pointer to the offset in the file from which the read
  6607. should take place.
  6608. Event - A pointer to a kernel event structure to be used for synchronization
  6609. purposes. The event will be set to the Signaled state once the in-page
  6610. operation completes.
  6611. IoStatusBlock - A pointer to the I/O status block in which the final status
  6612. and information should be stored.
  6613. Async - If TRUE the operation is asynchronous
  6614. Return Value:
  6615. The function value is the final status of the queue request to the I/O
  6616. system subcomponents.
  6617. Notes:
  6618. This routine is invoked at APC_LEVEL; this level is honored throughout the
  6619. execution of the entire I/O request, including completion.
  6620. --*/
  6621. {
  6622. PIRP irp;
  6623. PIO_STACK_LOCATION irpSp;
  6624. PDEVICE_OBJECT deviceObject;
  6625. //
  6626. // Increment performance counter. The Cache Manager I/Os always are
  6627. // "recursive".
  6628. //
  6629. if (MmIsRecursiveIoFault()) {
  6630. *CcMissCounter += (MemoryDescriptorList->ByteCount + PAGE_SIZE - 1) >> PAGE_SHIFT;
  6631. }
  6632. //
  6633. // Begin by getting a pointer to the device object that the file resides
  6634. // on.
  6635. //
  6636. deviceObject = IoGetRelatedDeviceObject( FileObject );
  6637. //
  6638. // Allocate an I/O Request Packet (IRP) for this in-page operation.
  6639. //
  6640. irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
  6641. if (!irp) {
  6642. if (MmIsFileObjectAPagingFile(FileObject)) {
  6643. InterlockedIncrement(&IoPageReadIrpAllocationFailure);
  6644. irp = IopAllocateReserveIrp(deviceObject->StackSize);
  6645. }
  6646. if (!irp) {
  6647. return STATUS_INSUFFICIENT_RESOURCES;
  6648. }
  6649. }
  6650. //
  6651. // Get a pointer to the first stack location in the packet. This location
  6652. // will be used to pass the function codes and parameters to the first
  6653. // driver.
  6654. //
  6655. irpSp = IoGetNextIrpStackLocation( irp );
  6656. //
  6657. // Fill in the IRP according to this request.
  6658. //
  6659. irp->MdlAddress = MemoryDescriptorList;
  6660. if (Async) {
  6661. irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SET_USER_EVENT;
  6662. } else {
  6663. irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO | IRP_INPUT_OPERATION;
  6664. }
  6665. irp->RequestorMode = KernelMode;
  6666. irp->UserIosb = IoStatusBlock;
  6667. irp->UserEvent = Event;
  6668. irp->UserBuffer = (PVOID) ((PCHAR) MemoryDescriptorList->StartVa + MemoryDescriptorList->ByteOffset);
  6669. irp->Tail.Overlay.OriginalFileObject = FileObject;
  6670. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  6671. //
  6672. // Fill in the normal read parameters.
  6673. //
  6674. irpSp->MajorFunction = IRP_MJ_READ;
  6675. irpSp->FileObject = FileObject;
  6676. irpSp->Parameters.Read.Length = MemoryDescriptorList->ByteCount;
  6677. irpSp->Parameters.Read.ByteOffset = *StartingOffset;
  6678. //
  6679. // For debugging purposes.
  6680. //
  6681. IoStatusBlock->Information = (ULONG_PTR)irp;
  6682. //
  6683. // Queue the packet to the appropriate driver based on whether or not there
  6684. // is a VPB associated with the device.
  6685. //
  6686. return IoCallDriver( deviceObject, irp );
  6687. }
  6688. NTSTATUS
  6689. IoPageRead(
  6690. IN PFILE_OBJECT FileObject,
  6691. IN PMDL MemoryDescriptorList,
  6692. IN PLARGE_INTEGER StartingOffset,
  6693. IN PKEVENT Event,
  6694. OUT PIO_STATUS_BLOCK IoStatusBlock
  6695. )
  6696. {
  6697. return IopPageReadInternal(FileObject,
  6698. MemoryDescriptorList,
  6699. StartingOffset,
  6700. Event,
  6701. IoStatusBlock,
  6702. FALSE
  6703. );
  6704. }
  6705. NTSTATUS
  6706. IoQueryFileInformation(
  6707. IN PFILE_OBJECT FileObject,
  6708. IN FILE_INFORMATION_CLASS FileInformationClass,
  6709. IN ULONG Length,
  6710. OUT PVOID FileInformation,
  6711. OUT PULONG ReturnedLength
  6712. )
  6713. /*++
  6714. Routine Description:
  6715. This routine returns the requested information about a specified file.
  6716. The information returned is determined by the FileInformationClass that
  6717. is specified, and it is placed into the caller's FileInformation buffer.
  6718. Arguments:
  6719. FileObject - Supplies a pointer to the file object about which the requested
  6720. information is returned.
  6721. FileInformationClass - Specifies the type of information which should be
  6722. returned about the file.
  6723. Length - Supplies the length, in bytes, of the FileInformation buffer.
  6724. FileInformation - Supplies a buffer to receive the requested information
  6725. returned about the file. This buffer must not be pageable and must
  6726. reside in system space.
  6727. ReturnedLength - Supplies a variable that is to receive the length of the
  6728. information written to the FileInformation buffer.
  6729. Return Value:
  6730. The status returned is the final completion status of the operation.
  6731. --*/
  6732. {
  6733. PAGED_CODE();
  6734. //
  6735. // Simply invoke the common routine to perform the query operation.
  6736. //
  6737. return IopQueryXxxInformation( FileObject,
  6738. FileInformationClass,
  6739. Length,
  6740. FileInformation,
  6741. ReturnedLength,
  6742. TRUE );
  6743. }
  6744. NTSTATUS
  6745. IoQueryVolumeInformation(
  6746. IN PFILE_OBJECT FileObject,
  6747. IN FS_INFORMATION_CLASS FsInformationClass,
  6748. IN ULONG Length,
  6749. OUT PVOID FsInformation,
  6750. OUT PULONG ReturnedLength
  6751. )
  6752. /*++
  6753. Routine Description:
  6754. This routine returns the requested information about a specified volume.
  6755. The information returned is determined by the FsInformationClass that
  6756. is specified, and it is placed into the caller's FsInformation buffer.
  6757. Arguments:
  6758. FileObject - Supplies a pointer to the file object about which the requested
  6759. information is returned.
  6760. FsInformationClass - Specifies the type of information which should be
  6761. returned about the volume.
  6762. Length - Supplies the length of the FsInformation buffer in bytes.
  6763. FsInformation - Supplies a buffer to receive the requested information
  6764. returned about the file. This buffer must not be pageable and must
  6765. reside in system space.
  6766. ReturnedLength - Supplies a variable that is to receive the length of the
  6767. information written to the FsInformation buffer.
  6768. Return Value:
  6769. The status returned is the final completion status of the operation.
  6770. --*/
  6771. {
  6772. PAGED_CODE();
  6773. //
  6774. // Simply invoke the common routine to perform the query operation.
  6775. //
  6776. return IopQueryXxxInformation( FileObject,
  6777. FsInformationClass,
  6778. Length,
  6779. FsInformation,
  6780. ReturnedLength,
  6781. FALSE );
  6782. }
  6783. VOID
  6784. IoQueueThreadIrp(
  6785. IN PIRP Irp
  6786. )
  6787. /*++
  6788. Routine Description:
  6789. This routine queues the specified I/O Request Packet (IRP) to the current
  6790. thread's IRP pending queue. This queue locates all of the outstanding
  6791. I/O requests for the thread.
  6792. Arguments:
  6793. Irp - Pointer to the I/O Request Packet (IRP) to be queued.
  6794. Return Value:
  6795. None.
  6796. --*/
  6797. {
  6798. //
  6799. // Simply queue the packet using the internal queueing routine.
  6800. //
  6801. IopQueueThreadIrp( Irp );
  6802. }
  6803. VOID
  6804. IoRaiseHardError(
  6805. IN PIRP Irp,
  6806. IN PVPB Vpb OPTIONAL,
  6807. IN PDEVICE_OBJECT RealDeviceObject
  6808. )
  6809. /*++
  6810. Routine Description:
  6811. This routine pops up a hard error in the context of the thread that
  6812. originally requested the I/O operation specified by the input IRP. This
  6813. is done by queueing a kernel APC to the original thread, passing it a
  6814. pointer to the device objects and the IRP. Once the pop up is performed,
  6815. the routine either completes the I/O request then, or it calls the driver
  6816. back with the same IRP.
  6817. If the original request was an IoPageRead, then it was at APC level and
  6818. we have to create a thread to "hold" this pop-up. Note that we have to
  6819. queue to an ExWorker thread to create the thread since this can only be
  6820. done from the system process.
  6821. Arguments:
  6822. Irp - A pointer to the I/O Request Packet (IRP) for the request that
  6823. failed.
  6824. Vpb - This is the volume parameter block of the offending media. If the
  6825. media not yet mounted, this parameter should be absent.
  6826. RealDeviceObject - A pointer to the device object that represents the
  6827. device that the file system believes it has mounted. This is
  6828. generally the "real" device object in the VPB, but may, in fact,
  6829. be a device object attached to the physical device.
  6830. Return Value:
  6831. None.
  6832. --*/
  6833. {
  6834. PIO_STACK_LOCATION IrpSp;
  6835. //
  6836. // If pop-ups are disabled for the requesting thread, just complete the
  6837. // request.
  6838. //
  6839. if ((Irp->Tail.Overlay.Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) != 0) {
  6840. //
  6841. // An error was incurred, so zero out the information field before
  6842. // completing the request if this was an input operation. Otherwise,
  6843. // IopCompleteRequest will try to copy to the user's buffer.
  6844. //
  6845. if (Irp->Flags & IRP_INPUT_OPERATION) {
  6846. Irp->IoStatus.Information = 0;
  6847. }
  6848. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  6849. return;
  6850. }
  6851. //
  6852. // If this Irp resulted from a call to IoPageRead(), the caller must
  6853. // have been at APC level, so don't try enqueing an APC.
  6854. //
  6855. // Also if this is a cleanup Irp, force this pop-up to go to the new
  6856. // thread so that it cannot be disabled.
  6857. //
  6858. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  6859. if ((Irp->Flags == (IRP_PAGING_IO |
  6860. IRP_NOCACHE |
  6861. IRP_SYNCHRONOUS_PAGING_IO |
  6862. IRP_INPUT_OPERATION)) ||
  6863. (IrpSp->MajorFunction == IRP_MJ_CLEANUP)) {
  6864. PIOP_APC_HARD_ERROR_PACKET packet;
  6865. packet = ExAllocatePoolWithTag( NonPagedPool,
  6866. sizeof( IOP_APC_HARD_ERROR_PACKET ),
  6867. 'rEoI' );
  6868. if ( packet == NULL ) {
  6869. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  6870. return;
  6871. }
  6872. ExInitializeWorkItem( &packet->Item, IopStartApcHardError, packet );
  6873. packet->Irp = Irp;
  6874. packet->Vpb = Vpb;
  6875. packet->RealDeviceObject = RealDeviceObject;
  6876. ExQueueWorkItem( &packet->Item, CriticalWorkQueue );
  6877. } else {
  6878. PKAPC apc;
  6879. //
  6880. // Begin by allocating and initializing an APC that can be sent to the
  6881. // target thread.
  6882. //
  6883. apc = ExAllocatePoolWithTag( NonPagedPool, sizeof( KAPC ), 'CPAK' );
  6884. //
  6885. // If we could not get the pool, we have no choice but to just complete
  6886. // the Irp, thereby passing the error onto the caller.
  6887. //
  6888. if ( apc == NULL ) {
  6889. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  6890. return;
  6891. }
  6892. KeInitializeApc( apc,
  6893. &Irp->Tail.Overlay.Thread->Tcb,
  6894. Irp->ApcEnvironment,
  6895. IopDeallocateApc,
  6896. IopAbortRequest,
  6897. IopRaiseHardError,
  6898. KernelMode,
  6899. Irp );
  6900. (VOID) KeInsertQueueApc( apc,
  6901. Vpb,
  6902. RealDeviceObject,
  6903. 0 );
  6904. }
  6905. }
  6906. BOOLEAN
  6907. IoRaiseInformationalHardError(
  6908. IN NTSTATUS ErrorStatus,
  6909. IN PUNICODE_STRING String OPTIONAL,
  6910. IN PKTHREAD Thread OPTIONAL
  6911. )
  6912. /*++
  6913. Routine Description:
  6914. This routine pops up a hard error in the hard error popup thread. The
  6915. routine returns immediately, enqueuing the actual pop-up to a worker
  6916. thread. The hard error that is raised is informational in the sense that
  6917. only the OK button is displayed.
  6918. Arguments:
  6919. ErrorStatus - The error condition.
  6920. String - Depending on the error, a string may have to be enqueued.
  6921. Thread - If present, enqueue an APC to this thread rather than using
  6922. the hard error thread.
  6923. Return Value:
  6924. BOOLEAN - TRUE if we decided to dispatch a pop-up. FALSE if we decided
  6925. not to because:
  6926. - pop-ups are disabled in the requested thread, or
  6927. - a pool allocation failed, or
  6928. - an equivalent pop-up is currently pending a user response (i.e.
  6929. waiting for the user to press <OK>) or in the queue, or
  6930. - too many pop-ups have already been queued.
  6931. --*/
  6932. //
  6933. // This macro compares two pop-ups to see if they are content equivalent.
  6934. //
  6935. #define ArePacketsEquivalent(P1,P2) ( \
  6936. (P1->ErrorStatus == P2->ErrorStatus) && \
  6937. ((!P1->String.Buffer && !P2->String.Buffer) || \
  6938. ((P1->String.Length == P2->String.Length) && \
  6939. (RtlEqualMemory(P1->String.Buffer, \
  6940. P2->String.Buffer, \
  6941. P1->String.Length)))) \
  6942. )
  6943. {
  6944. KIRQL oldIrql;
  6945. PVOID stringBuffer;
  6946. PLIST_ENTRY links;
  6947. PIOP_HARD_ERROR_PACKET hardErrorPacket;
  6948. //
  6949. // If pop-ups are disabled for the requesting thread, just return.
  6950. //
  6951. if (ARGUMENT_PRESENT(Thread) ?
  6952. ((CONTAINING_RECORD(Thread, ETHREAD, Tcb)->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) != 0) :
  6953. ((PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) != 0)) {
  6954. return FALSE;
  6955. }
  6956. //
  6957. // If this is one of those special error popup codes that CSRSS expects
  6958. // to be called with a correct set of arguments, disallow from a driver
  6959. //
  6960. if ( ErrorStatus == STATUS_VDM_HARD_ERROR ||
  6961. ErrorStatus == STATUS_UNHANDLED_EXCEPTION ||
  6962. ErrorStatus == STATUS_SERVICE_NOTIFICATION ) {
  6963. return FALSE;
  6964. }
  6965. //
  6966. // If this request is going to be sent to the hard error thread, and
  6967. // there are more than 25 entries already in the queue, don't
  6968. // add any more. We'll do another safe check later on.
  6969. //
  6970. if ( !ARGUMENT_PRESENT( Thread ) &&
  6971. (KeReadStateSemaphore( &IopHardError.WorkQueueSemaphore ) >=
  6972. IOP_MAXIMUM_OUTSTANDING_HARD_ERRORS) ) {
  6973. return FALSE;
  6974. } else {
  6975. if (IopHardError.NumPendingApcPopups > IOP_MAXIMUM_OUTSTANDING_HARD_ERRORS) {
  6976. return FALSE;
  6977. }
  6978. }
  6979. //
  6980. // Allocate the packet, and a buffer for the string if present.
  6981. //
  6982. hardErrorPacket = ExAllocatePoolWithTag( NonPagedPool,
  6983. sizeof(IOP_HARD_ERROR_PACKET),
  6984. 'rEoI');
  6985. if (!hardErrorPacket) { return FALSE; }
  6986. //
  6987. // Zero out the packet and fill the NT_STATUS we will pop up.
  6988. //
  6989. RtlZeroMemory( hardErrorPacket, sizeof(IOP_HARD_ERROR_PACKET) );
  6990. hardErrorPacket->ErrorStatus = ErrorStatus;
  6991. //
  6992. // If there is a string, copy it.
  6993. //
  6994. if ( ARGUMENT_PRESENT( String ) && String->Length ) {
  6995. stringBuffer = ExAllocatePoolWithTag( NonPagedPool,
  6996. String->Length,
  6997. 'rEoI' );
  6998. if (!stringBuffer) {
  6999. ExFreePool( hardErrorPacket );
  7000. return FALSE;
  7001. }
  7002. hardErrorPacket->String.Length = String->Length;
  7003. hardErrorPacket->String.MaximumLength = String->Length;
  7004. hardErrorPacket->String.Buffer = stringBuffer;
  7005. RtlCopyMemory( stringBuffer, String->Buffer, String->Length );
  7006. }
  7007. //
  7008. // If there is an Thread, enqueue an APC for ourself, otherwise send
  7009. // it off to the to the hard error thread.
  7010. //
  7011. if ( ARGUMENT_PRESENT( Thread ) ) {
  7012. PKAPC apc;
  7013. //
  7014. // Begin by allocating and initializing an APC that can be sent to the
  7015. // target thread.
  7016. //
  7017. apc = ExAllocatePoolWithTag( NonPagedPool, sizeof( KAPC ), 'CPAK' );
  7018. //
  7019. // If we could not get the pool, we have no choice but to just
  7020. // free the packet and return.
  7021. //
  7022. if ( apc == NULL ) {
  7023. if ( hardErrorPacket->String.Buffer ) {
  7024. ExFreePool( hardErrorPacket->String.Buffer );
  7025. }
  7026. ExFreePool( hardErrorPacket );
  7027. return FALSE;
  7028. }
  7029. InterlockedIncrement(&IopHardError.NumPendingApcPopups);
  7030. KeInitializeApc( apc,
  7031. Thread,
  7032. OriginalApcEnvironment,
  7033. IopDeallocateApc,
  7034. NULL,
  7035. IopRaiseInformationalHardError,
  7036. KernelMode,
  7037. hardErrorPacket );
  7038. (VOID) KeInsertQueueApc( apc, NULL, NULL, 0 );
  7039. } else {
  7040. //
  7041. // Get exclusive access to the work queue.
  7042. //
  7043. ExAcquireSpinLock( &IopHardError.WorkQueueSpinLock, &oldIrql );
  7044. //
  7045. // Check the Signal state again, if OK, go ahead and enqueue.
  7046. //
  7047. if ( KeReadStateSemaphore( &IopHardError.WorkQueueSemaphore ) >=
  7048. IOP_MAXIMUM_OUTSTANDING_HARD_ERRORS ) {
  7049. ExReleaseSpinLock( &IopHardError.WorkQueueSpinLock, oldIrql );
  7050. if ( hardErrorPacket->String.Buffer ) {
  7051. ExFreePool( hardErrorPacket->String.Buffer );
  7052. }
  7053. ExFreePool( hardErrorPacket );
  7054. return FALSE;
  7055. }
  7056. //
  7057. // If there is a pop-up currently up, check for a match
  7058. //
  7059. if (IopCurrentHardError &&
  7060. ArePacketsEquivalent( hardErrorPacket, IopCurrentHardError )) {
  7061. ExReleaseSpinLock( &IopHardError.WorkQueueSpinLock, oldIrql );
  7062. if ( hardErrorPacket->String.Buffer ) {
  7063. ExFreePool( hardErrorPacket->String.Buffer );
  7064. }
  7065. ExFreePool( hardErrorPacket );
  7066. return FALSE;
  7067. }
  7068. //
  7069. // Run down the list of queued pop-ups looking for a match.
  7070. //
  7071. links = IopHardError.WorkQueue.Flink;
  7072. while (links != &IopHardError.WorkQueue) {
  7073. PIOP_HARD_ERROR_PACKET queueHardErrorPacket;
  7074. queueHardErrorPacket = CONTAINING_RECORD( links,
  7075. IOP_HARD_ERROR_PACKET,
  7076. WorkQueueLinks );
  7077. if (ArePacketsEquivalent( hardErrorPacket,
  7078. queueHardErrorPacket )) {
  7079. ExReleaseSpinLock( &IopHardError.WorkQueueSpinLock, oldIrql );
  7080. if ( hardErrorPacket->String.Buffer ) {
  7081. ExFreePool( hardErrorPacket->String.Buffer );
  7082. }
  7083. ExFreePool( hardErrorPacket );
  7084. return FALSE;
  7085. }
  7086. links = links->Flink;
  7087. }
  7088. //
  7089. // Enqueue this packet.
  7090. //
  7091. InsertTailList( &IopHardError.WorkQueue,
  7092. &hardErrorPacket->WorkQueueLinks );
  7093. //
  7094. // Bump the count on the semaphore so that the hard error thread
  7095. // will know that an entry has been placed in the queue.
  7096. //
  7097. (VOID) KeReleaseSemaphore( &IopHardError.WorkQueueSemaphore,
  7098. 0,
  7099. 1L,
  7100. FALSE );
  7101. //
  7102. // If we are not currently running in an ExWorkerThread, queue
  7103. // a work item.
  7104. //
  7105. if ( !IopHardError.ThreadStarted ) {
  7106. IopHardError.ThreadStarted = TRUE;
  7107. ExQueueWorkItem( &IopHardError.ExWorkItem, DelayedWorkQueue );
  7108. }
  7109. //
  7110. // Finally, release the spinlockevent, allowing access to the work queue again.
  7111. // The combination of releasing both the event and the semaphore will
  7112. // enable the thread to wake up and obtain the entry.
  7113. //
  7114. ExReleaseSpinLock( &IopHardError.WorkQueueSpinLock, oldIrql );
  7115. }
  7116. return TRUE;
  7117. }
  7118. VOID
  7119. IoRegisterBootDriverReinitialization(
  7120. IN PDRIVER_OBJECT DriverObject,
  7121. IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
  7122. IN PVOID Context
  7123. )
  7124. /*++
  7125. Routine Description:
  7126. This routine is invoked by boot drivers during their initialization or
  7127. during their reinitialization to register with the I/O system to be
  7128. called again once all devices have been enumerated and started.
  7129. Note that it is possible for this to occur during a normally running
  7130. system, if the driver is loaded dynamically, so all references to the
  7131. reinitialization queue must be synchronized.
  7132. Arguments:
  7133. DriverObject - Pointer to the driver's driver object.
  7134. DriverReinitializationRoutine - The address of the reinitialization
  7135. routine that is to be invoked.
  7136. Context - Pointer to the context that is passed to the driver's
  7137. reinitialization routine.
  7138. Return Value:
  7139. None.
  7140. --*/
  7141. {
  7142. PREINIT_PACKET reinitEntry;
  7143. PAGED_CODE();
  7144. //
  7145. // Allocate a reinitialization entry to be inserted onto the list. Note
  7146. // that if the entry cannot be allocated, then the request is simply
  7147. // dropped on the floor.
  7148. //
  7149. reinitEntry = ExAllocatePoolWithTag( NonPagedPool,
  7150. sizeof( REINIT_PACKET ),
  7151. 'iRoI' );
  7152. if (!reinitEntry) {
  7153. return;
  7154. }
  7155. DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
  7156. reinitEntry->DriverObject = DriverObject;
  7157. reinitEntry->DriverReinitializationRoutine = DriverReinitializationRoutine;
  7158. reinitEntry->Context = Context;
  7159. IopInterlockedInsertTailList( &IopBootDriverReinitializeQueueHead,
  7160. &reinitEntry->ListEntry );
  7161. }
  7162. VOID
  7163. IoRegisterDriverReinitialization(
  7164. IN PDRIVER_OBJECT DriverObject,
  7165. IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
  7166. IN PVOID Context
  7167. )
  7168. /*++
  7169. Routine Description:
  7170. This routine is invoked by drivers during their initialization or during
  7171. their reinitialization to register with the I/O system to be called again
  7172. before I/O system initialization is complete. Note that it is possible
  7173. for this to occur during a normally running system, if the driver is
  7174. loaded dynamically, so all references to the reinitialization queue must
  7175. be synchronized.
  7176. Arguments:
  7177. DriverObject - Pointer to the driver's driver object.
  7178. DriverReinitializationRoutine - The address of the reinitialization
  7179. routine that is to be invoked.
  7180. Context - Pointer to the context that is passed to the driver's
  7181. reinitialization routine.
  7182. Return Value:
  7183. None.
  7184. --*/
  7185. {
  7186. PREINIT_PACKET reinitEntry;
  7187. PAGED_CODE();
  7188. //
  7189. // Allocate a reinitialization entry to be inserted onto the list. Note
  7190. // that if the entry cannot be allocated, then the request is simply
  7191. // dropped on the floor.
  7192. //
  7193. reinitEntry = ExAllocatePoolWithTag( NonPagedPool,
  7194. sizeof( REINIT_PACKET ),
  7195. 'iRoI' );
  7196. if (!reinitEntry) {
  7197. return;
  7198. }
  7199. DriverObject->Flags |= DRVO_REINIT_REGISTERED;
  7200. reinitEntry->DriverObject = DriverObject;
  7201. reinitEntry->DriverReinitializationRoutine = DriverReinitializationRoutine;
  7202. reinitEntry->Context = Context;
  7203. IopInterlockedInsertTailList( &IopDriverReinitializeQueueHead,
  7204. &reinitEntry->ListEntry );
  7205. }
  7206. VOID
  7207. IoRegisterFileSystem(
  7208. IN OUT PDEVICE_OBJECT DeviceObject
  7209. )
  7210. /*++
  7211. Routine Description:
  7212. This routine inserts the device object for the file system which the device
  7213. object represents into the list of file systems in the system.
  7214. Arguments:
  7215. DeviceObject - Pointer to device object for the file system.
  7216. Return Value:
  7217. None.
  7218. --*/
  7219. {
  7220. PNOTIFICATION_PACKET nPacket;
  7221. PLIST_ENTRY listHead = NULL;
  7222. PLIST_ENTRY entry;
  7223. PAGED_CODE();
  7224. //
  7225. // Allocate the I/O database resource for a write operation.
  7226. //
  7227. (VOID) ExAcquireResourceExclusiveLite( &IopDatabaseResource, TRUE );
  7228. //
  7229. // Insert the device object into the appropriate file system queue based on
  7230. // the driver type in the device object. Notice that if the device type is
  7231. // unrecognized, the file system is simply not registered.
  7232. //
  7233. if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) {
  7234. listHead = &IopNetworkFileSystemQueueHead;
  7235. } else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
  7236. listHead = &IopCdRomFileSystemQueueHead;
  7237. DeviceObject->DriverObject->Flags |= DRVO_BASE_FILESYSTEM_DRIVER;
  7238. } else if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
  7239. listHead = &IopDiskFileSystemQueueHead;
  7240. DeviceObject->DriverObject->Flags |= DRVO_BASE_FILESYSTEM_DRIVER;
  7241. } else if (DeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) {
  7242. listHead = &IopTapeFileSystemQueueHead;
  7243. DeviceObject->DriverObject->Flags |= DRVO_BASE_FILESYSTEM_DRIVER;
  7244. }
  7245. //
  7246. // Low priority filesystems are inserted one-from-back on the queue (ahead of
  7247. // raw, behind everything else), as opposed to on the front.
  7248. //
  7249. if (listHead != NULL) {
  7250. if (DeviceObject->Flags & DO_LOW_PRIORITY_FILESYSTEM ) {
  7251. InsertTailList( listHead->Blink,
  7252. &DeviceObject->Queue.ListEntry );
  7253. } else {
  7254. InsertHeadList( listHead,
  7255. &DeviceObject->Queue.ListEntry );
  7256. }
  7257. }
  7258. IopFsRegistrationOps++;
  7259. //
  7260. // Ensure that this file system's device is operable.
  7261. //
  7262. DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  7263. //
  7264. // Notify all of the registered drivers that this file system has been
  7265. // registered as an active file system of some type.
  7266. //
  7267. entry = IopFsNotifyChangeQueueHead.Flink;
  7268. while (entry != &IopFsNotifyChangeQueueHead) {
  7269. nPacket = CONTAINING_RECORD( entry, NOTIFICATION_PACKET, ListEntry );
  7270. entry = entry->Flink;
  7271. nPacket->NotificationRoutine( DeviceObject, TRUE );
  7272. }
  7273. //
  7274. // Release the I/O database resource.
  7275. //
  7276. ExReleaseResourceLite( &IopDatabaseResource );
  7277. //
  7278. // Increment the number of reasons that this driver cannot be unloaded.
  7279. //
  7280. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  7281. &DeviceObject->ReferenceCount );
  7282. }
  7283. VOID
  7284. IopNotifyAlreadyRegisteredFileSystems(
  7285. IN PLIST_ENTRY ListHead,
  7286. IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine,
  7287. IN BOOLEAN SkipRaw
  7288. )
  7289. /*++
  7290. Routine Description:
  7291. This routine calls the driver notification routine for filesystems
  7292. that have already been registered at the time of the call.
  7293. Arguments:
  7294. ListHead - Pointer to the filesystem registration list head.
  7295. DriverNotificationRoutine - Pointer to the routine that has to be called.
  7296. Return Value:
  7297. None.
  7298. --*/
  7299. {
  7300. PLIST_ENTRY entry;
  7301. PDEVICE_OBJECT fsDeviceObject;
  7302. entry = ListHead->Flink;
  7303. while (entry != ListHead) {
  7304. //
  7305. // Skip raw filesystem notification
  7306. //
  7307. if ((entry->Flink == ListHead) && (SkipRaw)) {
  7308. break;
  7309. }
  7310. fsDeviceObject = CONTAINING_RECORD( entry, DEVICE_OBJECT, Queue.ListEntry );
  7311. entry = entry->Flink;
  7312. DriverNotificationRoutine( fsDeviceObject, TRUE );
  7313. }
  7314. }
  7315. NTSTATUS
  7316. IoRegisterFsRegistrationChange(
  7317. IN PDRIVER_OBJECT DriverObject,
  7318. IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
  7319. )
  7320. /*++
  7321. Routine Description:
  7322. This routine registers the specified driver's notification routine to be
  7323. invoked whenever a file system registers or unregisters itself as an active
  7324. file system in the system.
  7325. Arguments:
  7326. DriverObject - Pointer to the driver object for the driver.
  7327. DriverNotificationRoutine - Address of routine to invoke when a file system
  7328. registers or unregisters itself.
  7329. Return Value:
  7330. The return status is the final value of the function.
  7331. --*/
  7332. {
  7333. PNOTIFICATION_PACKET nPacket;
  7334. PAGED_CODE();
  7335. //
  7336. // Begin by attempting to allocate storage for the shutdown packet. If
  7337. // one cannot be allocated, simply return an appropriate error.
  7338. //
  7339. nPacket = ExAllocatePoolWithTag( PagedPool|POOL_COLD_ALLOCATION,
  7340. sizeof( NOTIFICATION_PACKET ),
  7341. 'sFoI' );
  7342. if (!nPacket) {
  7343. return STATUS_INSUFFICIENT_RESOURCES;
  7344. }
  7345. //
  7346. // Initialize the notification packet and insert it onto the tail of the
  7347. // list.
  7348. //
  7349. nPacket->DriverObject = DriverObject;
  7350. nPacket->NotificationRoutine = DriverNotificationRoutine;
  7351. ExAcquireResourceExclusiveLite( &IopDatabaseResource, TRUE );
  7352. InsertTailList( &IopFsNotifyChangeQueueHead, &nPacket->ListEntry );
  7353. IopNotifyAlreadyRegisteredFileSystems(&IopNetworkFileSystemQueueHead, DriverNotificationRoutine, FALSE);
  7354. IopNotifyAlreadyRegisteredFileSystems(&IopCdRomFileSystemQueueHead, DriverNotificationRoutine, TRUE);
  7355. IopNotifyAlreadyRegisteredFileSystems(&IopDiskFileSystemQueueHead, DriverNotificationRoutine, TRUE);
  7356. IopNotifyAlreadyRegisteredFileSystems(&IopTapeFileSystemQueueHead, DriverNotificationRoutine, TRUE);
  7357. //
  7358. // Notify this driver about all already notified filesystems
  7359. // registered as an active file system of some type.
  7360. //
  7361. ExReleaseResourceLite( &IopDatabaseResource );
  7362. //
  7363. // Increment the number of reasons that this driver cannot be unloaded.
  7364. //
  7365. ObReferenceObject( DriverObject );
  7366. return STATUS_SUCCESS;
  7367. }
  7368. NTSTATUS
  7369. IoRegisterLastChanceShutdownNotification(
  7370. IN PDEVICE_OBJECT DeviceObject
  7371. )
  7372. /*++
  7373. Routine Description:
  7374. This routine allows a driver to register that it would like to have its
  7375. shutdown routine invoked at very late in system shutdown. This gives
  7376. the driver an opportunity to get control just before the system is fully
  7377. shutdown.
  7378. Arguments:
  7379. DeviceObject - Pointer to the driver's device object.
  7380. Return Value:
  7381. None.
  7382. --*/
  7383. {
  7384. PSHUTDOWN_PACKET shutdown;
  7385. PAGED_CODE();
  7386. //
  7387. // Begin by attempting to allocate storage for the shutdown packet. If
  7388. // one cannot be allocated, simply return an appropriate error.
  7389. //
  7390. shutdown = ExAllocatePoolWithTag( NonPagedPool,
  7391. sizeof( SHUTDOWN_PACKET ),
  7392. 'hSoI' );
  7393. if (!shutdown) {
  7394. return STATUS_INSUFFICIENT_RESOURCES;
  7395. }
  7396. //
  7397. // Initialize the shutdown packet and insert it onto the head of the list.
  7398. // Note that this is done because some drivers have dependencies on LIFO
  7399. // notification ordering.
  7400. //
  7401. ObReferenceObject(DeviceObject); // Ensure that the driver remains
  7402. shutdown->DeviceObject = DeviceObject;
  7403. IopInterlockedInsertHeadList( &IopNotifyLastChanceShutdownQueueHead,
  7404. &shutdown->ListEntry );
  7405. //
  7406. // Do the bookkeeping to indicate that this driver has successfully
  7407. // registered a shutdown notification routine.
  7408. //
  7409. DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
  7410. return STATUS_SUCCESS;
  7411. }
  7412. NTSTATUS
  7413. IoRegisterShutdownNotification(
  7414. IN PDEVICE_OBJECT DeviceObject
  7415. )
  7416. /*++
  7417. Routine Description:
  7418. This routine allows a driver to register that it would like to have its
  7419. shutdown routine invoked when the system is being shutdown. This gives
  7420. the driver an opportunity to get control just before the system is fully
  7421. shutdown.
  7422. Arguments:
  7423. DeviceObject - Pointer to the driver's device object.
  7424. Return Value:
  7425. None.
  7426. --*/
  7427. {
  7428. PSHUTDOWN_PACKET shutdown;
  7429. PAGED_CODE();
  7430. //
  7431. // Begin by attempting to allocate storage for the shutdown packet. If
  7432. // one cannot be allocated, simply return an appropriate error.
  7433. //
  7434. shutdown = ExAllocatePoolWithTag( NonPagedPool,
  7435. sizeof( SHUTDOWN_PACKET ),
  7436. 'hSoI' );
  7437. if (!shutdown) {
  7438. return STATUS_INSUFFICIENT_RESOURCES;
  7439. }
  7440. //
  7441. // Initialize the shutdown packet and insert it onto the head of the list.
  7442. // Note that this is done because some drivers have dependencies on LIFO
  7443. // notification ordering.
  7444. //
  7445. shutdown->DeviceObject = DeviceObject;
  7446. ObReferenceObject(DeviceObject); // Ensure that the driver remains
  7447. IopInterlockedInsertHeadList( &IopNotifyShutdownQueueHead,
  7448. &shutdown->ListEntry );
  7449. //
  7450. // Do the bookkeeping to indicate that this driver has successfully
  7451. // registered a shutdown notification routine.
  7452. //
  7453. DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
  7454. return STATUS_SUCCESS;
  7455. }
  7456. VOID
  7457. IoReleaseCancelSpinLock(
  7458. IN KIRQL Irql
  7459. )
  7460. /*++
  7461. Routine Description:
  7462. This routine is invoked to release the cancel spin lock. This spin lock
  7463. must be acquired before setting the address of a cancel routine in an
  7464. IRP and released after the cancel routine has been set.
  7465. Arguments:
  7466. Irql - Supplies the IRQL value returned from acquiring the spin lock.
  7467. Return Value:
  7468. None.
  7469. --*/
  7470. {
  7471. //
  7472. // Simply release the cancel spin lock.
  7473. //
  7474. KeReleaseQueuedSpinLock( LockQueueIoCancelLock, Irql );
  7475. }
  7476. VOID
  7477. IoReleaseVpbSpinLock(
  7478. IN KIRQL Irql
  7479. )
  7480. /*++
  7481. Routine Description:
  7482. This routine is invoked to release the Volume Parameter Block (VPB) spin
  7483. lock. This spin lock must be acquired before accessing the mount flag,
  7484. reference count, and device object fields of a VPB.
  7485. Arguments:
  7486. Irql - Supplies the IRQL value returned from acquiring the spin lock.
  7487. Return Value:
  7488. None.
  7489. --*/
  7490. {
  7491. //
  7492. // Simply release the VPB spin lock.
  7493. //
  7494. KeReleaseQueuedSpinLock( LockQueueIoVpbLock, Irql );
  7495. }
  7496. VOID
  7497. IoRemoveShareAccess(
  7498. IN PFILE_OBJECT FileObject,
  7499. IN OUT PSHARE_ACCESS ShareAccess
  7500. )
  7501. /*++
  7502. Routine Description:
  7503. This routine is invoked to remove the access and share access information
  7504. in a file system Share Access structure for a given open instance.
  7505. Arguments:
  7506. FileObject - Pointer to the file object of the current access being closed.
  7507. ShareAccess - Pointer to the share access structure that describes
  7508. how the file is currently being accessed.
  7509. Return Value:
  7510. None.
  7511. --*/
  7512. {
  7513. PAGED_CODE();
  7514. //
  7515. // If this accessor wanted some type of access other than READ_ or
  7516. // WRITE_ATTRIBUTES, then account for the fact that he has closed the
  7517. // file. Otherwise, he hasn't been accounted for in the first place
  7518. // so don't do anything.
  7519. //
  7520. //
  7521. // If this is a special filter fileobject ignore share access check if necessary.
  7522. //
  7523. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  7524. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  7525. if (fileObjectExtension->FileObjectExtensionFlags & FO_EXTENSION_IGNORE_SHARE_ACCESS_CHECK) {
  7526. return;
  7527. }
  7528. }
  7529. if (FileObject->ReadAccess ||
  7530. FileObject->WriteAccess ||
  7531. FileObject->DeleteAccess) {
  7532. //
  7533. // Decrement the number of opens in the Share Access structure.
  7534. //
  7535. ShareAccess->OpenCount--;
  7536. //
  7537. // For each access type, decrement the appropriate count in the Share
  7538. // Access structure.
  7539. //
  7540. if (FileObject->ReadAccess) {
  7541. ShareAccess->Readers--;
  7542. }
  7543. if (FileObject->WriteAccess) {
  7544. ShareAccess->Writers--;
  7545. }
  7546. if (FileObject->DeleteAccess) {
  7547. ShareAccess->Deleters--;
  7548. }
  7549. //
  7550. // For each shared access type, decrement the appropriate count in the
  7551. // Share Access structure.
  7552. //
  7553. if (FileObject->SharedRead) {
  7554. ShareAccess->SharedRead--;
  7555. }
  7556. if (FileObject->SharedWrite) {
  7557. ShareAccess->SharedWrite--;
  7558. }
  7559. if (FileObject->SharedDelete) {
  7560. ShareAccess->SharedDelete--;
  7561. }
  7562. }
  7563. }
  7564. VOID
  7565. IoSetDeviceToVerify(
  7566. IN PETHREAD Thread,
  7567. IN PDEVICE_OBJECT DeviceObject
  7568. )
  7569. /*++
  7570. Routine Description:
  7571. This routine sets the device to verify field in the thread object. This
  7572. function is invoked by file systems to NULL this field, or to set it to
  7573. predefined values.
  7574. Arguments:
  7575. Thread - Pointer to the thread whose field is to be set.
  7576. DeviceObject - Pointer to the device to be verified, or NULL, or ...
  7577. Return Value:
  7578. None.
  7579. Note:
  7580. This function cannot be made a macro, since fields in the thread object
  7581. move from release to release, so this must remain a full function.
  7582. --*/
  7583. {
  7584. //
  7585. // Simply set the device to be verified in the specified thread.
  7586. //
  7587. Thread->DeviceToVerify = DeviceObject;
  7588. }
  7589. VOID
  7590. IoSetHardErrorOrVerifyDevice(
  7591. IN PIRP Irp,
  7592. IN PDEVICE_OBJECT DeviceObject
  7593. )
  7594. /*++
  7595. Routine Description:
  7596. This routine is invoked when a driver realizes that the media
  7597. has possibly changed on a device, and it must be verified before
  7598. continuing, or a hard error has occured. The device is stored
  7599. in the thread local storage of the Irp's originating thread.
  7600. Arguments:
  7601. Irp - Pointer to an I/O Request Packet to get the thread.
  7602. DeviceObject - This is the device that needs to be verified.
  7603. Return Value:
  7604. None.
  7605. --*/
  7606. {
  7607. //
  7608. // If the cancel flag is set in the IRP and thread is NULL
  7609. // ignore the verification. This is because its possible for the IO
  7610. // manager to dequeue the IRP from the thread list.
  7611. //
  7612. if (!(Irp->Tail.Overlay.Thread)) {
  7613. return;
  7614. }
  7615. //
  7616. // Store the address of the device object that needs verification in
  7617. // the appropriate field of the thread pointed to by the specified I/O
  7618. // Request Packet.
  7619. //
  7620. ASSERT( Irp->Tail.Overlay.Thread != NULL );
  7621. Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
  7622. }
  7623. NTSTATUS
  7624. IoSetInformation(
  7625. IN PFILE_OBJECT FileObject,
  7626. IN FILE_INFORMATION_CLASS FileInformationClass,
  7627. IN ULONG Length,
  7628. IN PVOID FileInformation
  7629. )
  7630. /*++
  7631. Routine Description:
  7632. This routine sets the requested information for the specified file.
  7633. The information that is set is determined by the FileInformationClass
  7634. paramter, and the information itself is passed in the FileInformation
  7635. buffer.
  7636. Arguments:
  7637. FileObject - Supplies a pointer to the file object for the file that
  7638. is to be changed.
  7639. FileInformationClass - Specifies the type of information that should
  7640. be set on the file.
  7641. Length - Supplies the length of the FileInformation buffer in bytes.
  7642. FileInformation - A buffer containing the file information to set. This
  7643. buffer must not be pageable and must reside in system space.
  7644. Return Value:
  7645. The status returned is the final completion status of the operation.
  7646. --*/
  7647. {
  7648. PIRP irp;
  7649. NTSTATUS status;
  7650. PDEVICE_OBJECT deviceObject;
  7651. KEVENT event;
  7652. PIO_STACK_LOCATION irpSp;
  7653. IO_STATUS_BLOCK localIoStatus;
  7654. HANDLE targetHandle = NULL;
  7655. BOOLEAN synchronousIo;
  7656. PAGED_CODE();
  7657. //
  7658. // Reference the file object here so that no special checks need be made
  7659. // in I/O completion to determine whether or not to dereference the file
  7660. // object.
  7661. //
  7662. ObReferenceObject( FileObject );
  7663. //
  7664. // Make a special check here to determine whether this is a synchronous
  7665. // I/O operation. If it is, then wait here until the file is owned by
  7666. // the current thread. If this is not a (serialized) synchronous I/O
  7667. // operation, then initialize the local event.
  7668. //
  7669. if (FileObject->Flags & FO_SYNCHRONOUS_IO) {
  7670. BOOLEAN interrupted;
  7671. if (!IopAcquireFastLock( FileObject )) {
  7672. status = IopAcquireFileObjectLock( FileObject,
  7673. KernelMode,
  7674. (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
  7675. &interrupted );
  7676. if (interrupted) {
  7677. ObDereferenceObject( FileObject );
  7678. return status;
  7679. }
  7680. }
  7681. KeClearEvent( &FileObject->Event );
  7682. synchronousIo = TRUE;
  7683. } else {
  7684. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  7685. synchronousIo = FALSE;
  7686. }
  7687. //
  7688. // Get the address of the target device object.
  7689. //
  7690. deviceObject = IoGetRelatedDeviceObject( FileObject );
  7691. //
  7692. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  7693. // The allocation is performed with an exception handler in case there is
  7694. // not enough memory to satisfy the request.
  7695. //
  7696. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  7697. if (!irp) {
  7698. //
  7699. // An IRP could not be allocated. Cleanup and return an appropriate
  7700. // error status code.
  7701. //
  7702. IopAllocateIrpCleanup( FileObject, (PKEVENT) NULL );
  7703. return STATUS_INSUFFICIENT_RESOURCES;
  7704. }
  7705. irp->Tail.Overlay.OriginalFileObject = FileObject;
  7706. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  7707. irp->RequestorMode = KernelMode;
  7708. //
  7709. // Fill in the service independent parameters in the IRP.
  7710. //
  7711. if (synchronousIo) {
  7712. irp->UserEvent = (PKEVENT) NULL;
  7713. } else {
  7714. irp->UserEvent = &event;
  7715. irp->Flags = IRP_SYNCHRONOUS_API;
  7716. }
  7717. irp->UserIosb = &localIoStatus;
  7718. //
  7719. // Get a pointer to the stack location for the first driver. This will be
  7720. // used to pass the original function codes and parameters.
  7721. //
  7722. irpSp = IoGetNextIrpStackLocation( irp );
  7723. irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
  7724. irpSp->FileObject = FileObject;
  7725. //
  7726. // Set the system buffer address to the address of the caller's buffer and
  7727. // set the flags so that the buffer is not deallocated.
  7728. //
  7729. irp->AssociatedIrp.SystemBuffer = FileInformation;
  7730. irp->Flags |= IRP_BUFFERED_IO;
  7731. //
  7732. // Copy the caller's parameters to the service-specific portion of the IRP.
  7733. //
  7734. irpSp->Parameters.SetFile.Length = Length;
  7735. irpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
  7736. //
  7737. // Insert the packet at the head of the IRP list for the thread.
  7738. //
  7739. IopQueueThreadIrp( irp );
  7740. //
  7741. // Everything is now set to invoke the device driver with this request.
  7742. // However, it is possible that the information that the caller wants to
  7743. // set is device independent (I/O system dependent). If this is the case,
  7744. // then the request can be satisfied here without having to have all of
  7745. // the drivers implement the same code. Note that having the IRP is still
  7746. // necessary since the I/O completion code requires it.
  7747. //
  7748. if (FileInformationClass == FileModeInformation) {
  7749. PFILE_MODE_INFORMATION modeBuffer = FileInformation;
  7750. //
  7751. // Set or clear the appropriate flags in the file object.
  7752. //
  7753. if (!(FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)) {
  7754. if (modeBuffer->Mode & FILE_WRITE_THROUGH) {
  7755. FileObject->Flags |= FO_WRITE_THROUGH;
  7756. } else {
  7757. FileObject->Flags &= ~FO_WRITE_THROUGH;
  7758. }
  7759. }
  7760. if (modeBuffer->Mode & FILE_SEQUENTIAL_ONLY) {
  7761. FileObject->Flags |= FO_SEQUENTIAL_ONLY;
  7762. } else {
  7763. FileObject->Flags &= ~FO_SEQUENTIAL_ONLY;
  7764. }
  7765. if (modeBuffer->Mode & FO_SYNCHRONOUS_IO) {
  7766. if (modeBuffer->Mode & FILE_SYNCHRONOUS_IO_ALERT) {
  7767. FileObject->Flags |= FO_ALERTABLE_IO;
  7768. } else {
  7769. FileObject->Flags &= ~FO_ALERTABLE_IO;
  7770. }
  7771. }
  7772. status = STATUS_SUCCESS;
  7773. //
  7774. // Complete the I/O operation.
  7775. //
  7776. irp->IoStatus.Status = status;
  7777. irp->IoStatus.Information = 0;
  7778. IoSetNextIrpStackLocation( irp );
  7779. IoCompleteRequest( irp, 0 );
  7780. } else if (FileInformationClass == FileRenameInformation ||
  7781. FileInformationClass == FileLinkInformation ||
  7782. FileInformationClass == FileMoveClusterInformation) {
  7783. //
  7784. // Note that the following code assumes that a rename information
  7785. // and a set link information structure look exactly the same.
  7786. //
  7787. PFILE_RENAME_INFORMATION renameBuffer = FileInformation;
  7788. //
  7789. // Copy the value of the replace BOOLEAN (or the ClusterCount field)
  7790. // from the caller's buffer to the I/O stack location parameter
  7791. // field where it is expected by file systems.
  7792. //
  7793. if (FileInformationClass == FileMoveClusterInformation) {
  7794. irpSp->Parameters.SetFile.ClusterCount =
  7795. ((FILE_MOVE_CLUSTER_INFORMATION *) renameBuffer)->ClusterCount;
  7796. } else {
  7797. irpSp->Parameters.SetFile.ReplaceIfExists = renameBuffer->ReplaceIfExists;
  7798. }
  7799. //
  7800. // Check to see whether or not a fully qualified pathname was supplied.
  7801. // If so, then more processing is required.
  7802. //
  7803. if (renameBuffer->FileName[0] == (UCHAR) OBJ_NAME_PATH_SEPARATOR ||
  7804. renameBuffer->RootDirectory != NULL) {
  7805. //
  7806. // A fully qualified file name was specified as the target of the
  7807. // rename operation. Attempt to open the target file and ensure
  7808. // that the replacement policy for the file is consistent with the
  7809. // caller's request, and ensure that the file is on the same volume.
  7810. //
  7811. status = IopOpenLinkOrRenameTarget( &targetHandle,
  7812. irp,
  7813. renameBuffer,
  7814. FileObject );
  7815. if (!NT_SUCCESS( status )) {
  7816. IoSetNextIrpStackLocation( irp );
  7817. IoCompleteRequest( irp, 2 );
  7818. } else {
  7819. //
  7820. // The fully qualified file name specifies a file on the same
  7821. // volume and if it exists, then the caller specified that it
  7822. // should be replaced.
  7823. //
  7824. status = IoCallDriver( deviceObject, irp );
  7825. }
  7826. } else {
  7827. //
  7828. // This is a simple rename operation, so call the driver and let
  7829. // it perform the rename operation within the same directory as
  7830. // the source file.
  7831. //
  7832. status = IoCallDriver( deviceObject, irp );
  7833. }
  7834. } else {
  7835. //
  7836. // This is not a request that can be performed here, so invoke the
  7837. // driver at its appropriate dispatch entry with the IRP.
  7838. //
  7839. status = IoCallDriver( deviceObject, irp );
  7840. }
  7841. //
  7842. // If this operation was a synchronous I/O operation, check the return
  7843. // status to determine whether or not to wait on the file object. If
  7844. // the file object is to be waited on, wait for the operation to complete
  7845. // and obtain the final status from the file object itself.
  7846. //
  7847. if (synchronousIo) {
  7848. if (status == STATUS_PENDING) {
  7849. status = KeWaitForSingleObject( &FileObject->Event,
  7850. Executive,
  7851. KernelMode,
  7852. (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
  7853. (PLARGE_INTEGER) NULL );
  7854. if (status == STATUS_ALERTED) {
  7855. IopCancelAlertedRequest( &FileObject->Event, irp );
  7856. }
  7857. status = localIoStatus.Status;
  7858. }
  7859. IopReleaseFileObjectLock( FileObject );
  7860. } else {
  7861. //
  7862. // This is a normal synchronous I/O operation, as opposed to a
  7863. // serialized synchronous I/O operation. For this case, wait for
  7864. // the local event and copy the final status information back to
  7865. // the caller.
  7866. //
  7867. if (status == STATUS_PENDING) {
  7868. (VOID) KeWaitForSingleObject( &event,
  7869. Executive,
  7870. KernelMode,
  7871. FALSE,
  7872. (PLARGE_INTEGER) NULL );
  7873. status = localIoStatus.Status;
  7874. }
  7875. }
  7876. //
  7877. // If a target handle was created because of a rename operation, close
  7878. // the handle now.
  7879. //
  7880. if (targetHandle != (HANDLE) NULL) {
  7881. NtClose( targetHandle );
  7882. }
  7883. return status;
  7884. }
  7885. VOID
  7886. IoSetShareAccess(
  7887. IN ACCESS_MASK DesiredAccess,
  7888. IN ULONG DesiredShareAccess,
  7889. IN OUT PFILE_OBJECT FileObject,
  7890. OUT PSHARE_ACCESS ShareAccess
  7891. )
  7892. /*++
  7893. Routine Description:
  7894. This routine is invoked to set the access and share access information
  7895. in a file system Share Access structure for the first open.
  7896. Arguments:
  7897. DesiredAccess - Desired access of current open request.
  7898. DesiredShareAccess - Shared access requested by current open request.
  7899. FileObject - Pointer to the file object of the current open request.
  7900. ShareAccess - Pointer to the share access structure that describes
  7901. how the file is currently being accessed.
  7902. Return Value:
  7903. None.
  7904. --*/
  7905. {
  7906. BOOLEAN update = TRUE;
  7907. PAGED_CODE();
  7908. //
  7909. // Set the access type in the file object for the current accessor.
  7910. //
  7911. FileObject->ReadAccess = (BOOLEAN) ((DesiredAccess & (FILE_EXECUTE
  7912. | FILE_READ_DATA)) != 0);
  7913. FileObject->WriteAccess = (BOOLEAN) ((DesiredAccess & (FILE_WRITE_DATA
  7914. | FILE_APPEND_DATA)) != 0);
  7915. FileObject->DeleteAccess = (BOOLEAN) ((DesiredAccess & DELETE) != 0);
  7916. //
  7917. // If this is a special filter fileobject ignore share access check if necessary.
  7918. //
  7919. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  7920. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  7921. if (fileObjectExtension->FileObjectExtensionFlags & FO_EXTENSION_IGNORE_SHARE_ACCESS_CHECK) {
  7922. //
  7923. // This fileobject is marked to ignore share access checks
  7924. // so we also don't want to affect the file/directory's
  7925. // ShareAccess structure counts.
  7926. //
  7927. update = FALSE;
  7928. }
  7929. }
  7930. //
  7931. // Check to see whether the current file opener would like to read,
  7932. // write, or delete the file. If so, account for it in the share access
  7933. // structure; otherwise, skip it.
  7934. //
  7935. if (FileObject->ReadAccess ||
  7936. FileObject->WriteAccess ||
  7937. FileObject->DeleteAccess) {
  7938. //
  7939. // Only update the share modes if the user wants to read, write or
  7940. // delete the file.
  7941. //
  7942. FileObject->SharedRead = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_READ) != 0);
  7943. FileObject->SharedWrite = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_WRITE) != 0);
  7944. FileObject->SharedDelete = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_DELETE) != 0);
  7945. if (update) {
  7946. //
  7947. // Set the Share Access structure open count.
  7948. //
  7949. ShareAccess->OpenCount = 1;
  7950. //
  7951. // Set the number of readers, writers, and deleters in the Share Access
  7952. // structure.
  7953. //
  7954. ShareAccess->Readers = FileObject->ReadAccess;
  7955. ShareAccess->Writers = FileObject->WriteAccess;
  7956. ShareAccess->Deleters = FileObject->DeleteAccess;
  7957. //
  7958. // Set the number of shared readers, writers, and deleters in the Share
  7959. // Access structure.
  7960. //
  7961. ShareAccess->SharedRead = FileObject->SharedRead;
  7962. ShareAccess->SharedWrite = FileObject->SharedWrite;
  7963. ShareAccess->SharedDelete = FileObject->SharedDelete;
  7964. }
  7965. } else {
  7966. //
  7967. // No read, write, or delete access has been requested. Simply zero
  7968. // the appropriate fields in the structure so that the next accessor
  7969. // sees a consistent state.
  7970. //
  7971. if (update) {
  7972. ShareAccess->OpenCount = 0;
  7973. ShareAccess->Readers = 0;
  7974. ShareAccess->Writers = 0;
  7975. ShareAccess->Deleters = 0;
  7976. ShareAccess->SharedRead = 0;
  7977. ShareAccess->SharedWrite = 0;
  7978. ShareAccess->SharedDelete = 0;
  7979. }
  7980. }
  7981. }
  7982. BOOLEAN
  7983. IoSetThreadHardErrorMode(
  7984. IN BOOLEAN EnableHardErrors
  7985. )
  7986. /*++
  7987. Routine Description:
  7988. This routine either enables or disables hard errors for the current
  7989. thread and returns the old state of the flag.
  7990. Arguments:
  7991. EnableHardErrors - Supplies a BOOLEAN value indicating whether or not
  7992. hard errors are to be enabled for the current thread.
  7993. Return Value:
  7994. The final function value is the previous state of whether or not hard
  7995. errors were enabled.
  7996. --*/
  7997. {
  7998. PETHREAD thread;
  7999. BOOLEAN oldFlag;
  8000. //
  8001. // Get a pointer to the current thread, capture the current state of
  8002. // hard errors, and set the new state.
  8003. //
  8004. thread = PsGetCurrentThread();
  8005. oldFlag = ((thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED) == 0);
  8006. if (EnableHardErrors) {
  8007. PS_CLEAR_BITS (&thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED);
  8008. } else {
  8009. PS_SET_BITS (&thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED);
  8010. }
  8011. return oldFlag;
  8012. }
  8013. VOID
  8014. IoSetTopLevelIrp(
  8015. IN PIRP Irp
  8016. )
  8017. /*++
  8018. Routine Description:
  8019. This routine sets the top level IRP field in the current thread's thread
  8020. object. This function is invoked by file systems to either set this field
  8021. to the address of an I/O Request Packet (IRP) or to null it.
  8022. Arguments:
  8023. Irp - Pointer to the IRP to be stored in the top level IRP field.
  8024. Return Value:
  8025. None.
  8026. Note:
  8027. This function cannot be made a macro, since fields in the thread object
  8028. move from release to release, so this must remain a full function.
  8029. --*/
  8030. {
  8031. //
  8032. // Simply set the top level IRP field in the current thread's thread
  8033. // object.
  8034. //
  8035. (PIRP) (PsGetCurrentThread())->TopLevelIrp = Irp;
  8036. return;
  8037. }
  8038. VOID
  8039. IoShutdownSystem (
  8040. IN ULONG Phase
  8041. )
  8042. /*++
  8043. Routine Description:
  8044. This routine shuts down the I/O portion of the system in preparation
  8045. for a power-off or reboot.
  8046. Arguments:
  8047. RebootPending - Indicates whether a reboot is imminently pending.
  8048. Phase - Indicates which phase of shutdown is being performed.
  8049. Return Value:
  8050. None
  8051. --*/
  8052. {
  8053. PSHUTDOWN_PACKET shutdown;
  8054. PDEVICE_OBJECT deviceObject;
  8055. PIRP irp;
  8056. PLIST_ENTRY entry;
  8057. KEVENT event;
  8058. IO_STATUS_BLOCK ioStatus;
  8059. PVOID unlockHandle;
  8060. PAGED_CODE();
  8061. //
  8062. // Initialize the event used to synchronize the complete of all of the
  8063. // shutdown routines.
  8064. //
  8065. KeInitializeEvent( &event, NotificationEvent, FALSE );
  8066. if (Phase == 0) {
  8067. ZwClose(IopLinkTrackingServiceEventHandle);
  8068. IoShutdownPnpDevices();
  8069. //
  8070. // Walk the list of the drivers in the system that have registered
  8071. // themselves as wanting to know when the system is about to be
  8072. // shutdown and invoke each.
  8073. //
  8074. while ((entry = IopInterlockedRemoveHeadList( &IopNotifyShutdownQueueHead )) != NULL) {
  8075. shutdown = CONTAINING_RECORD( entry, SHUTDOWN_PACKET, ListEntry );
  8076. //
  8077. // Another driver has been found that has indicated that it requires
  8078. // shutdown notification. Invoke the driver's shutdown entry point.
  8079. //
  8080. deviceObject = IoGetAttachedDeviceReference( shutdown->DeviceObject );
  8081. irp = IoBuildSynchronousFsdRequest( IRP_MJ_SHUTDOWN,
  8082. deviceObject,
  8083. (PVOID) NULL,
  8084. 0,
  8085. (PLARGE_INTEGER) NULL,
  8086. &event,
  8087. &ioStatus );
  8088. if (IoCallDriver( deviceObject, irp ) == STATUS_PENDING) {
  8089. #if DBG
  8090. PUNICODE_STRING DeviceName = ObGetObjectName( shutdown->DeviceObject );
  8091. DbgPrint( "IO: Waiting for shutdown of device object (%x) - %wZ\n",
  8092. shutdown->DeviceObject,
  8093. DeviceName
  8094. );
  8095. #endif // DBG
  8096. (VOID) KeWaitForSingleObject( &event,
  8097. Executive,
  8098. KernelMode,
  8099. FALSE,
  8100. (PLARGE_INTEGER) NULL );
  8101. }
  8102. ObDereferenceObject(deviceObject);
  8103. ObDereferenceObject(shutdown->DeviceObject);
  8104. ExFreePool( shutdown );
  8105. KeClearEvent( &event );
  8106. }
  8107. IOV_UNLOAD_DRIVERS();
  8108. } else if (Phase == 1) {
  8109. #if defined(REMOTE_BOOT)
  8110. //
  8111. // If this is a remote boot client then allow the cache to close the database and
  8112. // mark it clean.
  8113. //
  8114. IopShutdownCsc();
  8115. #endif // defined(REMOTE_BOOT)
  8116. // Gain access to the file system header queues by acquiring the
  8117. // database resource for shared access.
  8118. //
  8119. ExAcquireResourceExclusiveLite( &IopDatabaseResource, TRUE );
  8120. IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead);
  8121. IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead);
  8122. IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
  8123. //
  8124. // Walk the list of the drivers in the system that have registered
  8125. // themselves as wanting to know at the last chance when the system
  8126. // is about to be shutdown and invoke each.
  8127. //
  8128. while ((entry = IopInterlockedRemoveHeadList( &IopNotifyLastChanceShutdownQueueHead )) != NULL) {
  8129. shutdown = CONTAINING_RECORD( entry, SHUTDOWN_PACKET, ListEntry );
  8130. //
  8131. // Another driver has been found that has indicated that it requires
  8132. // shutdown notification. Invoke the driver's shutdown entry point.
  8133. //
  8134. deviceObject = IoGetAttachedDevice( shutdown->DeviceObject );
  8135. irp = IoBuildSynchronousFsdRequest( IRP_MJ_SHUTDOWN,
  8136. deviceObject,
  8137. (PVOID) NULL,
  8138. 0,
  8139. (PLARGE_INTEGER) NULL,
  8140. &event,
  8141. &ioStatus );
  8142. if (IoCallDriver( deviceObject, irp ) == STATUS_PENDING) {
  8143. #if DBG
  8144. PUNICODE_STRING DeviceName = ObGetObjectName( shutdown->DeviceObject );
  8145. DbgPrint( "IO: Waiting for last chance shutdown of device object (%x) - %wZ\n",
  8146. shutdown->DeviceObject,
  8147. DeviceName
  8148. );
  8149. #endif // DBG
  8150. (VOID) KeWaitForSingleObject( &event,
  8151. Executive,
  8152. KernelMode,
  8153. FALSE,
  8154. (PLARGE_INTEGER) NULL );
  8155. }
  8156. ObDereferenceObject(deviceObject);
  8157. ObDereferenceObject(shutdown->DeviceObject);
  8158. ExFreePool( shutdown );
  8159. KeClearEvent( &event );
  8160. }
  8161. //
  8162. // N.B. The system has stopped. The IopDatabaseResource lock is
  8163. // not released so that no other mount operations can take place.
  8164. //
  8165. // ExReleaseResourceLite( &IopDatabaseResource );
  8166. //
  8167. }
  8168. return ;
  8169. }
  8170. VOID
  8171. IopShutdownBaseFileSystems(
  8172. IN PLIST_ENTRY ListHead
  8173. )
  8174. {
  8175. PLIST_ENTRY entry;
  8176. KEVENT event;
  8177. IO_STATUS_BLOCK ioStatus;
  8178. PDEVICE_OBJECT baseDeviceObject;
  8179. PDEVICE_OBJECT deviceObject;
  8180. PIRP irp;
  8181. //
  8182. // Loop through each of the disk file systems, invoking each to shutdown
  8183. // each of their mounted volumes.
  8184. //
  8185. KeInitializeEvent( &event, NotificationEvent, FALSE );
  8186. entry = RemoveHeadList(ListHead);
  8187. while (entry != ListHead) {
  8188. baseDeviceObject = CONTAINING_RECORD( entry, DEVICE_OBJECT, Queue.ListEntry );
  8189. //
  8190. // We have removed the entry. If the filesystem in this thread calls IoUnregisterFileSystem
  8191. // then we won't remove the entry from the list as the Flink == NULL.
  8192. //
  8193. baseDeviceObject->Queue.ListEntry.Flink = NULL;
  8194. baseDeviceObject->Queue.ListEntry.Blink = NULL;
  8195. //
  8196. // Prevent the driver from getting unloaded while shutdown handler is in progress.
  8197. // Also prevent the base device object from going away as we need to decrement the
  8198. // reasons for unload count later.
  8199. //
  8200. ObReferenceObject(baseDeviceObject);
  8201. IopInterlockedIncrementUlong( LockQueueIoDatabaseLock,
  8202. &baseDeviceObject->ReferenceCount );
  8203. deviceObject = baseDeviceObject;
  8204. if (baseDeviceObject->AttachedDevice) {
  8205. deviceObject = IoGetAttachedDevice( baseDeviceObject );
  8206. }
  8207. //
  8208. // Another file system has been found. Invoke this file system at
  8209. // its shutdown entry point.
  8210. //
  8211. irp = IoBuildSynchronousFsdRequest( IRP_MJ_SHUTDOWN,
  8212. deviceObject,
  8213. (PVOID) NULL,
  8214. 0,
  8215. (PLARGE_INTEGER) NULL,
  8216. &event,
  8217. &ioStatus );
  8218. //
  8219. // Its possible that the drivers are unloaded before this call returns but IoCallDriver
  8220. // takes a reference to the device object before calling the driver. So the image will not
  8221. // get unloaded.
  8222. //
  8223. if (IoCallDriver( deviceObject, irp ) == STATUS_PENDING) {
  8224. (VOID) KeWaitForSingleObject( &event,
  8225. Executive,
  8226. KernelMode,
  8227. FALSE,
  8228. (PLARGE_INTEGER) NULL );
  8229. }
  8230. entry = RemoveHeadList(ListHead);
  8231. KeClearEvent( &event );
  8232. IopDecrementDeviceObjectRef(baseDeviceObject, FALSE, TRUE);
  8233. ObDereferenceObject(baseDeviceObject);
  8234. }
  8235. }
  8236. VOID
  8237. IopStartNextPacket(
  8238. IN PDEVICE_OBJECT DeviceObject,
  8239. IN BOOLEAN Cancelable
  8240. )
  8241. /*++
  8242. Routine Description:
  8243. This routine is invoked to dequeue the next packet (IRP) from the
  8244. specified device work queue and invoke the device driver's start I/O
  8245. routine for it. If the Cancelable paramter is TRUE, then the update of
  8246. current IRP is synchronized using the cancel spinlock.
  8247. Arguments:
  8248. DeviceObject - Pointer to device object itself.
  8249. Cancelable - Indicates that IRPs in the device queue may be cancelable.
  8250. Return Value:
  8251. None.
  8252. --*/
  8253. {
  8254. KIRQL cancelIrql;
  8255. PIRP irp;
  8256. PKDEVICE_QUEUE_ENTRY packet;
  8257. //
  8258. // Begin by checking to see whether or not this driver's requests are
  8259. // to be considered cancelable. If so, then acquire the cancel spinlock.
  8260. //
  8261. if (Cancelable) {
  8262. IoAcquireCancelSpinLock( &cancelIrql );
  8263. }
  8264. //
  8265. // Clear the current IRP field before starting another request.
  8266. //
  8267. DeviceObject->CurrentIrp = (PIRP) NULL;
  8268. //
  8269. // Remove the next packet from the head of the queue. If a packet was
  8270. // found, then process it.
  8271. //
  8272. packet = KeRemoveDeviceQueue( &DeviceObject->DeviceQueue );
  8273. if (packet) {
  8274. irp = CONTAINING_RECORD( packet, IRP, Tail.Overlay.DeviceQueueEntry );
  8275. //
  8276. // A packet was located so make it the current packet for this
  8277. // device.
  8278. //
  8279. DeviceObject->CurrentIrp = irp;
  8280. if (Cancelable) {
  8281. //
  8282. // If the driver does not want the IRP in the cancelable state
  8283. // then set the routine to NULL
  8284. //
  8285. if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_NO_CANCEL) {
  8286. irp->CancelRoutine = NULL;
  8287. }
  8288. IoReleaseCancelSpinLock( cancelIrql );
  8289. }
  8290. //
  8291. // Invoke the driver's start I/O routine for this packet.
  8292. //
  8293. DeviceObject->DriverObject->DriverStartIo( DeviceObject, irp );
  8294. } else {
  8295. //
  8296. // No packet was found, so simply release the cancel spinlock if
  8297. // it was acquired.
  8298. //
  8299. if (Cancelable) {
  8300. IoReleaseCancelSpinLock( cancelIrql );
  8301. }
  8302. }
  8303. }
  8304. VOID
  8305. IopStartNextPacketByKey(
  8306. IN PDEVICE_OBJECT DeviceObject,
  8307. IN BOOLEAN Cancelable,
  8308. IN ULONG Key
  8309. )
  8310. /*++
  8311. Routine Description:
  8312. This routine is invoked to dequeue the next packet (IRP) from the
  8313. specified device work queue by key and invoke the device driver's start
  8314. I/O routine for it. If the Cancelable paramter is TRUE, then the
  8315. update of current IRP is synchronized using the cancel spinlock.
  8316. Arguments:
  8317. DeviceObject - Pointer to device object itself.
  8318. Cancelable - Indicates that IRPs in the device queue may be cancelable.
  8319. Key - Specifics the Key used to remove the entry from the queue.
  8320. Return Value:
  8321. None.
  8322. --*/
  8323. {
  8324. KIRQL cancelIrql;
  8325. PIRP irp;
  8326. PKDEVICE_QUEUE_ENTRY packet;
  8327. //
  8328. // Begin by determining whether or not requests for this device are to
  8329. // be considered cancelable. If so, then acquire the cancel spinlock.
  8330. //
  8331. if (Cancelable) {
  8332. IoAcquireCancelSpinLock( &cancelIrql );
  8333. }
  8334. //
  8335. // Clear the current IRP field before starting another request.
  8336. //
  8337. DeviceObject->CurrentIrp = (PIRP) NULL;
  8338. //
  8339. // Attempt to remove the indicated packet according to the key from the
  8340. // device queue. If one is found, then process it.
  8341. //
  8342. packet = KeRemoveByKeyDeviceQueue( &DeviceObject->DeviceQueue, Key );
  8343. if (packet) {
  8344. irp = CONTAINING_RECORD( packet, IRP, Tail.Overlay.DeviceQueueEntry );
  8345. //
  8346. // A packet was successfully located. Make it the current packet
  8347. // and invoke the driver's start I/O routine for it.
  8348. //
  8349. DeviceObject->CurrentIrp = irp;
  8350. if (Cancelable) {
  8351. //
  8352. // If the driver does not want the IRP in the cancelable state
  8353. // then set the routine to NULL
  8354. //
  8355. if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_NO_CANCEL) {
  8356. irp->CancelRoutine = NULL;
  8357. }
  8358. IoReleaseCancelSpinLock( cancelIrql );
  8359. }
  8360. DeviceObject->DriverObject->DriverStartIo( DeviceObject, irp );
  8361. } else {
  8362. //
  8363. // No packet was found, so release the cancel spinlock if it was
  8364. // acquired.
  8365. //
  8366. if (Cancelable) {
  8367. IoReleaseCancelSpinLock( cancelIrql );
  8368. }
  8369. }
  8370. }
  8371. VOID
  8372. IopStartPacket(
  8373. IN PDEVICE_OBJECT DeviceObject,
  8374. IN PIRP Irp,
  8375. IN PULONG Key OPTIONAL,
  8376. IN PDRIVER_CANCEL CancelFunction OPTIONAL
  8377. )
  8378. /*++
  8379. Routine Description:
  8380. This routine attempts to start the specified packet request (IRP) on the
  8381. specified device. If the device is already busy, then the packet is
  8382. simply queued to the device queue. If a non-NULL CancelFunction is
  8383. supplied, it will be put in the IRP. If the IRP has been canceled, the
  8384. CancelFunction will be called after the IRP has been inserted into the
  8385. queue or made the current packet.
  8386. Arguments:
  8387. DeviceObject - Pointer to device object itself.
  8388. Irp - I/O Request Packet which should be started on the device.
  8389. Key - Key to be used in inserting packet into device queue; optional
  8390. (if not specified, then packet is inserted at the tail).
  8391. CancelFunction - Pointer to an optional cancel routine.
  8392. Return Value:
  8393. None.
  8394. --*/
  8395. {
  8396. KIRQL oldIrql;
  8397. KIRQL cancelIrql;
  8398. BOOLEAN i;
  8399. //
  8400. // Raise the IRQL of the processor to dispatch level for synchronization.
  8401. //
  8402. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  8403. //
  8404. // If the driver has indicated that packets are cancelable, then acquire
  8405. // the cancel spinlock and set the address of the cancel function to
  8406. // indicate that the packet is not only cancelable, but indicates what
  8407. // routine to invoke should it be cancelled.
  8408. //
  8409. if (CancelFunction) {
  8410. IoAcquireCancelSpinLock( &cancelIrql );
  8411. Irp->CancelRoutine = CancelFunction;
  8412. }
  8413. //
  8414. // If a key parameter was specified, then insert the request into the
  8415. // work queue according to the key; otherwise, simply insert it at the
  8416. // tail.
  8417. //
  8418. if (Key) {
  8419. i = KeInsertByKeyDeviceQueue( &DeviceObject->DeviceQueue,
  8420. &Irp->Tail.Overlay.DeviceQueueEntry,
  8421. *Key );
  8422. } else {
  8423. i = KeInsertDeviceQueue( &DeviceObject->DeviceQueue,
  8424. &Irp->Tail.Overlay.DeviceQueueEntry );
  8425. }
  8426. //
  8427. // If the packet was not inserted into the queue, then this request is
  8428. // now the current packet for this device. Indicate so by storing its
  8429. // address in the current IRP field, and begin processing the request.
  8430. //
  8431. if (!i) {
  8432. DeviceObject->CurrentIrp = Irp;
  8433. if (CancelFunction) {
  8434. //
  8435. // If the driver does not want the IRP in the cancelable state
  8436. // then set the routine to NULL
  8437. //
  8438. if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_NO_CANCEL) {
  8439. Irp->CancelRoutine = NULL;
  8440. }
  8441. IoReleaseCancelSpinLock( cancelIrql );
  8442. }
  8443. //
  8444. // Invoke the driver's start I/O routine to get the request going on the device.
  8445. // The StartIo routine should handle the cancellation.
  8446. //
  8447. DeviceObject->DriverObject->DriverStartIo( DeviceObject, Irp );
  8448. } else {
  8449. //
  8450. // The packet was successfully inserted into the device's work queue.
  8451. // Make one last check to determine whether or not the packet has
  8452. // already been marked cancelled. If it has, then invoke the
  8453. // driver's cancel routine now. Note that because the cancel
  8454. // spinlock is currently being held, an attempt to cancel the request
  8455. // from another processor at this point will simply wait until this
  8456. // routine is finished, and then get it cancelled.
  8457. //
  8458. if (CancelFunction) {
  8459. if (Irp->Cancel) {
  8460. Irp->CancelIrql = cancelIrql;
  8461. Irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
  8462. CancelFunction( DeviceObject, Irp );
  8463. } else {
  8464. IoReleaseCancelSpinLock( cancelIrql );
  8465. }
  8466. }
  8467. }
  8468. //
  8469. // Restore the IRQL back to its value upon entry to this function before
  8470. // returning to the caller.
  8471. //
  8472. KeLowerIrql( oldIrql );
  8473. }
  8474. VOID
  8475. IopStartNextPacketByKeyEx(
  8476. IN PDEVICE_OBJECT DeviceObject,
  8477. IN ULONG Key,
  8478. IN int Flags)
  8479. /*++
  8480. Routine Description:
  8481. This routine ensures that if the IoStartPacket* routines are called from inside StartIo then
  8482. it defers calling the startio until after the StartIo call returns. It does this by keeping a count.
  8483. It also keeps track of whether its cancelable or has a key by storing the value in the
  8484. device object extension. They are updated without a lock because its incorrect to have two parallel
  8485. calls to IoStartNextPacket or IoStartNextPacketByKey.
  8486. Arguments:
  8487. DeviceObject - Pointer to device object itself.
  8488. Key - Specifics the Key used to remove the entry from the queue.
  8489. Flags - Specifies if the deferred call has a key or is cancelable.
  8490. Return Value:
  8491. None.
  8492. --*/
  8493. {
  8494. IN BOOLEAN Cancelable;
  8495. int doAnotherIteration;
  8496. do {
  8497. doAnotherIteration = 0;
  8498. if (InterlockedIncrement(&(DeviceObject->DeviceObjectExtension->StartIoCount)) > 1) {
  8499. DeviceObject->DeviceObjectExtension->StartIoFlags |= Flags;
  8500. DeviceObject->DeviceObjectExtension->StartIoKey = Key;
  8501. } else {
  8502. Cancelable = Flags & DOE_STARTIO_CANCELABLE;
  8503. DeviceObject->DeviceObjectExtension->StartIoFlags &=
  8504. ~(DOE_STARTIO_REQUESTED|DOE_STARTIO_REQUESTED_BYKEY|DOE_STARTIO_CANCELABLE);
  8505. DeviceObject->DeviceObjectExtension->StartIoKey = 0;
  8506. if (Flags & DOE_STARTIO_REQUESTED_BYKEY) {
  8507. IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
  8508. }else if (Flags &DOE_STARTIO_REQUESTED){
  8509. IopStartNextPacket(DeviceObject, Cancelable);
  8510. }
  8511. }
  8512. if (InterlockedDecrement(&(DeviceObject->DeviceObjectExtension->StartIoCount)) == 0) {
  8513. Flags = DeviceObject->DeviceObjectExtension->StartIoFlags &
  8514. (DOE_STARTIO_REQUESTED|DOE_STARTIO_REQUESTED_BYKEY|DOE_STARTIO_CANCELABLE);
  8515. Key = DeviceObject->DeviceObjectExtension->StartIoKey;
  8516. if (Flags & (DOE_STARTIO_REQUESTED|DOE_STARTIO_REQUESTED_BYKEY)) {
  8517. doAnotherIteration++;
  8518. }
  8519. }
  8520. } while (doAnotherIteration);
  8521. }
  8522. VOID
  8523. IoStartNextPacket(
  8524. IN PDEVICE_OBJECT DeviceObject,
  8525. IN BOOLEAN Cancelable)
  8526. /*++
  8527. Routine Description:
  8528. This routine checks the DOE flags to see if StartIO has to be deferred.
  8529. If so it calls the appropriate function.
  8530. Arguments:
  8531. DeviceObject - Pointer to device object itself.
  8532. Cancelable - Indicates that IRPs in the device queue may be cancelable.
  8533. Return Value:
  8534. None.
  8535. --*/
  8536. {
  8537. if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_DEFERRED) {
  8538. IopStartNextPacketByKeyEx(DeviceObject, 0, DOE_STARTIO_REQUESTED|(Cancelable ? DOE_STARTIO_CANCELABLE : 0));
  8539. } else {
  8540. IopStartNextPacket(DeviceObject, Cancelable);
  8541. }
  8542. }
  8543. VOID
  8544. IoStartNextPacketByKey(
  8545. IN PDEVICE_OBJECT DeviceObject,
  8546. IN BOOLEAN Cancelable,
  8547. IN ULONG Key)
  8548. /*++
  8549. Routine Description:
  8550. This routine checks the DOE flags to see if StartIO has to be deferred.
  8551. If so it calls the appropriate function.
  8552. Arguments:
  8553. DeviceObject - Pointer to device object itself.
  8554. Cancelable - Indicates that IRPs in the device queue may be cancelable.
  8555. Key - Specifics the Key used to remove the entry from the queue.
  8556. Return Value:
  8557. None.
  8558. --*/
  8559. {
  8560. if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_DEFERRED) {
  8561. IopStartNextPacketByKeyEx(DeviceObject, Key, DOE_STARTIO_REQUESTED_BYKEY|(Cancelable ? DOE_STARTIO_CANCELABLE : 0));
  8562. } else {
  8563. IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
  8564. }
  8565. }
  8566. VOID
  8567. IoStartPacket(
  8568. IN PDEVICE_OBJECT DeviceObject,
  8569. IN PIRP Irp,
  8570. IN PULONG Key OPTIONAL,
  8571. IN PDRIVER_CANCEL CancelFunction OPTIONAL
  8572. )
  8573. /*++
  8574. Routine Description:
  8575. This routine checks the DOE flags to see if StartIO has to be deferred.
  8576. If so it calls the appropriate function.
  8577. Arguments:
  8578. DeviceObject - Pointer to device object itself.
  8579. Irp - I/O Request Packet which should be started on the device.
  8580. Key - Key to be used in inserting packet into device queue; optional
  8581. (if not specified, then packet is inserted at the tail).
  8582. CancelFunction - Pointer to an optional cancel routine.
  8583. Return Value:
  8584. None.
  8585. --*/
  8586. {
  8587. int Flags;
  8588. KIRQL oldIrql;
  8589. if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_DEFERRED) {
  8590. InterlockedIncrement(&DeviceObject->DeviceObjectExtension->StartIoCount);
  8591. IopStartPacket(DeviceObject, Irp, Key, CancelFunction);
  8592. if (InterlockedDecrement(&(DeviceObject->DeviceObjectExtension->StartIoCount)) == 0) {
  8593. Flags = DeviceObject->DeviceObjectExtension->StartIoFlags &
  8594. (DOE_STARTIO_REQUESTED|DOE_STARTIO_REQUESTED_BYKEY|DOE_STARTIO_CANCELABLE);
  8595. if (Flags & (DOE_STARTIO_REQUESTED|DOE_STARTIO_REQUESTED_BYKEY)) {
  8596. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  8597. IopStartNextPacketByKeyEx(DeviceObject,
  8598. DeviceObject->DeviceObjectExtension->StartIoKey,
  8599. Flags);
  8600. KeLowerIrql( oldIrql );
  8601. }
  8602. }
  8603. } else {
  8604. IopStartPacket(DeviceObject, Irp, Key, CancelFunction);
  8605. }
  8606. }
  8607. VOID
  8608. IoSetStartIoAttributes(
  8609. IN PDEVICE_OBJECT DeviceObject,
  8610. IN BOOLEAN DeferredStartIo,
  8611. IN BOOLEAN NonCancelable
  8612. )
  8613. /*++
  8614. Routine Description:
  8615. This routine sets the StartIo attributes so that drivers can change the
  8616. behaviour of when StartIo can be called.
  8617. Arguments:
  8618. DeviceObject - Pointer to device object itself.
  8619. NonCancelable - If TRUE that IRP passed to StartIo is not in the cancelable state.
  8620. DeferredStartIo - If TRUE startIo is not called recursively and is deferred until the previous
  8621. StartIo call returns to the IO manager.
  8622. Return Value:
  8623. None.
  8624. --*/
  8625. {
  8626. if (DeferredStartIo) {
  8627. DeviceObject->DeviceObjectExtension->StartIoFlags |= DOE_STARTIO_DEFERRED;
  8628. }
  8629. if (NonCancelable) {
  8630. DeviceObject->DeviceObjectExtension->StartIoFlags |= DOE_STARTIO_NO_CANCEL;
  8631. }
  8632. }
  8633. VOID
  8634. IoStartTimer(
  8635. IN PDEVICE_OBJECT DeviceObject
  8636. )
  8637. /*++
  8638. Routine Description:
  8639. This routine starts the timer associated with the specified device object.
  8640. Arguments:
  8641. DeviceObject - Device object associated with the timer to be started.
  8642. Return Value:
  8643. None.
  8644. --*/
  8645. {
  8646. PIO_TIMER timer;
  8647. KIRQL irql;
  8648. //
  8649. // Get the address of the timer.
  8650. //
  8651. timer = DeviceObject->Timer;
  8652. //
  8653. // If the driver is not being unloaded, then it is okay to start timers.
  8654. //
  8655. if (!(DeviceObject->DeviceObjectExtension->ExtensionFlags &
  8656. (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED))) {
  8657. //
  8658. // Likewise, check to see whether or not the timer is already
  8659. // enabled. If so, then simply exit. Otherwise, enable the timer
  8660. // by placing it into the I/O system timer queue.
  8661. //
  8662. ExAcquireFastLock( &IopTimerLock, &irql );
  8663. if (!timer->TimerFlag) {
  8664. timer->TimerFlag = TRUE;
  8665. IopTimerCount++;
  8666. }
  8667. ExReleaseFastLock( &IopTimerLock, irql );
  8668. }
  8669. }
  8670. VOID
  8671. IoStopTimer(
  8672. IN PDEVICE_OBJECT DeviceObject
  8673. )
  8674. /*++
  8675. Routine Description:
  8676. This routines stops the timer associated with the specified device object
  8677. from invoking being invoked.
  8678. Arguments:
  8679. DeviceObject - Device object associated with the timer to be stopped.
  8680. Return Value:
  8681. None.
  8682. --*/
  8683. {
  8684. KIRQL irql;
  8685. PIO_TIMER timer;
  8686. //
  8687. // Obtain the I/O system timer queue lock, and disable the specified
  8688. // timer.
  8689. //
  8690. timer = DeviceObject->Timer;
  8691. ExAcquireFastLock( &IopTimerLock, &irql );
  8692. if (timer->TimerFlag) {
  8693. timer->TimerFlag = FALSE;
  8694. IopTimerCount--;
  8695. }
  8696. ExReleaseFastLock( &IopTimerLock, irql );
  8697. }
  8698. NTSTATUS
  8699. IoSynchronousPageWrite(
  8700. IN PFILE_OBJECT FileObject,
  8701. IN PMDL MemoryDescriptorList,
  8702. IN PLARGE_INTEGER StartingOffset,
  8703. IN PKEVENT Event,
  8704. OUT PIO_STATUS_BLOCK IoStatusBlock
  8705. )
  8706. /*++
  8707. Routine Description:
  8708. This routine provides a special, fast interface for the Modified Page Writer
  8709. (MPW) to write pages to the disk quickly and with very little overhead. All
  8710. of the special handling for this request is recognized by setting the
  8711. IRP_PAGING_IO flag in the IRP flags word.
  8712. Arguments:
  8713. FileObject - A pointer to a referenced file object describing which file
  8714. the write should be performed on.
  8715. MemoryDescriptorList - An MDL which describes the physical pages that the
  8716. pages should be written to the disk. All of the pages have been locked
  8717. in memory. The MDL also describes the length of the write operation.
  8718. StartingOffset - Pointer to the offset in the file from which the write
  8719. should take place.
  8720. Event - A pointer to a kernel event structure to be used for synchronization
  8721. purposes. The event will be set to the Signlaged state once the pages
  8722. have been written.
  8723. IoStatusBlock - A pointer to the I/O status block in which the final status
  8724. and information should be stored.
  8725. Return Value:
  8726. The function value is the final status of the queue request to the I/O
  8727. system subcomponents.
  8728. --*/
  8729. {
  8730. PIRP irp;
  8731. PIO_STACK_LOCATION irpSp;
  8732. PDEVICE_OBJECT deviceObject;
  8733. //
  8734. // Increment performance counters
  8735. //
  8736. if (CcIsFileCached(FileObject)) {
  8737. CcDataFlushes += 1;
  8738. CcDataPages += (MemoryDescriptorList->ByteCount + PAGE_SIZE - 1) >> PAGE_SHIFT;
  8739. }
  8740. //
  8741. // Begin by getting a pointer to the device object that the file resides
  8742. // on.
  8743. //
  8744. deviceObject = IoGetRelatedDeviceObject( FileObject );
  8745. //
  8746. // Allocate an I/O Request Packet (IRP) for this out-page operation.
  8747. //
  8748. irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
  8749. if (!irp) {
  8750. return STATUS_INSUFFICIENT_RESOURCES;
  8751. }
  8752. //
  8753. // Get a pointer to the first stack location in the packet. This location
  8754. // will be used to pass the function codes and parameters to the first
  8755. // driver.
  8756. //
  8757. irpSp = IoGetNextIrpStackLocation( irp );
  8758. //
  8759. // Fill in the IRP according to this request.
  8760. //
  8761. irp->MdlAddress = MemoryDescriptorList;
  8762. irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
  8763. irp->RequestorMode = KernelMode;
  8764. irp->UserIosb = IoStatusBlock;
  8765. irp->UserEvent = Event;
  8766. irp->UserBuffer = (PVOID) ((PCHAR) MemoryDescriptorList->StartVa + MemoryDescriptorList->ByteOffset);
  8767. irp->Tail.Overlay.OriginalFileObject = FileObject;
  8768. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  8769. //
  8770. // Fill in the normal write parameters.
  8771. //
  8772. irpSp->MajorFunction = IRP_MJ_WRITE;
  8773. irpSp->Parameters.Write.Length = MemoryDescriptorList->ByteCount;
  8774. irpSp->Parameters.Write.ByteOffset = *StartingOffset;
  8775. irpSp->FileObject = FileObject;
  8776. //
  8777. // Queue the packet to the appropriate driver based on whether or not there
  8778. // is a VPB associated with the device.
  8779. //
  8780. return IoCallDriver( deviceObject, irp );
  8781. }
  8782. PEPROCESS
  8783. IoThreadToProcess(
  8784. IN PETHREAD Thread
  8785. )
  8786. /*++
  8787. Routine Description:
  8788. This routine returns a pointer to the process for the specified thread.
  8789. Arguments:
  8790. Thread - Thread whose process is to be returned.
  8791. Return Value:
  8792. A pointer to the thread's process.
  8793. Note:
  8794. This function cannot be made a macro, since fields in the thread object
  8795. move from release to release, so this must remain a full function.
  8796. --*/
  8797. {
  8798. //
  8799. // Simply return the thread's process.
  8800. //
  8801. return THREAD_TO_PROCESS( Thread );
  8802. }
  8803. VOID
  8804. IoUnregisterFileSystem(
  8805. IN OUT PDEVICE_OBJECT DeviceObject
  8806. )
  8807. /*++
  8808. Routine Description:
  8809. This routine removes the device object for the file system from the active
  8810. list of file systems in the system.
  8811. Arguments:
  8812. DeviceObject - Pointer to device object for the file system.
  8813. Return Value:
  8814. None.
  8815. --*/
  8816. {
  8817. PNOTIFICATION_PACKET nPacket;
  8818. PLIST_ENTRY entry;
  8819. PAGED_CODE();
  8820. //
  8821. // Acquire the I/O database resource for a write operation.
  8822. //
  8823. (VOID)ExAcquireResourceExclusiveLite( &IopDatabaseResource, TRUE );
  8824. //
  8825. // Remove the device object from whatever queue it happens to be in at the
  8826. // moment. There is no need to check here to determine if the device queue
  8827. // is in a queue since it is assumed that the caller registered it as a
  8828. // valid file system.
  8829. //
  8830. if (DeviceObject->Queue.ListEntry.Flink != NULL) {
  8831. RemoveEntryList( &DeviceObject->Queue.ListEntry );
  8832. }
  8833. //
  8834. // Notify all of the registered drivers that this file system has been
  8835. // unregistered as an active file system of some type.
  8836. //
  8837. entry = IopFsNotifyChangeQueueHead.Flink;
  8838. while (entry != &IopFsNotifyChangeQueueHead) {
  8839. nPacket = CONTAINING_RECORD( entry, NOTIFICATION_PACKET, ListEntry );
  8840. entry = entry->Flink;
  8841. nPacket->NotificationRoutine( DeviceObject, FALSE );
  8842. }
  8843. IopFsRegistrationOps++;
  8844. //
  8845. // Release the I/O database resource.
  8846. //
  8847. ExReleaseResourceLite( &IopDatabaseResource );
  8848. //
  8849. // Decrement the number of reasons that this driver cannot be unloaded.
  8850. //
  8851. IopInterlockedDecrementUlong( LockQueueIoDatabaseLock,
  8852. &DeviceObject->ReferenceCount );
  8853. }
  8854. VOID
  8855. IoUnregisterFsRegistrationChange(
  8856. IN PDRIVER_OBJECT DriverObject,
  8857. IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
  8858. )
  8859. /*++
  8860. Routine Description:
  8861. This routine unregisters the specified driver's notification routine from
  8862. begin invoked whenever a file system registers or unregisters itself as an
  8863. active file system in the system.
  8864. Arguments:
  8865. DriverObject - Pointer to the driver object for the driver.
  8866. DriverNotificationRoutine - Address of routine to unregister.
  8867. Return Value:
  8868. None.
  8869. --*/
  8870. {
  8871. PNOTIFICATION_PACKET nPacket;
  8872. PLIST_ENTRY entry;
  8873. PAGED_CODE();
  8874. //
  8875. // Begin by acquiring the database resource exclusively.
  8876. //
  8877. ExAcquireResourceExclusiveLite( &IopDatabaseResource, TRUE );
  8878. //
  8879. // Walk the list of registered notification routines and unregister the
  8880. // specified routine.
  8881. //
  8882. for (entry = IopFsNotifyChangeQueueHead.Flink;
  8883. entry != &IopFsNotifyChangeQueueHead;
  8884. entry = entry->Flink) {
  8885. nPacket = CONTAINING_RECORD( entry, NOTIFICATION_PACKET, ListEntry );
  8886. if (nPacket->DriverObject == DriverObject &&
  8887. nPacket->NotificationRoutine == DriverNotificationRoutine) {
  8888. RemoveEntryList( entry );
  8889. ExFreePool( nPacket );
  8890. break;
  8891. }
  8892. }
  8893. ExReleaseResourceLite( &IopDatabaseResource );
  8894. ObDereferenceObject( DriverObject );
  8895. }
  8896. VOID
  8897. IoUnregisterShutdownNotification(
  8898. IN PDEVICE_OBJECT DeviceObject
  8899. )
  8900. /*++
  8901. Routine Description:
  8902. This routine removes a registered driver from the shutdown notification
  8903. queue. Henceforth, the driver will not be notified when the system is
  8904. being shutdown.
  8905. Arguments:
  8906. DeviceObject - Pointer to the driver's device object.
  8907. Return Value:
  8908. None.
  8909. --*/
  8910. {
  8911. PLIST_ENTRY entry;
  8912. PSHUTDOWN_PACKET shutdown;
  8913. KIRQL irql;
  8914. PAGED_CODE();
  8915. //
  8916. // Lock this code into memory for the duration of this function's execution.
  8917. //
  8918. ASSERT(ExPageLockHandle);
  8919. MmLockPagableSectionByHandle( ExPageLockHandle );
  8920. //
  8921. // Acquire the spinlock that protects the shutdown notification queue, and
  8922. // walk the queue looking for the caller's entry. Once found, remove it
  8923. // from the queue. It is an error to not find it, but it is ignored here.
  8924. //
  8925. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  8926. for (entry = IopNotifyShutdownQueueHead.Flink;
  8927. entry != &IopNotifyShutdownQueueHead;
  8928. entry = entry->Flink) {
  8929. //
  8930. // An entry has been located. If it is the one that is being searched
  8931. // for, simply remove it from the list and deallocate it.
  8932. //
  8933. shutdown = CONTAINING_RECORD( entry, SHUTDOWN_PACKET, ListEntry );
  8934. if (shutdown->DeviceObject == DeviceObject) {
  8935. RemoveEntryList( entry );
  8936. entry = entry->Blink;
  8937. ObDereferenceObject(DeviceObject);
  8938. ExFreePool( shutdown );
  8939. }
  8940. }
  8941. for (entry = IopNotifyLastChanceShutdownQueueHead.Flink;
  8942. entry != &IopNotifyLastChanceShutdownQueueHead;
  8943. entry = entry->Flink) {
  8944. //
  8945. // An entry has been located. If it is the one that is being searched
  8946. // for, simply remove it from the list and deallocate it.
  8947. //
  8948. shutdown = CONTAINING_RECORD( entry, SHUTDOWN_PACKET, ListEntry );
  8949. if (shutdown->DeviceObject == DeviceObject) {
  8950. RemoveEntryList( entry );
  8951. entry = entry->Blink;
  8952. ObDereferenceObject(DeviceObject);
  8953. ExFreePool( shutdown );
  8954. }
  8955. }
  8956. //
  8957. // Release the spinlock.
  8958. //
  8959. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  8960. MmUnlockPagableImageSection( ExPageLockHandle );
  8961. DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
  8962. }
  8963. VOID
  8964. IoUpdateShareAccess(
  8965. IN OUT PFILE_OBJECT FileObject,
  8966. IN OUT PSHARE_ACCESS ShareAccess
  8967. )
  8968. /*++
  8969. Routine Description:
  8970. This routine updates the share access context for a file according to
  8971. the desired access and share access by the current open requestor. The
  8972. IoCheckShareAccess routine must already have been invoked and succeeded
  8973. in order to invoke this routine. Note that when the former routine was
  8974. invoked the Update parameter must have been FALSE.
  8975. Arguments:
  8976. FileObject - Pointer to the file object of the current open request.
  8977. ShareAccess - Pointer to the share access structure that describes how
  8978. the file is currently being accessed.
  8979. Return Value:
  8980. None.
  8981. --*/
  8982. {
  8983. BOOLEAN update = TRUE;
  8984. PAGED_CODE();
  8985. //
  8986. // If this is a special filter fileobject ignore share access check if necessary.
  8987. //
  8988. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  8989. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension =(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  8990. if (fileObjectExtension->FileObjectExtensionFlags & FO_EXTENSION_IGNORE_SHARE_ACCESS_CHECK) {
  8991. //
  8992. // This fileobject is marked to ignore share access checks
  8993. // so we also don't want to affect the file/directory's
  8994. // ShareAccess structure counts.
  8995. //
  8996. update = FALSE;
  8997. }
  8998. }
  8999. //
  9000. // Check to see whether or not the desired accesses need read, write,
  9001. // or delete access to the file.
  9002. //
  9003. if ((FileObject->ReadAccess ||
  9004. FileObject->WriteAccess ||
  9005. FileObject->DeleteAccess) &&
  9006. update) {
  9007. //
  9008. // The open request requires read, write, or delete access so update
  9009. // the share access context for the file.
  9010. //
  9011. ShareAccess->OpenCount++;
  9012. ShareAccess->Readers += FileObject->ReadAccess;
  9013. ShareAccess->Writers += FileObject->WriteAccess;
  9014. ShareAccess->Deleters += FileObject->DeleteAccess;
  9015. ShareAccess->SharedRead += FileObject->SharedRead;
  9016. ShareAccess->SharedWrite += FileObject->SharedWrite;
  9017. ShareAccess->SharedDelete += FileObject->SharedDelete;
  9018. }
  9019. }
  9020. NTSTATUS
  9021. IoVerifyVolume(
  9022. IN PDEVICE_OBJECT DeviceObject,
  9023. IN BOOLEAN AllowRawMount
  9024. )
  9025. /*++
  9026. Routine Description:
  9027. This routine is invoked to check a mounted volume on the specified device
  9028. when it appears as if the media may have changed since it was last
  9029. accessed. If the volume is not the same volume, and a new mount is not
  9030. to be attempted, return the error.
  9031. If the verify fails, this routine is used to perform a new mount operation
  9032. on the device. In this case, a "clean" VPB is allocated and a new mount
  9033. operation is attempted. If no mount operation succeeds, then again the
  9034. error handling described above occurs.
  9035. Arguments:
  9036. DeviceObject - Pointer to device object on which the volume is to be
  9037. mounted.
  9038. AllowRawMount - Indicates that this verify is on behalf of a DASD open
  9039. request, thus we want to allow a raw mount if the verify fails.
  9040. Return Value:
  9041. The function value is a successful status code if a volume was successfully
  9042. mounted on the device. Otherwise, an error code is returned.
  9043. --*/
  9044. {
  9045. NTSTATUS status;
  9046. KEVENT event;
  9047. PIRP irp;
  9048. IO_STATUS_BLOCK ioStatus;
  9049. PIO_STACK_LOCATION irpSp;
  9050. BOOLEAN verifySkipped = FALSE;
  9051. PDEVICE_OBJECT fsDeviceObject;
  9052. PVPB mountVpb;
  9053. PAGED_CODE();
  9054. //
  9055. // Acquire the DeviceObject lock. Nothing in this routine can raise
  9056. // so no try {} finally {} is required.
  9057. //
  9058. status = KeWaitForSingleObject( &DeviceObject->DeviceLock,
  9059. Executive,
  9060. KernelMode,
  9061. FALSE,
  9062. (PLARGE_INTEGER) NULL );
  9063. ASSERT( status == STATUS_SUCCESS );
  9064. //
  9065. // If this volume is not mounted by anyone, skip the verify operation,
  9066. // but do the mount.
  9067. //
  9068. if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED)) {
  9069. verifySkipped = TRUE;
  9070. status = STATUS_SUCCESS;
  9071. } else {
  9072. //
  9073. // This volume needs to be verified. Initialize the event to be
  9074. // used while waiting for the operation to complete.
  9075. //
  9076. KeInitializeEvent( &event, NotificationEvent, FALSE );
  9077. status = STATUS_UNSUCCESSFUL;
  9078. //
  9079. // Allocate and initialize an IRP for this verify operation. Notice
  9080. // that the flags for this operation appear the same as a page read
  9081. // operation. This is because the completion code for both of the
  9082. // operations is exactly the same logic.
  9083. //
  9084. fsDeviceObject = DeviceObject->Vpb->DeviceObject;
  9085. while (fsDeviceObject->AttachedDevice) {
  9086. fsDeviceObject = fsDeviceObject->AttachedDevice;
  9087. }
  9088. irp = IoAllocateIrp( fsDeviceObject->StackSize, FALSE );
  9089. if (!irp) {
  9090. KeSetEvent( &DeviceObject->DeviceLock, 0, FALSE );
  9091. return STATUS_INSUFFICIENT_RESOURCES;
  9092. }
  9093. irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
  9094. irp->RequestorMode = KernelMode;
  9095. irp->UserEvent = &event;
  9096. irp->UserIosb = &ioStatus;
  9097. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  9098. irpSp = IoGetNextIrpStackLocation( irp );
  9099. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  9100. irpSp->MinorFunction = IRP_MN_VERIFY_VOLUME;
  9101. irpSp->Flags = AllowRawMount ? SL_ALLOW_RAW_MOUNT : 0;
  9102. irpSp->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
  9103. irpSp->Parameters.VerifyVolume.DeviceObject = DeviceObject->Vpb->DeviceObject;
  9104. status = IoCallDriver( fsDeviceObject, irp );
  9105. // IopLoadFileSystemDriver
  9106. // Wait for the I/O operation to complete.
  9107. //
  9108. if (status == STATUS_PENDING) {
  9109. (VOID) KeWaitForSingleObject( &event,
  9110. Executive,
  9111. KernelMode,
  9112. FALSE,
  9113. (PLARGE_INTEGER) NULL );
  9114. status = ioStatus.Status;
  9115. }
  9116. }
  9117. //
  9118. // If the verify operation was skipped or unsuccessful perform a mount
  9119. // operation.
  9120. //
  9121. if ((status == STATUS_WRONG_VOLUME) || verifySkipped) {
  9122. //
  9123. // A mount operation is to be attempted. Allocate a new VPB
  9124. // for this device and attempt to mount it. Note that at this
  9125. // point, allowing allocation of the VPB to fail is simply too
  9126. // difficult to deal with, so if one cannot be allocated normally,
  9127. // allocate one specifying that it must succeed.
  9128. //
  9129. if (NT_SUCCESS(IopCreateVpb (DeviceObject))) {
  9130. PoVolumeDevice (DeviceObject);
  9131. //
  9132. // Now mount the volume.
  9133. //
  9134. mountVpb = NULL;
  9135. if (!NT_SUCCESS( IopMountVolume( DeviceObject, AllowRawMount, TRUE, FALSE, &mountVpb ) )) {
  9136. DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
  9137. } else {
  9138. if (mountVpb) {
  9139. //
  9140. // Decrement the reference allocated in IopMountVolume.
  9141. //
  9142. IopInterlockedDecrementUlong( LockQueueIoVpbLock,
  9143. &mountVpb->ReferenceCount );
  9144. }
  9145. }
  9146. } else {
  9147. DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
  9148. }
  9149. }
  9150. //
  9151. // Release the device lock.
  9152. //
  9153. KeSetEvent( &DeviceObject->DeviceLock, 0, FALSE );
  9154. //
  9155. // Return the status from the verify operation as the final status of
  9156. // this function.
  9157. //
  9158. return status;
  9159. }
  9160. VOID
  9161. IoWriteErrorLogEntry(
  9162. IN OUT PVOID ElEntry
  9163. )
  9164. /*++
  9165. Routine Description:
  9166. This routine places the error log entry specified by the input argument
  9167. onto the queue of buffers to be written to the error log process's port.
  9168. The error log thread will then actually send it.
  9169. Arguments:
  9170. ElEntry Pointer to the error log entry.
  9171. Return Value:
  9172. None.
  9173. --*/
  9174. {
  9175. PERROR_LOG_ENTRY entry;
  9176. KIRQL oldIrql;
  9177. //
  9178. // Get the address of the error log entry header, acquire the spin lock,
  9179. // insert the entry onto the queue, if there are no pending requests
  9180. // then queue a worker thread request and release the spin lock.
  9181. //
  9182. entry = ((PERROR_LOG_ENTRY) ElEntry) - 1;
  9183. if (IopErrorLogDisabledThisBoot) {
  9184. //
  9185. // Do nothing, drop the reference.
  9186. //
  9187. if (entry->DeviceObject != NULL) {
  9188. //
  9189. // IopErrorLogThread tests for NULL before derefing.
  9190. // So do the same here.
  9191. //
  9192. ObDereferenceObject (entry->DeviceObject);
  9193. }
  9194. if (entry->DriverObject != NULL) {
  9195. ObDereferenceObject (entry->DriverObject);
  9196. }
  9197. InterlockedExchangeAdd( &IopErrorLogAllocation,
  9198. -((LONG) (entry->Size )));
  9199. ExFreePool (entry);
  9200. return;
  9201. }
  9202. //
  9203. // Set the time that the entry was logged.
  9204. //
  9205. KeQuerySystemTime( (PVOID) &entry->TimeStamp );
  9206. ExAcquireSpinLock( &IopErrorLogLock, &oldIrql );
  9207. //
  9208. // Queue the request to the error log queue.
  9209. //
  9210. InsertTailList( &IopErrorLogListHead, &entry->ListEntry );
  9211. //
  9212. // If there is no pending work, then queue a request to a worker thread.
  9213. //
  9214. if (!IopErrorLogPortPending) {
  9215. IopErrorLogPortPending = TRUE;
  9216. ExInitializeWorkItem( &IopErrorLogWorkItem, IopErrorLogThread, NULL );
  9217. ExQueueWorkItem( &IopErrorLogWorkItem, DelayedWorkQueue );
  9218. }
  9219. ExReleaseSpinLock(&IopErrorLogLock, oldIrql);
  9220. }
  9221. NTSTATUS
  9222. IoGetBootDiskInformation(
  9223. IN OUT PBOOTDISK_INFORMATION BootDiskInformation,
  9224. IN ULONG Size
  9225. )
  9226. /*++
  9227. Routine Description:
  9228. This routine provides the caller with the signature and offset of
  9229. the boot disk and system disk. This information is obtained from the
  9230. loader block. The callers have to be boot drivers which have registered
  9231. for a callback once all disk devices have been started
  9232. Arguments:
  9233. BootDiskInformation - Supplies a pointer to the structure allocated by the
  9234. caller for requested information.
  9235. Size - Size of the BootDiskInformation structure.
  9236. Return Value:
  9237. STATUS_SUCCESS - successful.
  9238. STATUS_TOO_LATE - indicates that the Loader Block has already been freed
  9239. STATUS_INVALID_PARAMETER - size allocated for boot disk information
  9240. is insufficient.
  9241. --*/
  9242. {
  9243. PLOADER_PARAMETER_BLOCK LoaderBlock = NULL;
  9244. STRING arcBootDeviceString;
  9245. UCHAR deviceNameBuffer[128];
  9246. STRING deviceNameString;
  9247. UNICODE_STRING deviceNameUnicodeString;
  9248. PDEVICE_OBJECT deviceObject;
  9249. UCHAR arcNameBuffer[128];
  9250. STRING arcNameString;
  9251. UNICODE_STRING arcNameUnicodeString;
  9252. PFILE_OBJECT fileObject;
  9253. NTSTATUS status;
  9254. IO_STATUS_BLOCK ioStatusBlock;
  9255. DISK_GEOMETRY diskGeometry;
  9256. PDRIVE_LAYOUT_INFORMATION_EX driveLayout;
  9257. PLIST_ENTRY listEntry;
  9258. PARC_DISK_SIGNATURE diskBlock;
  9259. ULONG diskNumber;
  9260. ULONG partitionNumber;
  9261. PCHAR arcName;
  9262. PULONG buffer;
  9263. PIRP irp;
  9264. KEVENT event;
  9265. LARGE_INTEGER offset;
  9266. ULONG checkSum;
  9267. ULONG i;
  9268. BOOLEAN singleBiosDiskFound;
  9269. PARC_DISK_INFORMATION arcInformation;
  9270. ULONG totalDriverDisksFound = IoGetConfigurationInformation()->DiskCount;
  9271. STRING arcSystemDeviceString;
  9272. STRING osLoaderPathString;
  9273. UNICODE_STRING osLoaderPathUnicodeString;
  9274. PARTITION_INFORMATION_EX PartitionInfo;
  9275. PBOOTDISK_INFORMATION_EX bootDiskInformationEx;
  9276. ULONG diskSignature = 0;
  9277. PULONG sectorBuffer;
  9278. PAGED_CODE();
  9279. if (IopLoaderBlock == NULL) {
  9280. return STATUS_TOO_LATE;
  9281. }
  9282. if (Size < sizeof(BOOTDISK_INFORMATION)) {
  9283. return STATUS_INVALID_PARAMETER;
  9284. }
  9285. if (Size < sizeof(BOOTDISK_INFORMATION_EX)) {
  9286. bootDiskInformationEx = NULL;
  9287. } else {
  9288. bootDiskInformationEx = (PBOOTDISK_INFORMATION_EX)BootDiskInformation;
  9289. }
  9290. LoaderBlock = (PLOADER_PARAMETER_BLOCK)IopLoaderBlock;
  9291. arcInformation = LoaderBlock->ArcDiskInformation;
  9292. //
  9293. // If a single bios disk was found if there is only a
  9294. // single entry on the disk signature list.
  9295. //
  9296. singleBiosDiskFound = (arcInformation->DiskSignatures.Flink->Flink ==
  9297. &arcInformation->DiskSignatures) ? (TRUE) : (FALSE);
  9298. //
  9299. // Get ARC boot device name from loader block.
  9300. //
  9301. RtlInitAnsiString( &arcBootDeviceString,
  9302. LoaderBlock->ArcBootDeviceName );
  9303. //
  9304. // Get ARC system device name from loader block.
  9305. //
  9306. RtlInitAnsiString( &arcSystemDeviceString,
  9307. LoaderBlock->ArcHalDeviceName );
  9308. //
  9309. // For each disk, get its drive layout and check to see if the
  9310. // signature is among the list of signatures in the loader block.
  9311. // If yes, check to see if the disk contains the boot or system
  9312. // partitions. If yes, fill up the requested structure.
  9313. //
  9314. for (diskNumber = 0;
  9315. diskNumber < totalDriverDisksFound;
  9316. diskNumber++) {
  9317. //
  9318. // Construct the NT name for a disk and obtain a reference.
  9319. //
  9320. sprintf( deviceNameBuffer,
  9321. "\\Device\\Harddisk%d\\Partition0",
  9322. diskNumber );
  9323. RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
  9324. status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
  9325. &deviceNameString,
  9326. TRUE );
  9327. if (!NT_SUCCESS( status )) {
  9328. continue;
  9329. }
  9330. status = IoGetDeviceObjectPointer( &deviceNameUnicodeString,
  9331. FILE_READ_ATTRIBUTES,
  9332. &fileObject,
  9333. &deviceObject );
  9334. RtlFreeUnicodeString( &deviceNameUnicodeString );
  9335. if (!NT_SUCCESS( status )) {
  9336. continue;
  9337. }
  9338. //
  9339. // Create IRP for get drive geometry device control.
  9340. //
  9341. irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_GEOMETRY,
  9342. deviceObject,
  9343. NULL,
  9344. 0,
  9345. &diskGeometry,
  9346. sizeof(DISK_GEOMETRY),
  9347. FALSE,
  9348. &event,
  9349. &ioStatusBlock );
  9350. if (!irp) {
  9351. ObDereferenceObject( fileObject );
  9352. continue;
  9353. }
  9354. KeInitializeEvent( &event,
  9355. NotificationEvent,
  9356. FALSE );
  9357. status = IoCallDriver( deviceObject,
  9358. irp );
  9359. if (status == STATUS_PENDING) {
  9360. KeWaitForSingleObject( &event,
  9361. Suspended,
  9362. KernelMode,
  9363. FALSE,
  9364. NULL );
  9365. status = ioStatusBlock.Status;
  9366. }
  9367. if (!NT_SUCCESS( status )) {
  9368. ObDereferenceObject( fileObject );
  9369. continue;
  9370. }
  9371. //
  9372. // Get partition information for this disk.
  9373. //
  9374. status = IoReadPartitionTableEx( deviceObject,
  9375. &driveLayout );
  9376. if (!NT_SUCCESS( status )) {
  9377. ObDereferenceObject( fileObject );
  9378. continue;
  9379. }
  9380. //
  9381. // Make sure sector size is at least 512 bytes.
  9382. //
  9383. if (diskGeometry.BytesPerSector < 512) {
  9384. diskGeometry.BytesPerSector = 512;
  9385. }
  9386. ObDereferenceObject( fileObject );
  9387. //
  9388. // For each ARC disk information record in the loader block
  9389. // match the disk signature and checksum to determine its ARC
  9390. // name and construct the NT ARC names symbolic links.
  9391. //
  9392. for (listEntry = arcInformation->DiskSignatures.Flink;
  9393. listEntry != &arcInformation->DiskSignatures;
  9394. listEntry = listEntry->Flink) {
  9395. //
  9396. // Get next record and compare disk signatures.
  9397. //
  9398. diskBlock = CONTAINING_RECORD( listEntry,
  9399. ARC_DISK_SIGNATURE,
  9400. ListEntry );
  9401. //
  9402. // Compare disk signatures.
  9403. //
  9404. // Or if there is only a single disk drive from
  9405. // both the bios and driver viewpoints then
  9406. // assign an arc name to that drive.
  9407. //
  9408. if ((singleBiosDiskFound &&
  9409. (totalDriverDisksFound == 1) &&
  9410. (driveLayout->PartitionStyle == PARTITION_STYLE_MBR)) ||
  9411. IopVerifyDiskSignature(driveLayout, diskBlock, &diskSignature)) {
  9412. //
  9413. // Create unicode device name for physical disk.
  9414. //
  9415. sprintf( deviceNameBuffer,
  9416. "\\Device\\Harddisk%d\\Partition0",
  9417. diskNumber );
  9418. RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
  9419. status = RtlAnsiStringToUnicodeString( &deviceNameUnicodeString,
  9420. &deviceNameString,
  9421. TRUE );
  9422. if (!NT_SUCCESS( status )) {
  9423. continue;
  9424. }
  9425. //
  9426. // Create unicode ARC name for this partition.
  9427. //
  9428. arcName = diskBlock->ArcName;
  9429. sprintf( arcNameBuffer,
  9430. "\\ArcName\\%s",
  9431. arcName );
  9432. RtlInitAnsiString( &arcNameString, arcNameBuffer );
  9433. status = RtlAnsiStringToUnicodeString( &arcNameUnicodeString,
  9434. &arcNameString,
  9435. TRUE );
  9436. if (!NT_SUCCESS( status )) {
  9437. continue;
  9438. }
  9439. //
  9440. // Create an ARC name for every partition on this disk.
  9441. //
  9442. for (partitionNumber = 0;
  9443. partitionNumber < driveLayout->PartitionCount;
  9444. partitionNumber++) {
  9445. //
  9446. // Create unicode NT device name.
  9447. //
  9448. sprintf( deviceNameBuffer,
  9449. "\\Device\\Harddisk%d\\Partition%d",
  9450. diskNumber,
  9451. partitionNumber+1 );
  9452. RtlInitAnsiString( &deviceNameString, deviceNameBuffer );
  9453. status = RtlAnsiStringToUnicodeString(
  9454. &deviceNameUnicodeString,
  9455. &deviceNameString,
  9456. TRUE );
  9457. if (!NT_SUCCESS( status )) {
  9458. continue;
  9459. }
  9460. //
  9461. // If we came through the single disk case.
  9462. //
  9463. if (diskSignature == 0) {
  9464. diskSignature = driveLayout->Mbr.Signature;
  9465. }
  9466. //
  9467. // Create unicode ARC name for this partition and
  9468. // check to see if this is the boot disk.
  9469. //
  9470. sprintf( arcNameBuffer,
  9471. "%spartition(%d)",
  9472. arcName,
  9473. partitionNumber+1 );
  9474. RtlInitAnsiString( &arcNameString, arcNameBuffer );
  9475. if (RtlEqualString( &arcNameString,
  9476. &arcBootDeviceString,
  9477. TRUE )) {
  9478. BootDiskInformation->BootDeviceSignature = diskSignature;
  9479. //
  9480. // Get Partition Information for the offset of the
  9481. // partition within the disk
  9482. //
  9483. status = IoGetDeviceObjectPointer(
  9484. &deviceNameUnicodeString,
  9485. FILE_READ_ATTRIBUTES,
  9486. &fileObject,
  9487. &deviceObject );
  9488. RtlFreeUnicodeString( &deviceNameUnicodeString );
  9489. if (!NT_SUCCESS( status )) {
  9490. continue;
  9491. }
  9492. //
  9493. // Create IRP for get drive geometry device control.
  9494. //
  9495. irp = IoBuildDeviceIoControlRequest(
  9496. IOCTL_DISK_GET_PARTITION_INFO_EX,
  9497. deviceObject,
  9498. NULL,
  9499. 0,
  9500. &PartitionInfo,
  9501. sizeof(PARTITION_INFORMATION_EX),
  9502. FALSE,
  9503. &event,
  9504. &ioStatusBlock );
  9505. if (!irp) {
  9506. ObDereferenceObject( fileObject );
  9507. continue;
  9508. }
  9509. KeInitializeEvent( &event,
  9510. NotificationEvent,
  9511. FALSE );
  9512. status = IoCallDriver( deviceObject,
  9513. irp );
  9514. if (status == STATUS_PENDING) {
  9515. KeWaitForSingleObject( &event,
  9516. Suspended,
  9517. KernelMode,
  9518. FALSE,
  9519. NULL );
  9520. status = ioStatusBlock.Status;
  9521. }
  9522. if (!NT_SUCCESS( status )) {
  9523. ObDereferenceObject( fileObject );
  9524. continue;
  9525. }
  9526. BootDiskInformation->BootPartitionOffset =
  9527. PartitionInfo.StartingOffset.QuadPart;
  9528. if (driveLayout->PartitionStyle == PARTITION_STYLE_GPT) {
  9529. if (bootDiskInformationEx) {
  9530. bootDiskInformationEx->BootDeviceIsGpt = TRUE;
  9531. //
  9532. // Structure copy.
  9533. //
  9534. bootDiskInformationEx->BootDeviceGuid = driveLayout->Gpt.DiskId;
  9535. }
  9536. } else {
  9537. if (bootDiskInformationEx) {
  9538. bootDiskInformationEx->BootDeviceIsGpt = FALSE;
  9539. }
  9540. }
  9541. ObDereferenceObject( fileObject );
  9542. }
  9543. //
  9544. // See if this is the system partition.
  9545. //
  9546. if (RtlEqualString( &arcNameString,
  9547. &arcSystemDeviceString,
  9548. TRUE )) {
  9549. BootDiskInformation->SystemDeviceSignature = diskSignature;
  9550. //
  9551. // Get Partition Information for the offset of the
  9552. // partition within the disk
  9553. //
  9554. status = IoGetDeviceObjectPointer(
  9555. &deviceNameUnicodeString,
  9556. FILE_READ_ATTRIBUTES,
  9557. &fileObject,
  9558. &deviceObject );
  9559. RtlFreeUnicodeString( &deviceNameUnicodeString );
  9560. if (!NT_SUCCESS( status )) {
  9561. continue;
  9562. }
  9563. //
  9564. // Create IRP for get drive geometry device control.
  9565. //
  9566. irp = IoBuildDeviceIoControlRequest(
  9567. IOCTL_DISK_GET_PARTITION_INFO_EX,
  9568. deviceObject,
  9569. NULL,
  9570. 0,
  9571. &PartitionInfo,
  9572. sizeof(PARTITION_INFORMATION_EX),
  9573. FALSE,
  9574. &event,
  9575. &ioStatusBlock );
  9576. if (!irp) {
  9577. ObDereferenceObject( fileObject );
  9578. continue;
  9579. }
  9580. KeInitializeEvent( &event,
  9581. NotificationEvent,
  9582. FALSE );
  9583. status = IoCallDriver( deviceObject,
  9584. irp );
  9585. if (status == STATUS_PENDING) {
  9586. KeWaitForSingleObject( &event,
  9587. Suspended,
  9588. KernelMode,
  9589. FALSE,
  9590. NULL );
  9591. status = ioStatusBlock.Status;
  9592. }
  9593. if (!NT_SUCCESS( status )) {
  9594. ObDereferenceObject( fileObject );
  9595. continue;
  9596. }
  9597. BootDiskInformation->SystemPartitionOffset =
  9598. PartitionInfo.StartingOffset.QuadPart;
  9599. if (driveLayout->PartitionStyle == PARTITION_STYLE_GPT) {
  9600. if (bootDiskInformationEx) {
  9601. bootDiskInformationEx->SystemDeviceIsGpt = TRUE;
  9602. //
  9603. // Structure copy.
  9604. //
  9605. bootDiskInformationEx->SystemDeviceGuid = driveLayout->Gpt.DiskId;
  9606. }
  9607. } else {
  9608. if (bootDiskInformationEx) {
  9609. bootDiskInformationEx->SystemDeviceIsGpt = FALSE;
  9610. }
  9611. }
  9612. ObDereferenceObject( fileObject );
  9613. }
  9614. }
  9615. }
  9616. }
  9617. ExFreePool( driveLayout );
  9618. }
  9619. return STATUS_SUCCESS;
  9620. }
  9621. //
  9622. // Thunks to support standard call callers
  9623. //
  9624. #ifdef IoCallDriver
  9625. #undef IoCallDriver
  9626. #endif
  9627. NTSTATUS
  9628. IoCallDriver(
  9629. IN PDEVICE_OBJECT DeviceObject,
  9630. IN OUT PIRP Irp
  9631. )
  9632. {
  9633. return IofCallDriver (DeviceObject, Irp);
  9634. }
  9635. #ifdef IoCompleteRequest
  9636. #undef IoCompleteRequest
  9637. #endif
  9638. VOID
  9639. IoCompleteRequest(
  9640. IN PIRP Irp,
  9641. IN CCHAR PriorityBoost
  9642. )
  9643. {
  9644. IofCompleteRequest (Irp, PriorityBoost);
  9645. }
  9646. PSECURITY_DESCRIPTOR
  9647. IopCreateDefaultDeviceSecurityDescriptor(
  9648. IN DEVICE_TYPE DeviceType,
  9649. IN ULONG DeviceCharacteristics,
  9650. IN BOOLEAN DeviceHasName,
  9651. IN PUCHAR Buffer,
  9652. OUT PACL *AllocatedAcl,
  9653. OUT PSECURITY_INFORMATION SecurityInformation OPTIONAL
  9654. )
  9655. {
  9656. PSECURITY_DESCRIPTOR descriptor = (PSECURITY_DESCRIPTOR) Buffer;
  9657. NTSTATUS status;
  9658. PAGED_CODE();
  9659. if(ARGUMENT_PRESENT(SecurityInformation)) {
  9660. (*SecurityInformation) = 0;
  9661. }
  9662. *AllocatedAcl = NULL;
  9663. switch ( DeviceType ) {
  9664. case FILE_DEVICE_DISK_FILE_SYSTEM:
  9665. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  9666. case FILE_DEVICE_FILE_SYSTEM:
  9667. case FILE_DEVICE_TAPE_FILE_SYSTEM: {
  9668. //
  9669. // Use the standard public default protection for these types of devices.
  9670. //
  9671. RtlCreateSecurityDescriptor(descriptor,
  9672. SECURITY_DESCRIPTOR_REVISION );
  9673. RtlSetDaclSecurityDescriptor(descriptor,
  9674. TRUE,
  9675. SePublicDefaultUnrestrictedDacl,
  9676. FALSE );
  9677. if(ARGUMENT_PRESENT(SecurityInformation)) {
  9678. (*SecurityInformation) |= DACL_SECURITY_INFORMATION;
  9679. }
  9680. break;
  9681. }
  9682. case FILE_DEVICE_CD_ROM:
  9683. case FILE_DEVICE_MASS_STORAGE:
  9684. case FILE_DEVICE_DISK:
  9685. case FILE_DEVICE_VIRTUAL_DISK:
  9686. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  9687. case FILE_DEVICE_DFS_FILE_SYSTEM:
  9688. case FILE_DEVICE_NETWORK: {
  9689. if ((DeviceHasName) &&
  9690. ((DeviceCharacteristics & FILE_FLOPPY_DISKETTE) != 0)) {
  9691. status = RtlCreateSecurityDescriptor(
  9692. descriptor,
  9693. SECURITY_DESCRIPTOR_REVISION );
  9694. ASSERT( NT_SUCCESS( status ) );
  9695. status = RtlSetDaclSecurityDescriptor(
  9696. descriptor,
  9697. TRUE,
  9698. SePublicOpenUnrestrictedDacl,
  9699. FALSE );
  9700. ASSERT( NT_SUCCESS( status ) );
  9701. if(ARGUMENT_PRESENT(SecurityInformation)) {
  9702. (*SecurityInformation) |= DACL_SECURITY_INFORMATION;
  9703. }
  9704. } else {
  9705. UCHAR i;
  9706. PACL acl;
  9707. BOOLEAN aceFound;
  9708. BOOLEAN aceFoundForCDROM;
  9709. PACCESS_ALLOWED_ACE ace;
  9710. //
  9711. // Protect the device so that an administrator can run chkdsk
  9712. // on it. This is done by making a copy of the default public
  9713. // ACL and changing the accesses granted to the administrators
  9714. // alias.
  9715. //
  9716. // The logic here is:
  9717. //
  9718. // - Copy the public default dacl into another buffer
  9719. //
  9720. // - Find the ACE granting ADMINISTRATORS access
  9721. //
  9722. // - Change the granted access mask of that ACE to give
  9723. // administrators write access.
  9724. //
  9725. //
  9726. acl = ExAllocatePoolWithTag(
  9727. PagedPool,
  9728. SePublicDefaultUnrestrictedDacl->AclSize,
  9729. 'eSoI' );
  9730. if (!acl) {
  9731. return NULL;
  9732. }
  9733. RtlCopyMemory( acl,
  9734. SePublicDefaultUnrestrictedDacl,
  9735. SePublicDefaultUnrestrictedDacl->AclSize );
  9736. //
  9737. // Find the Administrators ACE
  9738. //
  9739. aceFound = FALSE;
  9740. aceFoundForCDROM = FALSE;
  9741. for ( i = 0, status = RtlGetAce(acl, 0, &ace);
  9742. NT_SUCCESS(status);
  9743. i++, status = RtlGetAce(acl, i, &ace)) {
  9744. PSID sid;
  9745. sid = &(ace->SidStart);
  9746. if (RtlEqualSid( SeAliasAdminsSid, sid )) {
  9747. PACCESS_MASK mask;
  9748. ace->Mask |= ( GENERIC_READ |
  9749. GENERIC_WRITE |
  9750. GENERIC_EXECUTE );
  9751. aceFound = TRUE;
  9752. }
  9753. if (DeviceType == FILE_DEVICE_CD_ROM) {
  9754. if (RtlEqualSid( SeWorldSid, sid )) {
  9755. ace->Mask |= GENERIC_READ;
  9756. aceFoundForCDROM = TRUE;
  9757. }
  9758. }
  9759. }
  9760. //
  9761. // If the ACE wasn't found, then the public default ACL has been
  9762. // changed. For this case, this code needs to be updated to match
  9763. // the new public default DACL.
  9764. //
  9765. ASSERT(aceFound == TRUE);
  9766. if (DeviceType == FILE_DEVICE_CD_ROM) {
  9767. ASSERT(aceFoundForCDROM == TRUE);
  9768. }
  9769. //
  9770. // Finally, build a full security descriptor from the above DACL.
  9771. //
  9772. RtlCreateSecurityDescriptor( descriptor,
  9773. SECURITY_DESCRIPTOR_REVISION );
  9774. RtlSetDaclSecurityDescriptor( descriptor,
  9775. TRUE,
  9776. acl,
  9777. FALSE );
  9778. if(ARGUMENT_PRESENT(SecurityInformation)) {
  9779. (*SecurityInformation) |= DACL_SECURITY_INFORMATION;
  9780. }
  9781. *AllocatedAcl = acl;
  9782. }
  9783. break;
  9784. }
  9785. default: {
  9786. status = RtlCreateSecurityDescriptor( descriptor,
  9787. SECURITY_DESCRIPTOR_REVISION );
  9788. ASSERT( NT_SUCCESS( status ) );
  9789. status = RtlSetDaclSecurityDescriptor( descriptor,
  9790. TRUE,
  9791. SePublicOpenUnrestrictedDacl,
  9792. FALSE );
  9793. if(ARGUMENT_PRESENT(SecurityInformation)) {
  9794. (*SecurityInformation) |= DACL_SECURITY_INFORMATION;
  9795. }
  9796. break;
  9797. }
  9798. }
  9799. return descriptor;
  9800. }
  9801. NTSTATUS
  9802. IoGetRequestorSessionId(
  9803. IN PIRP Irp,
  9804. OUT PULONG pSessionId
  9805. )
  9806. /*++
  9807. Routine Description:
  9808. This routine returns the session ID for process that originally
  9809. requested the specified I/O operation.
  9810. Arguments:
  9811. Irp - Pointer to the I/O Request Packet.
  9812. pSessionId - Pointer to the session Id which is set upon successful return.
  9813. Return Value:
  9814. Returns STATUS_SUCCESS if the session ID was available, otherwise
  9815. STATUS_UNSUCCESSFUL.
  9816. --*/
  9817. {
  9818. PEPROCESS Process;
  9819. //
  9820. // Get the address of the process that requested the I/O operation.
  9821. //
  9822. if (Irp->Tail.Overlay.Thread) {
  9823. Process = THREAD_TO_PROCESS( Irp->Tail.Overlay.Thread );
  9824. *pSessionId = MmGetSessionId(Process);
  9825. return(STATUS_SUCCESS);
  9826. }
  9827. *pSessionId = (ULONG) -1;
  9828. return(STATUS_UNSUCCESSFUL);
  9829. }
  9830. VOID
  9831. IopUpdateOtherOperationCount(
  9832. VOID
  9833. )
  9834. /*++
  9835. Routine Description:
  9836. This routine is invoked to update the operation count for the current
  9837. process to indicate that an I/O service other than a read or write
  9838. has been invoked.
  9839. There is an implicit assumption that this call is always made in the context
  9840. of the issuing thread.
  9841. Arguments:
  9842. None.
  9843. Return Value:
  9844. None.
  9845. --*/
  9846. {
  9847. if (IoCountOperations == TRUE) {
  9848. IoOtherOperationCount += 1;
  9849. ExInterlockedAddLargeStatistic( &THREAD_TO_PROCESS(PsGetCurrentThread())->OtherOperationCount, 1);
  9850. }
  9851. }
  9852. VOID
  9853. IopUpdateReadOperationCount(
  9854. VOID
  9855. )
  9856. /*++
  9857. Routine Description:
  9858. This routine is invoked to update the read operation count for the
  9859. current process to indicate that the NtReadFile system service has
  9860. been invoked.
  9861. There is an implicit assumption that this call is always made in the context
  9862. of the issuing thread.
  9863. Arguments:
  9864. None.
  9865. Return Value:
  9866. None.
  9867. --*/
  9868. {
  9869. if (IoCountOperations == TRUE) {
  9870. IoReadOperationCount += 1;
  9871. ExInterlockedAddLargeStatistic( &THREAD_TO_PROCESS(PsGetCurrentThread())->ReadOperationCount, 1);
  9872. }
  9873. }
  9874. VOID
  9875. IopUpdateWriteOperationCount(
  9876. VOID
  9877. )
  9878. /*++
  9879. Routine Description:
  9880. This routine is invoked to update the write operation count for the
  9881. current process to indicate that the NtWriteFile service other has
  9882. been invoked.
  9883. There is an implicit assumption that this call is always made in the context
  9884. of the issuing thread.
  9885. Arguments:
  9886. None.
  9887. Return Value:
  9888. None.
  9889. --*/
  9890. {
  9891. if (IoCountOperations == TRUE) {
  9892. IoWriteOperationCount += 1;
  9893. ExInterlockedAddLargeStatistic( &THREAD_TO_PROCESS(PsGetCurrentThread())->WriteOperationCount, 1);
  9894. }
  9895. }
  9896. VOID
  9897. IopUpdateOtherTransferCount(
  9898. IN ULONG TransferCount
  9899. )
  9900. /*++
  9901. Routine Description:
  9902. This routine is invoked to update the transfer count for the current
  9903. process for an operation other than a read or write system service.
  9904. There is an implicit assumption that this call is always made in the context
  9905. of the issuing thread. Also note that overflow is folded into the thread's
  9906. process.
  9907. Arguments:
  9908. TransferCount - The count of the number of bytes transferred.
  9909. Return Value:
  9910. None.
  9911. --*/
  9912. {
  9913. if (IoCountOperations == TRUE) {
  9914. ExInterlockedAddLargeStatistic( &IoOtherTransferCount, TransferCount );
  9915. ExInterlockedAddLargeStatistic( &THREAD_TO_PROCESS(PsGetCurrentThread())->OtherTransferCount, TransferCount);
  9916. }
  9917. }
  9918. VOID
  9919. IopUpdateReadTransferCount(
  9920. IN ULONG TransferCount
  9921. )
  9922. /*++
  9923. Routine Description:
  9924. This routine is invoked to update the read transfer count for the
  9925. current process.
  9926. There is an implicit assumption that this call is always made in the context
  9927. of the issuing thread. Also note that overflow is folded into the thread's
  9928. process.
  9929. Arguments:
  9930. TransferCount - The count of the number of bytes transferred.
  9931. Return Value:
  9932. None.
  9933. --*/
  9934. {
  9935. if (IoCountOperations == TRUE) {
  9936. ExInterlockedAddLargeStatistic( &IoReadTransferCount, TransferCount );
  9937. ExInterlockedAddLargeStatistic( &THREAD_TO_PROCESS(PsGetCurrentThread())->ReadTransferCount, TransferCount);
  9938. }
  9939. }
  9940. VOID
  9941. IopUpdateWriteTransferCount(
  9942. IN ULONG TransferCount
  9943. )
  9944. /*++
  9945. Routine Description:
  9946. This routine is invoked to update the write transfer count for the
  9947. current process.
  9948. There is an implicit assumption that this call is always made in the context
  9949. of the issuing thread. Also note that overflow is folded into the thread's
  9950. process.
  9951. Arguments:
  9952. TransferCount - The count of the number of bytes transferred.
  9953. Return Value:
  9954. None.
  9955. --*/
  9956. {
  9957. if (IoCountOperations == TRUE) {
  9958. ExInterlockedAddLargeStatistic( &IoWriteTransferCount, TransferCount );
  9959. ExInterlockedAddLargeStatistic( &THREAD_TO_PROCESS(PsGetCurrentThread())->WriteTransferCount, TransferCount);
  9960. }
  9961. }
  9962. VOID
  9963. IoCancelFileOpen(
  9964. IN PDEVICE_OBJECT DeviceObject,
  9965. IN PFILE_OBJECT FileObject
  9966. )
  9967. /*++
  9968. Routine Description:
  9969. This routine is invoked by a filter driver to send a close to the
  9970. next filesystem driver below. It's needed as part of the file open
  9971. process. The filter driver forwards the open to the FSD and the FSD
  9972. returns success. The filter driver then examines some stuff and
  9973. decides that the open has to be failed. In this case it has to send
  9974. a close to the FSD.
  9975. We can safely assume a thread context because it has to be called only
  9976. in the context of file open. If the file object already has a handle
  9977. then the owner of the handle can then simply close the handle to the
  9978. file object and we will close the file.
  9979. This code is extracted from IopCloseFile and IopDeleteFile. So it is
  9980. duplication of code but it prevents duplication elsewhere in other FSDs.
  9981. Arguments:
  9982. FileObject - Points to the file that needs to be closed.
  9983. DeviceObject - Points to the device object of the filesystem driver below
  9984. the filter driver.
  9985. Return Value:
  9986. None
  9987. --*/
  9988. {
  9989. PIRP irp;
  9990. PIO_STACK_LOCATION irpSp;
  9991. PFAST_IO_DISPATCH fastIoDispatch;
  9992. NTSTATUS status;
  9993. KEVENT event;
  9994. KIRQL irql;
  9995. IO_STATUS_BLOCK ioStatusBlock;
  9996. PVPB vpb;
  9997. BOOLEAN referenceCountDecremented;
  9998. //
  9999. // Cannot call this function if a handle has already been created
  10000. // for this file.
  10001. //
  10002. ASSERT(!(FileObject->Flags & FO_HANDLE_CREATED));
  10003. if (ObReferenceObject(FileObject) > 2 || (FileObject->Flags & FO_HANDLE_CREATED)) {
  10004. KeBugCheckEx( INVALID_CANCEL_OF_FILE_OPEN, (ULONG_PTR) FileObject, (ULONG_PTR)DeviceObject, 0, 0 );
  10005. return;
  10006. }
  10007. ObDereferenceObject(FileObject);
  10008. //
  10009. // Initialize the local event that will be used to synchronize access
  10010. // to the driver completing this I/O operation.
  10011. //
  10012. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  10013. //
  10014. // Reset the event in the file object.
  10015. //
  10016. KeClearEvent( &FileObject->Event );
  10017. //
  10018. // Allocate and initialize the I/O Request Packet (IRP) for this
  10019. // operation.
  10020. //
  10021. irp = IopAllocateIrpMustSucceed( DeviceObject->StackSize );
  10022. irp->Tail.Overlay.OriginalFileObject = FileObject;
  10023. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  10024. irp->RequestorMode = KernelMode;
  10025. //
  10026. // Fill in the service independent parameters in the IRP.
  10027. //
  10028. irp->UserEvent = &event;
  10029. irp->UserIosb = &irp->IoStatus;
  10030. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  10031. irp->Flags = IRP_SYNCHRONOUS_API | IRP_CLOSE_OPERATION;
  10032. //
  10033. // Get a pointer to the stack location for the first driver. This will
  10034. // be used to pass the original function codes and parameters. No
  10035. // function-specific parameters are required for this operation.
  10036. //
  10037. irpSp = IoGetNextIrpStackLocation( irp );
  10038. irpSp->MajorFunction = IRP_MJ_CLEANUP;
  10039. irpSp->FileObject = FileObject;
  10040. //
  10041. // Insert the packet at the head of the IRP list for the thread.
  10042. //
  10043. IopQueueThreadIrp( irp );
  10044. //
  10045. // Invoke the driver at its appropriate dispatch entry with the IRP.
  10046. //
  10047. status = IoCallDriver( DeviceObject, irp );
  10048. //
  10049. // If no error was incurred, wait for the I/O operation to complete.
  10050. //
  10051. if (status == STATUS_PENDING) {
  10052. (VOID) KeWaitForSingleObject( &event,
  10053. UserRequest,
  10054. KernelMode,
  10055. FALSE,
  10056. (PLARGE_INTEGER) NULL );
  10057. }
  10058. //
  10059. // The following code tears down the IRP by hand since it may not
  10060. // be possible for it to be completed (either because this code was
  10061. // invoked as APC_LEVEL in the first place - or because the reference
  10062. // count on the object cannot be incremented due to this routine
  10063. // being invoked by the delete file procedure below). Cleanup IRPs
  10064. // therefore use close semantics (the close operation flag is set
  10065. // in the IRP) so that the I/O complete request routine itself sets
  10066. // the event to the Signaled state.
  10067. //
  10068. KeRaiseIrql( APC_LEVEL, &irql );
  10069. IopDequeueThreadIrp( irp );
  10070. KeLowerIrql( irql );
  10071. //
  10072. // Reuse the IRP for the next operation.
  10073. //
  10074. IoReuseIrp( irp , STATUS_SUCCESS);
  10075. //
  10076. // Reset the event in the file object.
  10077. //
  10078. KeClearEvent( &FileObject->Event );
  10079. KeClearEvent(&event);
  10080. //
  10081. // Get a pointer to the stack location for the first driver. This is
  10082. // where the function codes and parameters are placed.
  10083. //
  10084. irpSp = IoGetNextIrpStackLocation( irp );
  10085. //
  10086. // Fill in the IRP, indicating that this file object is being deleted.
  10087. //
  10088. irpSp->MajorFunction = IRP_MJ_CLOSE;
  10089. irpSp->FileObject = FileObject;
  10090. irp->UserIosb = &ioStatusBlock;
  10091. irp->UserEvent = &event;
  10092. irp->Tail.Overlay.OriginalFileObject = FileObject;
  10093. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  10094. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  10095. irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
  10096. //
  10097. // Place this packet in the thread's I/O pending queue.
  10098. //
  10099. IopQueueThreadIrp( irp );
  10100. //
  10101. // Decrement the reference count on the VPB, if necessary. We
  10102. // have to do this BEFORE handing the Irp to the file system
  10103. // because of a trick the file systems play with close, and
  10104. // believe me, you really don't want to know what it is.
  10105. //
  10106. // Since there is not a error path here (close cannot fail),
  10107. // and the file system is the only ome who can actually synchronize
  10108. // with the actual completion of close processing, the file system
  10109. // is the one responsible for Vpb deletion.
  10110. //
  10111. vpb = FileObject->Vpb;
  10112. if (vpb && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  10113. IopInterlockedDecrementUlong( LockQueueIoVpbLock,
  10114. &vpb->ReferenceCount );
  10115. FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
  10116. }
  10117. //
  10118. // Give the device driver the packet. If this request does not work,
  10119. // there is nothing that can be done about it. This is unfortunate
  10120. // because the driver may have had problems that it was about to
  10121. // report about other operations (e.g., write behind failures, etc.)
  10122. // that it can no longer report. The reason is that this routine
  10123. // is really initially invoked by NtClose, which has already closed
  10124. // the caller's handle, and that's what the return status from close
  10125. // indicates: the handle has successfully been closed.
  10126. //
  10127. status = IoCallDriver( DeviceObject, irp );
  10128. if (status == STATUS_PENDING) {
  10129. (VOID) KeWaitForSingleObject( &event,
  10130. Executive,
  10131. KernelMode,
  10132. FALSE,
  10133. (PLARGE_INTEGER) NULL );
  10134. }
  10135. //
  10136. // Perform any completion operations that need to be performed on
  10137. // the IRP that was used for this request. This is done here as
  10138. // as opposed to in normal completion code because there is a race
  10139. // condition between when this routine executes if it was invoked
  10140. // from a special kernel APC (e.g., some IRP was just completed and
  10141. // dereferenced this file object for the last time), and when the
  10142. // special kernel APC because of this packet's completion executing.
  10143. //
  10144. // This problem is solved by not having to queue a special kernel
  10145. // APC routine for completion of this packet. Rather, it is treated
  10146. // much like a synchronous paging I/O operation, except that the
  10147. // packet is not even freed during I/O completion. This is because
  10148. // the packet is still in this thread's queue, and there is no way
  10149. // to get it out except at APC_LEVEL. Unfortunately, the part of
  10150. // I/O completion that needs to dequeue the packet is running at
  10151. // DISPATCH_LEVEL.
  10152. //
  10153. // Hence, the packet must be removed from the queue (synchronized,
  10154. // of course), and then it must be freed.
  10155. //
  10156. KeRaiseIrql( APC_LEVEL, &irql );
  10157. IopDequeueThreadIrp( irp );
  10158. KeLowerIrql( irql );
  10159. IoFreeIrp( irp );
  10160. }
  10161. VOID
  10162. IoRetryIrpCompletions(
  10163. VOID
  10164. )
  10165. /*++
  10166. Routine Description:
  10167. This routine is called from Mm when a page fault has completed. It's
  10168. called on the special occasion when a thread faults a page and then when
  10169. it's waiting for the inpage to complete, an IopCompleteRequest APC fires
  10170. and we fault the same page again (say if the user buffer falls on the
  10171. same page). Note the fault during the APC may be referencing the same or
  10172. a different user virtual address but this is irrelevant - the problem lies
  10173. in the fact that both virtual address references are to the same physical
  10174. page and thus result in a collided fault in the Mm.
  10175. Mm detects this case (to avoid deadlock) and returns STATUS_FAULT_COLLISION
  10176. and the I/O manager bails out the APC after marking the Irp with the flag
  10177. IRP_RETRY_IO_COMPLETION. Later on when Mm has decided the fault has
  10178. progressed far enough to avoid deadlock, it calls back into this routine
  10179. which calls IopCompleteRequest again. The code in IopCompleteRequest is
  10180. written in a reentrant way so that the retry knows the completion is only
  10181. partially processed so far. We can fault in two places in IopCompleteRequest
  10182. and in both cases if we call IopCompleteRequest again they will now work.
  10183. This call must be called in the context of the thread that is faulting.
  10184. This function should be called at APC_LEVEL.
  10185. Arguments:
  10186. None.
  10187. Return Value:
  10188. None.
  10189. --*/
  10190. {
  10191. PLIST_ENTRY header;
  10192. PLIST_ENTRY entry;
  10193. KIRQL irql;
  10194. PETHREAD thread;
  10195. PIRP irp;
  10196. PVOID saveAuxiliaryPointer = NULL;
  10197. PFILE_OBJECT fileObject;
  10198. thread = PsGetCurrentThread();
  10199. ASSERT(KeGetCurrentIrql() == APC_LEVEL);
  10200. //
  10201. // Raise the IRQL so that the IrpList cannot be modified by a completion
  10202. // APC.
  10203. //
  10204. header = &thread->IrpList;
  10205. entry = thread->IrpList.Flink;
  10206. //
  10207. // Walk the list of pending IRPs, completing each of them.
  10208. //
  10209. while (header != entry) {
  10210. irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry );
  10211. entry = entry->Flink;
  10212. if (irp->Flags & IRP_RETRY_IO_COMPLETION) {
  10213. ASSERT(!(irp->Flags & IRP_CREATE_OPERATION));
  10214. irp->Flags &= ~IRP_RETRY_IO_COMPLETION;
  10215. fileObject = irp->Tail.Overlay.OriginalFileObject;
  10216. IopCompleteRequest(
  10217. &irp->Tail.Apc,
  10218. NULL,
  10219. NULL,
  10220. &fileObject,
  10221. &saveAuxiliaryPointer);
  10222. }
  10223. }
  10224. }
  10225. #if defined(_WIN64)
  10226. BOOLEAN
  10227. IoIs32bitProcess(
  10228. IN PIRP Irp OPTIONAL
  10229. )
  10230. /*+++
  10231. Routine Description:
  10232. This API returns TRUE if the process that originated the IRP is running a 32 bit x86
  10233. application. If there is no IRP then a NULL can be passed to the API and that implies
  10234. that the current process context is used to test if its running a 32 bit x86 application.
  10235. Its assumed a NULL will be passed by drivers executing in the fast io path.
  10236. Arguments:
  10237. IRP OPTIONAL.
  10238. Return Value:
  10239. None.
  10240. --*/
  10241. {
  10242. if (Irp) {
  10243. if (Irp->RequestorMode == UserMode) {
  10244. PEPROCESS Process;
  10245. Process = IoGetRequestorProcess(Irp);
  10246. if (Process && PsGetProcessWow64Process(Process)) {
  10247. return TRUE;
  10248. }
  10249. }
  10250. } else {
  10251. return ((ExGetPreviousMode() == UserMode) &&
  10252. (PsGetProcessWow64Process(PsGetCurrentProcess())));
  10253. }
  10254. return FALSE;
  10255. }
  10256. #endif
  10257. NTSTATUS
  10258. IoAsynchronousPageRead(
  10259. IN PFILE_OBJECT FileObject,
  10260. IN PMDL MemoryDescriptorList,
  10261. IN PLARGE_INTEGER StartingOffset,
  10262. IN PKEVENT Event,
  10263. OUT PIO_STATUS_BLOCK IoStatusBlock
  10264. )
  10265. {
  10266. return IopPageReadInternal(FileObject,
  10267. MemoryDescriptorList,
  10268. StartingOffset,
  10269. Event,
  10270. IoStatusBlock,
  10271. TRUE
  10272. );
  10273. }
  10274. NTSTATUS
  10275. IoQueryFileDosDeviceName(
  10276. IN PFILE_OBJECT FileObject,
  10277. OUT POBJECT_NAME_INFORMATION *ObjectNameInformation
  10278. )
  10279. /*++
  10280. Routine Description:
  10281. Thin shell around IopQueryNameInternal that returns a dos device name
  10282. for a file e.g c:\foo
  10283. Arguments:
  10284. FileObject - Points to the file that needs to be closed.
  10285. ObjectNameInformation - structure to return name in note this will be a flat
  10286. unicode string where the buffer is adjancent to the string
  10287. RetLength - returned length of structure
  10288. Return Value:
  10289. None
  10290. --*/
  10291. {
  10292. ULONG ObjectNameInfoLength;
  10293. POBJECT_NAME_INFORMATION ObjectNameInfo;
  10294. NTSTATUS Status;
  10295. //
  10296. // Allocate an initial buffer to query the filename, query, then
  10297. // retry if needed with the correct length.
  10298. //
  10299. ObjectNameInfoLength = 96*sizeof(WCHAR) + sizeof(UNICODE_STRING);
  10300. while (TRUE) {
  10301. ObjectNameInfo = ExAllocatePoolWithTag( PagedPool, ObjectNameInfoLength, 'nDoI');
  10302. if (ObjectNameInfo == NULL) {
  10303. return STATUS_INSUFFICIENT_RESOURCES;
  10304. }
  10305. Status = IopQueryNameInternal( FileObject,
  10306. TRUE,
  10307. TRUE,
  10308. ObjectNameInfo,
  10309. ObjectNameInfoLength,
  10310. &ObjectNameInfoLength );
  10311. if (Status == STATUS_SUCCESS) {
  10312. *ObjectNameInformation = ObjectNameInfo;
  10313. break;
  10314. }
  10315. ExFreePool( ObjectNameInfo );
  10316. if (Status != STATUS_BUFFER_OVERFLOW) {
  10317. break;
  10318. }
  10319. }
  10320. return Status;
  10321. }
  10322. NTSTATUS
  10323. IopUnloadSafeCompletion(
  10324. IN PDEVICE_OBJECT DeviceObject,
  10325. IN PIRP Irp,
  10326. IN PVOID Context
  10327. )
  10328. {
  10329. PIO_UNLOAD_SAFE_COMPLETION_CONTEXT Usc = Context;
  10330. NTSTATUS Status;
  10331. ObReferenceObject (Usc->DeviceObject);
  10332. Status = Usc->CompletionRoutine (DeviceObject, Irp, Usc->Context);
  10333. ObDereferenceObject (Usc->DeviceObject);
  10334. ExFreePool (Usc);
  10335. return Status;
  10336. }
  10337. NTSTATUS
  10338. IoSetCompletionRoutineEx(
  10339. IN PDEVICE_OBJECT DeviceObject,
  10340. IN PIRP Irp,
  10341. IN PIO_COMPLETION_ROUTINE CompletionRoutine,
  10342. IN PVOID Context,
  10343. IN BOOLEAN InvokeOnSuccess,
  10344. IN BOOLEAN InvokeOnError,
  10345. IN BOOLEAN InvokeOnCancel
  10346. )
  10347. //++
  10348. // Routine Description:
  10349. //
  10350. // This routine is invoked to set the address of a completion routine which
  10351. // is to be invoked when an I/O packet has been completed by a lower-level
  10352. // driver. This routine obtains a reference count to the specified device object
  10353. // to protect the completion routine from unload problems.
  10354. //
  10355. // Arguments:
  10356. //
  10357. // DeviceObject - Device object to take references on.
  10358. //
  10359. // Irp - Pointer to the I/O Request Packet itself.
  10360. //
  10361. // CompletionRoutine - Address of the completion routine that is to be
  10362. // invoked once the next level driver completes the packet.
  10363. //
  10364. // Context - Specifies a context parameter to be passed to the completion
  10365. // routine.
  10366. //
  10367. // InvokeOnSuccess - Specifies that the completion routine is invoked when the
  10368. // operation is successfully completed.
  10369. //
  10370. // InvokeOnError - Specifies that the completion routine is invoked when the
  10371. // operation completes with an error status.
  10372. //
  10373. // InvokeOnCancel - Specifies that the completion routine is invoked when the
  10374. // operation is being canceled.
  10375. //
  10376. // Return Value:
  10377. //
  10378. // None.
  10379. //
  10380. //--
  10381. {
  10382. PIO_UNLOAD_SAFE_COMPLETION_CONTEXT Usc;
  10383. Usc = ExAllocatePoolWithTag (NonPagedPool, sizeof (*Usc), 'sUoI');
  10384. if (Usc == NULL) {
  10385. return STATUS_INSUFFICIENT_RESOURCES;
  10386. }
  10387. Usc->DeviceObject = DeviceObject;
  10388. Usc->CompletionRoutine = CompletionRoutine;
  10389. Usc->Context = Context;
  10390. IoSetCompletionRoutine (Irp, IopUnloadSafeCompletion, Usc, InvokeOnSuccess, InvokeOnError, InvokeOnCancel);
  10391. return STATUS_SUCCESS;
  10392. }
  10393. NTSTATUS
  10394. IoCreateDriver(
  10395. IN PUNICODE_STRING DriverName OPTIONAL,
  10396. IN PDRIVER_INITIALIZE InitializationFunction
  10397. )
  10398. /*++
  10399. Routine Description:
  10400. This routine creates a driver object for a kernel component that
  10401. was not loaded as a driver. If the creation of the driver object
  10402. succeeds, Initialization function is invoked with the same parameters
  10403. as passed to DriverEntry.
  10404. Parameters:
  10405. DriverName - Supplies the name of the driver for which a driver object
  10406. is to be created.
  10407. InitializationFunction - Equivalent to DriverEntry().
  10408. ReturnValue:
  10409. Status code that indicates whether or not the function was successful.
  10410. Notes:
  10411. --*/
  10412. {
  10413. OBJECT_ATTRIBUTES objectAttributes;
  10414. NTSTATUS status;
  10415. PDRIVER_OBJECT driverObject;
  10416. HANDLE driverHandle;
  10417. ULONG objectSize;
  10418. USHORT length;
  10419. UNICODE_STRING driverName, serviceName;
  10420. WCHAR buffer[60];
  10421. ULONG i;
  10422. PAGED_CODE();
  10423. if (DriverName == NULL) {
  10424. //
  10425. // Madeup a name for the driver object.
  10426. //
  10427. length = (USHORT) _snwprintf(buffer, sizeof(buffer) / sizeof(WCHAR), L"\\Driver\\%08u", KeTickCount);
  10428. driverName.Length = length * sizeof(WCHAR);
  10429. driverName.MaximumLength = driverName.Length + sizeof(UNICODE_NULL);
  10430. driverName.Buffer = buffer; \
  10431. } else {
  10432. driverName = *DriverName;
  10433. }
  10434. //
  10435. // Attempt to create the driver object
  10436. //
  10437. InitializeObjectAttributes( &objectAttributes,
  10438. &driverName,
  10439. OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
  10440. NULL,
  10441. NULL );
  10442. objectSize = sizeof( DRIVER_OBJECT ) + sizeof( DRIVER_EXTENSION );
  10443. status = ObCreateObject( KernelMode,
  10444. IoDriverObjectType,
  10445. &objectAttributes,
  10446. KernelMode,
  10447. NULL,
  10448. objectSize,
  10449. 0,
  10450. 0,
  10451. &driverObject );
  10452. if( !NT_SUCCESS( status )){
  10453. //
  10454. // Driver object creation failed
  10455. //
  10456. return status;
  10457. }
  10458. //
  10459. // We've created a driver object, initialize it.
  10460. //
  10461. RtlZeroMemory( driverObject, objectSize );
  10462. driverObject->DriverExtension = (PDRIVER_EXTENSION)(driverObject + 1);
  10463. driverObject->DriverExtension->DriverObject = driverObject;
  10464. driverObject->Type = IO_TYPE_DRIVER;
  10465. driverObject->Size = sizeof( DRIVER_OBJECT );
  10466. driverObject->Flags = DRVO_BUILTIN_DRIVER;
  10467. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
  10468. driverObject->MajorFunction[i] = IopInvalidDeviceRequest;
  10469. driverObject->DriverInit = InitializationFunction;
  10470. serviceName.Buffer = (PWSTR)ExAllocatePool(PagedPool, driverName.Length + sizeof(WCHAR));
  10471. if (serviceName.Buffer) {
  10472. serviceName.MaximumLength = driverName.Length + sizeof(WCHAR);
  10473. serviceName.Length = driverName.Length;
  10474. RtlCopyMemory(serviceName.Buffer, driverName.Buffer, driverName.Length);
  10475. serviceName.Buffer[serviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
  10476. driverObject->DriverExtension->ServiceKeyName = serviceName;
  10477. } else {
  10478. status = STATUS_INSUFFICIENT_RESOURCES;
  10479. goto errorFreeDriverObject;
  10480. }
  10481. //
  10482. // Insert it into the object table.
  10483. //
  10484. status = ObInsertObject( driverObject,
  10485. NULL,
  10486. FILE_READ_DATA,
  10487. 0,
  10488. NULL,
  10489. &driverHandle );
  10490. if( !NT_SUCCESS( status )){
  10491. //
  10492. // Couldn't insert the driver object into the table.
  10493. // The object got dereferenced by the object manager. Just exit
  10494. //
  10495. goto errorReturn;
  10496. }
  10497. //
  10498. // Reference the handle and obtain a pointer to the driver object so that
  10499. // the handle can be deleted without the object going away.
  10500. //
  10501. status = ObReferenceObjectByHandle( driverHandle,
  10502. 0,
  10503. IoDriverObjectType,
  10504. KernelMode,
  10505. (PVOID *) &driverObject,
  10506. (POBJECT_HANDLE_INFORMATION) NULL );
  10507. if( !NT_SUCCESS( status )) {
  10508. //
  10509. // Backout here is probably bogus. If the ref didn't work then the handle is probably bad
  10510. // Do this right though just in case there are other common error returns for ObRef...
  10511. //
  10512. ZwMakeTemporaryObject( driverHandle ); // Cause handle close to free the object
  10513. ZwClose( driverHandle ); // Close the handle.
  10514. goto errorReturn;
  10515. }
  10516. ZwClose( driverHandle );
  10517. //
  10518. // Store the name of the device driver in the driver object so that it
  10519. // can be easily found by the error log thread.
  10520. //
  10521. driverObject->DriverName.Buffer = ExAllocatePool( PagedPool,
  10522. driverName.MaximumLength );
  10523. if (driverObject->DriverName.Buffer) {
  10524. driverObject->DriverName.MaximumLength = driverName.MaximumLength;
  10525. driverObject->DriverName.Length = driverName.Length;
  10526. RtlCopyMemory( driverObject->DriverName.Buffer,
  10527. driverName.Buffer,
  10528. driverName.MaximumLength );
  10529. }
  10530. //
  10531. // Call the driver initialization routine
  10532. //
  10533. status = (*InitializationFunction)(driverObject, NULL);
  10534. if( !NT_SUCCESS( status )){
  10535. errorFreeDriverObject:
  10536. //
  10537. // If we were unsuccessful, we need to get rid of the driverObject
  10538. // that we created.
  10539. //
  10540. ObMakeTemporaryObject( driverObject );
  10541. ObDereferenceObject( driverObject );
  10542. }
  10543. errorReturn:
  10544. return status;
  10545. }
  10546. VOID
  10547. IoDeleteDriver(
  10548. IN PDRIVER_OBJECT DriverObject
  10549. )
  10550. /*++
  10551. Routine Description:
  10552. This routine deletes a driver object created explicitly through
  10553. IoCreateDriver.
  10554. Parameters:
  10555. DriverObject - Supplies a pointer to the driver object to be deleted.
  10556. ReturnValue:
  10557. Status code that indicates whether or not the function was successful.
  10558. Notes:
  10559. --*/
  10560. {
  10561. ObDereferenceObject(DriverObject);
  10562. }
  10563. PDEVICE_OBJECT
  10564. IoGetLowerDeviceObject(
  10565. IN PDEVICE_OBJECT DeviceObject
  10566. )
  10567. /*++
  10568. Routine Description:
  10569. This routine gets the next lower device object on the device stack.
  10570. Parameters:
  10571. DeviceObject - Supplies a pointer to the deviceObject whose next device object needs
  10572. to be obtained.
  10573. ReturnValue:
  10574. NULL if driver is unloaded or marked for unload or if there is no attached deviceobject.
  10575. Otherwise a referenced pointer to the deviceobject is returned.
  10576. Notes:
  10577. --*/
  10578. {
  10579. KIRQL irql;
  10580. PDEVICE_OBJECT targetDeviceObject;
  10581. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  10582. if ((DeviceObject->DeviceObjectExtension->ExtensionFlags &
  10583. (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED))) {
  10584. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  10585. return NULL;
  10586. }
  10587. targetDeviceObject = NULL;
  10588. if (DeviceObject->DeviceObjectExtension->AttachedTo) {
  10589. targetDeviceObject = DeviceObject->DeviceObjectExtension->AttachedTo;
  10590. ObReferenceObject(targetDeviceObject);
  10591. }
  10592. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  10593. return targetDeviceObject;
  10594. }
  10595. NTSTATUS
  10596. IoEnumerateDeviceObjectList(
  10597. IN PDRIVER_OBJECT DriverObject,
  10598. IN PDEVICE_OBJECT *DeviceObjectList,
  10599. IN ULONG DeviceObjectListSize,
  10600. OUT PULONG ActualNumberDeviceObjects
  10601. )
  10602. /*++
  10603. Routine Description:
  10604. This routine gets the next lower device object on the device stack.
  10605. Parameters:
  10606. DriverObject - Driver Object whose device objects have to be enumerated.
  10607. DeviceObjectList - Pointer to an array where device object lists will be stored.
  10608. DeviceObjectListSize - Size in bytes of the DeviceObjectList array
  10609. ActualNumberDeviceObjects - The actual number of device objects in a driver object.
  10610. ReturnValue:
  10611. If size is not sufficient it will return STATUS_BUFFER_TOO_SMALL.
  10612. Notes:
  10613. --*/
  10614. {
  10615. KIRQL irql;
  10616. PDEVICE_OBJECT deviceObject;
  10617. ULONG numListEntries;
  10618. ULONG numDeviceObjects = 0;
  10619. NTSTATUS status = STATUS_SUCCESS;
  10620. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  10621. deviceObject = DriverObject->DeviceObject;
  10622. numListEntries = DeviceObjectListSize / sizeof(PDEVICE_OBJECT);
  10623. while (deviceObject) {
  10624. numDeviceObjects++;
  10625. deviceObject = deviceObject->NextDevice;
  10626. }
  10627. *ActualNumberDeviceObjects = numDeviceObjects;
  10628. if (numDeviceObjects > numListEntries) {
  10629. status = STATUS_BUFFER_TOO_SMALL;
  10630. }
  10631. deviceObject = DriverObject->DeviceObject;
  10632. while ((numListEntries > 0) && deviceObject) {
  10633. ObReferenceObject(deviceObject);
  10634. *DeviceObjectList = deviceObject;
  10635. DeviceObjectList++;
  10636. deviceObject = deviceObject->NextDevice;
  10637. numListEntries--;
  10638. }
  10639. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  10640. return status;
  10641. }
  10642. PDEVICE_OBJECT
  10643. IoGetDeviceAttachmentBaseRef(
  10644. IN PDEVICE_OBJECT DeviceObject
  10645. )
  10646. /*++
  10647. Routine Description:
  10648. This routine returns the lowest level device object associated with
  10649. the specified device.
  10650. Arguments:
  10651. DeviceObject - Supplies a pointer to the device for which the bottom of
  10652. attachment chain is to be found.
  10653. Return Value:
  10654. The function value is a reference to the lowest level device attached
  10655. to the specified device. If the supplied device object is that device
  10656. object, then a pointer to it is returned.
  10657. A reference is taken on the returned device object. It is the
  10658. responsibility of the caller to release it.
  10659. --*/
  10660. {
  10661. PDEVICE_OBJECT baseDeviceObject;
  10662. KIRQL irql;
  10663. //
  10664. // Any examination of attachment chain linkage must be done with
  10665. // IopDatabaseLock taken.
  10666. //
  10667. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  10668. //
  10669. // Find the base of the attachment chain.
  10670. //
  10671. baseDeviceObject = IopGetDeviceAttachmentBase( DeviceObject );
  10672. //
  10673. // Reference the device object before releasing the database lock.
  10674. //
  10675. ObReferenceObject( baseDeviceObject );
  10676. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  10677. return baseDeviceObject;
  10678. }
  10679. NTSTATUS
  10680. IoGetDiskDeviceObject(
  10681. IN PDEVICE_OBJECT FileSystemDeviceObject,
  10682. OUT PDEVICE_OBJECT *DiskDeviceObject
  10683. )
  10684. /*++
  10685. Routine Description:
  10686. This routine returns the disk device object associated with a filesystem
  10687. volume device object. The disk device object need not be an actual disk but
  10688. in general associated with storage.
  10689. Arguments:
  10690. FileSystemDeviceObject - Supplies a pointer to the device for which the bottom of
  10691. attachment chain is to be found.
  10692. DiskDeviceObject - Supplies storage for the return value.
  10693. Return Value:
  10694. The function returns the disk device object associated with a filesystem
  10695. device object. Returns a referenced device object. If the VPB reference count
  10696. is zero we cannot rely on the device object pointer.
  10697. --*/
  10698. {
  10699. KIRQL irql;
  10700. PVPB vpb;
  10701. //
  10702. // Filesystem deviceobject's VPB field should be NULL
  10703. //
  10704. if (FileSystemDeviceObject->Vpb) {
  10705. return STATUS_INVALID_PARAMETER;
  10706. }
  10707. IoAcquireVpbSpinLock(&irql);
  10708. vpb = FileSystemDeviceObject->DeviceObjectExtension->Vpb;
  10709. if (!vpb) {
  10710. IoReleaseVpbSpinLock(irql);
  10711. return STATUS_INVALID_PARAMETER;
  10712. }
  10713. if (vpb->ReferenceCount == 0) {
  10714. IoReleaseVpbSpinLock(irql);
  10715. return STATUS_VOLUME_DISMOUNTED;
  10716. }
  10717. if (!(vpb->Flags & VPB_MOUNTED)) {
  10718. IoReleaseVpbSpinLock(irql);
  10719. return STATUS_VOLUME_DISMOUNTED;
  10720. }
  10721. *DiskDeviceObject = vpb->RealDevice;
  10722. ObReferenceObject( *DiskDeviceObject);
  10723. IoReleaseVpbSpinLock(irql);
  10724. return STATUS_SUCCESS;
  10725. }
  10726. NTSTATUS
  10727. IoSetSystemPartition(
  10728. PUNICODE_STRING VolumeNameString
  10729. )
  10730. /*++
  10731. Routine Description:
  10732. This routine sets system partition regisry key to the volume name string. Used
  10733. by the mount manager in case volume name changes.
  10734. Arguments:
  10735. VolumeNameString - Name of the volume that is the system partition.
  10736. Return Value:
  10737. NTSTATUS
  10738. --*/
  10739. {
  10740. HANDLE systemHandle, setupHandle;
  10741. UNICODE_STRING nameString, volumeNameString, machineSystemName;
  10742. NTSTATUS status;
  10743. //
  10744. // Declare a unicode buffer big enough to contain the longest string we'll be using.
  10745. // (ANSI string in 'sizeof()' below on purpose--we want the number of chars here.)
  10746. //
  10747. WCHAR nameBuffer[sizeof("SystemPartition")];
  10748. //
  10749. // Open HKLM\SYSTEM key.
  10750. //
  10751. RtlInitUnicodeString(&machineSystemName, L"\\REGISTRY\\MACHINE\\SYSTEM");
  10752. status = IopOpenRegistryKeyEx( &systemHandle,
  10753. NULL,
  10754. &machineSystemName,
  10755. KEY_ALL_ACCESS
  10756. );
  10757. if (!NT_SUCCESS(status)) {
  10758. return status;
  10759. }
  10760. //
  10761. // Now open/create the setup subkey.
  10762. //
  10763. ASSERT( sizeof(L"Setup") <= sizeof(nameBuffer) );
  10764. nameBuffer[0] = L'S';
  10765. nameBuffer[1] = L'e';
  10766. nameBuffer[2] = L't';
  10767. nameBuffer[3] = L'u';
  10768. nameBuffer[4] = L'p';
  10769. nameBuffer[5] = L'\0';
  10770. nameString.MaximumLength = sizeof(L"Setup");
  10771. nameString.Length = sizeof(L"Setup") - sizeof(WCHAR);
  10772. nameString.Buffer = nameBuffer;
  10773. status = IopCreateRegistryKeyEx( &setupHandle,
  10774. systemHandle,
  10775. &nameString,
  10776. KEY_ALL_ACCESS,
  10777. REG_OPTION_NON_VOLATILE,
  10778. NULL
  10779. );
  10780. NtClose(systemHandle); // Don't need the handle to the HKLM\System key anymore.
  10781. if (!NT_SUCCESS(status)) {
  10782. return status;
  10783. }
  10784. ASSERT( sizeof(L"SystemPartition") <= sizeof(nameBuffer) );
  10785. nameBuffer[0] = L'S';
  10786. nameBuffer[1] = L'y';
  10787. nameBuffer[2] = L's';
  10788. nameBuffer[3] = L't';
  10789. nameBuffer[4] = L'e';
  10790. nameBuffer[5] = L'm';
  10791. nameBuffer[6] = L'P';
  10792. nameBuffer[7] = L'a';
  10793. nameBuffer[8] = L'r';
  10794. nameBuffer[9] = L't';
  10795. nameBuffer[10] = L'i';
  10796. nameBuffer[11] = L't';
  10797. nameBuffer[12] = L'i';
  10798. nameBuffer[13] = L'o';
  10799. nameBuffer[14] = L'n';
  10800. nameBuffer[15] = L'\0';
  10801. nameString.MaximumLength = sizeof(L"SystemPartition");
  10802. nameString.Length = sizeof(L"SystemPartition") - sizeof(WCHAR);
  10803. status = ZwSetValueKey(setupHandle,
  10804. &nameString,
  10805. TITLE_INDEX_VALUE,
  10806. REG_SZ,
  10807. VolumeNameString->Buffer,
  10808. VolumeNameString->Length + sizeof(WCHAR)
  10809. );
  10810. return status;
  10811. }
  10812. BOOLEAN
  10813. IoIsFileOriginRemote(
  10814. IN PFILE_OBJECT FileObject
  10815. )
  10816. /*++
  10817. Routine Description:
  10818. This routine returns the origin of the original create request for the
  10819. specified file. That is, was it created locally on this machine or remotely
  10820. on another machine via a network provider.
  10821. Arguments:
  10822. FileObject - Supplies the file object that is to be checked.
  10823. Return Value:
  10824. TRUE - Means the create request originated on a remote machine.
  10825. FALSE - Means the create request originated on the local machine.
  10826. --*/
  10827. {
  10828. BOOLEAN Remote;
  10829. //
  10830. // Check the origin flag and return the appropriate result.
  10831. //
  10832. if (FileObject->Flags & FO_REMOTE_ORIGIN) {
  10833. Remote = TRUE;
  10834. } else {
  10835. Remote = FALSE;
  10836. }
  10837. return Remote;
  10838. }
  10839. NTSTATUS
  10840. IoSetFileOrigin(
  10841. IN PFILE_OBJECT FileObject,
  10842. IN BOOLEAN Remote
  10843. )
  10844. /*++
  10845. Routine Description:
  10846. This routine sets the origin of the original create request for the
  10847. specified file. That is, was it created locally on this machine or remotely
  10848. on another machine via a network provider. By default file objects are
  10849. considered to have a local origin. Network providers should call this
  10850. function in their server for any file objects that were created to satisfy
  10851. a create request from their client.
  10852. Arguments:
  10853. FileObject - Supplies the file object that is to be set.
  10854. Remote - Supplies whether the file object is for a remote create request or not.
  10855. Return Value:
  10856. Returns STATUS_SUCCESS unless the origin is already set to what the caller is requesting.
  10857. --*/
  10858. {
  10859. NTSTATUS Status = STATUS_INVALID_PARAMETER_MIX;
  10860. //
  10861. // Set or clear the origin flag per the callers request.
  10862. //
  10863. if (Remote) {
  10864. if ((FileObject->Flags & FO_REMOTE_ORIGIN) == 0) {
  10865. FileObject->Flags |= FO_REMOTE_ORIGIN;
  10866. Status = STATUS_SUCCESS;
  10867. }
  10868. } else {
  10869. if (FileObject->Flags & FO_REMOTE_ORIGIN) {
  10870. FileObject->Flags &= ~FO_REMOTE_ORIGIN;
  10871. Status = STATUS_SUCCESS;
  10872. }
  10873. }
  10874. return Status;
  10875. }
  10876. PVOID
  10877. IoGetFileObjectFilterContext(
  10878. IN PFILE_OBJECT FileObject
  10879. )
  10880. /*++
  10881. Routine Description:
  10882. This routine returns the filter context associated with a fileobject that has an extension.
  10883. Arguments:
  10884. FileObject - FileObject for which the filter context is retrieved
  10885. Return Value:
  10886. NTSTATUS
  10887. --*/
  10888. {
  10889. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension;
  10890. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  10891. fileObjectExtension =(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  10892. return (fileObjectExtension->FilterContext);
  10893. }
  10894. return NULL;
  10895. }
  10896. NTSTATUS
  10897. IoChangeFileObjectFilterContext(
  10898. IN PFILE_OBJECT FileObject,
  10899. IN PVOID FilterContext,
  10900. IN BOOLEAN Set
  10901. )
  10902. /*++
  10903. Routine Description:
  10904. This routine set or clear fileobject filter context. It can be set only once.
  10905. Arguments:
  10906. FileObject - FileObject for which the filter context is retrieved
  10907. FilterContext - New Filter context to be set in the fileobject extension
  10908. Set - If TRUE allows FilterContext to be set in the fileobject only if the old value is NULL
  10909. If FALSE allows fileObject field to be cleared only if FileContext is the old value in the fileobject.
  10910. Return Value:
  10911. Returns NTSTATUS
  10912. --*/
  10913. {
  10914. PIOP_FILE_OBJECT_EXTENSION fileObjectExtension;
  10915. if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) {
  10916. fileObjectExtension =(PIOP_FILE_OBJECT_EXTENSION)(FileObject + 1);
  10917. if (Set) {
  10918. if (InterlockedCompareExchangePointer(&fileObjectExtension->FilterContext, FilterContext, NULL) != NULL)
  10919. return STATUS_ALREADY_COMMITTED;
  10920. return STATUS_SUCCESS;
  10921. } else {
  10922. if (InterlockedCompareExchangePointer(&fileObjectExtension->FilterContext, NULL, FilterContext) != FilterContext)
  10923. return STATUS_ALREADY_COMMITTED;
  10924. return STATUS_SUCCESS;
  10925. }
  10926. }
  10927. return STATUS_INVALID_PARAMETER;
  10928. }
  10929. BOOLEAN
  10930. IoIsDeviceEjectable(
  10931. IN PDEVICE_OBJECT DeviceObject
  10932. )
  10933. {
  10934. if ((FILE_FLOPPY_DISKETTE & DeviceObject->Characteristics)
  10935. || (InitWinPEModeType & INIT_WINPEMODE_INRAM)) {
  10936. return TRUE;
  10937. }
  10938. return FALSE;
  10939. }
  10940. NTSTATUS
  10941. IoValidateDeviceIoControlAccess(
  10942. IN PIRP Irp,
  10943. IN ULONG RequiredAccess
  10944. )
  10945. /*++
  10946. Routine Description:
  10947. This routine validates ioctl access bits based on granted access information passed in the IRP.
  10948. This routine is called by a driver to validate IOCTL access bits for IOCTLs that were originally
  10949. defined as FILE_ANY_ACCESS and cannot be changed for compatibility reasons but really has to be
  10950. validated for read/write access.
  10951. Arguments:
  10952. IRP - IRP for the device control
  10953. RequiredAccess - Is the expected access required by the driver. Should be FILE_READ_ACCESS, FILE_WRITE_ACCESS
  10954. or both.
  10955. Return Value:
  10956. Returns NTSTATUS
  10957. --*/
  10958. {
  10959. ACCESS_MASK grantedAccess;
  10960. PIO_STACK_LOCATION irpSp;
  10961. //
  10962. // Validate RequiredAccess.
  10963. //
  10964. if (RequiredAccess & (FILE_READ_ACCESS|FILE_WRITE_ACCESS)){
  10965. irpSp = IoGetCurrentIrpStackLocation(Irp);
  10966. //
  10967. // If the driver passes the wrong IRP fail the API.
  10968. //
  10969. if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) &&
  10970. (irpSp->MajorFunction != IRP_MJ_FILE_SYSTEM_CONTROL)) {
  10971. return STATUS_INVALID_PARAMETER;
  10972. }
  10973. //
  10974. // Kernel mode IRPs always succeed.
  10975. //
  10976. if (Irp->RequestorMode == KernelMode) {
  10977. return STATUS_SUCCESS;
  10978. }
  10979. //
  10980. // Get the granted access bits from the IRP.
  10981. //
  10982. grantedAccess = (irpSp->Flags & SL_READ_ACCESS_GRANTED) ? FILE_READ_DATA : 0;
  10983. grantedAccess |= (irpSp->Flags & SL_WRITE_ACCESS_GRANTED) ? FILE_WRITE_DATA : 0;
  10984. if (SeComputeGrantedAccesses ( grantedAccess, RequiredAccess ) != RequiredAccess ) {
  10985. return STATUS_ACCESS_DENIED;
  10986. } else {
  10987. return STATUS_SUCCESS;
  10988. }
  10989. } else {
  10990. return STATUS_INVALID_PARAMETER;
  10991. }
  10992. }