diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index 904d89f337..6a85fe4c79 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -7946,16 +7946,50 @@ test_nm_utils_uuid_generate_from_string(void) /*****************************************************************************/ static void -_check_uuid(NMUuidType uuid_type, - const NMUuid *type_arg, - const char *expected_uuid, - const char *str, - gssize slen, - char *uuid_test) +_check_uuid(NMUuidType uuid_type, + const NMUuid *type_arg, + const char *expected_uuid, + const char *str, + gssize slen, + const char *const *strv, + gssize strv_len) { + gs_free char *uuid_test = NULL; + gs_free char *uuid_test2 = NULL; + gboolean uuid_test2_valid = TRUE; + + g_assert(str); + g_assert(strv_len < 0 || strv); + + uuid_test = nm_uuid_generate_from_strings_strv(uuid_type, type_arg, strv, strv_len); + g_assert(uuid_test); g_assert(nm_uuid_is_normalized(uuid_test)); - g_assert(str); + + if (strv_len < 0 && strv) { + uuid_test2 = + nm_uuid_generate_from_strings_strv(uuid_type, type_arg, strv, NM_PTRARRAY_LEN(strv)); + } else if (strv_len >= 0) { + gssize l = nm_strv_find_first(strv, strv_len, NULL); + gs_free const char **strv2 = nm_strv_dup_packed(strv, l < 0 ? strv_len : l); + + uuid_test2 = nm_uuid_generate_from_strings_strv(uuid_type, + type_arg, + strv2 ?: NM_STRV_EMPTY_CC(), + -1); + if (l >= 0) { + /* there are NULL strings. The result won't be match. */ + uuid_test2_valid = FALSE; + } + } + if (uuid_test2) { + if (uuid_test2_valid) + g_assert_cmpstr(uuid_test, ==, uuid_test2); + else { + g_assert(nm_uuid_is_normalized(uuid_test)); + g_assert_cmpstr(uuid_test, !=, uuid_test2); + } + } if (!nm_streq(uuid_test, expected_uuid)) { g_error("UUID test failed (1): text=%s, len=%lld, expected=%s, uuid_test=%s", @@ -7978,24 +8012,19 @@ _check_uuid(NMUuidType uuid_type, expected_uuid, uuid_test); } - g_free(uuid_test); } -#define check_uuid(uuid_type, type_arg, expected_uuid, str, ...) \ - ({ \ - const NMUuidType _uuid_type = (uuid_type); \ - const NMUuid *_type_arg = type_arg; \ - const char *_expected_uuid = (expected_uuid); \ - const char *_str = (str); \ - const gsize _strlen = NM_STRLEN(str); \ - \ - _check_uuid( \ - _uuid_type, \ - _type_arg, \ - _expected_uuid, \ - _str, \ - _strlen, \ - nm_uuid_generate_from_strings_strv(_uuid_type, _type_arg, NM_MAKE_STRV(__VA_ARGS__))); \ +#define check_uuid(uuid_type, type_arg, expected_uuid, str, ...) \ + ({ \ + const NMUuidType _uuid_type = (uuid_type); \ + const NMUuid *_type_arg = type_arg; \ + const char *_expected_uuid = (expected_uuid); \ + const char *_str = (str); \ + const gsize _strlen = NM_STRLEN(str); \ + const char *const *_strv = NM_MAKE_STRV(__VA_ARGS__); \ + const gssize _strv_len = NM_NARG(__VA_ARGS__); \ + \ + _check_uuid(_uuid_type, _type_arg, _expected_uuid, _str, _strlen, _strv, _strv_len); \ }) static void @@ -8023,17 +8052,19 @@ test_nm_utils_uuid_generate_from_strings(void) "457229f4-fe49-32f5-8b09-c531d81f44d9", "x", 1, - nm_uuid_generate_from_strings_strv(NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1, NULL)); - check_uuid(NM_UUID_TYPE_VERSION3, - &nm_uuid_ns_1, - "b07c334a-399b-32de-8d50-58e4e08f98e3", - "", - NULL); + NULL, + -1); + check_uuid(NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1, "b07c334a-399b-32de-8d50-58e4e08f98e3", ""); check_uuid(NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1, "b8a426cb-bcb5-30a3-bd8f-6786fea72df9", "\0", ""); + check_uuid(NM_UUID_TYPE_VERSION3, + &nm_uuid_ns_1, + "9232afda-85fc-3b8f-8736-4f99c8d5db9c", + "_n", + NULL); check_uuid(NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1, "12a4a982-7aae-39e1-951e-41aeb1250959", @@ -8074,6 +8105,13 @@ test_nm_utils_uuid_generate_from_strings(void) "a\0a\0", "a", "a"); + check_uuid(NM_UUID_TYPE_VERSION3, + &nm_uuid_ns_1, + "f36cec99-1db8-3baa-8c3f-13e13d980318", + "a\0a\0001_1n", + "a", + NULL, + "a"); check_uuid(NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1, "fd698d86-1b60-3ebe-855f-7aada9950a8d", @@ -8117,6 +8155,13 @@ test_nm_utils_uuid_generate_from_strings(void) "\0b\0", "", "b"); + check_uuid(NM_UUID_TYPE_VERSION5, + _uuid(NM_UUID_NS_URL), + "db3dfd17-c785-509d-a0ca-740fdd68dc68", + "\0b\00011_n", + "", + "b", + NULL); check_uuid(NM_UUID_TYPE_VERSION3, _uuid(NM_UUID_NS_URL), "916dcdd8-5042-3b9b-9763-4312a31e5735", diff --git a/src/libnm-glib-aux/nm-uuid.c b/src/libnm-glib-aux/nm-uuid.c index 34c3be335b..cdfa5f629e 100644 --- a/src/libnm-glib-aux/nm-uuid.c +++ b/src/libnm-glib-aux/nm-uuid.c @@ -413,6 +413,10 @@ nm_uuid_generate_from_string_str(const char *s, * @type_args: the namespace UUID. * @strv: (allow-none): the strv list to hash. Can be NULL, in which * case the result is different from an empty array. + * @len: if negative, @strv is a NULL terminated array. Otherwise, + * it is the length of the strv array. In the latter case it may + * also contain NULL strings. The result hashes differently depending + * on whether we have a NULL terminated strv array or given length. * * Returns a @uuid_type UUID based on the concatenated C strings. * It does not simply concatenate them, but also includes the @@ -425,13 +429,43 @@ nm_uuid_generate_from_string_str(const char *s, char * nm_uuid_generate_from_strings_strv(NMUuidType uuid_type, const NMUuid *type_args, - const char *const *strv) + const char *const *strv, + gssize len) { nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, TRUE); gsize slen; const char *s; - if (!strv) { + if (len >= 0) { + gboolean has_nulls = FALSE; + gssize i; + + nm_assert(len == 0 || strv); + + for (i = 0; i < len; i++) { + if (strv[i]) + nm_str_buf_append_len(&str, strv[i], strlen(strv[i]) + 1u); + else + has_nulls = TRUE; + } + if (has_nulls) { + /* We either support a NULL terminated strv array, or a ptr array of fixed + * length (@len argument). + * + * If there are no NULLs within the first @len strings, then the result + * is the same. If there are any NULL strings, we need to encode that + * in a unique way. We do that by appending a bitmap of the elements + * whether they were set, plus one 'n' character (without NUL termination). + * None of the other branches below hashes to that, so this will uniquely + * encoded the NULL strings. + */ + for (i = 0; i < len; i++) + nm_str_buf_append_c(&str, strv[i] ? '1' : '_'); + nm_str_buf_append_c(&str, 'n'); + } + slen = str.len; + s = nm_str_buf_get_str_unsafe(&str); + } else if (!strv) { /* NULL is treated differently from an empty strv. We achieve that * by using a non-empty, non-NUL terminated string (which cannot happen * in the other cases). */ diff --git a/src/libnm-glib-aux/nm-uuid.h b/src/libnm-glib-aux/nm-uuid.h index 4e0941ffb7..d26616cf4f 100644 --- a/src/libnm-glib-aux/nm-uuid.h +++ b/src/libnm-glib-aux/nm-uuid.h @@ -125,16 +125,21 @@ char *nm_uuid_generate_from_string_str(const char *s, char *nm_uuid_generate_from_strings_strv(NMUuidType uuid_type, const NMUuid *type_args, - const char *const *strv); + const char *const *strv, + gssize len); -#define nm_uuid_generate_from_strings(uuid_type, type_args, ...) \ - nm_uuid_generate_from_strings_strv((uuid_type), (type_args), NM_MAKE_STRV(__VA_ARGS__)) +#define nm_uuid_generate_from_strings(uuid_type, type_args, ...) \ + nm_uuid_generate_from_strings_strv((uuid_type), \ + (type_args), \ + NM_MAKE_STRV(__VA_ARGS__), \ + NM_NARG(__VA_ARGS__)) /* Legacy function. Don't use for new code. */ #define nm_uuid_generate_from_strings_old(uuid_type, type_args, ...) \ nm_uuid_generate_from_strings_strv(NM_UUID_TYPE_VERSION3, \ &nm_uuid_ns_1, \ - NM_MAKE_STRV(__VA_ARGS__)) + NM_MAKE_STRV(__VA_ARGS__), \ + -1) /*****************************************************************************/