summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2004-06-09 13:37:52 +0000
committerJim Meyering <jim@meyering.net>2004-06-09 13:37:52 +0000
commite4ccef8ddc672f9e5ee4963db550f97c1ae2edc8 (patch)
tree1e366cfe6f14538087e8af43480bb56f23d1df4c /src
parent7c6999b6f83522d31aeabc6eaed9f923824723d1 (diff)
downloadcoreutils-e4ccef8ddc672f9e5ee4963db550f97c1ae2edc8.tar.xz
Adjust chmod and chown to be similar if -c or -v are given. In
particular, a no-op chown is no longer reported as a change; this reverts to previous behavior. Also, fix both commands so that -v report failures even if the failure is not due to the chmod or chown syscalls. * src/chown-core.c (change_file_owner): Return -1 on error, not 1 sometimes and -1 on others. Our caller ORs together our results, and (-1 | 1) == 0 on ones-complement hosts. With -v report all errors verbosely, not just some. Fix bug when chopt->root_dev_ino && !chopt->affect_symlink_referent: file_stats wasn't set properly in that case.
Diffstat (limited to 'src')
-rw-r--r--src/chown-core.c79
1 files changed, 46 insertions, 33 deletions
diff --git a/src/chown-core.c b/src/chown-core.c
index b43e1d91d..2811ff92e 100644
--- a/src/chown-core.c
+++ b/src/chown-core.c
@@ -167,18 +167,19 @@ describe_change (const char *file, enum Change_status changed,
to UID and/or GID as appropriate.
FIXME: describe old_uid and old_gid.
CHOPT specifies additional options.
- Return nonzero upon error, zero otherwise. */
+ Return 0 if successful, -1 if errors occurred. */
static int
change_file_owner (FTS *fts, FTSENT *ent,
uid_t uid, gid_t gid,
uid_t old_uid, gid_t old_gid,
struct Chown_option const *chopt)
{
- const char *file_full_name = ent->fts_path;
+ char const *file_full_name = ent->fts_path;
+ char const *file = ent->fts_accpath;
struct stat const *file_stats IF_LINT (= NULL);
struct stat stat_buf;
int errors = 0;
- bool do_chown = true;
+ bool do_chown;
bool symlink_changed = true;
switch (ent->fts_info)
@@ -195,23 +196,30 @@ change_file_owner (FTS *fts, FTSENT *ent,
case FTS_NS:
error (0, ent->fts_errno, _("cannot access %s"), quote (file_full_name));
- return 1;
+ errors = -1;
+ break;
case FTS_ERR:
error (0, ent->fts_errno, _("%s"), quote (file_full_name));
- return 1;
+ errors = -1;
+ break;
case FTS_DNR:
error (0, ent->fts_errno, _("cannot read directory %s"),
quote (file_full_name));
- return 1;
+ errors = -1;
+ break;
default:
break;
}
- if (old_uid != (uid_t) -1 || old_gid != (gid_t) -1
- || (chopt->root_dev_ino && chopt->affect_symlink_referent))
+ if (errors)
+ do_chown = false;
+ else if (old_uid == (uid_t) -1 && old_gid == (gid_t) -1
+ && chopt->verbosity == V_off && ! chopt->root_dev_ino)
+ do_chown = true;
+ else
{
file_stats = ent->fts_statp;
@@ -219,32 +227,30 @@ change_file_owner (FTS *fts, FTSENT *ent,
stat it to get the permissions of the referent. */
if (S_ISLNK (file_stats->st_mode) && chopt->affect_symlink_referent)
{
- if (stat (ent->fts_accpath, &stat_buf) != 0)
+ if (stat (file, &stat_buf) != 0)
{
error (0, errno, _("cannot dereference %s"),
quote (file_full_name));
- return 1;
+ errors = -1;
}
file_stats = &stat_buf;
}
- do_chown = ((old_uid == (uid_t) -1
- || file_stats->st_uid == old_uid)
- && (old_gid == (gid_t) -1
- || file_stats->st_gid == old_gid));
+ do_chown = (!errors
+ && (old_uid == (uid_t) -1 || old_uid == file_stats->st_uid)
+ && (old_gid == (gid_t) -1 || old_gid == file_stats->st_gid));
}
- if (do_chown)
+ if (do_chown && ROOT_DEV_INO_CHECK (chopt->root_dev_ino, file_stats))
{
- const char *file = ent->fts_accpath;
-
- if (ROOT_DEV_INO_CHECK (chopt->root_dev_ino, file_stats))
- {
- ROOT_DEV_INO_WARN (file_full_name);
- return 1;
- }
+ ROOT_DEV_INO_WARN (file_full_name);
+ errors = -1;
+ do_chown = false;
+ }
+ if (do_chown)
+ {
if (chopt->affect_symlink_referent)
{
/* Applying chown to a symlink and expecting it to affect
@@ -280,15 +286,23 @@ change_file_owner (FTS *fts, FTSENT *ent,
quote (file_full_name));
}
- if (chopt->verbosity == V_high
- || (chopt->verbosity == V_changes_only && !errors))
+ if (chopt->verbosity != V_off)
{
- enum Change_status ch_status = (!do_chown ? CH_NO_CHANGE_REQUESTED
- : !symlink_changed ? CH_NOT_APPLIED
- : errors ? CH_FAILED
- : CH_SUCCEEDED);
- describe_change (file_full_name, ch_status,
- chopt->user_name, chopt->group_name);
+ bool changed =
+ (do_chown && !errors && symlink_changed
+ && ! ((uid == (uid_t) -1 || uid == file_stats->st_uid)
+ && (gid == (gid_t) -1 || gid == file_stats->st_gid)));
+
+ if (changed || chopt->verbosity == V_high)
+ {
+ enum Change_status ch_status =
+ (errors ? CH_FAILED
+ : !symlink_changed ? CH_NOT_APPLIED
+ : !changed ? CH_NO_CHANGE_REQUESTED
+ : CH_SUCCEEDED);
+ describe_change (file_full_name, ch_status,
+ chopt->user_name, chopt->group_name);
+ }
}
if ( ! chopt->recurse)
@@ -315,9 +329,8 @@ chown_files (char **files, int bit_flags,
int fail = 0;
/* Use lstat and stat only if they're needed. */
- int stat_flags = ((chopt->root_dev_ino
- || required_uid != (uid_t) -1
- || required_gid != (gid_t) -1)
+ int stat_flags = ((required_uid != (uid_t) -1 || required_gid != (gid_t) -1
+ || chopt->verbosity != V_off || chopt->root_dev_ino)
? 0
: FTS_NOSTAT);