From: Kevin Day Date: Wed, 22 Jan 2025 02:48:30 +0000 (-0600) Subject: Update: The fl_path_canonical() should handle the NULL cases. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=ae12974271323f78773fa68c7cb39025ddfde4d9;p=fll Update: The fl_path_canonical() should handle the NULL cases. Allow for NULL within the strings. Update the processing code and add some unit tests. The documentation comment about canonical->used being reset to 0 before processing is incorrect and is now removed. --- diff --git a/level_1/fl_path/c/path.c b/level_1/fl_path/c/path.c index d7ffe5a..1c30d74 100644 --- a/level_1/fl_path/c/path.c +++ b/level_1/fl_path/c/path.c @@ -19,32 +19,29 @@ extern "C" { return F_okay; } - f_number_unsigned_t at = 0; - uint8_t previous_1 = f_path_separator_s.string[0]; uint8_t previous_2 = 0; + f_number_unsigned_t at = 0; f_number_unsigned_t size_chunk = 0; f_number_unsigned_t position = 0; canonical->used = 0; - if (path.string[0] == f_path_separator_s.string[0]) { - at = 1; + while (at < path.used && !path.string[at]) ++at; + + if (path.string[at] == f_path_separator_s.string[0]) { + ++at; } else { status = f_path_current(F_true, canonical); if (F_status_is_error(status)) return status; - - if (!path.string[0]) return F_okay; - - at = 0; } status = f_string_dynamic_append_assure(f_path_separator_s, canonical); if (F_status_is_error(status)) return status; - for (; at < path.used && path.string[at]; ++at) { + for (; at < path.used; ++at) { if (!size_chunk && path.string[at] == f_path_separator_current_s.string[0]) { if (!previous_1 || previous_1 == f_path_separator_s.string[0]) { @@ -85,7 +82,7 @@ extern "C" { } else { if (++size_chunk) { - status = f_string_append(path.string + position, size_chunk, canonical); + status = f_string_append_nulless(path.string + position, size_chunk, canonical); if (F_status_is_error(status)) return status; } } @@ -95,6 +92,11 @@ extern "C" { size_chunk = 0; position = 0; } + else if (!path.string[at]) { + + // NULLs must not affect the position and previous states. + if (size_chunk) ++size_chunk; + } else { if (!size_chunk) { position = at; @@ -127,7 +129,7 @@ extern "C" { } else if (!(previous_1 == f_path_separator_current_s.string[0] || previous_1 == f_path_separator_s.string[0])) { if (size_chunk) { - status = f_string_append(path.string + position, size_chunk, canonical); + status = f_string_append_nulless(path.string + position, size_chunk, canonical); if (F_status_is_error(status)) return status; } } diff --git a/level_1/fl_path/c/path.h b/level_1/fl_path/c/path.h index b770804..6fa567e 100644 --- a/level_1/fl_path/c/path.h +++ b/level_1/fl_path/c/path.h @@ -32,28 +32,27 @@ extern "C" { * This does not process symbolic links. * This has a max size of F_string_t_size_d. * This removes trailing slashes, but leaves the leading slash ('/' remains as-is, but '/a/' becomes '/a'). + * This removes redundant slashes '/'. * * An empty path (first character is NULL or path.used is 0) appends only the current path to canonical. * * @param path * The source path to determine what the canonical path is. + * NULLs within the path are not copied to the canonical. * This need not be NULL terminated. * @param canonical * The (allocated) canonical file path. - * The canonical->used is reset to 0 before processing. * This will be NULL terminated at canonical->used + 1. * * @return * F_okay on success. * * Errors (with error bit) from: f_path_current(). - * Errors (with error bit) from: f_string_append(). - * Errors (with error bit) from: f_string_append_assure(). + * Errors (with error bit) from: f_string_append_nulless(). * Errors (with error bit) from: f_string_dynamic_append_assure(). * * @see f_path_current() - * @see f_string_append() - * @see f_string_append_assure() + * @see f_string_append_nulless() * @see f_string_dynamic_append_assure() */ #ifndef _di_fl_path_canonical_ diff --git a/level_1/fl_path/tests/unit/c/test-path-canonical.c b/level_1/fl_path/tests/unit/c/test-path-canonical.c index fdfc4e7..a7313e3 100644 --- a/level_1/fl_path/tests/unit/c/test-path-canonical.c +++ b/level_1/fl_path/tests/unit/c/test-path-canonical.c @@ -41,6 +41,10 @@ void test__fl_path_canonical__back_paths(void **state) { macro_f_string_static_t_initialize_1("/z/../b/c", 0, 9), macro_f_string_static_t_initialize_1("/z/../b/c/", 0, 10), macro_f_string_static_t_initialize_1("/z/../b/c//", 0, 11), + macro_f_string_static_t_initialize_1("/z/.\0./b/c//", 0, 12), + macro_f_string_static_t_initialize_1("/z\0/.\0./b/c/\0/", 0, 14), + macro_f_string_static_t_initialize_1("\0a/../", 0, 6), + macro_f_string_static_t_initialize_1("a/../\0", 0, 6), }; const f_string_static_t expected[] = { @@ -68,6 +72,10 @@ void test__fl_path_canonical__back_paths(void **state) { macro_f_string_static_t_initialize_1("/b/c", 0, 4), macro_f_string_static_t_initialize_1("/b/c", 0, 4), macro_f_string_static_t_initialize_1("/b/c", 0, 4), + macro_f_string_static_t_initialize_1("/b/c", 0, 4), + macro_f_string_static_t_initialize_1("/b/c", 0, 4), + macro_f_string_static_t_initialize_1("", 0, 0), + macro_f_string_static_t_initialize_1("", 0, 0), }; const uint8_t prepend[] = { @@ -95,11 +103,17 @@ void test__fl_path_canonical__back_paths(void **state) { F_false, F_false, F_false, + F_false, + F_false, + F_true, + F_true, }; f_string_dynamic_t path = f_string_dynamic_t_initialize; - for (uint8_t i = 0; i < 24; ++i) { + for (uint8_t i = 0; i < 28; ++i) { + + path.used = 0; const f_status_t status = fl_path_canonical(contents[i], &path); @@ -112,8 +126,7 @@ void test__fl_path_canonical__back_paths(void **state) { f_char_t prepended_string[pwd_length + expected[i].used + 2]; f_string_static_t prepended = macro_f_string_static_t_initialize_1(prepended_string, 0, pwd_length + expected[i].used); - prepended_string[prepended.used] = 0; - prepended_string[prepended.used + 1] = 0; + memset(prepended_string, 0, pwd_length + expected[i].used + 2); if (pwd_length) { memcpy(prepended_string, pwd, pwd_length); @@ -200,6 +213,10 @@ void test__fl_path_canonical__present_paths(void **state) { macro_f_string_static_t_initialize_1(".//a/b", 0, 6), macro_f_string_static_t_initialize_1(".//a/b/", 0, 7), macro_f_string_static_t_initialize_1(".//a/b//", 0, 8), + macro_f_string_static_t_initialize_1(".//a/\0b//", 0, 9), + macro_f_string_static_t_initialize_1(".\0//a/\0b/\0/", 0, 11), + macro_f_string_static_t_initialize_1("\0a", 0, 2), + macro_f_string_static_t_initialize_1("a\0", 0, 2), }; const f_string_static_t expected[] = { @@ -221,11 +238,17 @@ void test__fl_path_canonical__present_paths(void **state) { macro_f_string_static_t_initialize_1("a/b", 0, 3), macro_f_string_static_t_initialize_1("a/b", 0, 3), macro_f_string_static_t_initialize_1("a/b", 0, 3), + macro_f_string_static_t_initialize_1("a/b", 0, 3), + macro_f_string_static_t_initialize_1("a/b", 0, 3), + macro_f_string_static_t_initialize_1("a", 0, 1), + macro_f_string_static_t_initialize_1("a", 0, 1), }; f_string_dynamic_t path = f_string_dynamic_t_initialize; - for (uint8_t i = 0; i < 18; ++i) { + for (uint8_t i = 0; i < 22; ++i) { + + path.used = 0; const f_status_t status = fl_path_canonical(contents[i], &path); @@ -237,8 +260,7 @@ void test__fl_path_canonical__present_paths(void **state) { f_char_t prepended_string[pwd_length + expected[i].used + 2]; f_string_static_t prepended = macro_f_string_static_t_initialize_1(prepended_string, 0, pwd_length + expected[i].used); - prepended_string[prepended.used] = 0; - prepended_string[prepended.used + 1] = 0; + memset(prepended_string, 0, pwd_length + expected[i].used + 2); if (pwd_length) { memcpy(prepended_string, pwd, pwd_length); @@ -288,6 +310,10 @@ void test__fl_path_canonical__root_paths(void **state) { macro_f_string_static_t_initialize_1("/a/b//", 0, 6), macro_f_string_static_t_initialize_1("//a/b//", 0, 7), macro_f_string_static_t_initialize_1("///a/b//", 0, 8), + macro_f_string_static_t_initialize_1("///a/\0b//", 0, 9), + macro_f_string_static_t_initialize_1("/\0//a/\0b\0//", 0, 11), + macro_f_string_static_t_initialize_1("\0/", 0, 2), + macro_f_string_static_t_initialize_1("/\0", 0, 2), }; const f_string_static_t expected[] = { @@ -309,11 +335,17 @@ void test__fl_path_canonical__root_paths(void **state) { macro_f_string_static_t_initialize_1("/a/b", 0, 4), macro_f_string_static_t_initialize_1("/a/b", 0, 4), macro_f_string_static_t_initialize_1("/a/b", 0, 4), + macro_f_string_static_t_initialize_1("/a/b", 0, 4), + macro_f_string_static_t_initialize_1("/a/b", 0, 4), + macro_f_string_static_t_initialize_1("/", 0, 1), + macro_f_string_static_t_initialize_1("/", 0, 1), }; f_string_dynamic_t path = f_string_dynamic_t_initialize; - for (uint8_t i = 0; i < 18; ++i) { + for (uint8_t i = 0; i < 22; ++i) { + + path.used = 0; const f_status_t status = fl_path_canonical(contents[i], &path); @@ -365,6 +397,10 @@ void test__fl_path_canonical__tilde_remains(void **state) { macro_f_string_static_t_initialize_1("//a/~/b", 0, 7), macro_f_string_static_t_initialize_1("//a/~b", 0, 6), macro_f_string_static_t_initialize_1("//a/~b/c", 0, 8), + macro_f_string_static_t_initialize_1("//a/~\0b/c", 0, 9), + macro_f_string_static_t_initialize_1("/\0/a/~\0b\0/c", 0, 11), + macro_f_string_static_t_initialize_1("\0~", 0, 2), + macro_f_string_static_t_initialize_1("~\0", 0, 2), }; const f_string_static_t expected[] = { @@ -391,6 +427,10 @@ void test__fl_path_canonical__tilde_remains(void **state) { macro_f_string_static_t_initialize_1("/a/~/b", 0, 6), macro_f_string_static_t_initialize_1("/a/~b", 0, 5), macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7), + macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7), + macro_f_string_static_t_initialize_1("/a/~b/c", 0, 7), + macro_f_string_static_t_initialize_1("~", 0, 1), + macro_f_string_static_t_initialize_1("~", 0, 1), }; const uint8_t prepend[] = { @@ -417,11 +457,17 @@ void test__fl_path_canonical__tilde_remains(void **state) { F_false, F_false, F_false, + F_false, + F_false, + F_true, + F_true, }; f_string_dynamic_t path = f_string_dynamic_t_initialize; - for (uint8_t i = 0; i < 23; ++i) { + for (uint8_t i = 0; i < 27; ++i) { + + path.used = 0; const f_status_t status = fl_path_canonical(contents[i], &path); @@ -434,8 +480,7 @@ void test__fl_path_canonical__tilde_remains(void **state) { f_char_t prepended_string[pwd_length + expected[i].used + 2]; f_string_static_t prepended = macro_f_string_static_t_initialize_1(prepended_string, 0, pwd_length + expected[i].used); - prepended_string[prepended.used] = 0; - prepended_string[prepended.used + 1] = 0; + memset(prepended_string, 0, pwd_length + expected[i].used + 2); if (pwd_length) { memcpy(prepended_string, pwd, pwd_length);