From 5154230f59b7f66abe33166cf14ef49d2c4e2219 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rapha=C3=ABl=20Beamonte?= Date: Thu, 14 Nov 2013 19:58:33 -0500 Subject: [PATCH] Introduce a new utils_partial_realpath function MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This new utils function allows to resolve partially the paths using realpath. As realpath(3) is not available to use for unexistent paths, this function that allows to resolve partially existent paths can be used in cases we don't know if the path fully exists. It first resolves the existent part using realpath(3) and then concatenate the unexistent part to it. Signed-off-by: Raphaël Beamonte Signed-off-by: David Goulet --- src/common/utils.c | 128 +++++++++++++++++++++++++++++++++++++++++++++ src/common/utils.h | 2 + 2 files changed, 130 insertions(+) diff --git a/src/common/utils.c b/src/common/utils.c index 6938a5ae5..57add319b 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -35,6 +35,134 @@ #include "utils.h" #include "defaults.h" +/* + * Return a partial realpath(3) of the path even if the full path does not + * exist. For instance, with /tmp/test1/test2/test3, if test2/ does not exist + * but the /tmp/test1 does, the real path for /tmp/test1 is concatened with + * /test2/test3 then returned. In normal time, realpath(3) fails if the end + * point directory does not exist. + * In case resolved_path is NULL, the string returned was allocated in the + * function and thus need to be freed by the caller. The size argument allows + * to specify the size of the resolved_path argument if given, or the size to + * allocate. + */ +LTTNG_HIDDEN +char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) +{ + char *cut_path, *try_path = NULL, *try_path_prev = NULL; + const char *next, *prev, *end; + + /* Safety net */ + if (path == NULL) { + goto error; + } + + /* + * Identify the end of the path, we don't want to treat the + * last char if it is a '/', we will just keep it on the side + * to be added at the end, and return a value coherent with + * the path given as argument + */ + end = path + strlen(path); + if (*(end-1) == '/') { + end--; + } + + /* Initiate the values of the pointers before looping */ + next = path; + prev = next; + /* Only to ensure try_path is not NULL to enter the while */ + try_path = (char *)next; + + /* Resolve the canonical path of the first part of the path */ + while (try_path != NULL && next != end) { + /* + * If there is not any '/' left, we want to try with + * the full path + */ + next = strpbrk(next + 1, "/"); + if (next == NULL) { + next = end; + } + + /* Cut the part we will be trying to resolve */ + cut_path = strndup(path, next - path); + + /* Try to resolve this part */ + try_path = realpath((char *)cut_path, NULL); + if (try_path == NULL) { + /* + * There was an error, we just want to be assured it + * is linked to an unexistent directory, if it's another + * reason, we spawn an error + */ + switch (errno) { + case ENOENT: + /* Ignore the error */ + break; + default: + PERROR("realpath (partial_realpath)"); + goto error; + break; + } + } else { + /* Save the place we are before trying the next step */ + free(try_path_prev); + try_path_prev = try_path; + prev = next; + } + + /* Free the allocated memory */ + free(cut_path); + }; + + /* Allocate memory for the resolved path if necessary */ + if (resolved_path == NULL) { + resolved_path = zmalloc(size); + if (resolved_path == NULL) { + PERROR("zmalloc resolved path"); + goto error; + } + } + + /* + * If we were able to solve at least partially the path, we can concatenate + * what worked and what didn't work + */ + if (try_path_prev != NULL) { + /* If we risk to concatenate two '/', we remove one of them */ + if (try_path_prev[strlen(try_path_prev) - 1] == '/' && prev[0] == '/') { + try_path_prev[strlen(try_path_prev) - 1] = '\0'; + } + + /* + * Duplicate the memory used by prev in case resolved_path and + * path are pointers for the same memory space + */ + cut_path = strdup(prev); + + /* Concatenate the strings */ + snprintf(resolved_path, size, "%s%s", try_path_prev, cut_path); + + /* Free the allocated memory */ + free(cut_path); + free(try_path_prev); + /* + * Else, we just copy the path in our resolved_path to + * return it as is + */ + } else { + strncpy(resolved_path, path, size); + } + + /* Then we return the 'partially' resolved path */ + return resolved_path; + +error: + free(resolved_path); + return NULL; +} + /* * 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 diff --git a/src/common/utils.h b/src/common/utils.h index c56942f56..036e416e7 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -27,6 +27,8 @@ #define GIBI_LOG2 30 char *utils_resolve_relative(const char *path); +char *utils_partial_realpath(const char *path, char *resolved_path, + size_t size); char *utils_expand_path(const char *path); int utils_create_pipe(int *dst); int utils_create_pipe_cloexec(int *dst); -- 2.34.1