diff options
author | Jim Meyering <jim@meyering.net> | 2000-04-17 08:19:52 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2000-04-17 08:19:52 +0000 |
commit | df85b33ee38e47c985ba5ede371eb9afeedb9e5a (patch) | |
tree | 5120a59761cd70207ac66c4faa4bf457bfca4077 /src | |
parent | d37e7835f90f4a2847a2648f390b8b00aea44d89 (diff) | |
download | coreutils-df85b33ee38e47c985ba5ede371eb9afeedb9e5a.tar.xz |
Accept new option: --from=CURRENT_OWNER:CURRENT_GROUP.
(enum) [FROM_OPTION]: New member.
(long_options): New getopt spec.
(change_file_owner): Add old_user, old_group parameters. Use them.
(change_dir_owner): Likewise.
(usage): Describe.
(main): New case.
Diffstat (limited to 'src')
-rw-r--r-- | src/chown.c | 110 |
1 files changed, 71 insertions, 39 deletions
diff --git a/src/chown.c b/src/chown.c index a32d74a2a..11c502515 100644 --- a/src/chown.c +++ b/src/chown.c @@ -79,6 +79,7 @@ enum Verbosity }; static int change_dir_owner PARAMS ((const char *dir, uid_t user, gid_t group, + uid_t old_user, gid_t old_group, const struct stat *statp)); /* The name the program was run with. */ @@ -112,7 +113,8 @@ static char *reference_file; enum { REFERENCE_FILE_OPTION = CHAR_MAX + 1, - DEREFERENCE_OPTION + DEREFERENCE_OPTION, + FROM_OPTION }; static struct option const long_options[] = @@ -120,6 +122,7 @@ static struct option const long_options[] = {"recursive", no_argument, 0, 'R'}, {"changes", no_argument, 0, 'c'}, {"dereference", no_argument, 0, DEREFERENCE_OPTION}, + {"from", required_argument, 0, FROM_OPTION}, {"no-dereference", no_argument, 0, 'h'}, {"quiet", no_argument, 0, 'f'}, {"silent", no_argument, 0, 'f'}, @@ -166,12 +169,14 @@ describe_change (const char *file, enum Change_status changed) printf ("%s\n", username); } -/* Change the ownership of FILE to UID USER and GID GROUP. +/* Change the ownership of FILE to UID USER and GID GROUP + provided it presently has UID OLDUSER and GID OLDGROUP. If it is a directory and -R is given, recurse. Return 0 if successful, 1 if errors occurred. */ static int -change_file_owner (int cmdline_arg, const char *file, uid_t user, gid_t group) +change_file_owner (int cmdline_arg, const char *file, uid_t user, gid_t group, + uid_t old_user, gid_t old_group) { struct stat file_stats; uid_t newuser; @@ -185,51 +190,58 @@ change_file_owner (int cmdline_arg, const char *file, uid_t user, gid_t group) return 1; } - newuser = user == (uid_t) -1 ? file_stats.st_uid : user; - newgroup = group == (gid_t) -1 ? file_stats.st_gid : group; - if (newuser != file_stats.st_uid || newgroup != file_stats.st_gid) + if ((old_user == (uid_t) -1 || file_stats.st_uid == old_user) && + (old_group == (gid_t) -1 || file_stats.st_gid == old_group)) { - int fail; - int symlink_changed = 1; - - if (S_ISLNK (file_stats.st_mode) && change_symlinks) + newuser = user == (uid_t) -1 ? file_stats.st_uid : user; + newgroup = group == (gid_t) -1 ? file_stats.st_gid : group; + if (newuser != file_stats.st_uid || newgroup != file_stats.st_gid) { - fail = lchown (file, newuser, newgroup); + int fail; + int symlink_changed = 1; - /* Ignore the failure if it's due to lack of support (ENOSYS) - and this is not a command line argument. */ - if (!cmdline_arg && fail && errno == ENOSYS) + if (S_ISLNK (file_stats.st_mode) && change_symlinks) { - fail = 0; - symlink_changed = 0; + fail = lchown (file, newuser, newgroup); + + /* Ignore the failure if it's due to lack of support (ENOSYS) + and this is not a command line argument. */ + if (!cmdline_arg && fail && errno == ENOSYS) + { + fail = 0; + symlink_changed = 0; + } + } + else + { + fail = chown (file, newuser, newgroup); } - } - else - { - fail = chown (file, newuser, newgroup); - } - if (verbosity == V_high || (verbosity == V_changes_only && !fail)) - { - enum Change_status ch_status = (! symlink_changed ? CH_NOT_APPLIED - : (fail ? CH_FAILED : CH_SUCCEEDED)); - describe_change (file, ch_status); - } + if (verbosity == V_high || (verbosity == V_changes_only && !fail)) + { + enum Change_status ch_status = (! symlink_changed + ? CH_NOT_APPLIED + : (fail + ? CH_FAILED : CH_SUCCEEDED)); + describe_change (file, ch_status); + } - if (fail) + if (fail) + { + if (force_silent == 0) + error (0, errno, "%s", file); + errors = 1; + } + } + else if (verbosity == V_high) { - if (force_silent == 0) - error (0, errno, "%s", file); - errors = 1; + describe_change (file, CH_NO_CHANGE_REQUESTED); } } - else if (verbosity == V_high) - { - describe_change (file, CH_NO_CHANGE_REQUESTED); - } if (recurse && S_ISDIR (file_stats.st_mode)) - errors |= change_dir_owner (file, user, group, &file_stats); + errors |= change_dir_owner (file, user, group, + old_user, old_group, &file_stats); return errors; } @@ -240,6 +252,7 @@ change_file_owner (int cmdline_arg, const char *file, uid_t user, gid_t group) static int change_dir_owner (const char *dir, uid_t user, gid_t group, + uid_t old_user, gid_t old_group, const struct stat *statp) { char *name_space, *namep; @@ -279,7 +292,7 @@ change_dir_owner (const char *dir, uid_t user, gid_t group, path = xrealloc (path, pathlength); } strcpy (path + dirlength, namep); - errors |= change_file_owner (0, path, user, group); + errors |= change_file_owner (0, path, user, group, old_user, old_group); } free (path); free (name_space); @@ -309,6 +322,11 @@ Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ -h, --no-dereference affect symbolic links instead of any referenced file\n\ (available only on systems that can change the\n\ ownership of a symlink)\n\ + --from=CURRENT_OWNER:CURRENT_GROUP\n\ + change the owner and/or group of each file only if\n\ + its current owner and/or group match those specified\n\ + here. Either may be omitted, in which case a match\n\ + is not required for the omitted attribute.\n\ -f, --silent, --quiet suppress most error messages\n\ --reference=RFILE use RFILE's owner and group rather than\n\ the specified OWNER:GROUP values\n\ @@ -318,7 +336,8 @@ Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ --version output version information and exit\n\ \n\ Owner is unchanged if missing. Group is unchanged if missing, but changed\n\ -to login group if implied by a `:'.\n\ +to login group if implied by a `:'. OWNER and GROUP may be numeric as well\n\ +as symbolic.\n\ ")); puts (_("\nReport bugs to <bug-fileutils@gnu.org>.")); close_stdout (); @@ -331,6 +350,9 @@ main (int argc, char **argv) { uid_t user = (uid_t) -1; /* New uid; -1 if not to be changed. */ gid_t group = (uid_t) -1; /* New gid; -1 if not to be changed. */ + uid_t old_user = (uid_t) -1; /* Old uid; -1 if unrestricted. */ + gid_t old_group = (uid_t) -1; /* Old gid; -1 if unrestricted. */ + int errors = 0; int optc; @@ -353,6 +375,15 @@ main (int argc, char **argv) case DEREFERENCE_OPTION: change_symlinks = 0; break; + case FROM_OPTION: + { + char *u_dummy, *g_dummy; + const char *e = parse_user_spec (argv[optind], &old_user, &old_group, + &u_dummy, &g_dummy); + if (e) + error (1, 0, "%s: %s", argv[optind], e); + break; + } case 'R': recurse = 1; break; @@ -406,7 +437,8 @@ main (int argc, char **argv) for (; optind < argc; ++optind) { strip_trailing_slashes (argv[optind]); - errors |= change_file_owner (1, argv[optind], user, group); + errors |= change_file_owner (1, argv[optind], user, group, + old_user, old_group); } if (verbosity != V_off) |