From 358109442c37bec57efd053aa777fd34bfe39186 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 6 Sep 2021 11:18:13 -0500 Subject: [PATCH] Add find -lname -ilname and -d as a synonym for -depth. --- lib/lib.h | 1 + lib/xwrap.c | 10 ++++++++-- toys/posix/find.c | 17 +++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/lib.h b/lib/lib.h index b7c6446e..920f0b3b 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -183,6 +183,7 @@ struct group *xgetgrnam(char *name); unsigned xgetuid(char *name); unsigned xgetgid(char *name); void xsetuser(struct passwd *pwd); +char *xreadlinkat(int dir, char *name); char *xreadlink(char *name); double xstrtod(char *s); long xparsetime(char *arg, long units, long *fraction); diff --git a/lib/xwrap.c b/lib/xwrap.c index 7296f580..d2680cda 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -751,7 +751,7 @@ void xsetuser(struct passwd *pwd) // This can return null (meaning file not found). It just won't return null // for memory allocation reasons. -char *xreadlink(char *name) +char *xreadlinkat(int dir, char *name) { int len, size = 0; char *buf = 0; @@ -760,7 +760,7 @@ char *xreadlink(char *name) for(;;) { size +=64; buf = xrealloc(buf, size); - len = readlink(name, buf, size); + len = readlinkat(dir, name, buf, size); if (len<0) { free(buf); @@ -773,6 +773,12 @@ char *xreadlink(char *name) } } +char *xreadlink(char *name) +{ + return xreadlinkat(AT_FDCWD, name); +} + + char *xreadfile(char *name, char *buf, off_t len) { if (!(buf = readfile(name, buf, len))) perror_exit("Bad '%s'", name); diff --git a/toys/posix/find.c b/toys/posix/find.c index 5d3f8e3e..f3d10f53 100644 --- a/toys/posix/find.c +++ b/toys/posix/find.c @@ -7,6 +7,7 @@ * Our "unspecified" behavior for no paths is to use "." * Parentheses can only stack 4096 deep * Not treating two {} as an error, but only using last + * TODO: -context USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN)) @@ -306,7 +307,7 @@ static int do_find(struct dirtree *new) if (new && check) test = !unlinkat(dirtree_parentfd(new), new->name, S_ISDIR(new->st.st_mode) ? AT_REMOVEDIR : 0); - } else if (!strcmp(s, "depth")) TT.depth = 1; + } else if (!strcmp(s, "depth") || !strcmp(s, "d")) TT.depth = 1; else if (!strcmp(s, "o") || !strcmp(s, "or")) { if (not) goto error; if (active) { @@ -363,13 +364,16 @@ static int do_find(struct dirtree *new) } else { if (!strcmp(s, "name") || !strcmp(s, "iname") || !strcmp(s, "wholename") || !strcmp(s, "iwholename") - || !strcmp(s, "path") || !strcmp(s, "ipath")) + || !strcmp(s, "path") || !strcmp(s, "ipath") + || !strcmp(s, "lname") || !strcmp(s, "ilname")) { int i = (*s == 'i'), is_path = (s[i] != 'n'); char *arg = ss[1], *path = 0, *name = new ? new->name : arg; // Handle path expansion and case flattening - if (new && is_path) name = path = dirtree_path(new, 0); + if (new && s[i] == 'l') + name = path = xreadlinkat(dirtree_parentfd(new), new->name); + else if (new && is_path) name = path = dirtree_path(new, 0); if (i) { if ((check || !new) && name) name = strlower(name); if (!new) dlist_add(&TT.argdata, name); @@ -377,7 +381,7 @@ static int do_find(struct dirtree *new) } if (check) { - test = !fnmatch(arg, is_path ? name : basename(name), + test = !fnmatch(arg, path ? name : basename(name), FNM_PATHNAME*(!is_path)); if (i) free(name); } @@ -630,10 +634,7 @@ static int do_find(struct dirtree *new) else if (ch == 'g') ll = (long)getgroupname(new->st.st_gid); else if (ch == 'u') ll = (long)getusername(new->st.st_uid); else if (ch == 'l') { - char *path = dirtree_path(new, 0); - - ll = (long)(ff = xreadlink(path)); - free(path); + ll = (long)(ff = xreadlinkat(dirtree_parentfd(new), new->name)); if (!ll) ll = (long)""; } else if (ch == 'M') { mode_to_string(new->st.st_mode, buf); -- 2.39.2