Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com To: ericblake AT comcast DOT net (Eric Blake) Cc: bug-coreutils AT gnu DOT org, cygwin AT cygwin DOT com Subject: Re: mkdir -p and EROFS References: <101220051447 DOT 16978 DOT 434D21E5000D25EB0000425222007610640A050E040D0C079D0A AT comcast DOT net> From: Paul Eggert Date: Wed, 12 Oct 2005 14:24:09 -0700 In-Reply-To: <101220051447.16978.434D21E5000D25EB0000425222007610640A050E040D0C079D0A@comcast.net> (Eric Blake's message of "Wed, 12 Oct 2005 14:47:01 +0000") Message-ID: <87r7aqqvie.fsf@penguin.cs.ucla.edu> User-Agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii ericblake AT comcast DOT net (Eric Blake) writes: > The algorithm change between 5.3.0 and 5.90 in lib/mkdir-p.c to > try mkdir() first instead of stat(), and key off of EEXIST, breaks > when mkdir() fails with EROFS on an intermediate directory when > the writable directory has been mounted inside a read-only tree. Thanks for reporting this. It is indeed a bug in coreutils/lib/mkdir-p.c. It can be triggered by other errors too. This is hard to write a test case for, but I'd like to fix things. Does the following patch work for you? Jim, if this works for Eric, is it OK to install this patch at this late date? 2005-10-12 Paul Eggert * mkdir-p.c (make_dir_parents): Don't fail if an intervening mkdir fails due to EROFS, or due to EEXIST or other reasons for that matter. Problem reported by Eric Blake. (ENOSYS): Remove; no longer needed. --- mkdir-p.c.~1.11.~ 2005-09-21 22:42:26.000000000 -0700 +++ mkdir-p.c 2005-10-12 14:21:22.000000000 -0700 @@ -45,10 +45,6 @@ #include "quote.h" #include "stat-macros.h" -#ifndef ENOSYS -# define ENOSYS EEXIST -#endif - #define WX_USR (S_IWUSR | S_IXUSR) /* Ensure that the directory ARG exists. @@ -175,6 +171,9 @@ make_dir_parents (char const *arg, while (true) { + bool dir_known_to_exist; + int mkdir_errno; + /* slash points to the leftmost unprocessed component of dir. */ basename_dir = slash; @@ -188,7 +187,10 @@ make_dir_parents (char const *arg, basename_dir = dir; *slash = '\0'; - if (mkdir (basename_dir, tmp_mode) == 0) + dir_known_to_exist = (mkdir (basename_dir, tmp_mode) == 0); + mkdir_errno = errno; + + if (dir_known_to_exist) { if (verbose_fmt_string) error (0, 0, verbose_fmt_string, quote (dir)); @@ -215,29 +217,30 @@ make_dir_parents (char const *arg, leading_dirs = new; } } - else if (errno == EEXIST || errno == ENOSYS) - { - /* A file is already there. Perhaps it is a directory. - If not, it will be diagnosed later. - - The ENOSYS is for Solaris 8 NFS clients, which can - fail with errno == ENOSYS if mkdir is invoked on an - NFS mount point. */ - } - else - { - error (0, errno, _("cannot create directory %s"), quote (dir)); - retval = false; - break; - } /* If we were able to save the initial working directory, then we can use chdir to change into each directory before creating an entry in that directory. This avoids making mkdir process O(n^2) file name components. */ - if (do_chdir && chdir (basename_dir) < 0) + if (do_chdir) + { + if (chdir (basename_dir) == 0) + dir_known_to_exist = true; + else if (dir_known_to_exist) + { + error (0, errno, _("cannot chdir to directory %s"), + quote (dir)); + retval = false; + break; + } + } + else if (!dir_known_to_exist) + dir_known_to_exist = (stat (basename_dir, &stats) == 0 + && S_ISDIR (stats.st_mode)); + + if (!dir_known_to_exist) { - error (0, errno, _("cannot chdir to directory %s"), + error (0, mkdir_errno, _("cannot create directory %s"), quote (dir)); retval = false; break; -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/