virbitmap: Introduce virBitmapParseUnlimitedAllowEmpty()

Some sysfs files contain either string representation of a bitmap
or just a newline character. An example of such file is:
/sys/devices/system/cpu/isolated. Our current implementation of
virBitmapParseUnlimited() fails in the latter case,
unfortunately. Introduce a slightly modified version that accepts
empty files.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
Michal Privoznik 2024-04-23 09:17:51 +02:00
parent 142ed263c0
commit b972cdc1a5
4 changed files with 79 additions and 5 deletions

View File

@ -1936,6 +1936,7 @@ virBitmapNextSetBit;
virBitmapOverlaps;
virBitmapParse;
virBitmapParseUnlimited;
virBitmapParseUnlimitedAllowEmpty;
virBitmapSetAll;
virBitmapSetBit;
virBitmapSetBitExpand;

View File

@ -368,6 +368,7 @@ virBitmapFormat(virBitmap *bitmap)
* @str: points to a string representing a human-readable bitmap
* @bitmap: a bitmap populated from @str
* @limited: Don't use self-expanding APIs, report error if bit exceeds bitmap size
* @allowEmpty: Allow @str to be empty string or contain nothing but spaces
*
* This function is the counterpart of virBitmapFormat. This function creates
* a bitmap, in which bits are set according to the content of @str.
@ -381,7 +382,8 @@ virBitmapFormat(virBitmap *bitmap)
static int
virBitmapParseInternal(const char *str,
virBitmap *bitmap,
bool limited)
bool limited,
bool allowEmpty)
{
bool neg = false;
const char *cur = str;
@ -389,13 +391,19 @@ virBitmapParseInternal(const char *str,
size_t i;
int start, last;
if (!str)
if (!str) {
if (allowEmpty)
return 0;
goto error;
}
virSkipSpaces(&cur);
if (*cur == '\0')
if (*cur == '\0') {
if (allowEmpty)
return 0;
goto error;
}
while (*cur != 0) {
/*
@ -505,7 +513,7 @@ virBitmapParse(const char *str,
{
g_autoptr(virBitmap) tmp = virBitmapNew(bitmapSize);
if (virBitmapParseInternal(str, tmp, true) < 0)
if (virBitmapParseInternal(str, tmp, true, false) < 0)
return -1;
*bitmap = g_steal_pointer(&tmp);
@ -534,7 +542,29 @@ virBitmapParseUnlimited(const char *str)
{
g_autoptr(virBitmap) tmp = virBitmapNew(0);
if (virBitmapParseInternal(str, tmp, false) < 0)
if (virBitmapParseInternal(str, tmp, false, false) < 0)
return NULL;
return g_steal_pointer(&tmp);
}
/**
* virBitmapParseUnlimitedAllowEmpty:
* @str: points to a string representing a human-readable bitmap
*
* Just like virBitmapParseUnlimited() except when the input string @str is
* empty (or contains just spaces) an empty bitmap is returned instead of an
* error.
*
* Returns @bitmap on success, or NULL in cas of error
*/
virBitmap *
virBitmapParseUnlimitedAllowEmpty(const char *str)
{
g_autoptr(virBitmap) tmp = virBitmapNew(0);
if (virBitmapParseInternal(str, tmp, false, true) < 0)
return NULL;
return g_steal_pointer(&tmp);

View File

@ -84,6 +84,9 @@ int virBitmapParse(const char *str,
virBitmap *
virBitmapParseUnlimited(const char *str);
virBitmap *
virBitmapParseUnlimitedAllowEmpty(const char *str);
virBitmap *virBitmapNewCopy(virBitmap *src) ATTRIBUTE_NONNULL(1);
virBitmap *virBitmapNewData(const void *data, int len) ATTRIBUTE_NONNULL(1);

View File

@ -705,6 +705,43 @@ test16(const void *opaque G_GNUC_UNUSED)
}
/* virBitmapParseUnlimitedAllowEmpty */
static int
test17(const void *opaque G_GNUC_UNUSED)
{
g_autoptr(virBitmap) map1 = NULL;
g_autoptr(virBitmap) map2 = NULL;
g_autofree char *map1_str = NULL;
g_autofree char *map2_str = NULL;
if (!(map1 = virBitmapParseUnlimitedAllowEmpty(NULL))) {
fprintf(stderr, "Expected success, got failure\n");
return -1;
}
if (!(map2 = virBitmapParseUnlimitedAllowEmpty(" "))) {
fprintf(stderr, "Expected success, got failure\n");
return -1;
}
if (!virBitmapIsAllClear(map1) ||
!virBitmapIsAllClear(map2) ||
!virBitmapEqual(map1, map2)) {
fprintf(stderr, "empty maps should equal\n");
return -1;
}
if (!(map1_str = virBitmapFormat(map1)) ||
!(map2_str = virBitmapFormat(map2)) ||
STRNEQ(map1_str, map2_str)) {
fprintf(stderr, "maps don't equal after format to string\n");
return -1;
}
return 0;
}
#define TESTBINARYOP(A, B, RES, FUNC) \
testBinaryOpData.a = A; \
testBinaryOpData.b = B; \
@ -781,6 +818,9 @@ mymain(void)
if (virTestRun("test16", test16, NULL) < 0)
ret = -1;
if (virTestRun("test17", test17, NULL) < 0)
ret = -1;
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}