summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--NEWS3
-rw-r--r--src/cp.c12
-rwxr-xr-xtests/cp/cp-parents9
4 files changed, 29 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index c7f04aad5..c2ad0b5e2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-02-02 Paul Eggert <eggert@cs.ucla.edu>
+
+ * NEWS: Document fix for cp --parents.
+ * src/cp.c (make_dir_parents_private): Report the error sooner with
+ "cp --parents DIR/FILE DEST" when DIR is a non-directory, thus not
+ creating the directory, DEST/DIR.
+ * tests/cp/cp-parents: Test for the non-race-condition bug fixed
+ by the above change.
+
2007-02-02 Jim Meyering <jim@meyering.net>
* src/nl.c (proc_text): Use "NULL", not "(struct re_registers *) 0".
diff --git a/NEWS b/NEWS
index ad0fd1d24..c90a1b3c5 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,9 @@ GNU coreutils NEWS -*- outline -*-
chmod no longer fails in an environment (e.g., a chroot) with openat
support but with insufficient /proc support.
+ "cp --parents F/G D" no longer creates a directory D/F when F is not
+ a directory (and F/G is therefore invalid).
+
cut no longer dumps core for usage like "cut -f2- f1 f2" with two or
more file arguments. This was due to a double-free bug, introduced
in coreutils-5.3.0.
diff --git a/src/cp.c b/src/cp.c
index 8fe11a1e7..aea63dce7 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -1,5 +1,5 @@
/* cp.c -- file copying (main routines)
- Copyright (C) 89, 90, 91, 1995-2006 Free Software Foundation.
+ Copyright (C) 89, 90, 91, 1995-2007 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -415,6 +415,7 @@ make_dir_parents_private (char const *const_dir, size_t src_offset,
mode_t src_mode;
mode_t omitted_permissions;
mode_t mkdir_mode;
+ int src_errno;
/* This component does not exist. We must set
*new_dst and new->mode inside this loop because,
@@ -422,9 +423,14 @@ make_dir_parents_private (char const *const_dir, size_t src_offset,
make_dir_parents_private creates only e_dir/../a if
./b already exists. */
*new_dst = true;
- if (XSTAT (x, src, &stats))
+ src_errno = (XSTAT (x, src, &stats) != 0
+ ? errno
+ : S_ISDIR (stats.st_mode)
+ ? 0
+ : ENOTDIR);
+ if (src_errno)
{
- error (0, errno, _("failed to get attributes of %s"),
+ error (0, src_errno, _("failed to get attributes of %s"),
quote (src));
return false;
}
diff --git a/tests/cp/cp-parents b/tests/cp/cp-parents
index 373e60776..6c123d225 100755
--- a/tests/cp/cp-parents
+++ b/tests/cp/cp-parents
@@ -2,7 +2,8 @@
# cp -R --parents dir-specified-with-trailing-slash/ other-dir
# would get a failed assertion.
-# Copyright (C) 2000, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
+# Copyright (C) 2000, 2002, 2004, 2005, 2006, 2007 Free Software
+# Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -48,6 +49,7 @@ cd $tmp || framework_failure=1
mkdir foo bar || framework_failure=1
mkdir -p a/b/c d e || framework_failure=1
+touch f || framework_failure=1
if test $framework_failure = 1; then
echo 'failure in testing framework'
@@ -65,6 +67,11 @@ cp -R --parents foo/ bar || fail=1
cp --verbose -a --parents a/b/c d > /dev/null 2>&1 || fail=1
test -d d/a/b/c || fail=1
+# With 6.7 and earlier, cp --parents f/g d would mistakenly create a
+# directory d/f, even though f is a regular file.
+cp --parents f/g d 2>/dev/null && fail=1
+test -d d/f && fail=1
+
# Check that re_protect works.
chmod go=w d/a
cp -a --parents d/a/b/c e || fail=1