]> Kevux Git Server - fll/commitdiff
Update: The fl_path_canonical() should handle the NULL cases.
authorKevin Day <Kevin@kevux.org>
Wed, 22 Jan 2025 02:48:30 +0000 (20:48 -0600)
committerKevin Day <Kevin@kevux.org>
Wed, 22 Jan 2025 03:31:01 +0000 (21:31 -0600)
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.

level_1/fl_path/c/path.c
level_1/fl_path/c/path.h
level_1/fl_path/tests/unit/c/test-path-canonical.c

index d7ffe5a452ccd07891988bc15a98e3a01981c6e8..1c30d7415c3a08cd75522e23d7cd699c28e300b4 100644 (file)
@@ -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;
       }
     }
index b770804e4ce5e9f2869d9c0fdded882fa6fef8b2..6fa567e6e4c1dc53aaf6e533401a1b4212b116fb 100644 (file)
@@ -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_
index fdfc4e73075193d3b561f43bf585ad932252a960..a7313e3576828499a2ec214d8827b553f1552aa4 100644 (file)
@@ -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);