summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2006-10-06 20:44:31 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2006-10-06 20:44:31 +0000
commit4767fc607e5fd38b2a9c8db2d876125aaa10e578 (patch)
treeb4468e643bfee985d4a797ce142567f17dbfe7a5
parent0fc6edb71490b03c79dd03c903a4b72ce2a23d81 (diff)
downloadcoreutils-4767fc607e5fd38b2a9c8db2d876125aaa10e578.tar.xz
Fix bug reported today by Mike Frysinger: mkdir -pv is logging the
wrong file name in some cases. * src/install.c (struct install_options): New type. (install_file_in_file_parents, main): Use it instead of struct cp_options. (process_dir): Remember the full name. (announce_mkdir, make_ancestor): Use the full name in announcements. * src/mkdir.c (struct mkdir_options): Add full_name member. (make_ancestor): Use the full name in announcements. (process_dir): Remember the full name. * tests/mkdir/Makefile.am (TESTS): Add p-v. * tests/mkdir/p-v: New file, to test this bug.
-rw-r--r--ChangeLog15
-rw-r--r--src/install.c47
-rw-r--r--src/mkdir.c8
-rw-r--r--tests/mkdir/Makefile.am2
-rwxr-xr-xtests/mkdir/p-v56
5 files changed, 108 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 517e37aef..84c9d866e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-10-06 Paul Eggert <eggert@cs.ucla.edu>
+
+ Fix bug reported today by Mike Frysinger: mkdir -pv is logging the
+ wrong file name in some cases.
+ * src/install.c (struct install_options): New type.
+ (install_file_in_file_parents, main):
+ Use it instead of struct cp_options.
+ (process_dir): Remember the full name.
+ (announce_mkdir, make_ancestor): Use the full name in announcements.
+ * src/mkdir.c (struct mkdir_options): Add full_name member.
+ (make_ancestor): Use the full name in announcements.
+ (process_dir): Remember the full name.
+ * tests/mkdir/Makefile.am (TESTS): Add p-v.
+ * tests/mkdir/p-v: New file, to test this bug.
+
2006-10-05 Paul Eggert <eggert@cs.ucla.edu>
* src/chgrp.c: Don't include lchown.h; no longer needed.
diff --git a/src/install.c b/src/install.c
index 9c5150fbc..aabbafaf0 100644
--- a/src/install.c
+++ b/src/install.c
@@ -66,12 +66,22 @@
/* Number of bytes of a file to copy at a time. */
#define READ_SIZE (32 * 1024)
+/* Options passed to subsidiary functions. */
+struct install_options
+{
+ /* Full name of file being installed. */
+ char const *full_name;
+
+ /* Options for cp-related code. */
+ struct cp_options cp;
+};
+
static bool change_timestamps (struct stat const *from_sb, char const *to);
static bool change_attributes (char const *name);
static bool copy_file (const char *from, const char *to,
const struct cp_options *x);
static bool install_file_in_file_parents (char const *from, char *to,
- struct cp_options *x);
+ struct install_options *x);
static bool install_file_in_dir (const char *from, const char *to_dir,
const struct cp_options *x);
static bool install_file_in_file (const char *from, const char *to,
@@ -198,6 +208,8 @@ target_directory_operand (char const *file)
static int
process_dir (char *dir, struct savewd *wd, void *options)
{
+ struct install_options *o = options;
+ o->full_name = dir;
return (make_dir_parents (dir, wd,
make_ancestor, options,
dir_mode, announce_mkdir,
@@ -216,7 +228,7 @@ main (int argc, char **argv)
char *backup_suffix_string;
char *version_control_string = NULL;
bool mkdir_and_install = false;
- struct cp_options x;
+ struct install_options x;
char const *target_directory = NULL;
bool no_target_directory = false;
int n_files;
@@ -230,7 +242,7 @@ main (int argc, char **argv)
atexit (close_stdout);
- cp_option_init (&x);
+ cp_option_init (&x.cp);
owner_name = NULL;
group_name = NULL;
@@ -268,7 +280,7 @@ main (int argc, char **argv)
mkdir_and_install = true;
break;
case 'v':
- x.verbose = true;
+ x.cp.verbose = true;
break;
case 'g':
group_name = optarg;
@@ -280,7 +292,7 @@ main (int argc, char **argv)
owner_name = optarg;
break;
case 'p':
- x.preserve_timestamps = true;
+ x.cp.preserve_timestamps = true;
break;
case 'S':
make_backups = true;
@@ -322,10 +334,10 @@ main (int argc, char **argv)
if (backup_suffix_string)
simple_backup_suffix = xstrdup (backup_suffix_string);
- x.backup_type = (make_backups
- ? xget_version (_("backup type"),
- version_control_string)
- : no_backups);
+ x.cp.backup_type = (make_backups
+ ? xget_version (_("backup type"),
+ version_control_string)
+ : no_backups);
n_files = argc - optind;
file = argv + optind;
@@ -385,15 +397,15 @@ main (int argc, char **argv)
{
if (! (mkdir_and_install
? install_file_in_file_parents (file[0], file[1], &x)
- : install_file_in_file (file[0], file[1], &x)))
+ : install_file_in_file (file[0], file[1], &x.cp)))
exit_status = EXIT_FAILURE;
}
else
{
int i;
- dest_info_init (&x);
+ dest_info_init (&x.cp);
for (i = 0; i < n_files; i++)
- if (! install_file_in_dir (file[i], target_directory, &x))
+ if (! install_file_in_dir (file[i], target_directory, &x.cp))
exit_status = EXIT_FAILURE;
}
}
@@ -406,7 +418,7 @@ main (int argc, char **argv)
static bool
install_file_in_file_parents (char const *from, char *to,
- struct cp_options *x)
+ struct install_options *x)
{
bool save_working_directory =
! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
@@ -437,7 +449,7 @@ install_file_in_file_parents (char const *from, char *to,
}
}
- return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
+ return (status == EXIT_SUCCESS && install_file_in_file (from, to, &x->cp));
}
/* Copy file FROM onto file TO and give TO the appropriate
@@ -624,8 +636,8 @@ get_ids (void)
static void
announce_mkdir (char const *dir, void *options)
{
- struct cp_options const *x = options;
- if (x->verbose)
+ struct install_options const *x = options;
+ if (x->cp.verbose)
error (0, 0, _("creating directory %s"), quote (dir));
}
@@ -633,9 +645,10 @@ announce_mkdir (char const *dir, void *options)
static int
make_ancestor (char const *dir, void *options)
{
+ struct install_options const *x = options;
int r = mkdir (dir, DEFAULT_MODE);
if (r == 0)
- announce_mkdir (dir, options);
+ announce_mkdir (x->full_name, options);
return r;
}
diff --git a/src/mkdir.c b/src/mkdir.c
index b28a02ac0..f8a0625a2 100644
--- a/src/mkdir.c
+++ b/src/mkdir.c
@@ -79,6 +79,9 @@ Mandatory arguments to long options are mandatory for short options too.\n\
/* Options passed to subsidiary functions. */
struct mkdir_options
{
+ /* Full name of directory that we are making. */
+ char const *full_name;
+
/* Function to make an ancestor, or NULL if ancestors should not be
made. */
int (*make_ancestor_function) (char const *, void *);
@@ -117,7 +120,7 @@ make_ancestor (char const *dir, void *options)
if (r == 0)
{
r = ! (o->ancestor_mode & S_IRUSR);
- announce_mkdir (dir, options);
+ announce_mkdir (o->full_name, options);
}
return r;
}
@@ -126,7 +129,8 @@ make_ancestor (char const *dir, void *options)
static int
process_dir (char *dir, struct savewd *wd, void *options)
{
- struct mkdir_options const *o = options;
+ struct mkdir_options *o = options;
+ o->full_name = dir;
return (make_dir_parents (dir, wd, o->make_ancestor_function, options,
o->mode, announce_mkdir,
o->mode_bits, (uid_t) -1, (gid_t) -1, true)
diff --git a/tests/mkdir/Makefile.am b/tests/mkdir/Makefile.am
index 7512f7b4b..7f4351655 100644
--- a/tests/mkdir/Makefile.am
+++ b/tests/mkdir/Makefile.am
@@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = 1.1 gnits
TESTS = \
p-thru-slink \
- p-3 p-1 p-2 special-1 perm parents t-slash p-slashdot
+ p-3 p-1 p-2 p-v special-1 perm parents t-slash p-slashdot
EXTRA_DIST = $(TESTS)
TESTS_ENVIRONMENT = \
srcdir=$(srcdir) \
diff --git a/tests/mkdir/p-v b/tests/mkdir/p-v
new file mode 100755
index 000000000..c80e0acda
--- /dev/null
+++ b/tests/mkdir/p-v
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Test mkdir -pv.
+
+# Copyright (C) 2006 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ mkdir --version
+fi
+
+# Make sure we get English translations.
+LANGUAGE=C
+export LANGUAGE
+LC_ALL=C
+export LC_ALL
+LANG=C
+export LANG
+
+pwd=`pwd`
+t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
+trap 'status=$?; cd $pwd; rm -rf $t0 && exit $status' 0
+trap '(exit $?); exit $?' 1 2 13 15
+
+framework_failure=0
+mkdir -p $tmp || framework_failure=1
+cd $tmp || framework_failure=1
+
+if test $framework_failure = 1; then
+ echo "$0: failure in testing framework" 1>&2
+ (exit 1); exit 1
+fi
+
+mkdir -pv foo/a/b/c/d 2>out || exit
+
+diff - out <<\EOF
+mkdir: created directory `foo'
+mkdir: created directory `foo/a'
+mkdir: created directory `foo/a/b'
+mkdir: created directory `foo/a/b/c'
+mkdir: created directory `foo/a/b/c/d'
+EOF