From 1c73876f5f7973ca41caaf0ce326254b1081713a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 3 Feb 2007 18:12:11 +0100 Subject: [PATCH] * 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. --- ChangeLog | 9 +++++++++ NEWS | 3 +++ src/cp.c | 12 +++++++++--- tests/cp/cp-parents | 9 ++++++++- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index c7f04aa..c2ad0b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-02-02 Paul Eggert + + * 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 * src/nl.c (proc_text): Use "NULL", not "(struct re_registers *) 0". diff --git a/NEWS b/NEWS index ad0fd1d..c90a1b3 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 8fe11a1..aea63dc 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 373e607..6c123d2 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 -- 2.7.4