mirror of https://github.com/tongzx/nt5src
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
2262 lines
55 KiB
/*++
|
|
|
|
Copyright (c) 1995-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
range.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the API routines that operate directly on ranges.
|
|
|
|
CM_Add_Range
|
|
CM_Create_Range_List
|
|
CM_Delete_Range
|
|
CM_Dup_Range_List
|
|
CM_Find_Range
|
|
CM_First_Range
|
|
CM_Free_Range_List
|
|
CM_Intersect_Range_List
|
|
CM_Invert_Range_List
|
|
CM_Merge_Range_List
|
|
CM_Next_Range
|
|
CM_Test_Range_Available
|
|
|
|
Author:
|
|
|
|
Paula Tomlinson (paulat) 10-17-1995
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
Revision History:
|
|
|
|
17-Oct-1995 paulat
|
|
|
|
Creation and initial implementation.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// includes
|
|
//
|
|
#include "precomp.h"
|
|
#include "cfgi.h"
|
|
#include "setupapi.h"
|
|
#include "spapip.h"
|
|
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
BOOL
|
|
IsValidRangeList(
|
|
IN RANGE_LIST rlh
|
|
);
|
|
|
|
CONFIGRET
|
|
AddRange(
|
|
IN PRange_Element pParentElement,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
IN ULONG ulFlags
|
|
);
|
|
|
|
CONFIGRET
|
|
InsertRange(
|
|
IN PRange_Element pParentElement,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue
|
|
);
|
|
|
|
CONFIGRET
|
|
DeleteRange(
|
|
IN PRange_Element pParentElement
|
|
);
|
|
|
|
CONFIGRET
|
|
JoinRange(
|
|
IN PRange_Element pParentElement,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue
|
|
);
|
|
|
|
CONFIGRET
|
|
CopyRanges(
|
|
IN PRange_Element pFromRange,
|
|
IN PRange_Element pToRange
|
|
);
|
|
|
|
CONFIGRET
|
|
ClearRanges(
|
|
IN PRange_Element pRange
|
|
);
|
|
|
|
CONFIGRET
|
|
TestRange(
|
|
IN PRange_Element rlh,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
OUT PRange_Element *pConflictingRange
|
|
);
|
|
|
|
|
|
//
|
|
// global data
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Add_Range(
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
IN RANGE_LIST rlh,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a memory range to a range list.
|
|
|
|
Parameters:
|
|
|
|
ullStartValue Low end of the range.
|
|
|
|
ullEndValue High end of the range.
|
|
|
|
rlh Handle of a range list.
|
|
|
|
ulFlags Supplies flags specifying options for ranges that conflict
|
|
with ranges alread in the list. May be one of the
|
|
following values:
|
|
|
|
CM_ADD_RANGE_ADDIFCONFLICT New range is merged with the
|
|
ranges it conflicts with.
|
|
CM_ADD_RANGE_DONOTADDIFCONFLICT Returns CR_FAILURE if there
|
|
is a conflict.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_FAILURE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE,
|
|
CR_INVALID_RANGE_LIST, or
|
|
CR_OUT_OF_MEMORY.
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
BOOL bLock = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlh)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, CM_ADD_RANGE_BITS)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ullStartValue > ullEndValue) {
|
|
Status = CR_INVALID_RANGE;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
bLock = TRUE;
|
|
|
|
Status = AddRange((PRange_Element)rlh, ullStartValue,
|
|
ullEndValue, ulFlags);
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Add_Range
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Create_Range_List(
|
|
OUT PRANGE_LIST prlh,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a list of ranges.
|
|
|
|
Parameters:
|
|
|
|
prlh Supplies the address of the variable that receives a
|
|
handle to the new range list.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_POINTER, or
|
|
CR_OUT_OF_MEMORY.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_List_Hdr pRangeHdr = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (prlh == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// allocate a buffer for the range list header struct
|
|
//
|
|
pRangeHdr = pSetupMalloc(sizeof(Range_List_Hdr));
|
|
|
|
if (pRangeHdr == NULL) {
|
|
Status = CR_OUT_OF_MEMORY;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// initialize the range list header buffer
|
|
//
|
|
pRangeHdr->RLH_Head = 0;
|
|
pRangeHdr->RLH_Header = (ULONG_PTR)pRangeHdr;
|
|
pRangeHdr->RLH_Signature = Range_List_Signature;
|
|
|
|
//
|
|
// initialize the private resource lock
|
|
//
|
|
InitPrivateResource(&(pRangeHdr->RLH_Lock));
|
|
|
|
//
|
|
// return a pointer to range list buffer to the caller
|
|
//
|
|
*prlh = (RANGE_LIST)pRangeHdr;
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Create_Range_List
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Delete_Range(
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
IN RANGE_LIST rlh,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes a range from a range list. If ullStartValue
|
|
and ullEndValue are set to 0 and DWORD_MAX, this API carries out
|
|
a special case, quickly emptying the lower 4 Gigabytes of the range.
|
|
If ullEndValue is instead DWORDLONG_MAX, the entire range list is
|
|
cleared, without having to process each element.
|
|
|
|
Parameters:
|
|
|
|
ullStartValue Low end of the range.
|
|
|
|
ullEndValue High end of the range.
|
|
|
|
rlh Handle of a range list.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_FAILURE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE,
|
|
CR_INVALID_RANGE_LIST, or
|
|
CR_OUT_OF_MEMORY.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRange = NULL, pPrevious = NULL, pCurrent = NULL;
|
|
BOOL bLock = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlh)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ullStartValue > ullEndValue) {
|
|
Status = CR_INVALID_RANGE;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
bLock = TRUE;
|
|
|
|
pPrevious = (PRange_Element)rlh;
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// first check the special case range values
|
|
//-------------------------------------------------------------
|
|
|
|
if (ullStartValue == 0) {
|
|
|
|
if (ullEndValue == DWORDLONG_MAX) {
|
|
//
|
|
// quick clear of all ranges
|
|
//
|
|
ClearRanges(pPrevious);
|
|
}
|
|
|
|
else if (ullEndValue == DWORD_MAX) {
|
|
//
|
|
// quick clear of lower 4 GB ranges
|
|
//
|
|
while (pPrevious->RL_Next != 0) {
|
|
pCurrent = (PRange_Element)pPrevious->RL_Next;
|
|
|
|
if (pCurrent->RL_Start >= DWORD_MAX) {
|
|
goto Clean0; // done
|
|
}
|
|
|
|
if (pCurrent->RL_End >= DWORD_MAX) {
|
|
pCurrent->RL_Start = DWORD_MAX;
|
|
goto Clean0; // done
|
|
}
|
|
|
|
DeleteRange(pPrevious); // pass the parent
|
|
}
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// search through each range in this list, if any part of the
|
|
// specified range is contained in this range list, remove the
|
|
// intersections
|
|
//-------------------------------------------------------------
|
|
|
|
while (pPrevious->RL_Next != 0) {
|
|
pRange = (PRange_Element)pPrevious->RL_Next;
|
|
|
|
//
|
|
// if this range is completely before the current range, then
|
|
// we can stop
|
|
//
|
|
if (ullEndValue < pRange->RL_Start) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if this range is completely after the current range, then
|
|
// skip to the next range
|
|
//
|
|
if (ullStartValue > pRange->RL_End) {
|
|
goto NextRange;
|
|
}
|
|
|
|
//
|
|
// if the range is completely contained, then delete the whole
|
|
// thing
|
|
//
|
|
if (ullStartValue <= pRange->RL_Start &&
|
|
ullEndValue >= pRange->RL_End) {
|
|
|
|
DeleteRange(pPrevious); // pass the parent range
|
|
|
|
//
|
|
// don't goto next range because that would increment the
|
|
// pPrevious counter. Since the current range was just deleted,
|
|
// we need to process the current spot still.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// if the start of the specified range intersects the current range,
|
|
// adjust the current range to exclude it
|
|
//
|
|
if (ullStartValue > pRange->RL_Start &&
|
|
ullStartValue <= pRange->RL_End) {
|
|
//
|
|
// if the specified range is in the middle of this range, then
|
|
// in addition to shrinking the first part of the range, I'll
|
|
// have to create a range for the second part
|
|
// | |<-- delete --->| |
|
|
//
|
|
if (ullEndValue < pRange->RL_End) {
|
|
AddRange(pRange, ullEndValue+1, pRange->RL_End,
|
|
CM_ADD_RANGE_ADDIFCONFLICT);
|
|
}
|
|
|
|
pRange->RL_End = ullStartValue-1;
|
|
|
|
//
|
|
// reset the delete range for further processing
|
|
//
|
|
if (ullEndValue > pRange->RL_End) {
|
|
ullStartValue = pRange->RL_End+1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the end of the specified range intersects the current range,
|
|
// adjust the current range to exclude it
|
|
//
|
|
if (ullEndValue >= pRange->RL_Start &&
|
|
ullEndValue <= pRange->RL_End) {
|
|
|
|
pRange->RL_Start = ullEndValue+1;
|
|
|
|
//
|
|
// reset the delete range for further processing
|
|
//
|
|
if (ullEndValue > pRange->RL_End) {
|
|
ullStartValue = pRange->RL_End+1;
|
|
}
|
|
}
|
|
|
|
|
|
NextRange:
|
|
|
|
pPrevious = (PRange_Element)pPrevious->RL_Next;
|
|
}
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Delete_Range
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Dup_Range_List(
|
|
IN RANGE_LIST rlhOld,
|
|
IN RANGE_LIST rlhNew,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies a range list.
|
|
|
|
Parameters:
|
|
|
|
rlhOld Supplies the handle of the range list to copy.
|
|
|
|
rlhNew Supplies the handle of a valid range list into which rlhOld
|
|
is copied. Anything contained in the rlhNew range list is
|
|
removed by the copy operation.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE_LIST, or
|
|
CR_OUT_OF_MEMORY
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRangeNew = NULL, pRangeOld = NULL;
|
|
BOOL bLockOld = FALSE, bLockNew = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlhOld)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsValidRangeList(rlhNew)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
|
|
bLockOld = TRUE;
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
bLockNew = TRUE;
|
|
|
|
pRangeNew = (PRange_Element)rlhNew;
|
|
pRangeOld = (PRange_Element)rlhOld;
|
|
|
|
//
|
|
// If the new range list is not empty, then delete ranges
|
|
//
|
|
if (pRangeNew->RL_Next != 0) {
|
|
ClearRanges(pRangeNew);
|
|
}
|
|
|
|
Status = CR_SUCCESS; // reset status flag to okay
|
|
|
|
|
|
//
|
|
// duplicate each of the old ranges
|
|
//
|
|
pRangeOld = (PRange_Element)pRangeOld->RL_Next;
|
|
CopyRanges(pRangeOld, pRangeNew);
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLockOld = bLockOld; // needed to prevent optimizing this flag away
|
|
bLockNew = bLockNew; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
|
|
if (bLockOld) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
|
|
}
|
|
if (bLockNew) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Dup_Range_List
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Find_Range(
|
|
OUT PDWORDLONG pullStart,
|
|
IN DWORDLONG ullStart,
|
|
IN ULONG ulLength,
|
|
IN DWORDLONG ullAlignment,
|
|
IN DWORDLONG ullEnd,
|
|
IN RANGE_LIST rlh,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to find a range in the supplied range list that
|
|
will accommodate the range requirements specified. [TBD: Verify
|
|
that this description is correct.]
|
|
|
|
Parameters:
|
|
|
|
pullStart Supplies the address of a variable that receives the
|
|
starting value of the allocated range.
|
|
|
|
ullStart Supplies the starting address that the range can have.
|
|
|
|
ulLength Supplies the length needed for the allocated range.
|
|
|
|
ullAlignment Supplies the alignment bitmask that specifies where the
|
|
allocated range can start. [TBD: verify that this is indeed
|
|
a bitmask]
|
|
|
|
ullEnd Supplies the ending address of the area from which the range
|
|
may be allocated.
|
|
|
|
rlh Supplies a handle to a range list in which the specified
|
|
range is to be found.
|
|
|
|
ulFlags TBD
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_POINTER,
|
|
CR_FAILURE
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRange = NULL;
|
|
DWORDLONG ullNewEnd;
|
|
BOOL bLock = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlh)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (pullStart == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
bLock = TRUE;
|
|
|
|
//
|
|
// Normalize aligment. Alignments are now like 0x00000FFF.
|
|
//
|
|
ullAlignment =~ ullAlignment;
|
|
|
|
//
|
|
// Test for impossible alignments (-1, not a power of 2 or start is
|
|
// less than alignment away from wrapping). Also test for invalid
|
|
// length.
|
|
//
|
|
if ((ullAlignment == DWORD_MAX) |
|
|
(ulLength == 0) |
|
|
((ullAlignment & (ullAlignment + 1)) != 0) |
|
|
(ullStart + ullAlignment < ullStart)) {
|
|
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Align the base.
|
|
//
|
|
ullStart += ullAlignment;
|
|
ullStart &= ~ullAlignment;
|
|
|
|
//
|
|
// Compute the new end.
|
|
//
|
|
ullNewEnd = ullStart + ulLength - 1;
|
|
|
|
//
|
|
// Make sure we do have space.
|
|
//
|
|
if ((ullNewEnd < ullStart) || (ullNewEnd > ullEnd)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Check if that range fits
|
|
//
|
|
if (TestRange((PRange_Element)rlh, ullStart, ullStart + ulLength - 1,
|
|
&pRange) == CR_SUCCESS) {
|
|
//
|
|
// We got it then, on the first try.
|
|
//
|
|
*pullStart = ullStart;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Search for a spot where this range will fit.
|
|
//
|
|
while (TRUE) {
|
|
//
|
|
// Start at the end of the conflicting range.
|
|
//
|
|
ullStart = pRange->RL_End + 1;
|
|
|
|
//
|
|
// Check for wrapping.
|
|
//
|
|
if (!ullStart) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Make sure the alignment adjustment won't wrap.
|
|
//
|
|
if (ullStart + ullAlignment < ullStart) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Adjust the alignment.
|
|
//
|
|
ullStart += ullAlignment;
|
|
ullStart &= ~ullAlignment;
|
|
|
|
//
|
|
// Compute the new end.
|
|
//
|
|
ullNewEnd = ullStart + ulLength - 1;
|
|
|
|
//
|
|
// Make sure the new end does not wrap and is still valid.
|
|
//
|
|
if ((ullNewEnd < ullStart) | (ullStart + ulLength - 1 > ullEnd)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Skip any prls which existed only below our new range
|
|
// (because we moved ulStart upward of them).
|
|
//
|
|
while ((pRange = (PRange_Element)pRange->RL_Next) != NULL &&
|
|
ullStart > pRange->RL_End) {
|
|
}
|
|
|
|
//
|
|
// If we don't have a prl or it's begining is after our end
|
|
//
|
|
if (pRange == NULL || ullNewEnd < pRange->RL_Start) {
|
|
*pullStart = ullStart;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Otherwise try with the new prl.
|
|
//
|
|
}
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Find_Range
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_First_Range(
|
|
IN RANGE_LIST rlh,
|
|
OUT PDWORDLONG pullStart,
|
|
OUT PDWORDLONG pullEnd,
|
|
OUT PRANGE_ELEMENT preElement,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the first range element in a range list.
|
|
|
|
Parameters:
|
|
|
|
rlh Supplies the handle of a range list.
|
|
|
|
pullStart Supplies the address of a variable that receives the
|
|
starting value of the first range element.
|
|
|
|
pullEnd Supplies the address of a variable that receives the
|
|
ending value of the first range element.
|
|
|
|
preElement Supplies the address of a variable that receives the
|
|
handle of the next range element.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_FAILURE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_POINTER, or
|
|
CR_INVALID_RANGE_LIST.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRange = NULL;
|
|
BOOL bLock = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlh)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (pullEnd == NULL || pullStart == NULL || preElement == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
bLock = TRUE;
|
|
|
|
pRange = (PRange_Element)rlh;
|
|
|
|
//
|
|
// is the range list empty?
|
|
//
|
|
if (pRange->RL_Next == 0) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// skip over the header to the first element
|
|
//
|
|
pRange = (PRange_Element)pRange->RL_Next;
|
|
|
|
*pullStart = pRange->RL_Start;
|
|
*pullEnd = pRange->RL_End;
|
|
*preElement = (RANGE_ELEMENT)pRange->RL_Next;
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_First_Range
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Free_Range_List(
|
|
IN RANGE_LIST rlh,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the specified range list and the memory allocated
|
|
for it.
|
|
|
|
Parameters:
|
|
|
|
rlh Supplies the handle of the range list to be freed.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE_LIST.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS, Status1 = CR_SUCCESS;
|
|
BOOL bLock = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlh)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
bLock = TRUE;
|
|
|
|
while (Status1 == CR_SUCCESS) {
|
|
//
|
|
// keep deleting the first range after the header (pass parent
|
|
// of range to delete)
|
|
//
|
|
Status1 = DeleteRange((PRange_Element)rlh);
|
|
}
|
|
|
|
//
|
|
// destroy the private resource lock
|
|
//
|
|
DestroyPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
|
|
//
|
|
// delete the range header
|
|
//
|
|
((PRange_List_Hdr)rlh)->RLH_Signature = 0;
|
|
pSetupFree((PRange_Element)rlh);
|
|
bLock = FALSE;
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Free_Range_List
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Intersect_Range_List(
|
|
IN RANGE_LIST rlhOld1,
|
|
IN RANGE_LIST rlhOld2,
|
|
IN RANGE_LIST rlhNew,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a range list from the intersection of two specified
|
|
range lists. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle
|
|
of a valid but empty range list.
|
|
|
|
Parameters:
|
|
|
|
rlhOld1 Supplies the handle of a range list to be used as part of the
|
|
intersection.
|
|
|
|
rlhOld2 Supplies the handle of a range list to be used as part of the
|
|
intersection.
|
|
|
|
rlhNew Supplies the handle of the range list that receives the
|
|
intersection of rlhOld1 and rlhOld2. Anything previously contained
|
|
in the rlhNew ragne list is removed by this operation.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE_LIST, or
|
|
CR_OUT_OF_MEMORY.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
DWORDLONG ulStart = 0, ulEnd = 0;
|
|
PRange_Element pRangeNew = NULL, pRangeOld1 = NULL, pRangeOld2 = NULL;
|
|
BOOL bLock1 = FALSE, bLock2 = FALSE, bLockNew = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlhOld1)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsValidRangeList(rlhOld2)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsValidRangeList(rlhNew)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
|
|
bLock1 = TRUE;
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
|
|
bLock2 = TRUE;
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
bLockNew = TRUE;
|
|
|
|
pRangeNew = (PRange_Element)rlhNew;
|
|
pRangeOld1 = (PRange_Element)rlhOld1;
|
|
pRangeOld2 = (PRange_Element)rlhOld2;
|
|
|
|
//
|
|
// If the new range list is not empty, then delete ranges
|
|
//
|
|
if (pRangeNew->RL_Next != 0) {
|
|
ClearRanges(pRangeNew);
|
|
}
|
|
|
|
//
|
|
// Special case: if either range is empty then there is no
|
|
// intersection by definition
|
|
//
|
|
if (pRangeOld1->RL_Next == 0 || pRangeOld2->RL_Next == 0) {
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
|
|
while (TRUE) {
|
|
//
|
|
// skip over Old2 ranges until intersects with or exceeds
|
|
// current Old1 range (or no more Old2 ranges left)
|
|
//
|
|
while (pRangeOld2->RL_End < pRangeOld1->RL_Start) {
|
|
|
|
if (pRangeOld2->RL_Next == 0) {
|
|
goto Clean0; // Old2 exhausted, we're done
|
|
}
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
}
|
|
|
|
//
|
|
// if this Old2 range exceeds Old1 range, then go to the
|
|
// next Old1 range and go through the main loop again
|
|
//
|
|
if (pRangeOld2->RL_Start > pRangeOld1->RL_End) {
|
|
|
|
if (pRangeOld1->RL_Next == 0) {
|
|
goto Clean0; // Old1 exhausted, we're done
|
|
}
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// if we got here there must be an intersection so add
|
|
// the intersected range to New
|
|
//
|
|
ulStart = max(pRangeOld1->RL_Start, pRangeOld2->RL_Start);
|
|
ulEnd = min(pRangeOld1->RL_End, pRangeOld2->RL_End);
|
|
|
|
Status = InsertRange(pRangeNew, ulStart, ulEnd);
|
|
if (Status != CR_SUCCESS) {
|
|
goto Clean0;
|
|
}
|
|
pRangeNew = (PRange_Element)pRangeNew->RL_Next;
|
|
|
|
//
|
|
// after handling the intersection, skip to next ranges in
|
|
// Old1 and Old2 as appropriate
|
|
//
|
|
if (pRangeOld1->RL_End <= ulEnd) {
|
|
if (pRangeOld1->RL_Next == 0) {
|
|
goto Clean0; // Old1 exhausted, we're done
|
|
}
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
}
|
|
|
|
if (pRangeOld2->RL_End <= ulEnd) {
|
|
if (pRangeOld2->RL_Next == 0) {
|
|
goto Clean0; // Old1 exhausted, we're done
|
|
}
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
}
|
|
}
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock1 = bLock1; // needed to prevent optimizing this flag away
|
|
bLock2 = bLock2; // needed to prevent optimizing this flag away
|
|
bLockNew = bLockNew; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
|
|
if (bLock1) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
|
|
}
|
|
if (bLock2) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
|
|
}
|
|
if (bLockNew) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Intersect_Range_List
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Invert_Range_List(
|
|
IN RANGE_LIST rlhOld,
|
|
IN RANGE_LIST rlhNew,
|
|
IN DWORDLONG ullMaxValue,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a range list that is the inverse of a specified
|
|
range list; all claimed ranges in the new list are specified as free
|
|
in the old list, and vice-versa. For example, the inversion of
|
|
{[2,4],[6,8]} when the ulMaxValue parameter is 15 is {[0,1],[5,5],[9,15]}.
|
|
If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid
|
|
but empty range list.
|
|
|
|
|
|
Parameters:
|
|
|
|
rlhOld Supplies the handle of a range list to be inverted.
|
|
|
|
rlhNew Supplies the handle of the range list that receives the
|
|
inverted copy of rlhOld. Anything previously contained in
|
|
the rlhNew range list is removed by this operation.
|
|
|
|
ullMaxValue Uppermost value of the inverted range list.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE_LIST,
|
|
CR_OUT_OF_MEMORY.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRangeNew = NULL, pRangeOld = NULL;
|
|
DWORDLONG ullStart = 0, ullEnd = 0;
|
|
BOOL bLockOld = FALSE, bLockNew = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlhOld)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsValidRangeList(rlhNew)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
|
|
bLockOld = TRUE;
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
bLockNew = TRUE;
|
|
|
|
pRangeNew = (PRange_Element)rlhNew;
|
|
pRangeOld = (PRange_Element)rlhOld;
|
|
|
|
//
|
|
// If the new range list is not empty, then delete ranges
|
|
//
|
|
if (pRangeNew->RL_Next != 0) {
|
|
ClearRanges(pRangeNew);
|
|
}
|
|
|
|
//
|
|
// special case: if the old range is empty, then the new range
|
|
// is the entire range (up to max)
|
|
//
|
|
if (pRangeOld->RL_Next == 0) {
|
|
Status = InsertRange(pRangeNew, 0, ullMaxValue);
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
//
|
|
// invert each of the old ranges
|
|
//
|
|
ullStart = ullEnd = 0;
|
|
|
|
while (pRangeOld->RL_Next != 0) {
|
|
|
|
pRangeOld = (PRange_Element)pRangeOld->RL_Next;
|
|
|
|
//
|
|
// Special start case: if range starts at 0, skip over it
|
|
//
|
|
if (pRangeOld->RL_Start != 0) {
|
|
|
|
//
|
|
// Special end case: check if we've hit the max for the new range
|
|
//
|
|
if (pRangeOld->RL_End >= ullMaxValue) {
|
|
|
|
ullEnd = min(ullMaxValue, pRangeOld->RL_Start - 1);
|
|
Status = InsertRange(pRangeNew, ullStart, ullEnd);
|
|
goto Clean0; // we're done
|
|
}
|
|
|
|
Status = InsertRange(pRangeNew, ullStart, pRangeOld->RL_Start - 1);
|
|
if (Status != CR_SUCCESS) {
|
|
goto Clean0;
|
|
}
|
|
|
|
pRangeNew = (PRange_Element)pRangeNew->RL_Next;
|
|
}
|
|
|
|
ullStart = pRangeOld->RL_End + 1;
|
|
}
|
|
|
|
//
|
|
// add the range that incorporates the end of the old range up to
|
|
// the max value specified
|
|
//
|
|
if (ullStart <= ullMaxValue) {
|
|
Status = InsertRange(pRangeNew, ullStart, ullMaxValue);
|
|
}
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLockOld = bLockOld; // needed to prevent optimizing this flag away
|
|
bLockNew = bLockNew; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
|
|
if (bLockOld) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
|
|
}
|
|
if (bLockNew) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Invert_Range_List
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Merge_Range_List(
|
|
IN RANGE_LIST rlhOld1,
|
|
IN RANGE_LIST rlhOld2,
|
|
IN RANGE_LIST rlhNew,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a range list from the union of two specified range
|
|
lists. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle of a
|
|
valid but empty range list.
|
|
|
|
Parameters:
|
|
|
|
rlhOld1 Supplies the handle of a range list to be used as part of the
|
|
union.
|
|
|
|
rlhOld2 Supplies the handle of a range list to be used as part of the
|
|
union.
|
|
|
|
rlhNew Supplies the handle of the range list that receives the union
|
|
of rlhOld1 and rlhOld2. Anything previously contained in the
|
|
rlhNew range list is removed by this operation.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE_LIST, or
|
|
CR_OUT_OF_MEMORY.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
DWORDLONG ullStart = 0, ullEnd = 0;
|
|
BOOL bOld1Empty = FALSE, bOld2Empty = FALSE;
|
|
PRange_Element pRangeNew = NULL, pRangeOld1 = NULL, pRangeOld2 = NULL;
|
|
BOOL bLock1 = FALSE, bLock2 = FALSE, bLockNew = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlhOld1)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsValidRangeList(rlhOld2)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsValidRangeList(rlhNew)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
|
|
bLock1 = TRUE;
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
|
|
bLock2 = TRUE;
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
bLockNew = TRUE;
|
|
|
|
pRangeNew = (PRange_Element)rlhNew;
|
|
pRangeOld1 = (PRange_Element)rlhOld1;
|
|
pRangeOld2 = (PRange_Element)rlhOld2;
|
|
|
|
//
|
|
// If the new range list is not empty, then clear it
|
|
//
|
|
if (pRangeNew->RL_Next != 0) {
|
|
ClearRanges(pRangeNew);
|
|
}
|
|
|
|
//
|
|
// Special case: if both ranges are empty then there is no
|
|
// union by definition
|
|
//
|
|
if (pRangeOld1->RL_Next == 0 && pRangeOld2->RL_Next == 0) {
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Special case: if one range is empty, then the union is just the other
|
|
//
|
|
if (pRangeOld1->RL_Next == 0) {
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
CopyRanges(pRangeOld2, pRangeNew); // from -> to
|
|
goto Clean0;
|
|
}
|
|
|
|
if (pRangeOld2->RL_Next == 0) {
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
CopyRanges(pRangeOld1, pRangeNew); // from -> to
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
|
|
|
|
while (TRUE) {
|
|
//
|
|
// Pick whichever range comes first between current Old1 range
|
|
// and current Old2 range
|
|
//
|
|
if (pRangeOld1->RL_Start <= pRangeOld2->RL_Start) {
|
|
|
|
ullStart = pRangeOld1->RL_Start;
|
|
ullEnd = pRangeOld1->RL_End;
|
|
|
|
if (pRangeOld1->RL_Next == 0) {
|
|
bOld1Empty = TRUE;
|
|
} else {
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
}
|
|
|
|
} else {
|
|
|
|
ullStart = pRangeOld2->RL_Start;
|
|
ullEnd = pRangeOld2->RL_End;
|
|
|
|
if (pRangeOld2->RL_Next == 0) {
|
|
bOld2Empty = TRUE;
|
|
} else {
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
}
|
|
}
|
|
|
|
//
|
|
// gather any ranges in Old1 that intersect (ullStart,ullEnd)
|
|
//
|
|
while (pRangeOld1->RL_Start <= ullEnd) {
|
|
|
|
ullEnd = max(ullEnd, pRangeOld1->RL_End);
|
|
|
|
if (pRangeOld1->RL_Next == 0) {
|
|
bOld1Empty = TRUE;
|
|
break;
|
|
}
|
|
pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
|
|
}
|
|
|
|
//
|
|
// gather any ranges in Old2 that intersect (ullStart,ullEnd)
|
|
//
|
|
while (pRangeOld2->RL_Start <= ullEnd) {
|
|
|
|
ullEnd = max(ullEnd, pRangeOld2->RL_End);
|
|
|
|
if (pRangeOld2->RL_Next == 0) {
|
|
bOld2Empty = TRUE;
|
|
break;
|
|
}
|
|
pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
|
|
}
|
|
|
|
//
|
|
// add (ullStart,ullEnd) to the new range
|
|
//
|
|
Status = InsertRange(pRangeNew, ullStart, ullEnd);
|
|
if (Status != CR_SUCCESS) {
|
|
goto Clean0;
|
|
}
|
|
pRangeNew = (PRange_Element)pRangeNew->RL_Next;
|
|
|
|
//
|
|
// As an optimization, if either range is exhausted first,
|
|
// then only need to duplicate the other remaining ranges.
|
|
//
|
|
if (bOld1Empty && bOld2Empty) {
|
|
goto Clean0; // both exhausted during last pass, we're done
|
|
}
|
|
|
|
if (bOld1Empty) { // Old1 exhausted, copy remaining from Old2
|
|
CopyRanges(pRangeOld2, pRangeNew);
|
|
goto Clean0;
|
|
}
|
|
|
|
if (bOld2Empty) { // Old2 exhausted, copy remaining from Old1
|
|
CopyRanges(pRangeOld1, pRangeNew);
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock1 = bLock1; // needed to prevent optimizing this flag away
|
|
bLock2 = bLock2; // needed to prevent optimizing this flag away
|
|
bLockNew = bLockNew; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
|
|
if (bLock1) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
|
|
}
|
|
if (bLock2) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
|
|
}
|
|
if (bLockNew) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Merge_Range_List
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Next_Range(
|
|
IN OUT PRANGE_ELEMENT preElement,
|
|
OUT PDWORDLONG pullStart,
|
|
OUT PDWORDLONG pullEnd,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the next range element in a range list. This
|
|
API returns CR_FAILURE if there are no more elements in the range
|
|
list.
|
|
|
|
Parameters:
|
|
|
|
preElement Supplies the address of the handle for the current range
|
|
element. Upon return, this variable receives the handle
|
|
of the next range element.
|
|
|
|
pullStart Supplies the address of the variable that receives the
|
|
starting value of the next range.
|
|
|
|
pullEnd Supplies the address of the variable that receives the
|
|
ending value of the next range.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_FAILURE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_POINTER, or
|
|
CR_INVALID_RANGE.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRange = NULL;
|
|
BOOL bLock = FALSE;
|
|
PRange_List_Hdr prlh = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (preElement == NULL || *preElement == 0) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (pullEnd == NULL || pullStart == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
prlh = (PRange_List_Hdr)((PRange_Element)(*preElement))->RL_Header;
|
|
LockPrivateResource(&(prlh->RLH_Lock));
|
|
bLock = TRUE;
|
|
|
|
pRange = (PRange_Element)(*preElement);
|
|
|
|
*pullStart = pRange->RL_Start;
|
|
*pullEnd = pRange->RL_End;
|
|
*preElement = (RANGE_ELEMENT)pRange->RL_Next;
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&(prlh->RLH_Lock));
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Next_Range
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Test_Range_Available(
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
IN RANGE_LIST rlh,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks a range against a range list to ensure that no
|
|
conflicts exist.
|
|
|
|
Parameters:
|
|
|
|
ullStartValue Supplies the low end of the range.
|
|
|
|
ullEndValue Supplies the high end of the range.
|
|
|
|
rlh Supplies the handle to a range list.
|
|
|
|
ulFlags Must be zero.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_FAILURE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_RANGE, or
|
|
CR_INVALID_RANGE_LIST.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pRange = NULL;
|
|
BOOL bLock = FALSE;
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!IsValidRangeList(rlh)) {
|
|
Status = CR_INVALID_RANGE_LIST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ullEndValue < ullStartValue) {
|
|
Status = CR_INVALID_RANGE;
|
|
goto Clean0;
|
|
}
|
|
|
|
LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
bLock = TRUE;
|
|
|
|
pRange = (PRange_Element)rlh;
|
|
|
|
//
|
|
// check each range for a conflict
|
|
//
|
|
while (pRange->RL_Next != 0) {
|
|
|
|
pRange = (PRange_Element)pRange->RL_Next;
|
|
|
|
//
|
|
// If I've already passed the test range, then it's available
|
|
//
|
|
if (ullEndValue < pRange->RL_Start) {
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// check if the start of the test range intersects the current range
|
|
//
|
|
if (ullStartValue >= pRange->RL_Start &&
|
|
ullStartValue <= pRange->RL_End) {
|
|
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// check if the end of the test range intersects the current range
|
|
//
|
|
if (ullEndValue >= pRange->RL_Start &&
|
|
ullEndValue <= pRange->RL_End) {
|
|
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// check if it's a complete overlap
|
|
//
|
|
if (ullStartValue <= pRange->RL_Start &&
|
|
ullEndValue >= pRange->RL_End) {
|
|
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we got this far, then we made it through the range list
|
|
// without hitting a conflict
|
|
//
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
bLock = bLock; // needed to prevent optimizing this flag away
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (bLock) {
|
|
UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Test_Range_Available
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// Private Utility Functions
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
BOOL
|
|
IsValidRangeList(
|
|
IN RANGE_LIST rlh
|
|
)
|
|
{
|
|
BOOL Status = TRUE;
|
|
PRange_List_Hdr pRangeHdr = NULL;
|
|
|
|
try {
|
|
|
|
if (rlh == 0 || rlh == (DWORD)-1) {
|
|
return FALSE;
|
|
}
|
|
|
|
pRangeHdr = (PRange_List_Hdr)rlh;
|
|
|
|
if (pRangeHdr->RLH_Signature != Range_List_Signature) {
|
|
Status = FALSE;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = FALSE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // IsValidRangeList
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
AddRange(
|
|
IN PRange_Element prlh,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
IN ULONG ulFlags
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pPrevious = NULL, pCurrent = NULL;
|
|
|
|
|
|
try {
|
|
|
|
pPrevious = prlh;
|
|
|
|
if (pPrevious->RL_Next == 0) {
|
|
//
|
|
// the range is empty
|
|
//
|
|
Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
while (pPrevious->RL_Next != 0) {
|
|
|
|
pCurrent = (PRange_Element)pPrevious->RL_Next;
|
|
|
|
|
|
if (ullStartValue < pCurrent->RL_Start) {
|
|
|
|
if (ullEndValue < pCurrent->RL_Start) {
|
|
//
|
|
// new range completely contained before this one,
|
|
// add new range between previous and current range
|
|
//
|
|
Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ullEndValue <= pCurrent->RL_End) {
|
|
//
|
|
// new range intersects current range, on the low side,
|
|
// enlarge this range to include the new range
|
|
//
|
|
if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
pCurrent->RL_Start = ullStartValue;
|
|
goto Clean0;
|
|
}
|
|
|
|
if ((pCurrent->RL_Next == 0) ||
|
|
(ullEndValue < ((PRange_Element)(pCurrent->RL_Next))->RL_Start)) {
|
|
//
|
|
// new range intersects current range on high and low
|
|
// side, extent range to include the new range
|
|
//
|
|
if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
pCurrent->RL_Start = ullStartValue;
|
|
pCurrent->RL_End = ullEndValue;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// new range intersects more than one range, needs to be
|
|
// merged
|
|
//
|
|
if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
Status = JoinRange(pPrevious, ullStartValue, ullEndValue);
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
if (ullStartValue <= pCurrent->RL_End+1) {
|
|
|
|
if (ullEndValue <= pCurrent->RL_End) {
|
|
//
|
|
// new range is completely contained inside the current
|
|
// range so nothing to do
|
|
//
|
|
if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
goto Clean0;
|
|
}
|
|
|
|
if ((pCurrent->RL_Next == 0) ||
|
|
(ullEndValue < ((PRange_Element)(pCurrent->RL_Next))->RL_Start)) {
|
|
//
|
|
// new range intersects current range on high end only,
|
|
// extend range to include the new range
|
|
//
|
|
if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
pCurrent->RL_End = ullEndValue;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// new range intersects more than one range, needs to be
|
|
// merged
|
|
//
|
|
if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
Status = JoinRange(pPrevious, ullStartValue, ullEndValue);
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// step to the next range
|
|
//
|
|
pPrevious = pCurrent;
|
|
pCurrent = (PRange_Element)pCurrent->RL_Next;
|
|
}
|
|
|
|
//
|
|
// if we got here then we need to just insert this range to the end
|
|
// of the range list
|
|
//
|
|
Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = 0;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // AddRange
|
|
|
|
|
|
|
|
CONFIGRET
|
|
InsertRange(
|
|
IN PRange_Element pParentElement,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue)
|
|
{
|
|
PRange_Element pNewElement = NULL;
|
|
|
|
|
|
pNewElement = (PRange_Element)pSetupMalloc(sizeof(Range_Element));
|
|
|
|
if (pNewElement == NULL) {
|
|
return CR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
pNewElement->RL_Next = pParentElement->RL_Next; // rejoin the link
|
|
pNewElement->RL_Start = ullStartValue;
|
|
pNewElement->RL_End = ullEndValue;
|
|
pNewElement->RL_Header = pParentElement->RL_Header;
|
|
pParentElement->RL_Next = (ULONG_PTR)pNewElement;
|
|
|
|
return CR_SUCCESS;
|
|
|
|
} // InsertRange
|
|
|
|
|
|
|
|
CONFIGRET
|
|
DeleteRange(
|
|
IN PRange_Element pParentElement
|
|
)
|
|
{
|
|
PRange_Element pTemp = NULL;
|
|
|
|
//
|
|
// must pass a valid parent of the range to delete (in otherwords,
|
|
// can't pass the last range)
|
|
//
|
|
|
|
if (pParentElement == 0) {
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
pTemp = (PRange_Element)(pParentElement->RL_Next);
|
|
if (pTemp == 0) {
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
pParentElement->RL_Next =
|
|
((PRange_Element)(pParentElement->RL_Next))->RL_Next;
|
|
|
|
pSetupFree(pTemp);
|
|
|
|
return CR_SUCCESS;
|
|
|
|
} // DeleteRange
|
|
|
|
|
|
|
|
CONFIGRET
|
|
JoinRange(
|
|
IN PRange_Element pParentElement,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PRange_Element pCurrent = NULL, pNext = NULL;
|
|
|
|
|
|
if (pParentElement->RL_Next == 0) {
|
|
return CR_SUCCESS; // at the end, nothing to join
|
|
}
|
|
|
|
//
|
|
// pCurrent is the starting range of intersecting ranges that need
|
|
// to be joined
|
|
//
|
|
pCurrent = (PRange_Element)pParentElement->RL_Next;
|
|
|
|
//
|
|
// set start of joined range
|
|
//
|
|
if (ullStartValue < pCurrent->RL_Start) {
|
|
pCurrent->RL_Start = ullStartValue;
|
|
}
|
|
|
|
//
|
|
// find the end of the joined range
|
|
//
|
|
while (pCurrent->RL_Next != 0) {
|
|
pNext = (PRange_Element)pCurrent->RL_Next;
|
|
|
|
//
|
|
// I know this next range needs to be absorbed in all cases so
|
|
// reset the end point to at least include the next range
|
|
//
|
|
pCurrent->RL_End = pNext->RL_End;
|
|
|
|
if (ullEndValue <= pNext->RL_End) {
|
|
DeleteRange(pCurrent); // delete the range following current
|
|
break; // we're done
|
|
}
|
|
|
|
if ((pNext->RL_Next == 0) ||
|
|
(ullEndValue < ((PRange_Element)(pNext->RL_Next))->RL_Start)) {
|
|
//
|
|
// adjust the end point of the newly joined range and then we're done
|
|
//
|
|
pCurrent->RL_End = ullEndValue;
|
|
DeleteRange(pCurrent); // delete the range following current
|
|
break;
|
|
}
|
|
|
|
DeleteRange(pCurrent); // delete the range following current
|
|
|
|
// if we got here, there are more ranges to join
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // JoinRange
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CopyRanges(
|
|
IN PRange_Element pFromRange,
|
|
IN PRange_Element pToRange
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
|
|
//
|
|
// copy each range in pFromRange to pToRange
|
|
//
|
|
while (TRUE) {
|
|
|
|
Status = AddRange(pToRange,
|
|
pFromRange->RL_Start,
|
|
pFromRange->RL_End,
|
|
CM_ADD_RANGE_ADDIFCONFLICT);
|
|
|
|
if (Status != CR_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
pToRange = (PRange_Element)pToRange->RL_Next;
|
|
|
|
if (pFromRange->RL_Next == 0) {
|
|
break;
|
|
}
|
|
|
|
pFromRange = (PRange_Element)pFromRange->RL_Next;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CopyRanges
|
|
|
|
|
|
|
|
CONFIGRET
|
|
ClearRanges(
|
|
IN PRange_Element pRange
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
|
|
//
|
|
// If the range list is not empty, then delete ranges
|
|
//
|
|
if (pRange->RL_Next != 0) {
|
|
|
|
while (Status == CR_SUCCESS) {
|
|
//
|
|
// keep deleting the first range after the header (pass parent
|
|
// of range to delete)
|
|
//
|
|
Status = DeleteRange(pRange);
|
|
}
|
|
}
|
|
|
|
return CR_SUCCESS; // Status is set to end deleting ranges, don't return it
|
|
|
|
} // ClearRanges
|
|
|
|
|
|
|
|
CONFIGRET
|
|
TestRange(
|
|
IN PRange_Element rlh,
|
|
IN DWORDLONG ullStartValue,
|
|
IN DWORDLONG ullEndValue,
|
|
OUT PRange_Element *pConflictingRange
|
|
)
|
|
|
|
{
|
|
PRange_Element pRange = (PRange_Element)rlh;
|
|
|
|
//
|
|
// check each range for a conflict
|
|
//
|
|
while (pRange->RL_Next != 0) {
|
|
|
|
pRange = (PRange_Element)pRange->RL_Next;
|
|
|
|
if (pRange->RL_Start > ullEndValue) {
|
|
//
|
|
// We've gone past the range in question so no conflict
|
|
//
|
|
return CR_SUCCESS;
|
|
}
|
|
|
|
if (pRange->RL_End < ullStartValue) {
|
|
//
|
|
// this range is still below the range in question, skip to next range
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// otherwise there's a conflict
|
|
//
|
|
*pConflictingRange = pRange;
|
|
return CR_FAILURE;
|
|
}
|
|
|
|
return CR_SUCCESS;
|
|
|
|
} // TestRange
|
|
|
|
|