From 4ad13b57a8c7b95dd375f4ef71f267af7f41e16e Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Sat, 4 Apr 2020 13:15:13 +0200 Subject: [PATCH] Calculate_relative_path(): fix when using symlinks --- src/io.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/io.c b/src/io.c index 84637379..0ce23ba1 100644 --- a/src/io.c +++ b/src/io.c @@ -1131,6 +1131,7 @@ int Remove_directory(const char * path) char * Calculate_relative_path(const char * ref_path, const char * path) { char * real_ref_path; + char * real_path; char * rel_path = NULL; int last_separator = -1; int i; @@ -1142,67 +1143,75 @@ char * Calculate_relative_path(const char * ref_path, const char * path) real_ref_path = Realpath(ref_path, NULL); if (real_ref_path == NULL) real_ref_path = strdup(ref_path); + real_path = Realpath(path, NULL); + if (real_path == NULL) + real_path = strdup(path); #if defined(WIN32) || defined(__MINT__) - if (real_ref_path[1] == ':' && path[1] == ':') + if (real_ref_path[1] == ':' && real_path[1] == ':') { // use same case for drive letter - real_ref_path[0] = (real_ref_path[0] & ~32) | (path[0] & 32); - if (real_ref_path[0] != path[0]) + real_ref_path[0] = (real_ref_path[0] & ~32) | (real_path[0] & 32); + if (real_ref_path[0] != real_path[0]) { free(real_ref_path); + free(real_path); return NULL; // path on different volumes, not possible } } #endif // look for common path parts - for (i = 0; real_ref_path[i] == path[i] && path[i] != '\0'; i++) + for (i = 0; real_ref_path[i] == real_path[i] && real_path[i] != '\0'; i++) { - if (path[i] == PATH_SEPARATOR[0]) + if (real_path[i] == PATH_SEPARATOR[0]) last_separator = i; #if defined(WIN32) - else if(path[i] == '/') + else if(real_path[i] == '/') last_separator = i; #endif } // at this point, all chars from index 0 to i-1 are identical in // real_ref_path and path. // real_ref_path[i] and path[i] are either different, or both '\0' - if (real_ref_path[i] == PATH_SEPARATOR[0] && real_ref_path[i + 1] == '\0' && path[i] == '\0') + if (real_ref_path[i] == PATH_SEPARATOR[0] && real_ref_path[i + 1] == '\0' && real_path[i] == '\0') { free(real_ref_path); + free(real_path); return strdup("."); // path are identical (real_ref_path has additional trailing separator) } if (real_ref_path[i] == '\0') { - if (path[i] == '\0') + if (real_path[i] == '\0') { free(real_ref_path); + free(real_path); return strdup("."); // path are identical } // path is under ref_path - if (path[i] == PATH_SEPARATOR[0]) + if (real_path[i] == PATH_SEPARATOR[0]) { free(real_ref_path); - len = strlen(path + i) + 1; + len = strlen(real_path + i) + 1; rel_path = GFX2_malloc(len + 1); if (rel_path != NULL) - snprintf(rel_path, len + 1, ".%s", path + i); + snprintf(rel_path, len + 1, ".%s", real_path + i); + free(real_path); return rel_path; } else if (i > 0 && real_ref_path[i - 1] == PATH_SEPARATOR[0]) { free(real_ref_path); - len = strlen(path + i - 1) + 1; + len = strlen(real_path + i - 1) + 1; rel_path = GFX2_malloc(len + 1); if (rel_path != NULL) - snprintf(rel_path, len + 1, ".%s", path + i - 1); + snprintf(rel_path, len + 1, ".%s", real_path + i - 1); + free(real_path); return rel_path; } } if (last_separator <= 0) { free(real_ref_path); - return strdup(path); // no common part found return absolute path + return real_path; // no common part found return absolute path } // count the number of path separators in the reference path for (i = last_separator; real_ref_path[i] != '\0'; i++) @@ -1213,15 +1222,16 @@ char * Calculate_relative_path(const char * ref_path, const char * path) free(real_ref_path); i = 0; // construct the relative path - len = separator_count * (2 + strlen(PATH_SEPARATOR)) + strlen(path + last_separator + 1) + 1; + len = separator_count * (2 + strlen(PATH_SEPARATOR)) + strlen(real_path + last_separator + 1) + 1; rel_path = GFX2_malloc(len + 1); if (rel_path != NULL) { while(separator_count-- > 0) i += snprintf(rel_path + i, len + 1 - i, "..%s", PATH_SEPARATOR); - strncpy(rel_path + i, path + last_separator + 1, len + 1 - i); + strncpy(rel_path + i, real_path + last_separator + 1, len + 1 - i); rel_path[len] = '\0'; } + free(real_path); return rel_path; }