- expanded_path_len = 0;
-
- /* We iterate over the provided path to expand the "//", "../" and "./" */
- for (curr_char = path; curr_char <= path_last_char; curr_char = next_slash + 1) {
- /* Find the next forward slash. */
- size_t curr_token_len;
-
- if (curr_char == path_last_char) {
- expanded_path_len++;
- break;
- }
-
- next_slash = memchr(curr_char, '/', path_last_char - curr_char);
- if (next_slash == NULL) {
- /* Reached the end of the provided path. */
- next_slash = path_last_char;
- }
-
- /* Compute how long is the previous token. */
- curr_token_len = next_slash - curr_char;
- switch(curr_token_len) {
- case 0:
- /*
- * The pointer has not move meaning that curr_char is
- * pointing to a slash. It that case there is no token
- * to copy, so continue the iteration to find the next
- * token
- */
- continue;
- case 1:
- /*
- * The pointer moved 1 character. Check if that
- * character is a dot ('.'), if it is: omit it, else
- * copy the token to the normalized path.
- */
- if (curr_char[0] == '.') {
- continue;
- }
- break;
- case 2:
- /*
- * The pointer moved 2 characters. Check if these
- * characters are double dots ('..'). If that is the
- * case, we need to remove the last token of the
- * normalized path.
- */
- if (curr_char[0] == '.' && curr_char[1] == '.') {
- /*
- * Find the previous path component by
- * using the memrchr function to find the
- * previous forward slash and substract that
- * len to the resulting path.
- */
- prev_slash = lttng_memrchr(path, '/', expanded_path_len);
- /*
- * If prev_slash is NULL, we reached the
- * beginning of the path. We can't go back any
- * further.
- */
- if (prev_slash != NULL) {
- expanded_path_len = prev_slash - path;
- }
- continue;
- }
- break;
- default:
- break;
- }
-
- /*
- * Copy the current token which is neither a '.' nor a '..'.
- */
- path[expanded_path_len++] = '/';
- memcpy(&path[expanded_path_len], curr_char, curr_token_len);
- expanded_path_len += curr_token_len;
- }
-
- if (expanded_path_len == 0) {
- path[expanded_path_len++] = '/';
- }
-
- path[expanded_path_len] = '\0';
-
-error:
- return path;
-}
-
-/*
- * Make a full resolution of the given path even if it doesn't exist.
- * This function uses the utils_partial_realpath function to resolve
- * symlinks and relatives paths at the start of the string, and
- * implements functionnalities to resolve the './' and '../' strings
- * in the middle of a path. This function is only necessary because
- * realpath(3) does not accept to resolve unexistent paths.
- * The returned string was allocated in the function, it is thus of
- * the responsibility of the caller to free this memory.
- */
-LTTNG_HIDDEN
-char *_utils_expand_path(const char *path, bool keep_symlink)
-{
- char *absolute_path = NULL;
- char *last_token;
- int is_dot, is_dotdot;
-
- /* 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;
- }
-
- if (path[0] == '/') {
- strncpy(absolute_path, path, PATH_MAX);
- } else {
- /*
- * This is a relative path. We need to get the present working
- * directory and start the path walk from there.
- */
- char current_working_dir[PATH_MAX];
- char *cwd_ret;
- cwd_ret = getcwd(current_working_dir, sizeof(current_working_dir));
- if (!cwd_ret) {
- goto error;
- }
- /*
- * Get the number of character in the CWD and allocate an array
- * to can hold it and the path provided by the caller.
- */
- snprintf(absolute_path, PATH_MAX, "%s/%s", current_working_dir, path);
- }
-
- if (keep_symlink) {
- /* Resolve partially our path */
- absolute_path = utils_partial_realpath(absolute_path,
- absolute_path, PATH_MAX);
- }
-
- absolute_path = expand_double_slashes_dot_and_dotdot(absolute_path);
- if (!absolute_path) {
- goto error;
- }
-
- /* Identify the last token */
- last_token = strrchr(absolute_path, '/');
-
- /* Verify that this token is not a relative path */
- is_dotdot = (strcmp(last_token, "/..") == 0);
- is_dot = (strcmp(last_token, "/.") == 0);
-
- /* If it is, take action */
- if (is_dot || is_dotdot) {
- /* For both, remove this token */
- *last_token = '\0';
-
- /* If it was a reference to parent directory, go back one more time */
- if (is_dotdot) {
- last_token = strrchr(absolute_path, '/');
-
- /* If there was only one level left, we keep the first '/' */
- if (last_token == absolute_path) {
- last_token++;
- }