mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-18 09:46:33 +02:00
* NEWS: Document that mkdir -p and install -d now fork on occasion.
* bootstrap.conf (gnulib_modules): Add savewd. * src/install.c: Include savewd.h. (process_dir): New function. (main, install_file_in_file_parents): Use it, along with the new savewd module, to avoid some race conditions. * src/mkdir.c: Include savewd.h. (struct mkdir_options): New members make_ancestor_function, mode, mode_bits. (make_ancestor): Return 1 if the resulting directory is not readable. (process_dir): New function. (main): Use it, along with new savewd module, to avoid some race conditions. Fill in new slots of struct mkdir_options, so that callees get the values. * tests/install/basic-1: Test for coreutils 5.97 bug that was fixed in coreutils 6.0, and which should still be fixed with this change. * tests/mkdir/p-3: Likewise.
This commit is contained in:
22
ChangeLog
22
ChangeLog
@@ -1,7 +1,23 @@
|
||||
2006-09-16 Jim Meyering <jim@meyering.net>
|
||||
2006-09-16 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* Makefile.maint (sc_require_config_h, sc_prohibit_assert_without_use):
|
||||
Discard stdout from the new use of grep.
|
||||
* NEWS: Document that mkdir -p and install -d now fork on occasion.
|
||||
* bootstrap.conf (gnulib_modules): Add savewd.
|
||||
* src/install.c: Include savewd.h.
|
||||
(process_dir): New function.
|
||||
(main, install_file_in_file_parents): Use it, along with the new
|
||||
savewd module, to avoid some race conditions.
|
||||
* src/mkdir.c: Include savewd.h.
|
||||
(struct mkdir_options): New members make_ancestor_function, mode,
|
||||
mode_bits.
|
||||
(make_ancestor): Return 1 if the resulting directory is not readable.
|
||||
(process_dir): New function.
|
||||
(main): Use it, along with new savewd module, to avoid some
|
||||
race conditions. Fill in new slots of struct mkdir_options, so
|
||||
that callees get the values.
|
||||
* tests/install/basic-1: Test for coreutils 5.97 bug that was
|
||||
fixed in coreutils 6.0, and which should still be fixed with
|
||||
this change.
|
||||
* tests/mkdir/p-3: Likewise.
|
||||
|
||||
2006-09-15 Jim Meyering <jim@meyering.net>
|
||||
|
||||
|
||||
5
NEWS
5
NEWS
@@ -4,6 +4,11 @@ GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
** Changes in behavior
|
||||
|
||||
mkdir -p and install -d (or -D) now use a method that forks a child
|
||||
process if the working directory is unreadable and a later argument
|
||||
uses a relative file name. This avoids some race conditions, but it
|
||||
means you may need to kill two processes to stop these programs.
|
||||
|
||||
rm now rejects attempts to remove the root directory, e.g., `rm -fr /'
|
||||
now fails without removing anything. Likewise for any file name with
|
||||
a final `./' or `../' component.
|
||||
|
||||
@@ -55,7 +55,7 @@ gnulib_modules="
|
||||
quote quotearg raise readlink readtokens readtokens0 readutmp
|
||||
realloc regex rename-dest-slash rmdir rmdir-errno rpmatch
|
||||
safe-read same
|
||||
save-cwd savedir settime sha1 sig2str ssize_t stat-macros
|
||||
save-cwd savedir savewd settime sha1 sig2str ssize_t stat-macros
|
||||
stat-time stdbool stdlib-safer stpcpy strcase strftime
|
||||
strpbrk strtoimax strtoumax strverscmp timespec tzset
|
||||
unicodeio unistd-safer unlink-busy unlinkdir unlocked-io
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "mkdir-p.h"
|
||||
#include "modechange.h"
|
||||
#include "quote.h"
|
||||
#include "savewd.h"
|
||||
#include "stat-time.h"
|
||||
#include "utimens.h"
|
||||
#include "xstrtol.h"
|
||||
@@ -193,11 +194,23 @@ target_directory_operand (char const *file)
|
||||
return is_a_dir;
|
||||
}
|
||||
|
||||
/* Process a command-line file name, for the -d option. */
|
||||
static int
|
||||
process_dir (char *dir, struct savewd *wd, void *options)
|
||||
{
|
||||
return (make_dir_parents (dir, wd,
|
||||
make_ancestor, options,
|
||||
dir_mode, announce_mkdir,
|
||||
dir_mode_bits, owner_id, group_id, false)
|
||||
? EXIT_SUCCESS
|
||||
: EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc;
|
||||
bool ok = true;
|
||||
int exit_status = EXIT_SUCCESS;
|
||||
const char *specified_mode = NULL;
|
||||
bool make_backups = false;
|
||||
char *backup_suffix_string;
|
||||
@@ -361,13 +374,7 @@ main (int argc, char **argv)
|
||||
get_ids ();
|
||||
|
||||
if (dir_arg)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_files; i++)
|
||||
ok &= make_dir_parents (file[i], make_ancestor, &x,
|
||||
dir_mode, announce_mkdir,
|
||||
dir_mode_bits, owner_id, group_id, false);
|
||||
}
|
||||
exit_status = savewd_process_files (n_files, file, process_dir, &x);
|
||||
else
|
||||
{
|
||||
/* FIXME: it's a little gross that this initialization is
|
||||
@@ -376,23 +383,22 @@ main (int argc, char **argv)
|
||||
|
||||
if (!target_directory)
|
||||
{
|
||||
if (mkdir_and_install)
|
||||
ok = install_file_in_file_parents (file[0], file[1], &x);
|
||||
else
|
||||
ok = install_file_in_file (file[0], file[1], &x);
|
||||
if (! (mkdir_and_install
|
||||
? install_file_in_file_parents (file[0], file[1], &x)
|
||||
: install_file_in_file (file[0], file[1], &x)))
|
||||
exit_status = EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
dest_info_init (&x);
|
||||
for (i = 0; i < n_files; i++)
|
||||
{
|
||||
ok &= install_file_in_dir (file[i], target_directory, &x);
|
||||
}
|
||||
if (! install_file_in_dir (file[i], target_directory, &x))
|
||||
exit_status = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
/* Copy file FROM onto file TO, creating any missing parent directories of TO.
|
||||
@@ -402,13 +408,36 @@ static bool
|
||||
install_file_in_file_parents (char const *from, char *to,
|
||||
struct cp_options *x)
|
||||
{
|
||||
if (mkancesdirs (to, make_ancestor, x) != 0)
|
||||
bool save_working_directory =
|
||||
! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
|
||||
int status = EXIT_SUCCESS;
|
||||
|
||||
struct savewd wd;
|
||||
savewd_init (&wd);
|
||||
if (! save_working_directory)
|
||||
savewd_finish (&wd);
|
||||
|
||||
if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
|
||||
{
|
||||
error (0, errno, _("cannot create directory %s"), to);
|
||||
return false;
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return install_file_in_file (from, to, x);
|
||||
if (save_working_directory)
|
||||
{
|
||||
int restore_result = savewd_restore (&wd, status);
|
||||
int restore_errno = errno;
|
||||
savewd_finish (&wd);
|
||||
if (EXIT_SUCCESS < restore_result)
|
||||
return false;
|
||||
if (restore_result < 0 && status == EXIT_SUCCESS)
|
||||
{
|
||||
error (0, restore_errno, _("cannot create directory %s"), to);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
|
||||
}
|
||||
|
||||
/* Copy file FROM onto file TO and give TO the appropriate
|
||||
|
||||
61
src/mkdir.c
61
src/mkdir.c
@@ -28,6 +28,7 @@
|
||||
#include "mkdir-p.h"
|
||||
#include "modechange.h"
|
||||
#include "quote.h"
|
||||
#include "savewd.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "mkdir"
|
||||
@@ -75,12 +76,22 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Options for announce_mkdir and make_ancestor. */
|
||||
/* Options passed to subsidiary functions. */
|
||||
struct mkdir_options
|
||||
{
|
||||
/* Function to make an ancestor, or NULL if ancestors should not be
|
||||
made. */
|
||||
int (*make_ancestor_function) (char const *, void *);
|
||||
|
||||
/* Mode for ancestor directory. */
|
||||
mode_t ancestor_mode;
|
||||
|
||||
/* Mode for directory itself. */
|
||||
mode_t mode;
|
||||
|
||||
/* File mode bits affected by MODE. */
|
||||
mode_t mode_bits;
|
||||
|
||||
/* If not null, format to use when reporting newly made directories. */
|
||||
char const *created_directory_format;
|
||||
};
|
||||
@@ -94,27 +105,44 @@ announce_mkdir (char const *dir, void *options)
|
||||
error (0, 0, o->created_directory_format, quote (dir));
|
||||
}
|
||||
|
||||
/* Make ancestor directory DIR, with options OPTIONS. */
|
||||
/* Make ancestor directory DIR, with options OPTIONS. Return 0 if
|
||||
successful and the resulting directory is readable, 1 if successful
|
||||
but the resulting directory is not readable, -1 (setting errno)
|
||||
otherwise. */
|
||||
static int
|
||||
make_ancestor (char const *dir, void *options)
|
||||
{
|
||||
struct mkdir_options const *o = options;
|
||||
int r = mkdir (dir, o->ancestor_mode);
|
||||
if (r == 0)
|
||||
announce_mkdir (dir, options);
|
||||
{
|
||||
r = ! (o->ancestor_mode & S_IRUSR);
|
||||
announce_mkdir (dir, options);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Process a command-line file name. */
|
||||
static int
|
||||
process_dir (char *dir, struct savewd *wd, void *options)
|
||||
{
|
||||
struct mkdir_options const *o = options;
|
||||
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)
|
||||
? EXIT_SUCCESS
|
||||
: EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
mode_t mode = S_IRWXUGO;
|
||||
mode_t mode_bits = 0;
|
||||
int (*make_ancestor_function) (char const *, void *) = NULL;
|
||||
const char *specified_mode = NULL;
|
||||
int exit_status = EXIT_SUCCESS;
|
||||
int optc;
|
||||
struct mkdir_options options;
|
||||
options.make_ancestor_function = NULL;
|
||||
options.mode = S_IRWXUGO;
|
||||
options.mode_bits = 0;
|
||||
options.created_directory_format = NULL;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
@@ -130,7 +158,7 @@ main (int argc, char **argv)
|
||||
switch (optc)
|
||||
{
|
||||
case 'p':
|
||||
make_ancestor_function = make_ancestor;
|
||||
options.make_ancestor_function = make_ancestor;
|
||||
break;
|
||||
case 'm':
|
||||
specified_mode = optarg;
|
||||
@@ -151,7 +179,7 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (make_ancestor_function || specified_mode)
|
||||
if (options.make_ancestor_function || specified_mode)
|
||||
{
|
||||
mode_t umask_value = umask (0);
|
||||
|
||||
@@ -163,19 +191,14 @@ main (int argc, char **argv)
|
||||
if (!change)
|
||||
error (EXIT_FAILURE, 0, _("invalid mode %s"),
|
||||
quote (specified_mode));
|
||||
mode = mode_adjust (S_IRWXUGO, true, umask_value, change,
|
||||
&mode_bits);
|
||||
options.mode = mode_adjust (S_IRWXUGO, true, umask_value, change,
|
||||
&options.mode_bits);
|
||||
free (change);
|
||||
}
|
||||
else
|
||||
mode &= ~umask_value;
|
||||
options.mode = S_IRWXUGO & ~umask_value;
|
||||
}
|
||||
|
||||
for (; optind < argc; ++optind)
|
||||
if (! make_dir_parents (argv[optind], make_ancestor_function, &options,
|
||||
mode, announce_mkdir,
|
||||
mode_bits, (uid_t) -1, (gid_t) -1, true))
|
||||
exit_status = EXIT_FAILURE;
|
||||
|
||||
exit (exit_status);
|
||||
exit (savewd_process_files (argc - optind, argv + optind,
|
||||
process_dir, &options));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
# Basic tests for "install".
|
||||
|
||||
# Copyright (C) 1998, 2000, 2001, 2002, 2004, 2005 Free Software
|
||||
# Copyright (C) 1998, 2000, 2001, 2002, 2004, 2005, 2006 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -95,16 +95,27 @@ test -d newdir3 || fail=1
|
||||
# initial working directory ($abs) after creating the first argument, and
|
||||
# hence cannot do anything meaningful with the following relative-named dirs.
|
||||
abs=$pwd/$tmp
|
||||
mkdir sub && cd sub
|
||||
chmod 0 .; ginstall -d $abs/xx/yy rel/sub1 rel/sub2 2> /dev/null && fail=1
|
||||
chmod 755 $abs/sub
|
||||
mkdir sub || fail=1
|
||||
(cd sub && chmod 0 . && ginstall -d $abs/xx/yy rel/sub1 rel/sub2 2> /dev/null) && fail=1
|
||||
chmod 755 sub
|
||||
|
||||
# Ensure that the first argument-dir has been created.
|
||||
test -d $abs/xx/yy || fail=1
|
||||
test -d xx/yy || fail=1
|
||||
|
||||
# Make sure that the `rel' directory was not created...
|
||||
test -d $abs/sub/rel && fail=1
|
||||
test -d sub/rel && fail=1
|
||||
# and make sure it was not created in the wrong place.
|
||||
test -d $abs/xx/rel && fail=1
|
||||
test -d xx/rel && fail=1
|
||||
|
||||
# Test that we can install from an unreadable directory with an
|
||||
# inaccessible parent. coreutils 5.97 fails this test.
|
||||
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
|
||||
test -d xx/zz || fail=1
|
||||
test -d sub1/d/rel/a || fail=1
|
||||
test -d sub1/d/rel/b || fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -37,7 +37,7 @@ mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
mkdir no-access || framework_failure=1
|
||||
mkdir no-acce2s || framework_failure=1
|
||||
mkdir no-acce3s || framework_failure=1
|
||||
mkdir -p no-acce3s/d || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
@@ -45,13 +45,18 @@ if test $framework_failure = 1; then
|
||||
fi
|
||||
|
||||
p=$pwd/$tmp
|
||||
(cd no-access; chmod 0 . && mkdir -p $p/a/b u/v) 2> /dev/null && fail=1
|
||||
(cd no-access && chmod 0 . && mkdir -p $p/a/b u/v) 2> /dev/null && fail=1
|
||||
test -d $p/a/b || fail=1
|
||||
|
||||
# Same as above, but with a following *absolute* name, it should succeed
|
||||
(cd no-acce2s; chmod 0 . && mkdir -p $p/b/b $p/z) || fail=1
|
||||
(cd no-acce2s && chmod 0 . && mkdir -p $p/b/b $p/z) || fail=1
|
||||
test -d $p/b/b && test -d $p/z || fail=1
|
||||
|
||||
test -d $p/z || fail=1
|
||||
# Same as above, but a trailing relative name in an unreadable directory
|
||||
# whose parent is inaccessible. coreutils 5.97 fails this test.
|
||||
(cd no-acce3s/d && chmod a-rx .. && chmod a-r . && mkdir -p a/b $p/b/c d/e &&
|
||||
test -d a/b && test -d d/e) || fail=1
|
||||
test -d $p/b/c || fail=1
|
||||
|
||||
b=`ls $p/a|tr -d '\n'`
|
||||
# With coreutils-5.3.0, this would fail with $b=bu.
|
||||
|
||||
Reference in New Issue
Block a user