>From 304b193729b4eb5218218a71320cb5c93b1d19ca 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..e48420d 100644 --- a/src/misc/realpath.c +++ b/src/misc/realpath.c @@ -9,13 +9,48 @@ void __procfdname(char *, unsigned); +int mergepaths(char *restrict a, const char *restrict r) +{ + size_t i, j; + i = j = 0; + + /* if r is absolute, skip a content */ + if (r[0] == '/') { + a[0] = '/'; + j = 1; + } else { + /* slash terminate a if needed */ + i = strlen(a)-1; + if (r[0] && (a[i-1] != '/')) a[i] = '/'; + else --i; + } + + /* resolve . and .. */ + for (; r[j]; ++j) { + if (r[j] == '.') { + if (r[j+1] == '/' || !r[j+1]) continue; + if (r[j+1] == '.' && (r[j+2] == '/' || !r[j+2])) { + while (i > 0 && a[--i] != '/'); + continue; + } + } else if (r[j] == '/' && a[i] == '/') continue; + a[++i] = r[j]; + } + /* terminate a */ + if (a[i] == '/' && i > 0) --i; + a[++i] = 0; + + return i; +} + char *realpath(const char *restrict filename, char *restrict resolved) { int fd; ssize_t r; + size_t i; struct stat st1, st2; char buf[15+3*sizeof(int)]; - char tmp[PATH_MAX]; + char tmp[PATH_MAX], link[PATH_MAX]; 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 */ + i = strlen(tmp) - 1; + while (i > 0 && tmp[--i] != '/'); + tmp[i] = 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