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 From: ericblake AT comcast DOT net (Eric Blake) To: Jim Meyering Cc: bug-coreutils AT gnu DOT org, cygwin AT cygwin DOT com Subject: Re: mkdir -p and EROFS Date: Wed, 12 Oct 2005 19:57:04 +0000 Message-Id: <101220051957.877.434D6A90000848A80000036D22007510900A050E040D0C079D0A@comcast.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="NextPart_Webmail_9m3u9jl4l_877_1129147024_0" Note-from-DJ: This may be spam --NextPart_Webmail_9m3u9jl4l_877_1129147024_0 Content-Type: text/plain Content-Transfer-Encoding: 8bit > ericblake AT comcast DOT net (Eric Blake) wrote: > > 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. > > Are you sure 5.3.0 behaved differently in this case? Yes. With unmodified 5.3.0, the sequence flat out fails (it was post 5.3.0 where Paul added a patch to respect leading // as different from /). In the cygwin distro of 5.3.0, where I backported the first cut of Paul's patch, the sequence of calls is: make_path("//EBLAKE/share/dir", ...) stat("//EBLAKE/share/dir") => ENOENT chdir("//") make_dir("EBLAKE", "//EBLAKE", ...) mkdir("EBLAKE") => EROFS, ignored stat("EBLAKE") chdir("EBLAKE") make_dir("share", "//EBLAKE/share", ...) mkdir("share") => EEXIST, ignored stat("share") chdir("share") make_dir("dir", "//EBLAKE/share/dir", ...) mkdir("dir") Subsequent changes were made prior to 5.90, including renaming the file and method to perform the optimizations of reducing syscalls, so the sequence of calls is now: make_dir_parents("//EBLAKE/share/dir", ...) stat("//EBLAKE/share/dir") => ENOENT chdir("//") mkdir("EBLAKE") => EROFS, not EEXIST or ENOSYS error(0, EROFS, "cannot create directory %s", "//EBLAKE") > The recent algorithm change was merely to eliminate the optimization > of initially stat'ing the full directory name. In your example, > that stat would fail and the function would end up performing the same > operations the 5.90 version performs. The difference is not the mkdir() failing with EROFS, but that 5.90 no longer does an (otherwise) redundant stat when mkdir fails. With the errno being set to a non-intuitive value of EROFS, information was lost compared to setting it to EEXIST. > > If mkdir-p.c were to handle Cygwin's EROFS like ENOSYS, we'd have to add > code to distinguish a legitimate EROFS (because a missing destination > directory cannot be created) from a cygwin-style should-be-EEXIST one. > That feels too kludgy. Not necessarily - the point of make_dir_parents optimization on EEXIST is that even though mkdir will fail with EEXIST when the file existed as a regular file, as opposed to a directory, the subsequent chdir() prior to the next component in the chain will catch that without the need for an intermediate stat(). Treating EROFS as EEXIST will lead to the same end behavior, with regards to mkdir(1) (ie. mkdir -p will either verify the complete named path exists, or die with some form of reasonable error in the process). 2005-10-12 Eric Blake * mkdir-p.c (make_dir_parents): Treat EROFS like EEXIST. Works around cygwin bug where EROFS is favored over EEXIST. -- Eric Blake --NextPart_Webmail_9m3u9jl4l_877_1129147024_0 Content-Type: application/octet-stream; name="coreutils.patch1" Content-Transfer-Encoding: 7bit Index: lib/mkdir-p.c =================================================================== RCS file: /cvsroot/coreutils/coreutils/lib/mkdir-p.c,v retrieving revision 1.11 diff -u -r1.11 mkdir-p.c --- lib/mkdir-p.c 22 Sep 2005 05:42:26 -0000 1.11 +++ lib/mkdir-p.c 12 Oct 2005 19:52:28 -0000 @@ -49,6 +49,10 @@ # define ENOSYS EEXIST #endif +#ifndef EROFS +# define EROFS EEXIST +#endif + #define WX_USR (S_IWUSR | S_IXUSR) /* Ensure that the directory ARG exists. @@ -215,14 +219,18 @@ leading_dirs = new; } } - else if (errno == EEXIST || errno == ENOSYS) + else if (errno == EEXIST || errno == ENOSYS || errno == EROFS) { /* 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. */ + NFS mount point. + + The EROFS is for cygwin, which can fail with + errno == EROFS if the file exists but is part of a + read only file system. */ } else { --NextPart_Webmail_9m3u9jl4l_877_1129147024_0 Content-Type: text/plain; charset=us-ascii -- 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/ --NextPart_Webmail_9m3u9jl4l_877_1129147024_0--