Add bt_common_normalize_path()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 29 May 2017 22:48:48 +0000 (18:48 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 9 Jun 2017 20:58:12 +0000 (16:58 -0400)
This new function does a part of realpath()'s job: it resolves `..` and
`.` in the path, resolves a relative path with a custom working
directory or the current working directory, and removes consecutive
separators (`/` or `\` depending on the platform) and the last
separator. The function always returns an absolute path. The function
does NOT resolve symbolic links.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
common/common.c
include/babeltrace/common-internal.h

index d6742962393758c689e03d7390810d20ea0268b2..032a1e06294b65aeed59a34f4276fdd543603808 100644 (file)
@@ -1008,3 +1008,120 @@ end_of_pattern:
        p++;
        return p[-1] == '*' && at_end_of_pattern(p, pattern, pattern_len);
 }
+
+static
+void append_path_parts(const char *path, GPtrArray *parts)
+{
+       const char *ch = path;
+       const char *last = path;
+
+       while (true) {
+               if (*ch == G_DIR_SEPARATOR || *ch == '\0') {
+                       if (ch - last > 0) {
+                               GString *part = g_string_new(NULL);
+
+                               assert(part);
+                               g_string_append_len(part, last, ch - last);
+                               g_ptr_array_add(parts, part);
+                       }
+
+                       if (*ch == '\0') {
+                               break;
+                       }
+
+                       last = ch + 1;
+               }
+
+               ch++;
+       }
+}
+
+static
+void destroy_gstring(void *gstring)
+{
+       (void) g_string_free(gstring, TRUE);
+}
+
+BT_HIDDEN
+GString *bt_common_normalize_path(const char *path, const char *wd)
+{
+       size_t i;
+       GString *norm_path;
+       GPtrArray *parts = NULL;
+
+       assert(path);
+       norm_path = g_string_new(G_DIR_SEPARATOR_S);
+       if (!norm_path) {
+               goto error;
+       }
+
+       parts = g_ptr_array_new_with_free_func(destroy_gstring);
+       if (!parts) {
+               goto error;
+       }
+
+       if (path[0] != G_DIR_SEPARATOR) {
+               /* Relative path: start with working directory */
+               if (wd) {
+                       append_path_parts(wd, parts);
+               } else {
+                       gchar *cd = g_get_current_dir();
+
+                       append_path_parts(cd, parts);
+                       g_free(cd);
+               }
+       }
+
+       /* Append parts of the path parameter */
+       append_path_parts(path, parts);
+
+       /* Resolve special `..` and `.` parts */
+       for (i = 0; i < parts->len; i++) {
+               GString *part = g_ptr_array_index(parts, i);
+
+               if (strcmp(part->str, "..") == 0) {
+                       if (i == 0) {
+                               /*
+                                * First part of absolute path is `..`:
+                                * this is invalid.
+                                */
+                               goto error;
+                       }
+
+                       /* Remove `..` and previous part */
+                       g_ptr_array_remove_index(parts, i - 1);
+                       g_ptr_array_remove_index(parts, i - 1);
+                       i -= 2;
+               } else if (strcmp(part->str, ".") == 0) {
+                       /* Remove `.` */
+                       g_ptr_array_remove_index(parts, i);
+                       i -= 1;
+               }
+       }
+
+       /* Create normalized path with what's left */
+       for (i = 0; i < parts->len; i++) {
+               GString *part = g_ptr_array_index(parts, i);
+
+               g_string_append(norm_path, part->str);
+
+               if (i < parts->len - 1) {
+                       g_string_append_c(norm_path, G_DIR_SEPARATOR);
+               }
+       }
+
+       goto end;
+
+error:
+       if (norm_path) {
+               g_string_free(norm_path, TRUE);
+               norm_path = NULL;
+       }
+
+end:
+       if (parts) {
+               g_ptr_array_free(parts, TRUE);
+       }
+
+       return norm_path;
+}
index fd8b12e3e862c17c10dce901b16c38fc0c1d152e..b843e57ec1aa738bec9d4804a19860fdfcd6c39d 100644 (file)
@@ -127,4 +127,7 @@ BT_HIDDEN
 bool bt_common_star_glob_match(const char *pattern, size_t pattern_len,
                 const char *candidate, size_t candidate_len);
 
+BT_HIDDEN
+GString *bt_common_normalize_path(const char *path, const char *wd);
+
 #endif /* BABELTRACE_COMMON_INTERNAL_H */
This page took 0.027113 seconds and 4 git commands to generate.