diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2014-11-20 04:14:16 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2014-11-20 04:14:16 +0000 |
commit | 0c60510cc1e3678cd9899e29038eee130b7b8673 (patch) | |
tree | e55c63ffd2b6885cc951e0a17e58cdc29925b7d0 /lib/libc/gen | |
parent | b13ed843019bc939d9da2e2970ec18b2a7896f72 (diff) |
Merge from FreeBSD:
--------
r260571 | jilles | 2014-01-12 12:30:55 -0800 (Sun, 12 Jan 2014) | 9 lines
fts: Stat things relative to the directory fd, if possible.
As a result, the kernel needs to process shorter pathnames if fts is not
changing directories (if fts follows symlinks (-L option to utilities), fts
cannot open "." or FTS_NOCHDIR was specified).
Side effect: If pathnames exceed PATH_MAX, [ENAMETOOLONG] is not hit at the
stat stage but later (opendir or application fts_accpath) or not at all.
--------
Prompted by a similar diff from (enh (at) google.com), who also reran a
performance test.
ok millert@
Diffstat (limited to 'lib/libc/gen')
-rw-r--r-- | lib/libc/gen/fts.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index 7af5d4a2382..afe5992b64a 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fts.c,v 1.47 2014/10/08 04:36:23 deraadt Exp $ */ +/* $OpenBSD: fts.c,v 1.48 2014/11/20 04:14:15 guenther Exp $ */ /*- * Copyright (c) 1990, 1993, 1994 @@ -49,7 +49,7 @@ static size_t fts_maxarglen(char * const *); static void fts_padjust(FTS *, FTSENT *); static int fts_palloc(FTS *, size_t); static FTSENT *fts_sort(FTS *, FTSENT *, int); -static u_short fts_stat(FTS *, FTSENT *, int); +static u_short fts_stat(FTS *, FTSENT *, int, int); static int fts_safe_changedir(FTS *, FTSENT *, int, char *); #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) @@ -116,7 +116,7 @@ fts_open(char * const *argv, int options, p->fts_level = FTS_ROOTLEVEL; p->fts_parent = parent; p->fts_accpath = p->fts_name; - p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1); /* Command-line "." and ".." are real directories. */ if (p->fts_info == FTS_DOT) @@ -270,7 +270,7 @@ fts_read(FTS *sp) /* Any type of file may be re-visited; re-stat and re-turn. */ if (instr == FTS_AGAIN) { - p->fts_info = fts_stat(sp, p, 0); + p->fts_info = fts_stat(sp, p, 0, -1); return (p); } @@ -282,7 +282,7 @@ fts_read(FTS *sp) */ if (instr == FTS_FOLLOW && (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { - p->fts_info = fts_stat(sp, p, 1); + p->fts_info = fts_stat(sp, p, 1, -1); if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) { p->fts_errno = errno; @@ -371,7 +371,7 @@ next: tmp = p; if (p->fts_instr == FTS_SKIP) goto next; if (p->fts_instr == FTS_FOLLOW) { - p->fts_info = fts_stat(sp, p, 1); + p->fts_info = fts_stat(sp, p, 1, -1); if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) { @@ -716,10 +716,11 @@ mem1: saved_errno = errno; if (ISSET(FTS_NOCHDIR)) { p->fts_accpath = p->fts_path; memmove(cp, p->fts_name, p->fts_namelen + 1); - } else + p->fts_info = fts_stat(sp, p, 0, dirfd(dirp)); + } else { p->fts_accpath = p->fts_name; - /* Stat it. */ - p->fts_info = fts_stat(sp, p, 0); + p->fts_info = fts_stat(sp, p, 0, -1); + } /* Decrement link count if applicable. */ if (nlinks > 0 && (p->fts_info == FTS_D || @@ -786,13 +787,20 @@ mem1: saved_errno = errno; } static u_short -fts_stat(FTS *sp, FTSENT *p, int follow) +fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) { FTSENT *t; dev_t dev; ino_t ino; struct stat *sbp, sb; int saved_errno; + const char *path; + + if (dfd == -1) { + path = p->fts_accpath; + dfd = AT_FDCWD; + } else + path = p->fts_name; /* If user needs stat info, stat buffer already allocated. */ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; @@ -803,16 +811,16 @@ fts_stat(FTS *sp, FTSENT *p, int follow) * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { - if (stat(p->fts_accpath, sbp)) { + if (fstatat(dfd, path, sbp, 0)) { saved_errno = errno; - if (!lstat(p->fts_accpath, sbp)) { + if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { errno = 0; return (FTS_SLNONE); } p->fts_errno = saved_errno; goto err; } - } else if (lstat(p->fts_accpath, sbp)) { + } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { p->fts_errno = errno; err: memset(sbp, 0, sizeof(struct stat)); return (FTS_NS); |