From 7bd0f40e2166788a91f0015cb7386e44f105fad8 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Tue, 25 Sep 2018 18:23:47 -0700 Subject: [PATCH] ls: Use *at functions instead of changing working directory --- ls.c | 52 ++++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/ls.c b/ls.c index b716aba..7535c0b 100644 --- a/ls.c +++ b/ls.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -55,18 +56,18 @@ static int first = 1; static char sort = 0; static int showdirs; -static void ls(const char *, const struct entry *, int); +static void ls(int, const char *, const struct entry *, int); static void -mkent(struct entry *ent, char *path, int dostat, int follow) +mkent(int dirfd, struct entry *ent, char *path, int dostat, int follow) { struct stat st; ent->name = path; if (!dostat) return; - if ((follow ? stat : lstat)(path, &st) < 0) - eprintf("%s %s:", follow ? "stat" : "lstat", path); + if (fstatat(dirfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) + eprintf("stat %s:", path); ent->mode = st.st_mode; ent->nlink = st.st_nlink; ent->uid = st.st_uid; @@ -130,7 +131,7 @@ printname(const char *name) } static void -output(const struct entry *ent) +output(int dirfd, const struct entry *ent) { struct group *gr; struct passwd *pw; @@ -208,7 +209,7 @@ output(const struct entry *ent) printname(ent->name); fputs(indicator(ent->mode), stdout); if (S_ISLNK(ent->mode)) { - if ((len = readlink(ent->name, buf, sizeof(buf) - 1)) < 0) + if ((len = readlinkat(dirfd, ent->name, buf, sizeof(buf) - 1)) < 0) eprintf("readlink %s:", ent->name); buf[len] = '\0'; printf(" -> %s%s", buf, indicator(ent->tmode)); @@ -239,7 +240,7 @@ entcmp(const void *va, const void *vb) } static void -lsdir(const char *path, const struct entry *dir) +lsdir(int dirfd, const char *path, const struct entry *dir) { DIR *dp; struct entry *ent, *ents = NULL; @@ -247,13 +248,12 @@ lsdir(const char *path, const struct entry *dir) size_t i, n = 0; char prefix[PATH_MAX]; - if (!(dp = opendir(dir->name))) { + dirfd = openat(dirfd, dir->name, O_RDONLY|O_DIRECTORY); + if (dirfd < 0 || !(dp = fdopendir(dirfd))) { ret = 1; weprintf("opendir %s%s:", path, dir->name); return; } - if (chdir(dir->name) < 0) - eprintf("chdir %s:", dir->name); while ((d = readdir(dp))) { if (d->d_name[0] == '.' && !aflag && !Aflag) @@ -264,12 +264,10 @@ lsdir(const char *path, const struct entry *dir) continue; ents = ereallocarray(ents, ++n, sizeof(*ents)); - mkent(&ents[n - 1], estrdup(d->d_name), Fflag || iflag || + mkent(dirfd, &ents[n - 1], estrdup(d->d_name), Fflag || iflag || lflag || pflag || Rflag || sort, Lflag); } - closedir(dp); - if (!Uflag) qsort(ents, n, sizeof(*ents), entcmp); @@ -279,7 +277,7 @@ lsdir(const char *path, const struct entry *dir) puts(":"); } for (i = 0; i < n; i++) - output(&ents[i]); + output(dirfd, &ents[i]); if (Rflag) { if (snprintf(prefix, PATH_MAX, "%s%s/", path, dir->name) >= @@ -294,13 +292,14 @@ lsdir(const char *path, const struct entry *dir) if (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Lflag) continue; - ls(prefix, ent, 1); + ls(dirfd, prefix, ent, 1); } } for (i = 0; i < n; ++i) free(ents[i].name); free(ents); + closedir(dp); } static int @@ -325,13 +324,12 @@ visit(const struct entry *ent) } static void -ls(const char *path, const struct entry *ent, int listdir) +ls(int dirfd, const char *path, const struct entry *ent, int listdir) { int treeind; - char cwd[PATH_MAX]; if (!listdir) { - output(ent); + output(dirfd, ent); } else if (S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode))) { if ((treeind = visit(ent)) < 0) { @@ -340,19 +338,13 @@ ls(const char *path, const struct entry *ent, int listdir) return; } - if (!getcwd(cwd, PATH_MAX)) - eprintf("getcwd:"); - if (first) first = 0; else putchar('\n'); - lsdir(path, ent); + lsdir(dirfd, path, ent); tree[treeind].ino = 0; - - if (chdir(cwd) < 0) - eprintf("chdir %s:", cwd); } } @@ -446,15 +438,15 @@ main(int argc, char *argv[]) case 0: /* fallthrough */ *--argv = ".", ++argc; case 1: - mkent(&ent, argv[0], 1, Hflag || Lflag); - ls("", &ent, (!dflag && S_ISDIR(ent.mode)) || + mkent(AT_FDCWD, &ent, argv[0], 1, Hflag || Lflag); + ls(AT_FDCWD, "", &ent, (!dflag && S_ISDIR(ent.mode)) || (S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) && !(dflag || Fflag || lflag))); break; default: for (i = ds = fs = 0, fents = dents = NULL; i < argc; ++i) { - mkent(&ent, argv[i], 1, Hflag || Lflag); + mkent(AT_FDCWD, &ent, argv[i], 1, Hflag || Lflag); if ((!dflag && S_ISDIR(ent.mode)) || (S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) && @@ -473,12 +465,12 @@ main(int argc, char *argv[]) qsort(dents, ds, sizeof(ent), entcmp); for (i = 0; i < fs; ++i) - ls("", &fents[i], 0); + ls(AT_FDCWD, "", &fents[i], 0); free(fents); if (fs && ds) putchar('\n'); for (i = 0; i < ds; ++i) - ls("", &dents[i], 1); + ls(AT_FDCWD, "", &dents[i], 1); free(dents); } -- 2.17.1