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.

2262 lines
55 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. range.c
  5. Abstract:
  6. This module contains the API routines that operate directly on ranges.
  7. CM_Add_Range
  8. CM_Create_Range_List
  9. CM_Delete_Range
  10. CM_Dup_Range_List
  11. CM_Find_Range
  12. CM_First_Range
  13. CM_Free_Range_List
  14. CM_Intersect_Range_List
  15. CM_Invert_Range_List
  16. CM_Merge_Range_List
  17. CM_Next_Range
  18. CM_Test_Range_Available
  19. Author:
  20. Paula Tomlinson (paulat) 10-17-1995
  21. Environment:
  22. User mode only.
  23. Revision History:
  24. 17-Oct-1995 paulat
  25. Creation and initial implementation.
  26. --*/
  27. //
  28. // includes
  29. //
  30. #include "precomp.h"
  31. #include "cfgi.h"
  32. #include "setupapi.h"
  33. #include "spapip.h"
  34. //
  35. // Private prototypes
  36. //
  37. BOOL
  38. IsValidRangeList(
  39. IN RANGE_LIST rlh
  40. );
  41. CONFIGRET
  42. AddRange(
  43. IN PRange_Element pParentElement,
  44. IN DWORDLONG ullStartValue,
  45. IN DWORDLONG ullEndValue,
  46. IN ULONG ulFlags
  47. );
  48. CONFIGRET
  49. InsertRange(
  50. IN PRange_Element pParentElement,
  51. IN DWORDLONG ullStartValue,
  52. IN DWORDLONG ullEndValue
  53. );
  54. CONFIGRET
  55. DeleteRange(
  56. IN PRange_Element pParentElement
  57. );
  58. CONFIGRET
  59. JoinRange(
  60. IN PRange_Element pParentElement,
  61. IN DWORDLONG ullStartValue,
  62. IN DWORDLONG ullEndValue
  63. );
  64. CONFIGRET
  65. CopyRanges(
  66. IN PRange_Element pFromRange,
  67. IN PRange_Element pToRange
  68. );
  69. CONFIGRET
  70. ClearRanges(
  71. IN PRange_Element pRange
  72. );
  73. CONFIGRET
  74. TestRange(
  75. IN PRange_Element rlh,
  76. IN DWORDLONG ullStartValue,
  77. IN DWORDLONG ullEndValue,
  78. OUT PRange_Element *pConflictingRange
  79. );
  80. //
  81. // global data
  82. //
  83. CONFIGRET
  84. CM_Add_Range(
  85. IN DWORDLONG ullStartValue,
  86. IN DWORDLONG ullEndValue,
  87. IN RANGE_LIST rlh,
  88. IN ULONG ulFlags
  89. )
  90. /*++
  91. Routine Description:
  92. This routine adds a memory range to a range list.
  93. Parameters:
  94. ullStartValue Low end of the range.
  95. ullEndValue High end of the range.
  96. rlh Handle of a range list.
  97. ulFlags Supplies flags specifying options for ranges that conflict
  98. with ranges alread in the list. May be one of the
  99. following values:
  100. CM_ADD_RANGE_ADDIFCONFLICT New range is merged with the
  101. ranges it conflicts with.
  102. CM_ADD_RANGE_DONOTADDIFCONFLICT Returns CR_FAILURE if there
  103. is a conflict.
  104. Return Value:
  105. If the function succeeds, the return value is CR_SUCCESS.
  106. If the function fails, the return value is one of the following:
  107. CR_FAILURE,
  108. CR_INVALID_FLAG,
  109. CR_INVALID_RANGE,
  110. CR_INVALID_RANGE_LIST, or
  111. CR_OUT_OF_MEMORY.
  112. --*/
  113. {
  114. CONFIGRET Status = CR_SUCCESS;
  115. BOOL bLock = FALSE;
  116. try {
  117. //
  118. // validate parameters
  119. //
  120. if (!IsValidRangeList(rlh)) {
  121. Status = CR_INVALID_RANGE_LIST;
  122. goto Clean0;
  123. }
  124. if (INVALID_FLAGS(ulFlags, CM_ADD_RANGE_BITS)) {
  125. Status = CR_INVALID_FLAG;
  126. goto Clean0;
  127. }
  128. if (ullStartValue > ullEndValue) {
  129. Status = CR_INVALID_RANGE;
  130. goto Clean0;
  131. }
  132. LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  133. bLock = TRUE;
  134. Status = AddRange((PRange_Element)rlh, ullStartValue,
  135. ullEndValue, ulFlags);
  136. Clean0:
  137. NOTHING;
  138. } except(EXCEPTION_EXECUTE_HANDLER) {
  139. bLock = bLock; // needed to prevent optimizing this flag away
  140. Status = CR_FAILURE;
  141. }
  142. if (bLock) {
  143. UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  144. }
  145. return Status;
  146. } // CM_Add_Range
  147. CONFIGRET
  148. CM_Create_Range_List(
  149. OUT PRANGE_LIST prlh,
  150. IN ULONG ulFlags
  151. )
  152. /*++
  153. Routine Description:
  154. This routine creates a list of ranges.
  155. Parameters:
  156. prlh Supplies the address of the variable that receives a
  157. handle to the new range list.
  158. ulFlags Must be zero.
  159. Return Value:
  160. If the function succeeds, the return value is CR_SUCCESS.
  161. If the function fails, the return value is one of the following:
  162. CR_INVALID_FLAG,
  163. CR_INVALID_POINTER, or
  164. CR_OUT_OF_MEMORY.
  165. --*/
  166. {
  167. CONFIGRET Status = CR_SUCCESS;
  168. PRange_List_Hdr pRangeHdr = NULL;
  169. try {
  170. //
  171. // validate parameters
  172. //
  173. if (INVALID_FLAGS(ulFlags, 0)) {
  174. Status = CR_INVALID_FLAG;
  175. goto Clean0;
  176. }
  177. if (prlh == NULL) {
  178. Status = CR_INVALID_POINTER;
  179. goto Clean0;
  180. }
  181. //
  182. // allocate a buffer for the range list header struct
  183. //
  184. pRangeHdr = pSetupMalloc(sizeof(Range_List_Hdr));
  185. if (pRangeHdr == NULL) {
  186. Status = CR_OUT_OF_MEMORY;
  187. goto Clean0;
  188. }
  189. //
  190. // initialize the range list header buffer
  191. //
  192. pRangeHdr->RLH_Head = 0;
  193. pRangeHdr->RLH_Header = (ULONG_PTR)pRangeHdr;
  194. pRangeHdr->RLH_Signature = Range_List_Signature;
  195. //
  196. // initialize the private resource lock
  197. //
  198. InitPrivateResource(&(pRangeHdr->RLH_Lock));
  199. //
  200. // return a pointer to range list buffer to the caller
  201. //
  202. *prlh = (RANGE_LIST)pRangeHdr;
  203. Clean0:
  204. NOTHING;
  205. } except(EXCEPTION_EXECUTE_HANDLER) {
  206. Status = CR_FAILURE;
  207. }
  208. return Status;
  209. } // CM_Create_Range_List
  210. CONFIGRET
  211. CM_Delete_Range(
  212. IN DWORDLONG ullStartValue,
  213. IN DWORDLONG ullEndValue,
  214. IN RANGE_LIST rlh,
  215. IN ULONG ulFlags
  216. )
  217. /*++
  218. Routine Description:
  219. This routine deletes a range from a range list. If ullStartValue
  220. and ullEndValue are set to 0 and DWORD_MAX, this API carries out
  221. a special case, quickly emptying the lower 4 Gigabytes of the range.
  222. If ullEndValue is instead DWORDLONG_MAX, the entire range list is
  223. cleared, without having to process each element.
  224. Parameters:
  225. ullStartValue Low end of the range.
  226. ullEndValue High end of the range.
  227. rlh Handle of a range list.
  228. ulFlags Must be zero.
  229. Return Value:
  230. If the function succeeds, the return value is CR_SUCCESS.
  231. If the function fails, the return value is one of the following:
  232. CR_FAILURE,
  233. CR_INVALID_FLAG,
  234. CR_INVALID_RANGE,
  235. CR_INVALID_RANGE_LIST, or
  236. CR_OUT_OF_MEMORY.
  237. --*/
  238. {
  239. CONFIGRET Status = CR_SUCCESS;
  240. PRange_Element pRange = NULL, pPrevious = NULL, pCurrent = NULL;
  241. BOOL bLock = FALSE;
  242. try {
  243. //
  244. // validate parameters
  245. //
  246. if (!IsValidRangeList(rlh)) {
  247. Status = CR_INVALID_RANGE_LIST;
  248. goto Clean0;
  249. }
  250. if (INVALID_FLAGS(ulFlags, 0)) {
  251. Status = CR_INVALID_FLAG;
  252. goto Clean0;
  253. }
  254. if (ullStartValue > ullEndValue) {
  255. Status = CR_INVALID_RANGE;
  256. goto Clean0;
  257. }
  258. LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  259. bLock = TRUE;
  260. pPrevious = (PRange_Element)rlh;
  261. //-------------------------------------------------------------
  262. // first check the special case range values
  263. //-------------------------------------------------------------
  264. if (ullStartValue == 0) {
  265. if (ullEndValue == DWORDLONG_MAX) {
  266. //
  267. // quick clear of all ranges
  268. //
  269. ClearRanges(pPrevious);
  270. }
  271. else if (ullEndValue == DWORD_MAX) {
  272. //
  273. // quick clear of lower 4 GB ranges
  274. //
  275. while (pPrevious->RL_Next != 0) {
  276. pCurrent = (PRange_Element)pPrevious->RL_Next;
  277. if (pCurrent->RL_Start >= DWORD_MAX) {
  278. goto Clean0; // done
  279. }
  280. if (pCurrent->RL_End >= DWORD_MAX) {
  281. pCurrent->RL_Start = DWORD_MAX;
  282. goto Clean0; // done
  283. }
  284. DeleteRange(pPrevious); // pass the parent
  285. }
  286. goto Clean0;
  287. }
  288. }
  289. //-------------------------------------------------------------
  290. // search through each range in this list, if any part of the
  291. // specified range is contained in this range list, remove the
  292. // intersections
  293. //-------------------------------------------------------------
  294. while (pPrevious->RL_Next != 0) {
  295. pRange = (PRange_Element)pPrevious->RL_Next;
  296. //
  297. // if this range is completely before the current range, then
  298. // we can stop
  299. //
  300. if (ullEndValue < pRange->RL_Start) {
  301. break;
  302. }
  303. //
  304. // if this range is completely after the current range, then
  305. // skip to the next range
  306. //
  307. if (ullStartValue > pRange->RL_End) {
  308. goto NextRange;
  309. }
  310. //
  311. // if the range is completely contained, then delete the whole
  312. // thing
  313. //
  314. if (ullStartValue <= pRange->RL_Start &&
  315. ullEndValue >= pRange->RL_End) {
  316. DeleteRange(pPrevious); // pass the parent range
  317. //
  318. // don't goto next range because that would increment the
  319. // pPrevious counter. Since the current range was just deleted,
  320. // we need to process the current spot still.
  321. //
  322. continue;
  323. }
  324. //
  325. // if the start of the specified range intersects the current range,
  326. // adjust the current range to exclude it
  327. //
  328. if (ullStartValue > pRange->RL_Start &&
  329. ullStartValue <= pRange->RL_End) {
  330. //
  331. // if the specified range is in the middle of this range, then
  332. // in addition to shrinking the first part of the range, I'll
  333. // have to create a range for the second part
  334. // | |<-- delete --->| |
  335. //
  336. if (ullEndValue < pRange->RL_End) {
  337. AddRange(pRange, ullEndValue+1, pRange->RL_End,
  338. CM_ADD_RANGE_ADDIFCONFLICT);
  339. }
  340. pRange->RL_End = ullStartValue-1;
  341. //
  342. // reset the delete range for further processing
  343. //
  344. if (ullEndValue > pRange->RL_End) {
  345. ullStartValue = pRange->RL_End+1;
  346. }
  347. }
  348. //
  349. // if the end of the specified range intersects the current range,
  350. // adjust the current range to exclude it
  351. //
  352. if (ullEndValue >= pRange->RL_Start &&
  353. ullEndValue <= pRange->RL_End) {
  354. pRange->RL_Start = ullEndValue+1;
  355. //
  356. // reset the delete range for further processing
  357. //
  358. if (ullEndValue > pRange->RL_End) {
  359. ullStartValue = pRange->RL_End+1;
  360. }
  361. }
  362. NextRange:
  363. pPrevious = (PRange_Element)pPrevious->RL_Next;
  364. }
  365. Clean0:
  366. NOTHING;
  367. } except(EXCEPTION_EXECUTE_HANDLER) {
  368. bLock = bLock; // needed to prevent optimizing this flag away
  369. Status = CR_FAILURE;
  370. }
  371. if (bLock) {
  372. UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  373. }
  374. return Status;
  375. } // CM_Delete_Range
  376. CONFIGRET
  377. CM_Dup_Range_List(
  378. IN RANGE_LIST rlhOld,
  379. IN RANGE_LIST rlhNew,
  380. IN ULONG ulFlags
  381. )
  382. /*++
  383. Routine Description:
  384. This routine copies a range list.
  385. Parameters:
  386. rlhOld Supplies the handle of the range list to copy.
  387. rlhNew Supplies the handle of a valid range list into which rlhOld
  388. is copied. Anything contained in the rlhNew range list is
  389. removed by the copy operation.
  390. ulFlags Must be zero.
  391. Return Value:
  392. If the function succeeds, the return value is CR_SUCCESS.
  393. If the function fails, the return value is one of the following:
  394. CR_INVALID_FLAG,
  395. CR_INVALID_RANGE_LIST, or
  396. CR_OUT_OF_MEMORY
  397. --*/
  398. {
  399. CONFIGRET Status = CR_SUCCESS;
  400. PRange_Element pRangeNew = NULL, pRangeOld = NULL;
  401. BOOL bLockOld = FALSE, bLockNew = FALSE;
  402. try {
  403. //
  404. // validate parameters
  405. //
  406. if (!IsValidRangeList(rlhOld)) {
  407. Status = CR_INVALID_RANGE_LIST;
  408. goto Clean0;
  409. }
  410. if (!IsValidRangeList(rlhNew)) {
  411. Status = CR_INVALID_RANGE_LIST;
  412. goto Clean0;
  413. }
  414. if (INVALID_FLAGS(ulFlags, 0)) {
  415. Status = CR_INVALID_FLAG;
  416. goto Clean0;
  417. }
  418. LockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
  419. bLockOld = TRUE;
  420. LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  421. bLockNew = TRUE;
  422. pRangeNew = (PRange_Element)rlhNew;
  423. pRangeOld = (PRange_Element)rlhOld;
  424. //
  425. // If the new range list is not empty, then delete ranges
  426. //
  427. if (pRangeNew->RL_Next != 0) {
  428. ClearRanges(pRangeNew);
  429. }
  430. Status = CR_SUCCESS; // reset status flag to okay
  431. //
  432. // duplicate each of the old ranges
  433. //
  434. pRangeOld = (PRange_Element)pRangeOld->RL_Next;
  435. CopyRanges(pRangeOld, pRangeNew);
  436. Clean0:
  437. NOTHING;
  438. } except(EXCEPTION_EXECUTE_HANDLER) {
  439. bLockOld = bLockOld; // needed to prevent optimizing this flag away
  440. bLockNew = bLockNew; // needed to prevent optimizing this flag away
  441. Status = CR_FAILURE;
  442. }
  443. if (bLockOld) {
  444. UnlockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
  445. }
  446. if (bLockNew) {
  447. UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  448. }
  449. return Status;
  450. } // CM_Dup_Range_List
  451. CONFIGRET
  452. CM_Find_Range(
  453. OUT PDWORDLONG pullStart,
  454. IN DWORDLONG ullStart,
  455. IN ULONG ulLength,
  456. IN DWORDLONG ullAlignment,
  457. IN DWORDLONG ullEnd,
  458. IN RANGE_LIST rlh,
  459. IN ULONG ulFlags
  460. )
  461. /*++
  462. Routine Description:
  463. This routine attempts to find a range in the supplied range list that
  464. will accommodate the range requirements specified. [TBD: Verify
  465. that this description is correct.]
  466. Parameters:
  467. pullStart Supplies the address of a variable that receives the
  468. starting value of the allocated range.
  469. ullStart Supplies the starting address that the range can have.
  470. ulLength Supplies the length needed for the allocated range.
  471. ullAlignment Supplies the alignment bitmask that specifies where the
  472. allocated range can start. [TBD: verify that this is indeed
  473. a bitmask]
  474. ullEnd Supplies the ending address of the area from which the range
  475. may be allocated.
  476. rlh Supplies a handle to a range list in which the specified
  477. range is to be found.
  478. ulFlags TBD
  479. Return Value:
  480. If the function succeeds, the return value is CR_SUCCESS.
  481. If the function fails, the return value is one of the following:
  482. CR_INVALID_FLAG,
  483. CR_INVALID_POINTER,
  484. CR_FAILURE
  485. --*/
  486. {
  487. CONFIGRET Status = CR_SUCCESS;
  488. PRange_Element pRange = NULL;
  489. DWORDLONG ullNewEnd;
  490. BOOL bLock = FALSE;
  491. try {
  492. //
  493. // validate parameters
  494. //
  495. if (!IsValidRangeList(rlh)) {
  496. Status = CR_INVALID_RANGE_LIST;
  497. goto Clean0;
  498. }
  499. if (pullStart == NULL) {
  500. Status = CR_INVALID_POINTER;
  501. goto Clean0;
  502. }
  503. if (INVALID_FLAGS(ulFlags, 0)) {
  504. Status = CR_INVALID_FLAG;
  505. goto Clean0;
  506. }
  507. LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  508. bLock = TRUE;
  509. //
  510. // Normalize aligment. Alignments are now like 0x00000FFF.
  511. //
  512. ullAlignment =~ ullAlignment;
  513. //
  514. // Test for impossible alignments (-1, not a power of 2 or start is
  515. // less than alignment away from wrapping). Also test for invalid
  516. // length.
  517. //
  518. if ((ullAlignment == DWORD_MAX) |
  519. (ulLength == 0) |
  520. ((ullAlignment & (ullAlignment + 1)) != 0) |
  521. (ullStart + ullAlignment < ullStart)) {
  522. Status = CR_FAILURE;
  523. goto Clean0;
  524. }
  525. //
  526. // Align the base.
  527. //
  528. ullStart += ullAlignment;
  529. ullStart &= ~ullAlignment;
  530. //
  531. // Compute the new end.
  532. //
  533. ullNewEnd = ullStart + ulLength - 1;
  534. //
  535. // Make sure we do have space.
  536. //
  537. if ((ullNewEnd < ullStart) || (ullNewEnd > ullEnd)) {
  538. Status = CR_FAILURE;
  539. goto Clean0;
  540. }
  541. //
  542. // Check if that range fits
  543. //
  544. if (TestRange((PRange_Element)rlh, ullStart, ullStart + ulLength - 1,
  545. &pRange) == CR_SUCCESS) {
  546. //
  547. // We got it then, on the first try.
  548. //
  549. *pullStart = ullStart;
  550. goto Clean0;
  551. }
  552. //
  553. // Search for a spot where this range will fit.
  554. //
  555. while (TRUE) {
  556. //
  557. // Start at the end of the conflicting range.
  558. //
  559. ullStart = pRange->RL_End + 1;
  560. //
  561. // Check for wrapping.
  562. //
  563. if (!ullStart) {
  564. Status = CR_FAILURE;
  565. goto Clean0;
  566. }
  567. //
  568. // Make sure the alignment adjustment won't wrap.
  569. //
  570. if (ullStart + ullAlignment < ullStart) {
  571. Status = CR_FAILURE;
  572. goto Clean0;
  573. }
  574. //
  575. // Adjust the alignment.
  576. //
  577. ullStart += ullAlignment;
  578. ullStart &= ~ullAlignment;
  579. //
  580. // Compute the new end.
  581. //
  582. ullNewEnd = ullStart + ulLength - 1;
  583. //
  584. // Make sure the new end does not wrap and is still valid.
  585. //
  586. if ((ullNewEnd < ullStart) | (ullStart + ulLength - 1 > ullEnd)) {
  587. Status = CR_FAILURE;
  588. goto Clean0;
  589. }
  590. //
  591. // Skip any prls which existed only below our new range
  592. // (because we moved ulStart upward of them).
  593. //
  594. while ((pRange = (PRange_Element)pRange->RL_Next) != NULL &&
  595. ullStart > pRange->RL_End) {
  596. }
  597. //
  598. // If we don't have a prl or it's begining is after our end
  599. //
  600. if (pRange == NULL || ullNewEnd < pRange->RL_Start) {
  601. *pullStart = ullStart;
  602. goto Clean0;
  603. }
  604. //
  605. // Otherwise try with the new prl.
  606. //
  607. }
  608. Clean0:
  609. NOTHING;
  610. } except(EXCEPTION_EXECUTE_HANDLER) {
  611. bLock = bLock; // needed to prevent optimizing this flag away
  612. Status = CR_FAILURE;
  613. }
  614. if (bLock) {
  615. UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  616. }
  617. return Status;
  618. } // CM_Find_Range
  619. CONFIGRET
  620. CM_First_Range(
  621. IN RANGE_LIST rlh,
  622. OUT PDWORDLONG pullStart,
  623. OUT PDWORDLONG pullEnd,
  624. OUT PRANGE_ELEMENT preElement,
  625. IN ULONG ulFlags
  626. )
  627. /*++
  628. Routine Description:
  629. This routine retrieves the first range element in a range list.
  630. Parameters:
  631. rlh Supplies the handle of a range list.
  632. pullStart Supplies the address of a variable that receives the
  633. starting value of the first range element.
  634. pullEnd Supplies the address of a variable that receives the
  635. ending value of the first range element.
  636. preElement Supplies the address of a variable that receives the
  637. handle of the next range element.
  638. ulFlags Must be zero.
  639. Return Value:
  640. If the function succeeds, the return value is CR_SUCCESS.
  641. If the function fails, the return value is one of the following:
  642. CR_FAILURE,
  643. CR_INVALID_FLAG,
  644. CR_INVALID_POINTER, or
  645. CR_INVALID_RANGE_LIST.
  646. --*/
  647. {
  648. CONFIGRET Status = CR_SUCCESS;
  649. PRange_Element pRange = NULL;
  650. BOOL bLock = FALSE;
  651. try {
  652. //
  653. // validate parameters
  654. //
  655. if (!IsValidRangeList(rlh)) {
  656. Status = CR_INVALID_RANGE_LIST;
  657. goto Clean0;
  658. }
  659. if (pullEnd == NULL || pullStart == NULL || preElement == NULL) {
  660. Status = CR_INVALID_POINTER;
  661. goto Clean0;
  662. }
  663. if (INVALID_FLAGS(ulFlags, 0)) {
  664. Status = CR_INVALID_FLAG;
  665. goto Clean0;
  666. }
  667. LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  668. bLock = TRUE;
  669. pRange = (PRange_Element)rlh;
  670. //
  671. // is the range list empty?
  672. //
  673. if (pRange->RL_Next == 0) {
  674. Status = CR_FAILURE;
  675. goto Clean0;
  676. }
  677. //
  678. // skip over the header to the first element
  679. //
  680. pRange = (PRange_Element)pRange->RL_Next;
  681. *pullStart = pRange->RL_Start;
  682. *pullEnd = pRange->RL_End;
  683. *preElement = (RANGE_ELEMENT)pRange->RL_Next;
  684. Clean0:
  685. NOTHING;
  686. } except(EXCEPTION_EXECUTE_HANDLER) {
  687. bLock = bLock; // needed to prevent optimizing this flag away
  688. Status = CR_FAILURE;
  689. }
  690. if (bLock) {
  691. UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  692. }
  693. return Status;
  694. } // CM_First_Range
  695. CONFIGRET
  696. CM_Free_Range_List(
  697. IN RANGE_LIST rlh,
  698. IN ULONG ulFlags
  699. )
  700. /*++
  701. Routine Description:
  702. This routine frees the specified range list and the memory allocated
  703. for it.
  704. Parameters:
  705. rlh Supplies the handle of the range list to be freed.
  706. ulFlags Must be zero.
  707. Return Value:
  708. If the function succeeds, the return value is CR_SUCCESS.
  709. If the function fails, the return value is one of the following:
  710. CR_INVALID_FLAG,
  711. CR_INVALID_RANGE_LIST.
  712. --*/
  713. {
  714. CONFIGRET Status = CR_SUCCESS, Status1 = CR_SUCCESS;
  715. BOOL bLock = FALSE;
  716. try {
  717. //
  718. // validate parameters
  719. //
  720. if (!IsValidRangeList(rlh)) {
  721. Status = CR_INVALID_RANGE_LIST;
  722. goto Clean0;
  723. }
  724. if (INVALID_FLAGS(ulFlags, 0)) {
  725. Status = CR_INVALID_FLAG;
  726. goto Clean0;
  727. }
  728. LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  729. bLock = TRUE;
  730. while (Status1 == CR_SUCCESS) {
  731. //
  732. // keep deleting the first range after the header (pass parent
  733. // of range to delete)
  734. //
  735. Status1 = DeleteRange((PRange_Element)rlh);
  736. }
  737. //
  738. // destroy the private resource lock
  739. //
  740. DestroyPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  741. //
  742. // delete the range header
  743. //
  744. ((PRange_List_Hdr)rlh)->RLH_Signature = 0;
  745. pSetupFree((PRange_Element)rlh);
  746. bLock = FALSE;
  747. Clean0:
  748. NOTHING;
  749. } except(EXCEPTION_EXECUTE_HANDLER) {
  750. bLock = bLock; // needed to prevent optimizing this flag away
  751. Status = CR_FAILURE;
  752. }
  753. if (bLock) {
  754. UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  755. }
  756. return Status;
  757. } // CM_Free_Range_List
  758. CONFIGRET
  759. CM_Intersect_Range_List(
  760. IN RANGE_LIST rlhOld1,
  761. IN RANGE_LIST rlhOld2,
  762. IN RANGE_LIST rlhNew,
  763. IN ULONG ulFlags
  764. )
  765. /*++
  766. Routine Description:
  767. This routine creates a range list from the intersection of two specified
  768. range lists. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle
  769. of a valid but empty range list.
  770. Parameters:
  771. rlhOld1 Supplies the handle of a range list to be used as part of the
  772. intersection.
  773. rlhOld2 Supplies the handle of a range list to be used as part of the
  774. intersection.
  775. rlhNew Supplies the handle of the range list that receives the
  776. intersection of rlhOld1 and rlhOld2. Anything previously contained
  777. in the rlhNew ragne list is removed by this operation.
  778. ulFlags Must be zero.
  779. Return Value:
  780. If the function succeeds, the return value is CR_SUCCESS.
  781. If the function fails, the return value is one of the following:
  782. CR_INVALID_FLAG,
  783. CR_INVALID_RANGE_LIST, or
  784. CR_OUT_OF_MEMORY.
  785. --*/
  786. {
  787. CONFIGRET Status = CR_SUCCESS;
  788. DWORDLONG ulStart = 0, ulEnd = 0;
  789. PRange_Element pRangeNew = NULL, pRangeOld1 = NULL, pRangeOld2 = NULL;
  790. BOOL bLock1 = FALSE, bLock2 = FALSE, bLockNew = FALSE;
  791. try {
  792. //
  793. // validate parameters
  794. //
  795. if (!IsValidRangeList(rlhOld1)) {
  796. Status = CR_INVALID_RANGE_LIST;
  797. goto Clean0;
  798. }
  799. if (!IsValidRangeList(rlhOld2)) {
  800. Status = CR_INVALID_RANGE_LIST;
  801. goto Clean0;
  802. }
  803. if (!IsValidRangeList(rlhNew)) {
  804. Status = CR_INVALID_RANGE_LIST;
  805. goto Clean0;
  806. }
  807. if (INVALID_FLAGS(ulFlags, 0)) {
  808. Status = CR_INVALID_FLAG;
  809. goto Clean0;
  810. }
  811. LockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
  812. bLock1 = TRUE;
  813. LockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
  814. bLock2 = TRUE;
  815. LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  816. bLockNew = TRUE;
  817. pRangeNew = (PRange_Element)rlhNew;
  818. pRangeOld1 = (PRange_Element)rlhOld1;
  819. pRangeOld2 = (PRange_Element)rlhOld2;
  820. //
  821. // If the new range list is not empty, then delete ranges
  822. //
  823. if (pRangeNew->RL_Next != 0) {
  824. ClearRanges(pRangeNew);
  825. }
  826. //
  827. // Special case: if either range is empty then there is no
  828. // intersection by definition
  829. //
  830. if (pRangeOld1->RL_Next == 0 || pRangeOld2->RL_Next == 0) {
  831. goto Clean0;
  832. }
  833. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  834. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  835. while (TRUE) {
  836. //
  837. // skip over Old2 ranges until intersects with or exceeds
  838. // current Old1 range (or no more Old2 ranges left)
  839. //
  840. while (pRangeOld2->RL_End < pRangeOld1->RL_Start) {
  841. if (pRangeOld2->RL_Next == 0) {
  842. goto Clean0; // Old2 exhausted, we're done
  843. }
  844. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  845. }
  846. //
  847. // if this Old2 range exceeds Old1 range, then go to the
  848. // next Old1 range and go through the main loop again
  849. //
  850. if (pRangeOld2->RL_Start > pRangeOld1->RL_End) {
  851. if (pRangeOld1->RL_Next == 0) {
  852. goto Clean0; // Old1 exhausted, we're done
  853. }
  854. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  855. continue;
  856. }
  857. //
  858. // if we got here there must be an intersection so add
  859. // the intersected range to New
  860. //
  861. ulStart = max(pRangeOld1->RL_Start, pRangeOld2->RL_Start);
  862. ulEnd = min(pRangeOld1->RL_End, pRangeOld2->RL_End);
  863. Status = InsertRange(pRangeNew, ulStart, ulEnd);
  864. if (Status != CR_SUCCESS) {
  865. goto Clean0;
  866. }
  867. pRangeNew = (PRange_Element)pRangeNew->RL_Next;
  868. //
  869. // after handling the intersection, skip to next ranges in
  870. // Old1 and Old2 as appropriate
  871. //
  872. if (pRangeOld1->RL_End <= ulEnd) {
  873. if (pRangeOld1->RL_Next == 0) {
  874. goto Clean0; // Old1 exhausted, we're done
  875. }
  876. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  877. }
  878. if (pRangeOld2->RL_End <= ulEnd) {
  879. if (pRangeOld2->RL_Next == 0) {
  880. goto Clean0; // Old1 exhausted, we're done
  881. }
  882. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  883. }
  884. }
  885. Clean0:
  886. NOTHING;
  887. } except(EXCEPTION_EXECUTE_HANDLER) {
  888. bLock1 = bLock1; // needed to prevent optimizing this flag away
  889. bLock2 = bLock2; // needed to prevent optimizing this flag away
  890. bLockNew = bLockNew; // needed to prevent optimizing this flag away
  891. Status = CR_FAILURE;
  892. }
  893. if (bLock1) {
  894. UnlockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
  895. }
  896. if (bLock2) {
  897. UnlockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
  898. }
  899. if (bLockNew) {
  900. UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  901. }
  902. return Status;
  903. } // CM_Intersect_Range_List
  904. CONFIGRET
  905. CM_Invert_Range_List(
  906. IN RANGE_LIST rlhOld,
  907. IN RANGE_LIST rlhNew,
  908. IN DWORDLONG ullMaxValue,
  909. IN ULONG ulFlags
  910. )
  911. /*++
  912. Routine Description:
  913. This routine creates a range list that is the inverse of a specified
  914. range list; all claimed ranges in the new list are specified as free
  915. in the old list, and vice-versa. For example, the inversion of
  916. {[2,4],[6,8]} when the ulMaxValue parameter is 15 is {[0,1],[5,5],[9,15]}.
  917. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid
  918. but empty range list.
  919. Parameters:
  920. rlhOld Supplies the handle of a range list to be inverted.
  921. rlhNew Supplies the handle of the range list that receives the
  922. inverted copy of rlhOld. Anything previously contained in
  923. the rlhNew range list is removed by this operation.
  924. ullMaxValue Uppermost value of the inverted range list.
  925. ulFlags Must be zero.
  926. Return Value:
  927. If the function succeeds, the return value is CR_SUCCESS.
  928. If the function fails, the return value is one of the following:
  929. CR_INVALID_FLAG,
  930. CR_INVALID_RANGE_LIST,
  931. CR_OUT_OF_MEMORY.
  932. --*/
  933. {
  934. CONFIGRET Status = CR_SUCCESS;
  935. PRange_Element pRangeNew = NULL, pRangeOld = NULL;
  936. DWORDLONG ullStart = 0, ullEnd = 0;
  937. BOOL bLockOld = FALSE, bLockNew = FALSE;
  938. try {
  939. //
  940. // validate parameters
  941. //
  942. if (!IsValidRangeList(rlhOld)) {
  943. Status = CR_INVALID_RANGE_LIST;
  944. goto Clean0;
  945. }
  946. if (!IsValidRangeList(rlhNew)) {
  947. Status = CR_INVALID_RANGE_LIST;
  948. goto Clean0;
  949. }
  950. if (INVALID_FLAGS(ulFlags, 0)) {
  951. Status = CR_INVALID_FLAG;
  952. goto Clean0;
  953. }
  954. LockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
  955. bLockOld = TRUE;
  956. LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  957. bLockNew = TRUE;
  958. pRangeNew = (PRange_Element)rlhNew;
  959. pRangeOld = (PRange_Element)rlhOld;
  960. //
  961. // If the new range list is not empty, then delete ranges
  962. //
  963. if (pRangeNew->RL_Next != 0) {
  964. ClearRanges(pRangeNew);
  965. }
  966. //
  967. // special case: if the old range is empty, then the new range
  968. // is the entire range (up to max)
  969. //
  970. if (pRangeOld->RL_Next == 0) {
  971. Status = InsertRange(pRangeNew, 0, ullMaxValue);
  972. goto Clean0;
  973. }
  974. //
  975. // invert each of the old ranges
  976. //
  977. ullStart = ullEnd = 0;
  978. while (pRangeOld->RL_Next != 0) {
  979. pRangeOld = (PRange_Element)pRangeOld->RL_Next;
  980. //
  981. // Special start case: if range starts at 0, skip over it
  982. //
  983. if (pRangeOld->RL_Start != 0) {
  984. //
  985. // Special end case: check if we've hit the max for the new range
  986. //
  987. if (pRangeOld->RL_End >= ullMaxValue) {
  988. ullEnd = min(ullMaxValue, pRangeOld->RL_Start - 1);
  989. Status = InsertRange(pRangeNew, ullStart, ullEnd);
  990. goto Clean0; // we're done
  991. }
  992. Status = InsertRange(pRangeNew, ullStart, pRangeOld->RL_Start - 1);
  993. if (Status != CR_SUCCESS) {
  994. goto Clean0;
  995. }
  996. pRangeNew = (PRange_Element)pRangeNew->RL_Next;
  997. }
  998. ullStart = pRangeOld->RL_End + 1;
  999. }
  1000. //
  1001. // add the range that incorporates the end of the old range up to
  1002. // the max value specified
  1003. //
  1004. if (ullStart <= ullMaxValue) {
  1005. Status = InsertRange(pRangeNew, ullStart, ullMaxValue);
  1006. }
  1007. Clean0:
  1008. NOTHING;
  1009. } except(EXCEPTION_EXECUTE_HANDLER) {
  1010. bLockOld = bLockOld; // needed to prevent optimizing this flag away
  1011. bLockNew = bLockNew; // needed to prevent optimizing this flag away
  1012. Status = CR_FAILURE;
  1013. }
  1014. if (bLockOld) {
  1015. UnlockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
  1016. }
  1017. if (bLockNew) {
  1018. UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  1019. }
  1020. return Status;
  1021. } // CM_Invert_Range_List
  1022. CONFIGRET
  1023. CM_Merge_Range_List(
  1024. IN RANGE_LIST rlhOld1,
  1025. IN RANGE_LIST rlhOld2,
  1026. IN RANGE_LIST rlhNew,
  1027. IN ULONG ulFlags
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. This routine creates a range list from the union of two specified range
  1032. lists. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle of a
  1033. valid but empty range list.
  1034. Parameters:
  1035. rlhOld1 Supplies the handle of a range list to be used as part of the
  1036. union.
  1037. rlhOld2 Supplies the handle of a range list to be used as part of the
  1038. union.
  1039. rlhNew Supplies the handle of the range list that receives the union
  1040. of rlhOld1 and rlhOld2. Anything previously contained in the
  1041. rlhNew range list is removed by this operation.
  1042. ulFlags Must be zero.
  1043. Return Value:
  1044. If the function succeeds, the return value is CR_SUCCESS.
  1045. If the function fails, the return value is one of the following:
  1046. CR_INVALID_FLAG,
  1047. CR_INVALID_RANGE_LIST, or
  1048. CR_OUT_OF_MEMORY.
  1049. --*/
  1050. {
  1051. CONFIGRET Status = CR_SUCCESS;
  1052. DWORDLONG ullStart = 0, ullEnd = 0;
  1053. BOOL bOld1Empty = FALSE, bOld2Empty = FALSE;
  1054. PRange_Element pRangeNew = NULL, pRangeOld1 = NULL, pRangeOld2 = NULL;
  1055. BOOL bLock1 = FALSE, bLock2 = FALSE, bLockNew = FALSE;
  1056. try {
  1057. //
  1058. // validate parameters
  1059. //
  1060. if (!IsValidRangeList(rlhOld1)) {
  1061. Status = CR_INVALID_RANGE_LIST;
  1062. goto Clean0;
  1063. }
  1064. if (!IsValidRangeList(rlhOld2)) {
  1065. Status = CR_INVALID_RANGE_LIST;
  1066. goto Clean0;
  1067. }
  1068. if (!IsValidRangeList(rlhNew)) {
  1069. Status = CR_INVALID_RANGE_LIST;
  1070. goto Clean0;
  1071. }
  1072. if (INVALID_FLAGS(ulFlags, 0)) {
  1073. Status = CR_INVALID_FLAG;
  1074. goto Clean0;
  1075. }
  1076. LockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
  1077. bLock1 = TRUE;
  1078. LockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
  1079. bLock2 = TRUE;
  1080. LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  1081. bLockNew = TRUE;
  1082. pRangeNew = (PRange_Element)rlhNew;
  1083. pRangeOld1 = (PRange_Element)rlhOld1;
  1084. pRangeOld2 = (PRange_Element)rlhOld2;
  1085. //
  1086. // If the new range list is not empty, then clear it
  1087. //
  1088. if (pRangeNew->RL_Next != 0) {
  1089. ClearRanges(pRangeNew);
  1090. }
  1091. //
  1092. // Special case: if both ranges are empty then there is no
  1093. // union by definition
  1094. //
  1095. if (pRangeOld1->RL_Next == 0 && pRangeOld2->RL_Next == 0) {
  1096. goto Clean0;
  1097. }
  1098. //
  1099. // Special case: if one range is empty, then the union is just the other
  1100. //
  1101. if (pRangeOld1->RL_Next == 0) {
  1102. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  1103. CopyRanges(pRangeOld2, pRangeNew); // from -> to
  1104. goto Clean0;
  1105. }
  1106. if (pRangeOld2->RL_Next == 0) {
  1107. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  1108. CopyRanges(pRangeOld1, pRangeNew); // from -> to
  1109. goto Clean0;
  1110. }
  1111. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  1112. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  1113. while (TRUE) {
  1114. //
  1115. // Pick whichever range comes first between current Old1 range
  1116. // and current Old2 range
  1117. //
  1118. if (pRangeOld1->RL_Start <= pRangeOld2->RL_Start) {
  1119. ullStart = pRangeOld1->RL_Start;
  1120. ullEnd = pRangeOld1->RL_End;
  1121. if (pRangeOld1->RL_Next == 0) {
  1122. bOld1Empty = TRUE;
  1123. } else {
  1124. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  1125. }
  1126. } else {
  1127. ullStart = pRangeOld2->RL_Start;
  1128. ullEnd = pRangeOld2->RL_End;
  1129. if (pRangeOld2->RL_Next == 0) {
  1130. bOld2Empty = TRUE;
  1131. } else {
  1132. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  1133. }
  1134. }
  1135. //
  1136. // gather any ranges in Old1 that intersect (ullStart,ullEnd)
  1137. //
  1138. while (pRangeOld1->RL_Start <= ullEnd) {
  1139. ullEnd = max(ullEnd, pRangeOld1->RL_End);
  1140. if (pRangeOld1->RL_Next == 0) {
  1141. bOld1Empty = TRUE;
  1142. break;
  1143. }
  1144. pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
  1145. }
  1146. //
  1147. // gather any ranges in Old2 that intersect (ullStart,ullEnd)
  1148. //
  1149. while (pRangeOld2->RL_Start <= ullEnd) {
  1150. ullEnd = max(ullEnd, pRangeOld2->RL_End);
  1151. if (pRangeOld2->RL_Next == 0) {
  1152. bOld2Empty = TRUE;
  1153. break;
  1154. }
  1155. pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
  1156. }
  1157. //
  1158. // add (ullStart,ullEnd) to the new range
  1159. //
  1160. Status = InsertRange(pRangeNew, ullStart, ullEnd);
  1161. if (Status != CR_SUCCESS) {
  1162. goto Clean0;
  1163. }
  1164. pRangeNew = (PRange_Element)pRangeNew->RL_Next;
  1165. //
  1166. // As an optimization, if either range is exhausted first,
  1167. // then only need to duplicate the other remaining ranges.
  1168. //
  1169. if (bOld1Empty && bOld2Empty) {
  1170. goto Clean0; // both exhausted during last pass, we're done
  1171. }
  1172. if (bOld1Empty) { // Old1 exhausted, copy remaining from Old2
  1173. CopyRanges(pRangeOld2, pRangeNew);
  1174. goto Clean0;
  1175. }
  1176. if (bOld2Empty) { // Old2 exhausted, copy remaining from Old1
  1177. CopyRanges(pRangeOld1, pRangeNew);
  1178. goto Clean0;
  1179. }
  1180. }
  1181. Clean0:
  1182. NOTHING;
  1183. } except(EXCEPTION_EXECUTE_HANDLER) {
  1184. bLock1 = bLock1; // needed to prevent optimizing this flag away
  1185. bLock2 = bLock2; // needed to prevent optimizing this flag away
  1186. bLockNew = bLockNew; // needed to prevent optimizing this flag away
  1187. Status = CR_FAILURE;
  1188. }
  1189. if (bLock1) {
  1190. UnlockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
  1191. }
  1192. if (bLock2) {
  1193. UnlockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
  1194. }
  1195. if (bLockNew) {
  1196. UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
  1197. }
  1198. return Status;
  1199. } // CM_Merge_Range_List
  1200. CONFIGRET
  1201. CM_Next_Range(
  1202. IN OUT PRANGE_ELEMENT preElement,
  1203. OUT PDWORDLONG pullStart,
  1204. OUT PDWORDLONG pullEnd,
  1205. IN ULONG ulFlags
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This routine returns the next range element in a range list. This
  1210. API returns CR_FAILURE if there are no more elements in the range
  1211. list.
  1212. Parameters:
  1213. preElement Supplies the address of the handle for the current range
  1214. element. Upon return, this variable receives the handle
  1215. of the next range element.
  1216. pullStart Supplies the address of the variable that receives the
  1217. starting value of the next range.
  1218. pullEnd Supplies the address of the variable that receives the
  1219. ending value of the next range.
  1220. ulFlags Must be zero.
  1221. Return Value:
  1222. If the function succeeds, the return value is CR_SUCCESS.
  1223. If the function fails, the return value is one of the following:
  1224. CR_FAILURE,
  1225. CR_INVALID_FLAG,
  1226. CR_INVALID_POINTER, or
  1227. CR_INVALID_RANGE.
  1228. --*/
  1229. {
  1230. CONFIGRET Status = CR_SUCCESS;
  1231. PRange_Element pRange = NULL;
  1232. BOOL bLock = FALSE;
  1233. PRange_List_Hdr prlh = NULL;
  1234. try {
  1235. //
  1236. // validate parameters
  1237. //
  1238. if (preElement == NULL || *preElement == 0) {
  1239. Status = CR_FAILURE;
  1240. goto Clean0;
  1241. }
  1242. if (pullEnd == NULL || pullStart == NULL) {
  1243. Status = CR_INVALID_POINTER;
  1244. goto Clean0;
  1245. }
  1246. if (INVALID_FLAGS(ulFlags, 0)) {
  1247. Status = CR_INVALID_FLAG;
  1248. goto Clean0;
  1249. }
  1250. prlh = (PRange_List_Hdr)((PRange_Element)(*preElement))->RL_Header;
  1251. LockPrivateResource(&(prlh->RLH_Lock));
  1252. bLock = TRUE;
  1253. pRange = (PRange_Element)(*preElement);
  1254. *pullStart = pRange->RL_Start;
  1255. *pullEnd = pRange->RL_End;
  1256. *preElement = (RANGE_ELEMENT)pRange->RL_Next;
  1257. Clean0:
  1258. NOTHING;
  1259. } except(EXCEPTION_EXECUTE_HANDLER) {
  1260. bLock = bLock; // needed to prevent optimizing this flag away
  1261. Status = CR_FAILURE;
  1262. }
  1263. if (bLock) {
  1264. UnlockPrivateResource(&(prlh->RLH_Lock));
  1265. }
  1266. return Status;
  1267. } // CM_Next_Range
  1268. CONFIGRET
  1269. CM_Test_Range_Available(
  1270. IN DWORDLONG ullStartValue,
  1271. IN DWORDLONG ullEndValue,
  1272. IN RANGE_LIST rlh,
  1273. IN ULONG ulFlags
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This routine checks a range against a range list to ensure that no
  1278. conflicts exist.
  1279. Parameters:
  1280. ullStartValue Supplies the low end of the range.
  1281. ullEndValue Supplies the high end of the range.
  1282. rlh Supplies the handle to a range list.
  1283. ulFlags Must be zero.
  1284. Return Value:
  1285. If the function succeeds, the return value is CR_SUCCESS.
  1286. If the function fails, the return value is one of the following:
  1287. CR_FAILURE,
  1288. CR_INVALID_FLAG,
  1289. CR_INVALID_RANGE, or
  1290. CR_INVALID_RANGE_LIST.
  1291. --*/
  1292. {
  1293. CONFIGRET Status = CR_SUCCESS;
  1294. PRange_Element pRange = NULL;
  1295. BOOL bLock = FALSE;
  1296. try {
  1297. //
  1298. // validate parameters
  1299. //
  1300. if (!IsValidRangeList(rlh)) {
  1301. Status = CR_INVALID_RANGE_LIST;
  1302. goto Clean0;
  1303. }
  1304. if (INVALID_FLAGS(ulFlags, 0)) {
  1305. Status = CR_INVALID_FLAG;
  1306. goto Clean0;
  1307. }
  1308. if (ullEndValue < ullStartValue) {
  1309. Status = CR_INVALID_RANGE;
  1310. goto Clean0;
  1311. }
  1312. LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  1313. bLock = TRUE;
  1314. pRange = (PRange_Element)rlh;
  1315. //
  1316. // check each range for a conflict
  1317. //
  1318. while (pRange->RL_Next != 0) {
  1319. pRange = (PRange_Element)pRange->RL_Next;
  1320. //
  1321. // If I've already passed the test range, then it's available
  1322. //
  1323. if (ullEndValue < pRange->RL_Start) {
  1324. goto Clean0;
  1325. }
  1326. //
  1327. // check if the start of the test range intersects the current range
  1328. //
  1329. if (ullStartValue >= pRange->RL_Start &&
  1330. ullStartValue <= pRange->RL_End) {
  1331. Status = CR_FAILURE;
  1332. goto Clean0;
  1333. }
  1334. //
  1335. // check if the end of the test range intersects the current range
  1336. //
  1337. if (ullEndValue >= pRange->RL_Start &&
  1338. ullEndValue <= pRange->RL_End) {
  1339. Status = CR_FAILURE;
  1340. goto Clean0;
  1341. }
  1342. //
  1343. // check if it's a complete overlap
  1344. //
  1345. if (ullStartValue <= pRange->RL_Start &&
  1346. ullEndValue >= pRange->RL_End) {
  1347. Status = CR_FAILURE;
  1348. goto Clean0;
  1349. }
  1350. }
  1351. //
  1352. // if we got this far, then we made it through the range list
  1353. // without hitting a conflict
  1354. //
  1355. Clean0:
  1356. NOTHING;
  1357. } except(EXCEPTION_EXECUTE_HANDLER) {
  1358. bLock = bLock; // needed to prevent optimizing this flag away
  1359. Status = CR_FAILURE;
  1360. }
  1361. if (bLock) {
  1362. UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
  1363. }
  1364. return Status;
  1365. } // CM_Test_Range_Available
  1366. //------------------------------------------------------------------------
  1367. // Private Utility Functions
  1368. //------------------------------------------------------------------------
  1369. BOOL
  1370. IsValidRangeList(
  1371. IN RANGE_LIST rlh
  1372. )
  1373. {
  1374. BOOL Status = TRUE;
  1375. PRange_List_Hdr pRangeHdr = NULL;
  1376. try {
  1377. if (rlh == 0 || rlh == (DWORD)-1) {
  1378. return FALSE;
  1379. }
  1380. pRangeHdr = (PRange_List_Hdr)rlh;
  1381. if (pRangeHdr->RLH_Signature != Range_List_Signature) {
  1382. Status = FALSE;
  1383. }
  1384. } except(EXCEPTION_EXECUTE_HANDLER) {
  1385. Status = FALSE;
  1386. }
  1387. return Status;
  1388. } // IsValidRangeList
  1389. CONFIGRET
  1390. AddRange(
  1391. IN PRange_Element prlh,
  1392. IN DWORDLONG ullStartValue,
  1393. IN DWORDLONG ullEndValue,
  1394. IN ULONG ulFlags
  1395. )
  1396. {
  1397. CONFIGRET Status = CR_SUCCESS;
  1398. PRange_Element pPrevious = NULL, pCurrent = NULL;
  1399. try {
  1400. pPrevious = prlh;
  1401. if (pPrevious->RL_Next == 0) {
  1402. //
  1403. // the range is empty
  1404. //
  1405. Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
  1406. goto Clean0;
  1407. }
  1408. while (pPrevious->RL_Next != 0) {
  1409. pCurrent = (PRange_Element)pPrevious->RL_Next;
  1410. if (ullStartValue < pCurrent->RL_Start) {
  1411. if (ullEndValue < pCurrent->RL_Start) {
  1412. //
  1413. // new range completely contained before this one,
  1414. // add new range between previous and current range
  1415. //
  1416. Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
  1417. goto Clean0;
  1418. }
  1419. if (ullEndValue <= pCurrent->RL_End) {
  1420. //
  1421. // new range intersects current range, on the low side,
  1422. // enlarge this range to include the new range
  1423. //
  1424. if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
  1425. Status = CR_FAILURE;
  1426. goto Clean0;
  1427. }
  1428. pCurrent->RL_Start = ullStartValue;
  1429. goto Clean0;
  1430. }
  1431. if ((pCurrent->RL_Next == 0) ||
  1432. (ullEndValue < ((PRange_Element)(pCurrent->RL_Next))->RL_Start)) {
  1433. //
  1434. // new range intersects current range on high and low
  1435. // side, extent range to include the new range
  1436. //
  1437. if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
  1438. Status = CR_FAILURE;
  1439. goto Clean0;
  1440. }
  1441. pCurrent->RL_Start = ullStartValue;
  1442. pCurrent->RL_End = ullEndValue;
  1443. goto Clean0;
  1444. }
  1445. //
  1446. // new range intersects more than one range, needs to be
  1447. // merged
  1448. //
  1449. if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
  1450. Status = CR_FAILURE;
  1451. goto Clean0;
  1452. }
  1453. Status = JoinRange(pPrevious, ullStartValue, ullEndValue);
  1454. goto Clean0;
  1455. }
  1456. if (ullStartValue <= pCurrent->RL_End+1) {
  1457. if (ullEndValue <= pCurrent->RL_End) {
  1458. //
  1459. // new range is completely contained inside the current
  1460. // range so nothing to do
  1461. //
  1462. if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
  1463. Status = CR_FAILURE;
  1464. goto Clean0;
  1465. }
  1466. goto Clean0;
  1467. }
  1468. if ((pCurrent->RL_Next == 0) ||
  1469. (ullEndValue < ((PRange_Element)(pCurrent->RL_Next))->RL_Start)) {
  1470. //
  1471. // new range intersects current range on high end only,
  1472. // extend range to include the new range
  1473. //
  1474. if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
  1475. Status = CR_FAILURE;
  1476. goto Clean0;
  1477. }
  1478. pCurrent->RL_End = ullEndValue;
  1479. goto Clean0;
  1480. }
  1481. //
  1482. // new range intersects more than one range, needs to be
  1483. // merged
  1484. //
  1485. if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
  1486. Status = CR_FAILURE;
  1487. goto Clean0;
  1488. }
  1489. Status = JoinRange(pPrevious, ullStartValue, ullEndValue);
  1490. goto Clean0;
  1491. }
  1492. //
  1493. // step to the next range
  1494. //
  1495. pPrevious = pCurrent;
  1496. pCurrent = (PRange_Element)pCurrent->RL_Next;
  1497. }
  1498. //
  1499. // if we got here then we need to just insert this range to the end
  1500. // of the range list
  1501. //
  1502. Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
  1503. Clean0:
  1504. NOTHING;
  1505. } except(EXCEPTION_EXECUTE_HANDLER) {
  1506. Status = 0;
  1507. }
  1508. return Status;
  1509. } // AddRange
  1510. CONFIGRET
  1511. InsertRange(
  1512. IN PRange_Element pParentElement,
  1513. IN DWORDLONG ullStartValue,
  1514. IN DWORDLONG ullEndValue)
  1515. {
  1516. PRange_Element pNewElement = NULL;
  1517. pNewElement = (PRange_Element)pSetupMalloc(sizeof(Range_Element));
  1518. if (pNewElement == NULL) {
  1519. return CR_OUT_OF_MEMORY;
  1520. }
  1521. pNewElement->RL_Next = pParentElement->RL_Next; // rejoin the link
  1522. pNewElement->RL_Start = ullStartValue;
  1523. pNewElement->RL_End = ullEndValue;
  1524. pNewElement->RL_Header = pParentElement->RL_Header;
  1525. pParentElement->RL_Next = (ULONG_PTR)pNewElement;
  1526. return CR_SUCCESS;
  1527. } // InsertRange
  1528. CONFIGRET
  1529. DeleteRange(
  1530. IN PRange_Element pParentElement
  1531. )
  1532. {
  1533. PRange_Element pTemp = NULL;
  1534. //
  1535. // must pass a valid parent of the range to delete (in otherwords,
  1536. // can't pass the last range)
  1537. //
  1538. if (pParentElement == 0) {
  1539. return CR_FAILURE;
  1540. }
  1541. pTemp = (PRange_Element)(pParentElement->RL_Next);
  1542. if (pTemp == 0) {
  1543. return CR_FAILURE;
  1544. }
  1545. pParentElement->RL_Next =
  1546. ((PRange_Element)(pParentElement->RL_Next))->RL_Next;
  1547. pSetupFree(pTemp);
  1548. return CR_SUCCESS;
  1549. } // DeleteRange
  1550. CONFIGRET
  1551. JoinRange(
  1552. IN PRange_Element pParentElement,
  1553. IN DWORDLONG ullStartValue,
  1554. IN DWORDLONG ullEndValue
  1555. )
  1556. {
  1557. CONFIGRET Status = CR_SUCCESS;
  1558. PRange_Element pCurrent = NULL, pNext = NULL;
  1559. if (pParentElement->RL_Next == 0) {
  1560. return CR_SUCCESS; // at the end, nothing to join
  1561. }
  1562. //
  1563. // pCurrent is the starting range of intersecting ranges that need
  1564. // to be joined
  1565. //
  1566. pCurrent = (PRange_Element)pParentElement->RL_Next;
  1567. //
  1568. // set start of joined range
  1569. //
  1570. if (ullStartValue < pCurrent->RL_Start) {
  1571. pCurrent->RL_Start = ullStartValue;
  1572. }
  1573. //
  1574. // find the end of the joined range
  1575. //
  1576. while (pCurrent->RL_Next != 0) {
  1577. pNext = (PRange_Element)pCurrent->RL_Next;
  1578. //
  1579. // I know this next range needs to be absorbed in all cases so
  1580. // reset the end point to at least include the next range
  1581. //
  1582. pCurrent->RL_End = pNext->RL_End;
  1583. if (ullEndValue <= pNext->RL_End) {
  1584. DeleteRange(pCurrent); // delete the range following current
  1585. break; // we're done
  1586. }
  1587. if ((pNext->RL_Next == 0) ||
  1588. (ullEndValue < ((PRange_Element)(pNext->RL_Next))->RL_Start)) {
  1589. //
  1590. // adjust the end point of the newly joined range and then we're done
  1591. //
  1592. pCurrent->RL_End = ullEndValue;
  1593. DeleteRange(pCurrent); // delete the range following current
  1594. break;
  1595. }
  1596. DeleteRange(pCurrent); // delete the range following current
  1597. // if we got here, there are more ranges to join
  1598. }
  1599. return Status;
  1600. } // JoinRange
  1601. CONFIGRET
  1602. CopyRanges(
  1603. IN PRange_Element pFromRange,
  1604. IN PRange_Element pToRange
  1605. )
  1606. {
  1607. CONFIGRET Status = CR_SUCCESS;
  1608. //
  1609. // copy each range in pFromRange to pToRange
  1610. //
  1611. while (TRUE) {
  1612. Status = AddRange(pToRange,
  1613. pFromRange->RL_Start,
  1614. pFromRange->RL_End,
  1615. CM_ADD_RANGE_ADDIFCONFLICT);
  1616. if (Status != CR_SUCCESS) {
  1617. break;
  1618. }
  1619. pToRange = (PRange_Element)pToRange->RL_Next;
  1620. if (pFromRange->RL_Next == 0) {
  1621. break;
  1622. }
  1623. pFromRange = (PRange_Element)pFromRange->RL_Next;
  1624. }
  1625. return Status;
  1626. } // CopyRanges
  1627. CONFIGRET
  1628. ClearRanges(
  1629. IN PRange_Element pRange
  1630. )
  1631. {
  1632. CONFIGRET Status = CR_SUCCESS;
  1633. //
  1634. // If the range list is not empty, then delete ranges
  1635. //
  1636. if (pRange->RL_Next != 0) {
  1637. while (Status == CR_SUCCESS) {
  1638. //
  1639. // keep deleting the first range after the header (pass parent
  1640. // of range to delete)
  1641. //
  1642. Status = DeleteRange(pRange);
  1643. }
  1644. }
  1645. return CR_SUCCESS; // Status is set to end deleting ranges, don't return it
  1646. } // ClearRanges
  1647. CONFIGRET
  1648. TestRange(
  1649. IN PRange_Element rlh,
  1650. IN DWORDLONG ullStartValue,
  1651. IN DWORDLONG ullEndValue,
  1652. OUT PRange_Element *pConflictingRange
  1653. )
  1654. {
  1655. PRange_Element pRange = (PRange_Element)rlh;
  1656. //
  1657. // check each range for a conflict
  1658. //
  1659. while (pRange->RL_Next != 0) {
  1660. pRange = (PRange_Element)pRange->RL_Next;
  1661. if (pRange->RL_Start > ullEndValue) {
  1662. //
  1663. // We've gone past the range in question so no conflict
  1664. //
  1665. return CR_SUCCESS;
  1666. }
  1667. if (pRange->RL_End < ullStartValue) {
  1668. //
  1669. // this range is still below the range in question, skip to next range
  1670. //
  1671. continue;
  1672. }
  1673. //
  1674. // otherwise there's a conflict
  1675. //
  1676. *pConflictingRange = pRange;
  1677. return CR_FAILURE;
  1678. }
  1679. return CR_SUCCESS;
  1680. } // TestRange