X-Git-Url: https://git.saurik.com/apple/shell_cmds.git/blobdiff_plain/e1a085bab7df5bb0af9b495e350271357a7cd388..b5fe885ee63a0f46dc66d5ba8af23cad26f23e04:/find/function.c?ds=sidebyside diff --git a/find/function.c b/find/function.c index 0e6028e..a673a02 100644 --- a/find/function.c +++ b/find/function.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -41,7 +37,7 @@ static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95"; #endif /* not lint */ #include -__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.71 2011/06/13 05:22:07 avatar Exp $"); #include #include @@ -50,7 +46,6 @@ __FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion #include #include #include -#include #include #include @@ -67,15 +62,17 @@ __FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion #include #include -#include "find.h" - #ifdef __APPLE__ #include +#include +#include #include #else #define COMPAT_MODE(func, mode) 1 #endif +#include "find.h" + static PLAN *palloc(OPTION *); static long long find_parsenum(PLAN *, const char *, char *, char *); static long long find_parsetime(PLAN *, const char *, char *); @@ -84,6 +81,7 @@ static char *nextarg(OPTION *, char ***); extern char **environ; static PLAN *lastexecplus = NULL; +int execplus_error; #define COMPARE(a, b) do { \ switch (plan->flags & F_ELG_MASK) { \ @@ -320,10 +318,10 @@ f_Xtime(PLAN *plan, FTSENT *entry) else xtime = entry->fts_statp->st_mtime; - if (COMPAT_MODE("bin/find", "unix2003") || plan->flags & F_EXACTTIME) - COMPARE((now - xtime) / 86400, plan->t_data); + if (plan->flags & F_EXACTTIME) + COMPARE(now - xtime, plan->t_data); else - COMPARE((now - xtime + 86400 - 1) / 86400, plan->t_data); + COMPARE((now - xtime + (COMPAT_MODE("bin/find", "unix2003") ? 0 : 86400 - 1)) / 86400, plan->t_data); } PLAN * @@ -337,7 +335,7 @@ c_Xtime(OPTION *option, char ***argvp) new = palloc(option); new->t_data = find_parsetime(new, option->name, value); - if (!(new->flags & F_EXACTTIME)) + if (!(new->flags & F_EXACTTIME) && !COMPAT_MODE("bin/find", "unix2003")) TIME_CORRECT(new); return new; } @@ -370,56 +368,115 @@ c_mXXdepth(OPTION *option, char ***argvp) return new; } -#ifndef __APPLE__ /* * -acl function -- * * Show files with EXTENDED ACL attributes. */ +#ifdef __APPLE__ int f_acl(PLAN *plan __unused, FTSENT *entry) { - int match, entries; + acl_t facl; + int match; acl_entry_t ae; + + match = 0; + if ((facl = acl_get_link_np(entry->fts_accpath, ACL_TYPE_EXTENDED)) != NULL) { + if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 0) { + match = 1; + } + acl_free(facl); + } + return match; +} +#else /* !__APPLE__ */ +int +f_acl(PLAN *plan __unused, FTSENT *entry) +{ acl_t facl; + acl_type_t acl_type; + int acl_supported = 0, ret, trivial; if (S_ISLNK(entry->fts_statp->st_mode)) return 0; - if ((match = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED)) <= 0) { - if (match < 0 && errno != EINVAL) - warn("%s", entry->fts_accpath); - else - return 0; + ret = pathconf(entry->fts_accpath, _PC_ACL_NFS4); + if (ret > 0) { + acl_supported = 1; + acl_type = ACL_TYPE_NFS4; + } else if (ret < 0 && errno != EINVAL) { + warn("%s", entry->fts_accpath); + return (0); } - match = 0; - if ((facl = acl_get_file(entry->fts_accpath,ACL_TYPE_ACCESS)) != NULL) { - if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) { - /* - * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS - * must have at least three entries (owner, group, - * other). - */ - entries = 1; - while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) { - if (++entries > 3) { - match = 1; - break; - } - } + if (acl_supported == 0) { + ret = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED); + if (ret > 0) { + acl_supported = 1; + acl_type = ACL_TYPE_ACCESS; + } else if (ret < 0 && errno != EINVAL) { + warn("%s", entry->fts_accpath); + return (0); } - acl_free(facl); - } else + } + if (acl_supported == 0) + return (0); + + facl = acl_get_file(entry->fts_accpath, acl_type); + if (facl == NULL) { warn("%s", entry->fts_accpath); - return match; + return (0); + } + ret = acl_is_trivial_np(facl, &trivial); + acl_free(facl); + if (ret) { + warn("%s", entry->fts_accpath); + acl_free(facl); + return (0); + } + if (trivial) + return (0); + return (1); } +#endif /* __APPLE__ */ PLAN * c_acl(OPTION *option, char ***argvp __unused) { +#ifndef __APPLE__ ftsoptions &= ~FTS_NOSTAT; +#endif /* !__APPLE__ */ return (palloc(option)); } -#endif /* !__APPLE__ */ + +#ifdef __APPLE__ +int +f_xattr(PLAN *plan __unused, FTSENT *entry) +{ + ssize_t xattr; + int match; + + match = 0; + xattr = listxattr(entry->fts_accpath, NULL, 0, XATTR_NOFOLLOW); + if (xattr > 0) { + match = 1; + } + return match; +} + +int +f_xattrname(PLAN *plan, FTSENT *entry) +{ + ssize_t xattr; + int match; + + match = 0; + xattr = getxattr(entry->fts_accpath, plan->c_data, NULL, 0, 0, XATTR_NOFOLLOW); + if (xattr > 0) { + match = 1; + } + return match; +} +#endif /* __APPLE__ */ /* * -delete functions -- @@ -436,11 +493,13 @@ f_delete(PLAN *plan __unused, FTSENT *entry) /* sanity check */ if (isdepth == 0 || /* depth off */ - (ftsoptions & FTS_NOSTAT) || /* not stat()ing */ - !(ftsoptions & FTS_PHYSICAL) || /* physical off */ - (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */ + (ftsoptions & FTS_NOSTAT)) /* not stat()ing */ errx(1, "-delete: insecure options got turned on"); + if (!(ftsoptions & FTS_PHYSICAL) || /* physical off */ + (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */ + errx(1, "-delete: forbidden when symlinks are followed"); + /* Potentially unsafe - do not accept relative paths whatsoever */ if (strchr(entry->fts_accpath, '/') != NULL) errx(1, "-delete: %s: relative path potentially not safe", @@ -450,7 +509,7 @@ f_delete(PLAN *plan __unused, FTSENT *entry) if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && geteuid() == 0) - chflags(entry->fts_accpath, + lchflags(entry->fts_accpath, entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)); /* rmdir directories, unlink everything else */ @@ -471,8 +530,6 @@ c_delete(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; /* no optimise */ - ftsoptions |= FTS_PHYSICAL; /* disable -follow */ - ftsoptions &= ~FTS_LOGICAL; /* disable -follow */ isoutput = 1; /* possible output */ isdepth = 1; /* -depth implied */ @@ -483,7 +540,7 @@ c_delete(OPTION *option, char ***argvp __unused) /* * always_true -- * - * Always true, used for -maxdepth, -mindepth, -xdev and -follow + * Always true, used for -maxdepth, -mindepth, -xdev, -follow, and -true */ int f_always_true(PLAN *plan __unused, FTSENT *entry __unused) @@ -559,7 +616,7 @@ f_empty(PLAN *plan __unused, FTSENT *entry) empty = 1; dir = opendir(entry->fts_accpath); if (dir == NULL) - err(1, "%s", entry->fts_accpath); + return 0; for (dp = readdir(dir); dp; dp = readdir(dir)) if (dp->d_name[0] != '.' || (dp->d_name[1] != '\0' && @@ -663,8 +720,10 @@ doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv)) plan->e_psize = plan->e_pbsize; } pid = waitpid(pid, &status, 0); - if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status)) - _exit(WEXITSTATUS(status)); + if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status) && !execplus_error) { + /* Test 140 (8907531, 10656525) */ + execplus_error = WEXITSTATUS(status); + } return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status)); } @@ -771,7 +830,7 @@ done: *argvp = argv + 1; /* Finish any pending -exec ... {} + functions. */ void -finish_execplus() +finish_execplus(void) { PLAN *p; @@ -852,7 +911,8 @@ f_fstype(PLAN *plan, FTSENT *entry) static dev_t curdev; /* need a guaranteed illegal dev value */ static int first = 1; struct statfs sb; - static int val_type, val_flags; + static int val_flags; + static char fstype[sizeof(sb.f_fstypename)]; char *p, save[2] = {0,0}; if ((plan->flags & F_MTMASK) == F_MTUNKNOWN) @@ -894,13 +954,13 @@ f_fstype(PLAN *plan, FTSENT *entry) * always copy both of them. */ val_flags = sb.f_flags; - val_type = sb.f_type; + strlcpy(fstype, sb.f_fstypename, sizeof(fstype)); } switch (plan->flags & F_MTMASK) { case F_MTFLAG: return val_flags & plan->mt_data; case F_MTTYPE: - return val_type == plan->mt_data; + return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0); default: abort(); } @@ -911,22 +971,11 @@ c_fstype(OPTION *option, char ***argvp) { char *fsname; PLAN *new; - struct vfsconf vfc; fsname = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); - - /* - * Check first for a filesystem name. - */ - if (getvfsbyname(fsname, &vfc) == 0) { - new->flags |= F_MTTYPE; - new->mt_data = vfc.vfc_typenum; - return new; - } - switch (*fsname) { case 'l': if (!strcmp(fsname, "local")) { @@ -944,12 +993,8 @@ c_fstype(OPTION *option, char ***argvp) break; } - /* - * We need to make filesystem checks for filesystems - * that exists but aren't in the kernel work. - */ - fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname); - new->flags |= F_MTUNKNOWN; + new->flags |= F_MTTYPE; + new->c_data = fsname; return new; } @@ -981,7 +1026,7 @@ c_group(OPTION *option, char ***argvp) g = getgrnam(gname); if (g == NULL) { char* cp = gname; - if( gname[0] == '-' || gname[0] == '+' ) + if (gname[0] == '-' || gname[0] == '+') gname++; gid = atoi(gname); if (gid == 0 && gname[0] != '0') @@ -1019,6 +1064,30 @@ c_inum(OPTION *option, char ***argvp) return new; } +/* + * -samefile FN + * + * True if the file has the same inode (eg hard link) FN + */ + +/* f_samefile is just f_inum */ +PLAN * +c_samefile(OPTION *option, char ***argvp) +{ + char *fn; + PLAN *new; + struct stat sb; + + fn = nextarg(option, argvp); + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(option); + if (stat(fn, &sb)) + err(1, "%s", fn); + new->i_data = sb.st_ino; + return new; +} + /* * -links n functions -- * @@ -1074,7 +1143,31 @@ c_ls(OPTION *option, char ***argvp __unused) int f_name(PLAN *plan, FTSENT *entry) { - return !fnmatch(plan->c_data, entry->fts_name, + char fn[PATH_MAX]; + const char *name; + ssize_t len; + + if (plan->flags & F_LINK) { + /* + * The below test both avoids obviously useless readlink() + * calls and ensures that symlinks with existent target do + * not match if symlinks are being followed. + * Assumption: fts will stat all symlinks that are to be + * followed and will return the stat information. + */ + if (entry->fts_info != FTS_NSOK && entry->fts_info != FTS_SL && + entry->fts_info != FTS_SLNONE) + return 0; + len = readlink(entry->fts_accpath, fn, sizeof(fn) - 1); + if (len == -1) + return 0; + fn[len] = '\0'; + name = fn; + } else if (entry->fts_namelen == 0) { + name = basename(entry->fts_path); + } else + name = entry->fts_name; + return !fnmatch(plan->c_data, name, plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0); } @@ -1123,7 +1216,7 @@ c_newer(OPTION *option, char ***argvp) new = palloc(option); /* compare against what */ if (option->flags & F_TIME2_T) { - new->t_data = get_date(fn_or_tspec, (struct timeb *) 0); + new->t_data = get_date(fn_or_tspec); if (new->t_data == (time_t) -1) errx(1, "Can't parse date/time: %s", fn_or_tspec); } else { @@ -1133,6 +1226,8 @@ c_newer(OPTION *option, char ***argvp) new->t_data = sb.st_ctime; else if (option->flags & F_TIME2_A) new->t_data = sb.st_atime; + else if (option->flags & F_TIME2_B) + new->t_data = sb.st_birthtime; else new->t_data = sb.st_mtime; } @@ -1367,7 +1462,7 @@ c_regex(OPTION *option, char ***argvp) return new; } -/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */ +/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or, c_true, c_false */ PLAN * c_simple(OPTION *option, char ***argvp __unused) @@ -1649,3 +1744,29 @@ f_or(PLAN *plan, FTSENT *entry) } /* c_or == c_simple */ + +/* + * -false + * + * Always false. + */ +int +f_false(PLAN *plan __unused, FTSENT *entry __unused) +{ + return 0; +} + +/* c_false == c_simple */ + +/* + * -quit + * + * Exits the program + */ +int +f_quit(PLAN *plan __unused, FTSENT *entry __unused) +{ + exit(0); +} + +/* c_quit == c_simple */