git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] Set errno to EEXIST if mkdir returns EACCES or EPERM

From
Junio C Hamano <junkio@cox.net>
Date
Jan 30, 2006, 20:33 UTC
Message-ID
<7vvew14frk.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<20060130193839.GA6575@steel.home>
Alex Riesen <raa.lkml@gmail.com> writes:
Show 12 quoted lines
> ... and the directory already exists. I.E. Cygwin is such
> a case: mkdir fail for mounts which reference directly
> to windows mounts ("drives").
>
> ---
>
> The discussion, which ended up with this patch can be read
> here: http://www.cygwin.com/ml/cygwin/2006-01/msg01276.html
>
> BTW, there is this:
> http://www.cygwin.com/ml/cygwin/2006-01/msg01380.html
> So this patch will probably be not needed soon.

Thanks for all the background information. Although it is very tempting for me to adopt your patch as an easy way out, I would feel *dirty* if I did so.

Eric Blake is right in his argument in that thread. Our code should not depend on the Linux EEXIST behaviour. The reason Cygwin folks want to be as close to Linux is to work around application bugs like this. Which is a valid concern for them, but it does not mean the application has license to depend on Linux behaviour.

We, as an application, should take a different attitude -- we should fix things to make things portable, not work things around, if both are equally easily doable. I do not object to using a function that has a semantics Linux mkdir() gives us, but calling that mkdir() does not feel quite right.

Also the wrapper implies that in our future use of mkdir() we cannot tell the difference between EEXIST and other errors if we later wanted to.

So let's look at our existing uses first:

apply.c:1577: if (mkdir(buf, 0777) < 0) { apply.c-1578- if (errno != EEXIST) apply.c-1579- break; apply.c-1580- } apply.c-1581- }

This is "we want to see buf directory exist and we would create one if there isn't". Instead of checking errno, we could stat as your patch does.

entry.c:15: if (mkdir(buf, 0777)) { entry.c-16- if (errno == EEXIST) { entry.c-17- struct stat st; entry.c:18: if (len > state->base_dir_len && state->force && !unlink(buf) && !mkdir(buf, 0777)) entry.c-19- continue; entry.c-20- if (!stat(buf, &st) && S_ISDIR(st.st_mode)) entry.c-21- continue; /* ok */ entry.c-22- }

This is a bit more involved. "we want to have buf directory and we would create it, and if force is given to have something under that directory, we would even unlink the nondirectory that sits there".

I asked "git-grep" where else we use mkdir(), and all other users want the semantics of the apply.c use quoted above.

So I'd rather see us create a generic helper function like this:
	int make_directory(const char *path, int force)
        {
		struct stat st;
		int mkdir_errno;
		if (!mkdir(path, 0777))
			return 0;
                mkdir_errno = errno;
		if (!lstat(path, &st) && S_ISDIR(st.st_mode))
                	return 0;
                if (!force) {
		bad:
                	errno = mkdir_errno;
                        return -1;
                }
                if (!unlink(path, &st) && !mkdir(path, 0777))
                	return 0;
                /* we might have failed to unlink an existing symlink
		 * which happens to point at an existing directory; that
                 * directory is not what we want here.
                 */
		if (!lstat(path, &st) && S_ISDIR(st.st_mode))
                	return 0;
		goto bad;
        }

and have current callers of mkdir() use it, regardless of the platform. It may not worth saving mkdir_errno, though.

Then everybody but entry.c one would say force=0, and entry.c one passes force appropriately using the condition it uses in its current if() statement.

Previous: Alex RiesenNext: Alex Riesen
Message 2 of 3 in “Set errno to EEXIST if mkdir returns EACCES or EPERM”
  1. Set errno to EEXIST if mkdir returns EACCES or EPERMAlex Riesen, Jan 30, 2006
  2. Junio C HamanoJan 30, 2006
  3. Alex RiesenJan 30, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.