left-to-right in some cases.
* src/chmod.c (wd_errno): New var.
(chmod_file): New function, with most of the contents of the
old prcess_file function.
(process_files): Use it. This gives file names to fts one
at a time, so that they are processed left-to-right as POSIX
requires.
* src/chown-core.c (wd_errno, chown_files): Likewise.
(chown_file): New function.
* tests/install/basic-1: Redo test so as to not workaround
the chmod bug, thereby testing for it.
2006-09-18 Paul Eggert <eggert@cs.ucla.edu>
+ Fix bug where chmod, chown, and chgrp did not process operands
+ left-to-right in some cases.
+ * src/chmod.c (wd_errno): New var.
+ (chmod_file): New function, with most of the contents of the
+ old prcess_file function.
+ (process_files): Use it. This gives file names to fts one
+ at a time, so that they are processed left-to-right as POSIX
+ requires.
+ * src/chown-core.c (wd_errno, chown_files): Likewise.
+ (chown_file): New function.
+ * tests/install/basic-1: Redo test so as to not workaround
+ the chmod bug, thereby testing for it.
+
* src/shuf.c (main): Quote the entire range when reporting an
invalid one, rather than just the part that contained the error.
Otherwise NULL. */
static struct dev_ino *root_dev_ino;
+/* Error number associated with the working directory, or 0 if no
+ error has been found. */
+static int wd_errno;
+
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
return ok;
}
-/* Recursively change the modes of the specified FILES (the last entry
- of which is NULL). BIT_FLAGS controls how fts works.
+/* Recursively change the modes of the command-line operand FILE.
+ BIT_FLAGS controls how fts works.
Return true if successful. */
static bool
-process_files (char **files, int bit_flags)
+chmod_file (char *file, int bit_flags)
{
+ char *files[2];
bool ok = true;
-
- FTS *fts = xfts_open (files, bit_flags, NULL);
+ FTS *fts;
+ files[0] = file;
+ files[1] = NULL;
+ fts = xfts_open (files, bit_flags, NULL);
while (1)
{
ok &= process_file (fts, ent);
}
- /* Ignore failure, since the only way it can do so is in failing to
- return to the original directory, and since we're about to exit,
- that doesn't matter. */
- fts_close (fts);
+ if (fts_close (fts) != 0)
+ wd_errno = errno;
+
+ return ok;
+}
+
+/* Recursively change the modes of the specified FILES (the last entry
+ of which is NULL). BIT_FLAGS controls how fts works.
+ Return true if successful. */
+static bool
+process_files (char **files, int bit_flags)
+{
+ bool ok = true;
+ wd_errno = 0;
+
+ for (; *files; files++)
+ {
+ if (! IS_ABSOLUTE_FILE_NAME (*files) && wd_errno)
+ {
+ error (0, wd_errno, ".");
+ ok = false;
+ }
+ else
+ ok &= chmod_file (*files, bit_flags);
+ }
return ok;
}
RC_error
};
+/* Error number associated with the working directory, or 0 if no
+ error has been found. */
+static int wd_errno;
+
extern void
chopt_init (struct Chown_option *chopt)
{
return ok;
}
-/* Change the owner and/or group of the specified FILES.
+/* Change the owner and/or group of the specified FILE.
BIT_FLAGS specifies how to treat each symlink-to-directory
that is encountered during a recursive traversal.
CHOPT specifies additional options.
If REQUIRED_UID and/or REQUIRED_GID is not -1, then change only
files with user ID and group ID that match the non-(-1) value(s).
Return true if successful. */
-extern bool
-chown_files (char **files, int bit_flags,
- uid_t uid, gid_t gid,
- uid_t required_uid, gid_t required_gid,
- struct Chown_option const *chopt)
+static bool
+chown_file (char *file, int bit_flags,
+ uid_t uid, gid_t gid,
+ uid_t required_uid, gid_t required_gid,
+ struct Chown_option const *chopt)
{
bool ok = true;
? 0
: FTS_NOSTAT);
- FTS *fts = xfts_open (files, bit_flags | stat_flags, NULL);
+ FTS *fts;
+ char *files[2];
+ files[0] = file;
+ files[1] = NULL;
+ fts = xfts_open (files, bit_flags | stat_flags, NULL);
while (1)
{
required_uid, required_gid, chopt);
}
- /* Ignore failure, since the only way it can do so is in failing to
- return to the original directory, and since we're about to exit,
- that doesn't matter. */
- fts_close (fts);
+ if (fts_close (fts) != 0)
+ wd_errno = errno;
+
+ return ok;
+}
+
+/* Change the owner and/or group of the specified FILES.
+ BIT_FLAGS specifies how to treat each symlink-to-directory
+ that is encountered during a recursive traversal.
+ CHOPT specifies additional options.
+ If UID is not -1, then change the owner id of each file to UID.
+ If GID is not -1, then change the group id of each file to GID.
+ If REQUIRED_UID and/or REQUIRED_GID is not -1, then change only
+ files with user ID and group ID that match the non-(-1) value(s).
+ Return true if successful. */
+extern bool
+chown_files (char **files, int bit_flags,
+ uid_t uid, gid_t gid,
+ uid_t required_uid, gid_t required_gid,
+ struct Chown_option const *chopt)
+{
+ bool ok = true;
+
+ for (; *files; files++)
+ {
+ if (! IS_ABSOLUTE_FILE_NAME (*files) && wd_errno)
+ {
+ error (0, wd_errno, ".");
+ ok = false;
+ }
+ else
+ ok &= chown_file (*files, bit_flags, uid, gid,
+ required_uid, required_gid, chopt);
+ }
return ok;
}
mkdir -p sub1/d || fail=1
(cd sub1/d && chmod a-rx .. && chmod a-r . &&
ginstall -d $abs/xx/zz rel/a rel/b 2> /dev/null) || fail=1
-chmod 755 sub1 || fail=1
-chmod 755 sub1/d || fail=1
+chmod 755 sub1 sub1/d || fail=1
test -d xx/zz || fail=1
test -d sub1/d/rel/a || fail=1
test -d sub1/d/rel/b || fail=1