diff -r -u fileutils-3.16/man/chown.1 fileutils-3.16b/man/chown.1 --- fileutils-3.16/man/chown.1 Fri Jul 12 04:33:54 1996 +++ fileutils-3.16b/man/chown.1 Sun Feb 8 02:41:42 1998 @@ -6,11 +6,7 @@ [\-Rcfv] [\-\-recursive] [\-\-changes] [\-\-help] [\-\-version] [\-\-silent] [\-\-quiet] [\-\-verbose] [user][:.][group] file... .SH DESCRIPTION -This documentation is no longer being maintained and may be inaccurate -or incomplete. The Texinfo documentation is now the authoritative source. -.PP -This manual page -documents the GNU version of +This manual page documents the GNU version of .BR chown . .B chown changes the user and/or group ownership of each given file, according @@ -41,6 +37,13 @@ .TP .I "\-R, \-\-recursive" Recursively change ownership of directories and their contents. +.TP +.I "\-F, \-\-from=ouid.ogid" +Only change ownership of files with given owner and/or group. +.TP +.I "\-h, \-\-no-dereference" +Do not follow symbolic links, but change the owner of the links +themselves (if possible). This is the default with \-R. .TP .I "\-\-help" Print a usage message on standard output and exit successfully. diff -r -u fileutils-3.16/src/chown.c fileutils-3.16b/src/chown.c --- fileutils-3.16/src/chown.c Sat Nov 23 23:11:10 1996 +++ fileutils-3.16b/src/chown.c Sun Feb 8 02:47:38 1998 @@ -28,6 +28,8 @@ Written by David MacKenzie . */ +/* Added "chown -R aeb --from 405 .", aeb, 980105 */ + #include #include #include @@ -61,6 +63,7 @@ char *xrealloc (); static int change_dir_owner __P ((char *dir, uid_t user, gid_t group, + uid_t olduser, gid_t oldgroup, struct stat *statp)); /* The name the program was run with. */ @@ -102,6 +105,7 @@ {"quiet", no_argument, 0, 'f'}, {"silent", no_argument, 0, 'f'}, {"verbose", no_argument, 0, 'v'}, + {"from", required_argument, 0, 'F'}, {"help", no_argument, &show_help, 1}, {"version", no_argument, &show_version, 1}, {0, 0, 0, 0} @@ -123,12 +127,14 @@ 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 (char *file, uid_t user, gid_t group) +change_file_owner (char *file, uid_t user, gid_t group, + uid_t olduser, gid_t oldgroup) { struct stat file_stats; uid_t newuser; @@ -142,32 +148,50 @@ 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 ((olduser == (uid_t) -1 || file_stats.st_uid == olduser) && + (oldgroup == (gid_t) -1 || file_stats.st_gid == oldgroup)) { - int fail; - - if (verbose) - describe_change (file, 1); - - if (change_symlinks) - fail = LCHOWN (file, newuser, newgroup); - else - fail = chown (file, newuser, newgroup); + 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) + { + int fail; + + if (change_symlinks) + fail = LCHOWN (file, newuser, newgroup); +#ifdef S_ISLNK + /* Unfortunately, nobody knows whether chown() + will follow symlinks or not. Testing at compile time + is no guarantee that the behaviour is the same at run + time. It seems safest not to follow symlinks at all + on "chown -R". */ + else if (recurse && S_ISLNK(file_stats.st_mode)) + fail = 1; +#endif + else + fail = chown (file, newuser, newgroup); - if (fail) - { - if (force_silent == 0) - error (0, errno, "%s", file); - errors = 1; - } + if (fail < 0) + { + if (force_silent == 0) + error (0, errno, "%s", file); + errors = 1; + } + else if (verbose) + { + if (!fail) + describe_change (file, 1); + else + printf(_("symbolic link %s unchanged\n"), file); + } + } + else if (verbose && changes_only == 0) + describe_change (file, 0); } - else if (verbose && changes_only == 0) - describe_change (file, 0); if (recurse && S_ISDIR (file_stats.st_mode)) - errors |= change_dir_owner (file, user, group, &file_stats); + errors |= change_dir_owner (file, user, group, olduser, oldgroup, + &file_stats); return errors; } @@ -177,7 +201,8 @@ Return 0 if successful, 1 if errors occurred. */ static int -change_dir_owner (char *dir, uid_t user, gid_t group, struct stat *statp) +change_dir_owner (char *dir, uid_t user, gid_t group, uid_t olduser, + gid_t oldgroup, struct stat *statp) { char *name_space, *namep; char *path; /* Full path of each entry to process. */ @@ -216,7 +241,7 @@ path = xrealloc (path, pathlength); } strcpy (path + dirlength, namep); - errors |= change_file_owner (path, user, group); + errors |= change_file_owner (path, user, group, olduser, oldgroup); } free (path); free (name_space); @@ -240,11 +265,12 @@ Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ \n\ -c, --changes be verbose whenever change occurs\n\ - -h, --no-dereference affect symbolic links instead of any referenced file\n\ - (available only on systems with lchown system call)\n\ -f, --silent, --quiet suppress most error messages\n\ - -R, --recursive operate on files and directories recursively\n\ -v, --verbose explain what is being done\n\ + -h, --no-dereference affect symbolic links instead of any referenced file\n\ + -R, --recursive operate on files and directories recursively\n\ + -F, --from OO.OG only change the owner and/or group when it was OO.OG\n\ + (where OO or .OG may be missing, and may be numeric)\n\ --help display this help and exit\n\ --version output version information and exit\n\ \n\ @@ -261,9 +287,11 @@ { 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 olduser = (uid_t) -1; /* Old uid; -1 if unrestricted. */ + gid_t oldgroup = (uid_t) -1; /* Old gid; -1 if unrestricted. */ int errors = 0; int optc; - char *e; + char *e, *un, *gn; program_name = argv[0]; setlocale (LC_ALL, ""); @@ -271,8 +299,8 @@ textdomain (PACKAGE); recurse = force_silent = verbose = changes_only = 0; - - while ((optc = getopt_long (argc, argv, "Rcfhv", long_options, (int *) 0)) + + while ((optc = getopt_long (argc, argv, "RcfhvF:", long_options, (int *) 0)) != EOF) { switch (optc) @@ -295,6 +323,11 @@ case 'v': verbose = 1; break; + case 'F': + e = parse_user_spec (optarg, &olduser, &oldgroup, &un, &gn); + if (e) + error (1, 0, "%s: %s", optarg, e); + break; default: usage (1); } @@ -331,7 +364,7 @@ for (++optind; optind < argc; ++optind) { strip_trailing_slashes (argv[optind]); - errors |= change_file_owner (argv[optind], user, group); + errors |= change_file_owner (argv[optind], user, group, olduser, oldgroup); } exit (errors);