X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fmkdir-p.c;h=f38dbc71f866b407c0e4d0fc72a20cd50d47464f;hb=cdfe647f8d29540cdfe90cef0fa568c5d2fd4481;hp=f097e67669d3e1355a0da47594133395b8508c7d;hpb=eeb96e1a6b5e0b31a4011d7d333999592c0bb2e9;p=gnulib.git diff --git a/lib/mkdir-p.c b/lib/mkdir-p.c index f097e6766..f38dbc71f 100644 --- a/lib/mkdir-p.c +++ b/lib/mkdir-p.c @@ -1,12 +1,12 @@ /* mkdir-p.c -- Ensure that a directory and its parents exist. - Copyright (C) 1990, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + Copyright (C) 1990, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, + 2006, 2007 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + 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, or (at your option) - any later version. + the Free Software Foundation; either version 3 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 @@ -14,8 +14,7 @@ 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. */ + along with this program. If not, see . */ /* Written by Paul Eggert, David MacKenzie, and Jim Meyering. */ @@ -25,24 +24,28 @@ #include #include +#include #include "gettext.h" #define _(msgid) gettext (msgid) -#include "dirchownmod.c" +#include "dirchownmod.h" #include "dirname.h" #include "error.h" #include "quote.h" #include "mkancesdirs.h" #include "savewd.h" -#include "stat-macros.h" + +#ifndef HAVE_FCHMOD +# define HAVE_FCHMOD false +#endif /* Ensure that the directory DIR exists. WD is the working directory, as in savewd.c. If MAKE_ANCESTOR is not null, create any ancestor directories that - don't already exist, by invoking MAKE_ANCESTOR (ANCESTOR, OPTIONS). + don't already exist, by invoking MAKE_ANCESTOR (DIR, ANCESTOR, OPTIONS). This function should return zero if successful, -1 (setting errno) otherwise. In this case, DIR may be modified by storing '\0' bytes into it, to access the ancestor directories, and this modification @@ -82,7 +85,7 @@ bool make_dir_parents (char *dir, struct savewd *wd, - int (*make_ancestor) (char const *, void *), + int (*make_ancestor) (char const *, char const *, void *), void *options, mode_t mode, void (*announce) (char const *, void *), @@ -111,18 +114,33 @@ make_dir_parents (char *dir, if (0 <= prefix_len) { - if (mkdir (dir + prefix_len, mode) == 0) + /* If the ownership might change, or if the directory will be + writeable to other users and its special mode bits may + change after the directory is created, create it with + more restrictive permissions at first, so unauthorized + users cannot nip in before the directory is ready. */ + bool keep_owner = owner == (uid_t) -1 && group == (gid_t) -1; + bool keep_special_mode_bits = + ((mode_bits & (S_ISUID | S_ISGID)) | (mode & S_ISVTX)) == 0; + mode_t mkdir_mode = mode; + if (! keep_owner) + mkdir_mode &= ~ (S_IRWXG | S_IRWXO); + else if (! keep_special_mode_bits) + mkdir_mode &= ~ (S_IWGRP | S_IWOTH); + + if (mkdir (dir + prefix_len, mkdir_mode) == 0) { announce (dir, options); - preserve_existing = - (owner == (uid_t) -1 && group == (gid_t) -1 - && ! ((mode_bits & (S_ISUID | S_ISGID)) | (mode & S_ISVTX))); + preserve_existing = keep_owner & keep_special_mode_bits; savewd_chdir_options |= (SAVEWD_CHDIR_NOFOLLOW | (mode & S_IRUSR ? SAVEWD_CHDIR_READABLE : 0)); } else - mkdir_errno = errno; + { + mkdir_errno = errno; + mkdir_mode = -1; + } if (preserve_existing) { @@ -159,7 +177,6 @@ make_dir_parents (char *dir, } else { - mode_t mkdir_mode = (mkdir_errno == 0 ? mode : -1); char const *subdir = (chdir_ok ? "." : dir + prefix_len); if (dirchownmod (fd, subdir, mkdir_mode, owner, group, mode, mode_bits) @@ -175,7 +192,7 @@ make_dir_parents (char *dir, (! chdir_failed_unexpectedly ? errno : ! chdir_ok && (mode & S_IXUSR) ? chdir_errno : open_result[1]), - _(owner == (uid_t) -1 && group == (gid_t) -1 + _(keep_owner ? "cannot change permissions of %s" : "cannot change owner and permissions of %s"), quote (dir));