Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

931 lines
24 KiB

  1. /*++
  2. Copyright (C) 2002 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. This module contains routines that port drivers export to miniports to allow
  7. them to read and write registry data. The Keys are relative to the miniport's
  8. <ServiceName>\Parameters key.
  9. Author:
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #define MAX_REGISTRY_BUFFER_SIZE 0x10000
  17. #define PORT_TAG_REGISTRY_BUFFER 'BRlP'
  18. #define PORT_REGISTRY_INFO_INITIALIZED 0x00000001
  19. #define PORT_REGISTRY_BUFFER_ALLOCATED 0x00000002
  20. NTSTATUS
  21. PortMiniportRegistryInitialize(
  22. IN OUT PPORT_REGISTRY_INFO PortContext
  23. )
  24. /*++
  25. Routine Description:
  26. This routine is called by the port driver to init the registry routine's internal
  27. data.
  28. Arguments:
  29. PortContext - Used to identify the caller and instatiation of the caller.
  30. Return Value:
  31. STATUS_SUCCESS for now. If this is extended, it might require allocations, etc.
  32. --*/
  33. {
  34. NTSTATUS status;
  35. ASSERT(PortContext->Size == sizeof(PORT_REGISTRY_INFO));
  36. //
  37. // Initialize the spinlock and list entry.
  38. //
  39. KeInitializeSpinLock(&PortContext->SpinLock);
  40. InitializeListHead(&PortContext->ListEntry);
  41. //
  42. // Ensure that buffer is NULL at this time. It's only valid after we allocate it.
  43. //
  44. PortContext->Buffer = NULL;
  45. //
  46. // Indiacate that this is ready to go.
  47. //
  48. PortContext->Flags = PORT_REGISTRY_INFO_INITIALIZED;
  49. return STATUS_SUCCESS;
  50. }
  51. VOID
  52. PortMiniportRegistryDestroy(
  53. IN PPORT_REGISTRY_INFO PortContext
  54. )
  55. /*++
  56. Routine Description:
  57. This routine is called by the port driver when it unloads a miniport.
  58. It will free the resources and cleanup whatever else.
  59. Arguments:
  60. PortContext - Used to identify the caller and instatiation of the caller.
  61. Return Value:
  62. NOTHING
  63. --*/
  64. {
  65. KIRQL irql;
  66. KeAcquireSpinLock(&PortContext->SpinLock, &irql);
  67. //
  68. // See whether there is still a buffer hanging around.
  69. //
  70. if (PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) {
  71. ASSERT(PortContext->Buffer);
  72. //
  73. // Free it.
  74. //
  75. ExFreePool(PortContext->Buffer);
  76. } else {
  77. //
  78. // This should be NULL if it's not allocated.
  79. //
  80. ASSERT(PortContext->Buffer == NULL);
  81. }
  82. //
  83. // Clean up.
  84. //
  85. PortContext->Flags = 0;
  86. PortContext->Buffer = NULL;
  87. KeReleaseSpinLock(&PortContext->SpinLock, irql);
  88. return;
  89. }
  90. NTSTATUS
  91. PortAllocateRegistryBuffer(
  92. IN PPORT_REGISTRY_INFO PortContext
  93. )
  94. /*++
  95. Routine Description:
  96. This routine is called by the port driver to allocate a registry buffer of Length for the
  97. miniport.
  98. The caller should initialize Length before calling this routine.
  99. Length is checked against a max. and alignment requirements and updated accordingly, if
  100. necessary.
  101. Arguments:
  102. PortContext - Value used to identify the caller and instatiation of the caller.
  103. Return Value:
  104. The buffer field is updated or NULL if some error prevents the allocation.
  105. Length is updated to reflect the actual size.
  106. SUCCESS, INSUFFICIENT_RESOURCES, or BUSY if the miniport already has a buffer.
  107. --*/
  108. {
  109. PUCHAR buffer = NULL;
  110. ULONG length;
  111. NTSTATUS status;
  112. //
  113. // The size must be correct.
  114. //
  115. ASSERT(PortContext->Size == sizeof(PORT_REGISTRY_INFO));
  116. //
  117. // Must be initialized via the init routine.
  118. //
  119. ASSERT(PortContext->Flags & PORT_REGISTRY_INFO_INITIALIZED );
  120. //
  121. // Can't be here twice.
  122. //
  123. ASSERT((PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) == 0);
  124. //
  125. // Capture the length.
  126. //
  127. length = PortContext->LengthNeeded;
  128. //
  129. // See if the miniport is attempted a double allocate.
  130. //
  131. if (PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) {
  132. //
  133. // This would say that there better be a buffer.
  134. //
  135. ASSERT(PortContext->Buffer);
  136. //
  137. // Buffer already outstanding, so don't allow this.
  138. //
  139. status = STATUS_DEVICE_BUSY;
  140. } else {
  141. //
  142. // Check the upper bound.
  143. //
  144. if (length > MAX_REGISTRY_BUFFER_SIZE) {
  145. //
  146. // The request is too large, reset it. The port driver or miniport will have
  147. // to deal with the change.
  148. //
  149. length = MAX_REGISTRY_BUFFER_SIZE;
  150. }
  151. //
  152. // Allocate the buffer.
  153. //
  154. buffer = ExAllocatePoolWithTag(NonPagedPool,
  155. length,
  156. PORT_TAG_REGISTRY_BUFFER);
  157. if (buffer == NULL) {
  158. //
  159. // Set the caller's length to 0 as the allocation failed.
  160. //
  161. PortContext->AllocatedLength = 0;
  162. status = STATUS_INSUFFICIENT_RESOURCES;
  163. } else {
  164. //
  165. // Indicate that the allocation of Length was successful, and
  166. // that the miniport has a registry buffer.
  167. //
  168. PortContext->Flags |= PORT_REGISTRY_BUFFER_ALLOCATED;
  169. PortContext->Buffer = buffer;
  170. PortContext->AllocatedLength = length;
  171. //
  172. // Zero it for them to be nice.
  173. //
  174. RtlZeroMemory(buffer, length);
  175. status = STATUS_SUCCESS;
  176. }
  177. }
  178. return status;
  179. }
  180. NTSTATUS
  181. PortFreeRegistryBuffer(
  182. IN PPORT_REGISTRY_INFO PortContext
  183. )
  184. /*++
  185. Routine Description:
  186. Frees the buffer allocated via PortAllocateRegistryBuffer.
  187. Arguments:
  188. PortContext - Value used to identify the caller and instatiation of the caller.
  189. Return Value:
  190. INVALID_PARAMETER if the buffer isn't already allocated.
  191. SUCCESS
  192. --*/
  193. {
  194. //
  195. // The size must be correct.
  196. //
  197. ASSERT(PortContext->Size == sizeof(PORT_REGISTRY_INFO));
  198. //
  199. // Must be initialized via the init routine.
  200. //
  201. ASSERT(PortContext->Flags & PORT_REGISTRY_INFO_INITIALIZED );
  202. //
  203. // Can't be here, unless a buffer has been allocated.
  204. //
  205. ASSERT(PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED);
  206. //
  207. // If it's not allocated, return an error.
  208. //
  209. if ((PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) == 0) {
  210. ASSERT(PortContext->Buffer == NULL);
  211. return STATUS_INVALID_PARAMETER;
  212. }
  213. //
  214. // Poison the buffer to catch poorly-written miniports.
  215. //
  216. RtlZeroMemory(PortContext->Buffer, PortContext->AllocatedLength);
  217. //
  218. // Free the buffer.
  219. //
  220. ExFreePool(PortContext->Buffer);
  221. //
  222. // Indicate that it's gone.
  223. //
  224. PortContext->Flags &= ~PORT_REGISTRY_BUFFER_ALLOCATED;
  225. PortContext->AllocatedLength = 0;
  226. PortContext->Buffer = NULL;
  227. return STATUS_SUCCESS;
  228. }
  229. ULONG
  230. WCharToAscii(
  231. OUT PUCHAR Destination,
  232. IN PWCHAR Source,
  233. IN ULONG BufferSize
  234. )
  235. /*+++
  236. Routine Description:
  237. This routine is used to convert the Source buffer into ASCII.
  238. NOTE: BufferSize should include the NULL-Terminator, while the return value does not.
  239. Arguements:
  240. Destination - ASCII buffer to place the converted values.
  241. Source - WCHAR buffer containing the string to convert.
  242. BufferSize - Size, in bytes, of Destination.
  243. Return Value:
  244. The converted buffer and the count of converted chars. The NULL-termination
  245. isn't included.
  246. --*/
  247. {
  248. ULONG convertedCount = 0;
  249. ULONG i;
  250. RtlZeroMemory(Destination, BufferSize);
  251. if (Source) {
  252. //
  253. // Run through the Source buffer and convert the WCHAR to ASCII, placing
  254. // the converted value in Destination. Ensure that the destination buffer
  255. // isn't overflowed.
  256. //
  257. for (i = 0; (i < (BufferSize - 1)) && (*Source); i++, convertedCount++) {
  258. *Destination = (UCHAR)*Source;
  259. Destination++;
  260. Source++;
  261. }
  262. }
  263. return convertedCount;
  264. }
  265. ULONG
  266. AsciiToWChar(
  267. IN PWCHAR Destination,
  268. IN PUCHAR Source,
  269. IN ULONG BufferSize
  270. )
  271. /*+++
  272. Routine Description:
  273. This routine is used to convert the Source buffer into WCHAR.
  274. NOTE: BufferSize should include the NULL-Terminator, while the return value does not.
  275. Arguements:
  276. Destination - WCHAR buffer to place the converted values.
  277. Source - ASCII buffer containing the string to convert.
  278. BufferSize - Size, in bytes, of Destination.
  279. Return Value:
  280. The converted buffer and the count of converted chars. The NULL-termination
  281. isn't included.
  282. --*/
  283. {
  284. ULONG convertedCount = 0;
  285. ULONG i;
  286. RtlZeroMemory(Destination, BufferSize);
  287. if (Source) {
  288. //
  289. // Run through source buffer and convert the ascii values to WCHAR and put
  290. // the convert into Destination. Ensure that neither source nor dest are
  291. // overflowed.
  292. //
  293. for (i = 0; (i < (BufferSize - 1)) && (*Source); i++, convertedCount++) {
  294. *Destination = (WCHAR)*Source;
  295. Destination++;
  296. Source++;
  297. }
  298. }
  299. return convertedCount;
  300. }
  301. NTSTATUS
  302. PortAsciiToUnicode(
  303. IN PUCHAR AsciiString,
  304. OUT PUNICODE_STRING UnicodeString
  305. )
  306. {
  307. ANSI_STRING ansiString;
  308. //
  309. // Convert ValueName to Unicode.
  310. //
  311. RtlInitAnsiString(&ansiString, AsciiString);
  312. return RtlAnsiStringToUnicodeString(UnicodeString, &ansiString, TRUE);
  313. }
  314. NTSTATUS
  315. PortpBinaryReadCallBack(
  316. IN PWSTR ValueName,
  317. IN ULONG Type,
  318. IN PVOID Buffer,
  319. IN ULONG BufferLength,
  320. IN PVOID Context,
  321. IN PVOID EntryContext
  322. )
  323. /*++
  324. Routine Description:
  325. This routine is the callback function for handling REG_BINARY reads. It will determine
  326. whether the buffer in the PORT_REGISTRY_INFO is of sufficient size to handle the data,
  327. and copy it over, if necessary. Otherwise the data length needed is updated.
  328. Arguments:
  329. ValueName - The name of the data to be returned.
  330. Type - The reg. data type for this request.
  331. ValueLength - Size, in bytes, of ValueData
  332. Context - Not used.
  333. PortContext - Blob containing the miniports buffer and it's size.
  334. Return Value:
  335. SUCCESS or BUFFER_TOO_SMALL (which unfortunately gets updated by the RTL function to
  336. SUCCESS. InternalStatus is updated to the real status and the length field within
  337. the REGISTRY_INFO struct. is updated.
  338. --*/
  339. {
  340. PPORT_REGISTRY_INFO portContext = EntryContext;
  341. PUCHAR currentBuffer;
  342. NTSTATUS status = STATUS_BUFFER_TOO_SMALL;
  343. //
  344. // Determine whether the supplied buffer is big enough to hold the data.
  345. //
  346. if (portContext->CurrentLength >= BufferLength) {
  347. //
  348. // Determine the correct offset into the buffer.
  349. //
  350. currentBuffer = portContext->Buffer + portContext->Offset;
  351. //
  352. // The Rtl routine will free it's buffer, so get the data now.
  353. //
  354. RtlCopyMemory(currentBuffer, Buffer, BufferLength);
  355. //
  356. // Update the status to show the data in the buffer is valid.
  357. //
  358. status = STATUS_SUCCESS;
  359. }
  360. //
  361. // Update the length. This will either tell them how big the buffer
  362. // should be, or how large the returned data actually is.
  363. // The Read routine will handle the rest.
  364. //
  365. portContext->CurrentLength = BufferLength;
  366. portContext->InternalStatus = status;
  367. //
  368. // Return the status to the Read routine.
  369. //
  370. return status;
  371. }
  372. NTSTATUS
  373. PortRegistryRead(
  374. IN PUNICODE_STRING RegistryKeyName,
  375. IN PUNICODE_STRING ValueName,
  376. IN ULONG Type,
  377. IN PPORT_REGISTRY_INFO PortContext
  378. )
  379. /*++
  380. Routine Description:
  381. This routine is used by the portdriver to read the info. at ValueName from the regkey
  382. This assumes that the data is a REG_SZ, REG_DWORD, or REG_BINARY only.
  383. REG_SZ data is converted into a NULL-terminiated ASCII string from the UNICODE.
  384. DWORD and BINARY data are directly copied into the caller's buffer if it's of
  385. correct size.
  386. Arguments:
  387. RegistryKeyName - The absolute key name where ValueName lives.
  388. ValueName - The name of the data to be returned.
  389. Type - The reg. data type for this request.
  390. PortContext - Blob containing the miniports buffer and it's size.
  391. Return Value:
  392. STATUS of the registry routines, INSUFFICIENT_RESOURCES, or BUFFER_TOO_SMALL.
  393. If TOO_SMALL, LengthNeeded within the PortContext is updated to reflect the size needed.
  394. --*/
  395. {
  396. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  397. WCHAR defaultData[] = { L"\0" };
  398. ULONG defaultUlong = (ULONG)-1;
  399. UNICODE_STRING unicodeString;
  400. NTSTATUS status;
  401. ULONG length;
  402. PUCHAR currentBuffer;
  403. RtlZeroMemory(queryTable, sizeof(queryTable));
  404. //
  405. // Calculate the actual buffer location where this data should go.
  406. // This presupposes that the port-driver has done all the validation, otherwise
  407. // this will be blindly copying into who-knows-where.
  408. //
  409. currentBuffer = PortContext->Buffer + PortContext->Offset;
  410. //
  411. // Looking for what lives at ValueName.
  412. //
  413. queryTable[0].Name = ValueName->Buffer;
  414. //
  415. // Indicate that there is no call-back routine and to return everything as one big
  416. // blob.
  417. //
  418. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  419. //
  420. // Handle setting up for the various types that are supported.
  421. //
  422. if (Type == REG_SZ) {
  423. RtlZeroMemory(&unicodeString, sizeof(UNICODE_STRING));
  424. //
  425. // Local storage for the returned data. The routine will allocate the buffer
  426. // and set Length.
  427. //
  428. queryTable[0].EntryContext = &unicodeString;
  429. queryTable[0].DefaultData = defaultData;
  430. queryTable[0].DefaultLength = sizeof(defaultData);
  431. } else if (Type == REG_DWORD) {
  432. //
  433. // The data will be placed in the first ulong of the caller's
  434. // buffer.
  435. //
  436. queryTable[0].EntryContext = currentBuffer;
  437. queryTable[0].DefaultData = &defaultUlong;
  438. queryTable[0].DefaultLength = sizeof(ULONG);
  439. } else {
  440. //
  441. // Clear the flags because we need a callback to determine
  442. // the real size of the binary data.
  443. //
  444. queryTable[0].Flags = 0;
  445. queryTable[0].QueryRoutine = PortpBinaryReadCallBack;
  446. queryTable[0].EntryContext = PortContext;
  447. queryTable[0].DefaultData = &defaultUlong;
  448. queryTable[0].DefaultLength = sizeof(ULONG);
  449. }
  450. //
  451. // Set the type.
  452. //
  453. queryTable[0].DefaultType = Type;
  454. //
  455. // Call the query routine. This will either be direct, or result in the callback
  456. // function getting invoked.
  457. //
  458. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  459. RegistryKeyName->Buffer,
  460. queryTable,
  461. NULL,
  462. NULL);
  463. if (NT_SUCCESS(status)) {
  464. if (Type == REG_SZ) {
  465. //
  466. // Have their data. Now figure out whether it fits. The Query function allocates
  467. // the unicode string buffer.
  468. //
  469. if ((unicodeString.Length) &&
  470. ((unicodeString.Length / sizeof(WCHAR)) <= PortContext->CurrentLength)) {
  471. //
  472. // Magically convert.
  473. //
  474. length = WCharToAscii(currentBuffer,
  475. unicodeString.Buffer,
  476. PortContext->CurrentLength);
  477. //
  478. // Set the length of the buffer.
  479. //
  480. PortContext->CurrentLength = length;
  481. } else {
  482. ASSERT(unicodeString.Length);
  483. //
  484. // Update the Length to indicate how big it should actually be.
  485. //
  486. PortContext->LengthNeeded = (unicodeString.Length + 1) / sizeof(WCHAR);
  487. PortContext->CurrentLength = 0;
  488. status = STATUS_BUFFER_TOO_SMALL;
  489. }
  490. //
  491. // Free our string, as the data has already been copied, or won't be copied
  492. // into the caller's buffer.
  493. //
  494. ExFreePool(unicodeString.Buffer);
  495. } else if (Type == REG_DWORD) {
  496. //
  497. // The data should already be there.
  498. //
  499. PortContext->CurrentLength = sizeof(ULONG);
  500. } else {
  501. //
  502. // The Rtl routine has this annoying effect of fixing up BUFFER_TOO_SMALL
  503. // into SUCCESS. Check for this case.
  504. //
  505. if (PortContext->InternalStatus == STATUS_BUFFER_TOO_SMALL) {
  506. //
  507. // Reset the status correctly for the caller.
  508. //
  509. status = PortContext->InternalStatus;
  510. //
  511. // Update length needed, so that the miniport can realloc.
  512. //
  513. PortContext->LengthNeeded = PortContext->CurrentLength;
  514. PortContext->CurrentLength = 0;
  515. } else {
  516. //
  517. // The callback did all the necessary work.
  518. //
  519. NOTHING;
  520. }
  521. }
  522. } else {
  523. //
  524. // Indicate to the caller that the error is NOT due to a length mismatch or
  525. // that the Buffer is too small. The difference is that if too small, the callback
  526. // routine adjusted CurrentLength.
  527. //
  528. PortContext->LengthNeeded = PortContext->CurrentLength;
  529. PortContext->CurrentLength = 0;
  530. }
  531. return status;
  532. }
  533. NTSTATUS
  534. PortRegistryWrite(
  535. IN PUNICODE_STRING RegistryKeyName,
  536. IN PUNICODE_STRING ValueName,
  537. IN ULONG Type,
  538. IN PPORT_REGISTRY_INFO PortContext
  539. )
  540. /*++
  541. Routine Description:
  542. This routine is used by the port-driver to write the contents of Buffer to ValueName
  543. which is located at the reg. key RegistryKeyName.
  544. Buffer is first converted to UNICODE then the write takes place.
  545. Arguments:
  546. RegistryKeyName - The absolute path to the key name.
  547. ValueName - The name of the data to be written.
  548. Type - The reg. data type for this operation.
  549. PortContext - Blob containing the miniports buffer and it's size.
  550. Return Value:
  551. STATUS from the registry routines, or INSUFFICIENT_RESOURCES
  552. --*/
  553. {
  554. UNICODE_STRING unicodeString;
  555. ULONG bufferLength;
  556. PUCHAR currentBuffer;
  557. LONG offset;
  558. ULONG length;
  559. NTSTATUS status;
  560. //
  561. // Determine whether the field exists.
  562. //
  563. status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
  564. RegistryKeyName->Buffer);
  565. if (!NT_SUCCESS(status)) {
  566. //
  567. // The key doesn't exist. Create it.
  568. //
  569. status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
  570. RegistryKeyName->Buffer);
  571. }
  572. if (!NT_SUCCESS(status)) {
  573. //
  574. // Can't go on. Return the error to the port-driver and it can figure
  575. // out what best to do.
  576. //
  577. return status;
  578. }
  579. //
  580. // Calculate the actual buffer location where this data lives.
  581. // This presupposes that the port-driver has done all the validation.
  582. //
  583. currentBuffer = PortContext->Buffer + PortContext->Offset;
  584. if (Type == REG_SZ) {
  585. //
  586. // Determine the size needed for the WCHAR.
  587. //
  588. bufferLength = PortContext->CurrentLength * sizeof(WCHAR);
  589. //
  590. // Allocate a buffer to build the converted data in.
  591. //
  592. unicodeString.Buffer = ExAllocatePool(NonPagedPool, bufferLength + sizeof(UNICODE_NULL));
  593. if (unicodeString.Buffer == NULL) {
  594. return STATUS_INSUFFICIENT_RESOURCES;
  595. }
  596. RtlZeroMemory(unicodeString.Buffer, bufferLength + sizeof(UNICODE_NULL));
  597. //
  598. // Set the lengths.
  599. //
  600. unicodeString.MaximumLength = (USHORT)(bufferLength + sizeof(UNICODE_NULL));
  601. unicodeString.Length = (USHORT)bufferLength;
  602. //
  603. // Convert it.
  604. //
  605. length = AsciiToWChar(unicodeString.Buffer,
  606. currentBuffer,
  607. unicodeString.Length);
  608. //
  609. // Length is now set for the call below. Get the buffer by resetting
  610. // currentbuffer to that of the unicode string's.
  611. //
  612. currentBuffer = (PUCHAR)unicodeString.Buffer;
  613. } else if (Type == REG_DWORD){
  614. //
  615. // always this size.
  616. //
  617. length = sizeof(ULONG);
  618. } else {
  619. //
  620. // For BINARY use the passed in buffer (currentBuffer) and length.
  621. //
  622. length = PortContext->CurrentLength;
  623. }
  624. //
  625. // Write the data to the specified key/Value
  626. //
  627. status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  628. RegistryKeyName->Buffer,
  629. ValueName->Buffer,
  630. Type,
  631. currentBuffer,
  632. length);
  633. return status;
  634. }
  635. NTSTATUS
  636. PortBuildRegKeyName(
  637. IN PUNICODE_STRING RegistryPath,
  638. IN OUT PUNICODE_STRING KeyName,
  639. IN ULONG PortNumber,
  640. IN ULONG Global
  641. )
  642. /*++
  643. Routine Description:
  644. This routine will build the registry keyname to the miniport's
  645. Device(N) key based on RegistryPath and whether the key is for global miniport
  646. data, or specific to one scsiN.
  647. Arguments:
  648. RegistryPath - The path to the miniport's service key.
  649. KeyName - Storage for the whole path.
  650. PortNumber - The adapter ordinal. Valid only if Global is FALSE.
  651. Global - Indicates whether the Device or Device(N) path should be built.
  652. Return Value:
  653. SUCCESS - KeyName is valid.
  654. INSUFFICIENT_RESOURCES
  655. --*/
  656. {
  657. UNICODE_STRING unicodeValue;
  658. UNICODE_STRING tempKeyName;
  659. ANSI_STRING ansiKeyName;
  660. ULONG maxLength;
  661. NTSTATUS status;
  662. UCHAR paramsBuffer[24];
  663. //
  664. // If this is global, it represents ALL adapters being controlled by
  665. // the miniport. Otherwise, it's the scsiN key only.
  666. //
  667. if (Global) {
  668. RtlInitAnsiString(&ansiKeyName, "\\Parameters\\Device");
  669. RtlAnsiStringToUnicodeString(&tempKeyName, &ansiKeyName, TRUE);
  670. } else {
  671. //
  672. // Get the scsiport'N'.
  673. //
  674. sprintf(paramsBuffer, "\\Parameters\\Device%d", PortNumber);
  675. RtlInitAnsiString(&ansiKeyName, paramsBuffer);
  676. RtlAnsiStringToUnicodeString(&tempKeyName, &ansiKeyName, TRUE);
  677. }
  678. //
  679. // The total length will be the size of the path to <services> plus the parameters\device
  680. // string. Add enough for a NULL at the end.
  681. //
  682. maxLength = RegistryPath->MaximumLength + tempKeyName.MaximumLength + 2;
  683. KeyName->Buffer = ExAllocatePool(NonPagedPool, maxLength);
  684. if (KeyName->Buffer == NULL) {
  685. return STATUS_INSUFFICIENT_RESOURCES;
  686. }
  687. RtlZeroMemory(KeyName->Buffer, maxLength);
  688. //
  689. // Clone the Reg.Path.
  690. //
  691. KeyName->MaximumLength = (USHORT)maxLength;
  692. RtlCopyUnicodeString(KeyName,
  693. RegistryPath);
  694. //
  695. // Have a copy of the path to the services name. Add the rest of the keyname
  696. // to it.
  697. //
  698. status = RtlAppendUnicodeStringToString(KeyName, &tempKeyName);
  699. //
  700. // Free the buffer allocated above.
  701. //
  702. RtlFreeUnicodeString(&tempKeyName);
  703. return status;
  704. }