diff options
-rw-r--r-- | lib/xwrap.c | 49 | ||||
-rwxr-xr-x | tests/readlink.test | 3 | ||||
-rw-r--r-- | toys/other/readlink.c | 9 |
3 files changed, 37 insertions, 24 deletions
diff --git a/lib/xwrap.c b/lib/xwrap.c index 562cbaf4..54985db3 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -481,7 +481,7 @@ void xstat(char *path, struct stat *st) char *xabspath(char *path, int exact) { struct string_list *todo, *done = 0; - int try = 9999, dirfd = open("/", 0);; + int try = 9999, dirfd = open("/", 0), missing = 0; char *ret; // If this isn't an absolute path, start with cwd. @@ -492,11 +492,12 @@ char *xabspath(char *path, int exact) free(temp); } else splitpath(path, &todo); - // Iterate through path components + // Iterate through path components in todo, prepend processed ones to done. while (todo) { struct string_list *new = llist_pop(&todo), **tail; ssize_t len; + // Eventually break out of endless loops if (!try--) { errno = ELOOP; goto error; @@ -507,29 +508,37 @@ char *xabspath(char *path, int exact) int x = new->str[1]; free(new); - if (x) { - if (done) free(llist_pop(&done)); - len = 0; - } else continue; + if (!x) continue; + if (done) free(llist_pop(&done)); + len = 0; + + if (missing) missing--; + else { + if (-1 == (x = openat(dirfd, "..", 0))) goto error; + close(dirfd); + dirfd = x; + } + continue; + } // Is this a symlink? - } else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf)); - + len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf)); if (len>4095) goto error; + + // Not a symlink: add to linked list, move dirfd, fail if error if (len<1) { int fd; - char *s = ".."; - - // For .. just move dirfd - if (len) { - // Not a symlink: add to linked list, move dirfd, fail if error - if ((exact || todo) && errno != EINVAL) goto error; - new->next = done; - done = new; - if (errno == EINVAL && !todo) break; - s = new->str; + + new->next = done; + done = new; + if (errno == EINVAL && !todo) break; + if (errno == ENOENT && exact<0) { + missing++; + continue; } - fd = openat(dirfd, s, 0); + if (errno != EINVAL && (exact || todo)) goto error; + + fd = openat(dirfd, new->str, 0); if (fd == -1 && (exact || todo || errno != ENOENT)) goto error; close(dirfd); dirfd = fd; @@ -588,7 +597,7 @@ error: llist_traverse(todo, free); llist_traverse(done, free); - return NULL; + return 0; } void xchdir(char *path) diff --git a/tests/readlink.test b/tests/readlink.test index 48104e58..52121770 100755 --- a/tests/readlink.test +++ b/tests/readlink.test @@ -48,6 +48,9 @@ testing "-f link/missing" "readlink -f dir/boing" \ "$APWD/sub/boing\n" "" "" testing "-f /dev/null/file" \ "readlink -f /dev/null/file 2>/dev/null || echo yes" "yes\n" "" "" +testing "-m missing/dir" "readlink -m sub/two/three" "$APWD/sub/two/three\n" "" "" +testing "-m missing/../elsewhere" "readlink -m sub/two/../../three" "$APWD/three\n" "" "" +testing "-m file/dir" "readlink -m sub/bang/two 2>/dev/null || echo err" "err\n" "" "" rm link ln -sf / link || exit 1 testing "-f link->/" "readlink -e link/dev" "/dev\n" "" "" diff --git a/toys/other/readlink.c b/toys/other/readlink.c index fecd1ef8..2e0cf11e 100644 --- a/toys/other/readlink.c +++ b/toys/other/readlink.c @@ -2,7 +2,7 @@ * * Copyright 2007 Rob Landley <rob@landley.net> -USE_READLINK(NEWTOY(readlink, "<1>1fenq[-fe]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_READLINK(NEWTOY(readlink, "<1>1nqmef[-mef]", TOYFLAG_USR|TOYFLAG_BIN)) config READLINK bool "readlink" @@ -16,6 +16,7 @@ config READLINK -e cannonical path to existing entry (fail if missing) -f full path (fail if directory missing) + -m ignore missing entries, show where it would be -n no trailing newline -q quiet (no output, just error code) */ @@ -28,9 +29,9 @@ void readlink_main(void) char *s; // Calculating full cannonical path? - - if (toys.optflags & (FLAG_f|FLAG_e)) - s = xabspath(*toys.optargs, toys.optflags & FLAG_e); + // Take advantage of flag positions to calculate m = -1, f = 0, e = 1 + if (toys.optflags & (FLAG_f|FLAG_e|FLAG_m)) + s = xabspath(*toys.optargs, (toys.optflags&(FLAG_f|FLAG_e))-1); else s = xreadlink(*toys.optargs); if (s) { |