X-Git-Url: https://git.saurik.com/apple/file_cmds.git/blobdiff_plain/c59d3020309de26dad218fd055f00ee3dca42cf2..e19e38b253de139e081f5d462bc053e7b809ea38:/chown/chown.c diff --git a/chown/chown.c b/chown/chown.c index 44a0f43..8391f7a 100644 --- a/chown/chown.c +++ b/chown/chown.c @@ -58,6 +58,13 @@ __RCSID("$FreeBSD: src/usr.sbin/chown/chown.c,v 1.24 2002/07/17 16:22:24 dwmalon #include #include #include +#include + +#ifdef __APPLE__ +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ void a_gid(const char *); void a_uid(const char *); @@ -75,26 +82,31 @@ main(int argc, char **argv) { FTS *ftsp; FTSENT *p; - int Hflag, Lflag, Rflag, fflag, hflag, vflag; + int Hflag, Lflag, Pflag, Rflag, fflag, hflag, vflag; int ch, fts_options, rval; char *cp; + int unix2003_compat = 0; + int symlink_found = 0; + if (argc < 1) + usage(); cp = strrchr(argv[0], '/'); cp = (cp != NULL) ? cp + 1 : argv[0]; ischown = (strcmp(cp, "chown") == 0); - Hflag = Lflag = Rflag = fflag = hflag = vflag = 0; + Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0; while ((ch = getopt(argc, argv, "HLPRfhv")) != -1) switch (ch) { case 'H': Hflag = 1; - Lflag = 0; + Lflag = Pflag = 0; break; case 'L': Lflag = 1; - Hflag = 0; + Hflag = Pflag = 0; break; case 'P': + Pflag = 1; Hflag = Lflag = 0; break; case 'R': @@ -118,6 +130,8 @@ main(int argc, char **argv) if (argc < 2) usage(); + if (!Rflag && (Hflag || Lflag || Pflag)) + warnx("options -H, -L, -P only useful with -R"); if (Rflag) { fts_options = FTS_PHYSICAL; @@ -136,6 +150,7 @@ main(int argc, char **argv) uid = (uid_t)-1; gid = (gid_t)-1; if (ischown) { + unix2003_compat = COMPAT_MODE("bin/chown", "Unix2003"); if ((cp = strchr(*argv, ':')) != NULL) { *cp++ = '\0'; a_gid(cp); @@ -148,13 +163,16 @@ main(int argc, char **argv) } #endif a_uid(*argv); - } else + } else { + unix2003_compat = COMPAT_MODE("bin/chgrp", "Unix2003"); a_gid(*argv); + } if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) err(1, NULL); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { + symlink_found = 0; switch (p->fts_info) { case FTS_D: /* Change it at FTS_DP. */ if (!Rflag) @@ -178,15 +196,33 @@ main(int argc, char **argv) */ if (hflag) break; - else + else { + symlink_found = 1; + if (unix2003_compat) { + if (Hflag || Lflag) { /* -H or -L was specified */ + if (p->fts_errno) { + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + rval = 1; + continue; + } + } + break; /* Otherwise symlinks keep going */ + } continue; + } default: break; } - if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) && - (gid == (gid_t)-1 || gid == p->fts_statp->st_gid)) - continue; - if ((hflag ? lchown : chown)(p->fts_accpath, uid, gid) == -1) { + if (unix2003_compat) { + /* Can only avoid updating times if both uid and gid are -1 */ + if ((uid == (uid_t)-1) && (gid == (gid_t)-1)) + continue; + } else { + if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) && + (gid == (gid_t)-1 || gid == p->fts_statp->st_gid)) + continue; + } + if (((hflag || symlink_found) ? lchown : chown)(p->fts_accpath, uid, gid) == -1) { if (!fflag) { chownerr(p->fts_path); rval = 1;