From a2e78ff0442a6a4c290577ff2ecf3c4307c3e9f5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rapha=C3=ABl=20Beamonte?= Date: Wed, 13 Nov 2013 00:34:35 -0500 Subject: [PATCH] Introduce a new utils_resolve_relative function MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This function aims to resolve relative path such as './' and '../' in the middle of a path string. This allows to use paths such as '~/../test' that are received as '/home/x/../test' for instance. Signed-off-by: Raphaël Beamonte --- src/common/utils.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ src/common/utils.h | 1 + 2 files changed, 69 insertions(+) diff --git a/src/common/utils.c b/src/common/utils.c index da4c036b9..4ccf36a6c 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -35,6 +35,74 @@ #include "utils.h" #include "defaults.h" +/* + * Resolve the './' and '../' strings in the middle of a path using + * our very own way to do it, so that it works even if the directory + * does not exist + */ +LTTNG_HIDDEN +char *utils_resolve_relative(const char *path) +{ + char *next, *previous, *slash, *start_path, *absolute_path = NULL; + + /* Safety net */ + if (path == NULL) { + goto error; + } + + /* Allocate memory for the absolute path */ + absolute_path = zmalloc(PATH_MAX); + if (absolute_path == NULL) { + PERROR("zmalloc expand path"); + goto error; + } + + /* Copy the path in the absolute path */ + strncpy(absolute_path, path, PATH_MAX); + + /* As long as we find '/./' in the path string */ + while ((next = strstr(absolute_path, "/./"))) { + + /* We prepare the start_path not containing it */ + start_path = strndup(absolute_path, next - absolute_path); + + /* And we concatenate it with the part after this string */ + snprintf(absolute_path, PATH_MAX, "%s%s", start_path, next + 2); + + free(start_path); + } + + /* As long as we find '/../' in the path string */ + while ((next = strstr(absolute_path, "/../"))) { + /* If the path starts with '/../', there's a problem */ + if (next == absolute_path) { + ERR("%s: Path cannot be resolved", path); + goto error; + } + + /* We find the last level of directory */ + previous = absolute_path; + while ((slash = strpbrk(previous + 1, "/")) && slash != next) { + previous = slash; + } + + /* Then we prepare the start_path not containing it */ + start_path = strndup(absolute_path, previous - absolute_path); + + /* And we concatenate it with the part after the '/../' */ + snprintf(absolute_path, PATH_MAX, "%s%s", start_path, next + 3); + + free(start_path); + } + + return absolute_path; + +error: + free(absolute_path); + return NULL; +} + + /* * Return the realpath(3) of the path even if the last directory token does not * exist. For example, with /tmp/test1/test2, if test2/ does not exist but the diff --git a/src/common/utils.h b/src/common/utils.h index 52f2798d1..c56942f56 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -26,6 +26,7 @@ #define MEBI_LOG2 20 #define GIBI_LOG2 30 +char *utils_resolve_relative(const char *path); char *utils_expand_path(const char *path); int utils_create_pipe(int *dst); int utils_create_pipe_cloexec(int *dst); -- 2.34.1