diff --git a/src/nnn.c b/src/nnn.c index 3c637896..0980e445 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -1027,6 +1027,59 @@ static char *common_prefix(const char *s, char *prefix) return prefix; } +/* + * The library function realpath() resolves symlinks. + * If there's a symlink in file list we want to show the symlink not what it's points to. + */ +static char *xrealpath(const char *path, const char *cwd) +{ + if (!path || !cwd) + return NULL; + + size_t dst_size = 0, src_size = strlen(path), cwd_size = strlen(cwd); + const char *src, *next; + char *dst; + char *resolved_path = malloc(src_size + (*path == '/' ? 0 : cwd_size) + 1); + if (!resolved_path) + return NULL; + + /* Turn relative paths into absolute */ + if (path[0] != '/') + dst_size = xstrlcpy(resolved_path, cwd, cwd_size + 1) - 1; + else + resolved_path[0] = '\0'; + + src = path; + dst = resolved_path + dst_size; + for (next = NULL; next != path + src_size;) { + next = strchr(src, '/'); + if (!next) + next = path + src_size; + + if (next - src == 2 && src[0] == '.' && src[1] == '.') { + if (dst - resolved_path) { + dst = xmemrchr((uchar *)resolved_path, '/', dst-resolved_path); + *dst = '\0'; + } + } else if (next - src == 1 && src[0] == '.') { + /* NOP */ + } else if (next - src) { + *(dst++) = '/'; + xstrlcpy(dst, src, next - src + 1); + dst += next - src; + } + + src = next + 1; + } + + if (*resolved_path == '\0') { + resolved_path[0] = '/'; + resolved_path[1] = '\0'; + } + + return resolved_path; +} + static char *xbasename(char *path) { char *base = xmemrchr((uchar *)path, '/', strlen(path)); // NOLINT @@ -6201,10 +6254,12 @@ static char *load_input() DPRINTF_S(paths[0]); for (i = 0; i < entries; ++i) { - if (selforparent(paths[i])) + if (selforparent(paths[i])) { + paths[i] = NULL; continue; + } - if (!(paths[i] = realpath(paths[i], NULL))) { + if (!(paths[i] = xrealpath(paths[i], cwd))) { entries = i; // free from the previous entry goto malloc_2;