diff --git a/src/util/virstring.c b/src/util/virstring.c index fcbb37556e..b244e6c75f 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -568,12 +568,15 @@ virStrdup(char **dest, * caller's body where virStrndup is called from. Consider * using VIR_STRNDUP which sets these automatically. * + * In case @n is smaller than zero, the whole @src string is + * copied. + * * Returns: 0 for NULL src, 1 on successful copy, -1 otherwise. */ int virStrndup(char **dest, const char *src, - size_t n, + ssize_t n, bool report, int domcode, const char *filename, @@ -582,6 +585,8 @@ virStrndup(char **dest, { if (!src) return 0; + if (n < 0) + n = strlen(src); if (!(*dest = strndup(src, n))) { if (report) virReportOOMErrorFull(domcode, filename, funcname, linenr); diff --git a/src/util/virstring.h b/src/util/virstring.h index 534ce9139e..34ffae118a 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -93,7 +93,7 @@ int virStrdup(char **dest, const char *src, bool report, int domcode, const char *filename, const char *funcname, size_t linenr) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1); -int virStrndup(char **dest, const char *src, size_t n, bool report, int domcode, +int virStrndup(char **dest, const char *src, ssize_t n, bool report, int domcode, const char *filename, const char *funcname, size_t linenr) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1); @@ -132,7 +132,9 @@ int virStrndup(char **dest, const char *src, size_t n, bool report, int domcode, * @n: the maximum number of bytes to copy * * Duplicate @src string and store it into @dst. If @src is longer than @n, - * only @n bytes are copied and terminating null byte '\0' is added. + * only @n bytes are copied and terminating null byte '\0' is added. If @n + * is a negative number, then the whole @src string is copied. That is, + * VIR_STRDUP(dst, src) and VIR_STRNDUP(dst, src, -1) are equal. * * This macro is safe to use on arguments with side effects. * @@ -150,7 +152,10 @@ int virStrndup(char **dest, const char *src, size_t n, bool report, int domcode, * @n: the maximum number of bytes to copy * * Duplicate @src string and store it into @dst. If @src is longer than @n, - * only @n bytes are copied and terminating null byte '\0' is added. + * only @n bytes are copied and terminating null byte '\0' is added. If @n + * is a negative number, then the whole @src string is copied. That is, + * VIR_STRDUP_QUIET(dst, src) and VIR_STRNDUP_QUIET(dst, src, -1) are + * equal. * * This macro is safe to use on arguments with side effects. * diff --git a/tests/virstringtest.c b/tests/virstringtest.c index da06c0f7f7..e249f684e9 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -196,6 +196,40 @@ cleanup: return ret; } +static int +testStrndupNegative(const void *opaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + char *dst; + const char *src = "Hello world"; + int value; + + if ((value = VIR_STRNDUP(dst, src, 5)) != 1) { + fprintf(stderr, "unexpected virStrndup result %d, expected 1\n", value); + goto cleanup; + } + + if (STRNEQ_NULLABLE(dst, "Hello")) { + fprintf(stderr, "unexpected content '%s'", dst); + goto cleanup; + } + + VIR_FREE(dst); + if ((value = VIR_STRNDUP(dst, src, -1)) != 1) { + fprintf(stderr, "unexpected virStrndup result %d, expected 1\n", value); + goto cleanup; + } + + if (STRNEQ_NULLABLE(dst, src)) { + fprintf(stderr, "unexpected content '%s'", dst); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(dst); + return ret; +} static int mymain(void) @@ -245,6 +279,9 @@ mymain(void) if (virtTestRun("strdup", 1, testStrdup, NULL) < 0) ret = -1; + if (virtTestRun("strdup", 1, testStrndupNegative, NULL) < 0) + ret = -1; + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; }