>From 5c2c2717e4bd8cf8a9f816c043e102e317e1d949 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 1 Nov 2016 12:53:53 +0100 Subject: [PATCH] realpath: add fallback processing without /proc --- src/misc/realpath.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/misc/realpath.c b/src/misc/realpath.c index 88c849c..b387b59 100644 --- a/src/misc/realpath.c +++ b/src/misc/realpath.c @@ -9,13 +9,48 @@ void __procfdname(char *, unsigned); +int mergepaths(char *restrict absolute, const char *restrict relative) +{ + char *a = absolute; + const char *r = relative; + + /* if relative is absolute, skip absolute */ + if (*r == '/') { + *a = '/'; + ++r; + } else { + /* slash terminate absolute if needed */ + for (; *a; ++a); + if (*r && (a[-1] != '/')) *a = '/'; + else --a; + } + + /* resolve . and .. */ + for (; *r; ++r) { + if (*r == '.') { + if (r[1] == '/' || !r[1]) continue; + if (r[1] == '.' && (r[2] == '/' || !r[2])) { + while (a > absolute && *--a != '/'); + continue; + } + } else if (*r == '/' && *a == '/') continue; + *++a = *r; + } + /* terminate absolute */ + if (*a == '/' && a > absolute) --a; + *++a = 0; + + return a - absolute; +} + char *realpath(const char *restrict filename, char *restrict resolved) { int fd; ssize_t r; struct stat st1, st2; char buf[15+3*sizeof(int)]; - char tmp[PATH_MAX]; + char tmp[PATH_MAX], link[PATH_MAX]; + char *p; if (!filename) { errno = EINVAL; @@ -27,7 +62,7 @@ char *realpath(const char *restrict filename, char *restrict resolved) __procfdname(buf, fd); r = readlink(buf, tmp, sizeof tmp - 1); - if (r < 0) goto err; + if (r < 0) goto noproc; tmp[r] = 0; fstat(fd, &st1); @@ -37,8 +72,34 @@ char *realpath(const char *restrict filename, char *restrict resolved) goto err; } +end: __syscall(SYS_close, fd); return resolved ? strcpy(resolved, tmp) : strdup(tmp); + +noproc: + if (*filename != '/') + if (syscall(SYS_getcwd, tmp, sizeof(tmp)) < 0) goto err; + + /* concatenate cwd and target */ + r = mergepaths(tmp, filename); + + if (lstat(tmp, &st1) < 0) goto err; + /* resolve link chain if any */ + while (S_ISLNK(st1.st_mode)) { + if ((r = readlink(tmp, link, sizeof(link))) < 0) goto err; + link[r] = 0; + + /* remove link name */ + for (p = tmp; *p; ++p); + while (p > tmp && *--p != '/'); + *p = 0; + + /* merge path and link target */ + mergepaths(tmp, link); + if (lstat(tmp, &st1) < 0) goto err; + } + goto end; + err: __syscall(SYS_close, fd); return 0; -- 2.10.2