Subject: Re: mkdir -p and EROFS
From: [email-masked] (Eric Blake)
To: Jim Meyering <[email-masked]>
Cc: [email-masked], [email-masked]
Date: Wed, 12 Oct 2005 19:57:04 +0000

> [email-masked] (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  <[email-masked]>

	* mkdir-p.c (make_dir_parents): Treat EROFS like EEXIST.  Works
	around cygwin bug where EROFS is favored over EEXIST.

--
Eric Blake

--
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/