summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2008-01-09 11:24:12 +0100
committerJim Meyering <meyering@redhat.com>2008-01-09 11:24:12 +0100
commit424feb63014ebd6908b934d3d0d53b46a58ecebd (patch)
tree57651ace1edd4adfb90f13c23c51130229a26f3b
parente80379051b72cff4c948c7045491c9faa8a2a643 (diff)
downloadcoreutils-424feb63014ebd6908b934d3d0d53b46a58ecebd.tar.xz
Fix a minor race condition when using cp -p --parents.
* src/cp.c (make_dir_parents_private): If stat fails on the parent directory, do not add it to the list of directories whose modes might need fixing later. Also, do not bother invoking 'stat' unless the stat results might be needed later.
-rw-r--r--ChangeLog8
-rw-r--r--src/cp.c47
2 files changed, 37 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index e834634c3..7e543ba62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-01-08 Paul Eggert <eggert@cs.ucla.edu>
+
+ Fix a minor race condition when using cp -p --parents.
+ * src/cp.c (make_dir_parents_private): If stat fails on the parent
+ directory, do not add it to the list of directories whose modes
+ might need fixing later. Also, do not bother invoking 'stat'
+ unless the stat results might be needed later.
+
2008-01-08 Jim Meyering <meyering@redhat.com>
parent-perm: avoid a bizarre test failure.
diff --git a/src/cp.c b/src/cp.c
index 01d98cc64..a46f900bc 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -403,28 +403,39 @@ make_dir_parents_private (char const *const_dir, size_t src_offset,
slash++;
while ((slash = strchr (slash, '/')))
{
- int src_errno;
- /* Add this directory to the list of directories whose modes need
- fixing later. */
- struct dir_attr *new = xmalloc (sizeof *new);
- new->slash_offset = slash - dir;
- new->restore_mode = false;
- new->next = *attr_list;
- *attr_list = new;
+ struct dir_attr *new IF_LINT (= NULL);
+ bool missing_dir;
*slash = '\0';
- src_errno = (stat (src, &new->st) != 0
- ? errno
- : S_ISDIR (new->st.st_mode)
- ? 0
- : ENOTDIR);
- if (src_errno)
+ missing_dir = (stat (dir, &stats) != 0);
+
+ if (missing_dir | x->preserve_ownership | x->preserve_mode
+ | x->preserve_timestamps)
{
- error (0, src_errno, _("failed to get attributes of %s"),
- quote (src));
- return false;
+ /* Add this directory to the list of directories whose
+ modes might need fixing later. */
+ struct stat src_st;
+ int src_errno = (stat (src, &src_st) != 0
+ ? errno
+ : S_ISDIR (src_st.st_mode)
+ ? 0
+ : ENOTDIR);
+ if (src_errno)
+ {
+ error (0, src_errno, _("failed to get attributes of %s"),
+ quote (src));
+ return false;
+ }
+
+ new = xmalloc (sizeof *new);
+ new->st = src_st;
+ new->slash_offset = slash - dir;
+ new->restore_mode = false;
+ new->next = *attr_list;
+ *attr_list = new;
}
- if (stat (dir, &stats) != 0)
+
+ if (missing_dir)
{
mode_t src_mode;
mode_t omitted_permissions;