diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2016-08-28 04:09:00 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2016-08-28 04:09:00 +0000 |
commit | d2384f62b868ac27ea234d65577933862ca99188 (patch) | |
tree | 22fab5b8e9cbff000d9a368e3f402ca4505365ee | |
parent | c60a4319a91c5edb15e1427a612eb600216dd5ec (diff) |
Don't call lstat() before readlink() just to see if it's a symlink,
as readlink() will tell you that more cheaply.
ok millert@
-rw-r--r-- | lib/libc/stdlib/realpath.c | 31 | ||||
-rw-r--r-- | libexec/ld.so/dl_realpath.c | 38 |
2 files changed, 38 insertions, 31 deletions
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c index 27f1a29061d..c691252ccf5 100644 --- a/lib/libc/stdlib/realpath.c +++ b/lib/libc/stdlib/realpath.c @@ -1,4 +1,4 @@ -/* $OpenBSD: realpath.c,v 1.20 2015/10/13 20:55:37 millert Exp $ */ +/* $OpenBSD: realpath.c,v 1.21 2016/08/28 04:08:59 guenther Exp $ */ /* * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> * @@ -27,8 +27,6 @@ * SUCH DAMAGE. */ -#include <sys/stat.h> - #include <errno.h> #include <stdlib.h> #include <string.h> @@ -47,7 +45,6 @@ char * realpath(const char *path, char *resolved) { - struct stat sb; char *p, *q, *s; size_t left_len, resolved_len; unsigned symlinks; @@ -148,21 +145,27 @@ realpath(const char *path, char *resolved) errno = ENAMETOOLONG; goto err; } - if (lstat(resolved, &sb) != 0) { - if (errno == ENOENT && p == NULL) { - errno = serrno; - return (resolved); + slen = readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) { + switch (errno) { + case EINVAL: + /* not a symlink, continue to next component */ + continue; + case ENOENT: + if (p == NULL) { + errno = serrno; + return (resolved); + } + /* FALLTHROUGH */ + default: + goto err; } - goto err; - } - if (S_ISLNK(sb.st_mode)) { + } else { if (symlinks++ > SYMLOOP_MAX) { errno = ELOOP; goto err; } - slen = readlink(resolved, symlink, sizeof(symlink) - 1); - if (slen < 0) - goto err; + symlink[slen] = '\0'; if (symlink[0] == '/') { resolved[1] = 0; diff --git a/libexec/ld.so/dl_realpath.c b/libexec/ld.so/dl_realpath.c index 498ee3ca054..91a86686b87 100644 --- a/libexec/ld.so/dl_realpath.c +++ b/libexec/ld.so/dl_realpath.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dl_realpath.c,v 1.3 2014/10/19 03:56:28 doug Exp $ */ +/* $OpenBSD: dl_realpath.c,v 1.4 2016/08/28 04:08:59 guenther Exp $ */ /* * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> * @@ -28,11 +28,10 @@ */ #include <sys/types.h> +#include <sys/errno.h> #include <limits.h> #include "archdep.h" -#define ENOENT -2 - /* * This file was copied from libc/stdlib/realpath.c and modified for ld.so's * syscall method which returns -errno. @@ -48,12 +47,11 @@ char * _dl_realpath(const char *path, char *resolved) { - struct stat sb; const char *p, *s; char *q; size_t left_len, resolved_len; unsigned symlinks; - int slen, mem_allocated, ret; + int slen, mem_allocated; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; if (path[0] == '\0') { @@ -135,27 +133,33 @@ _dl_realpath(const char *path, char *resolved) } /* - * Append the next path component and lstat() it. If - * lstat() fails we still can return successfully if - * there are no more path components left. + * Append the next path component and readlink() it. If + * readlink() fails we still can return successfully if + * it wasn't a exists but isn't a symlink, or if there + * are no more path components left. */ resolved_len = _dl_strlcat(resolved, next_token, PATH_MAX); if (resolved_len >= PATH_MAX) { goto err; } - if ((ret = _dl_lstat(resolved, &sb)) != 0) { - if (ret == ENOENT && p == NULL) { - return (resolved); + slen = _dl_readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) { + switch (slen) { + case -EINVAL: + /* not a symlink, continue to next component */ + continue; + case -ENOENT: + if (p == NULL) + return (resolved); + /* FALLTHROUGH */ + default: + goto err; } - goto err; - } - if (S_ISLNK(sb.st_mode)) { + } else { if (symlinks++ > SYMLOOP_MAX) { goto err; } - slen = _dl_readlink(resolved, symlink, sizeof(symlink) - 1); - if (slen < 0) - goto err; + symlink[slen] = '\0'; if (symlink[0] == '/') { resolved[1] = 0; |