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.

2266 lines
58 KiB

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