From b67faf329cebf0805b2b73cc775ccfc7a05390de Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 16 Sep 2006 20:03:56 +0000 Subject: * 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. --- src/mkdir.c | 61 ++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'src/mkdir.c') diff --git a/src/mkdir.c b/src/mkdir.c index 852bc3e15..b28a02ac0 100644 --- a/src/mkdir.c +++ b/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)); } -- cgit v1.2.3-54-g00ecf