Discussion:
Question about open, O_CREAT, and directories
Tom Ridge
2014-06-16 09:49:13 UTC
Permalink
Dear List,

Reading the spec for open, it appears that the intention is that open
with O_CREAT cannot be used to create directories. The reasoning is
that a command such as:

open /a/b [O_CREAT]

would ordinarily create a non-directory file b in directory a. In
order to create a directory, one might try:

open /a/b/ [O_CREAT]

but this would fail if b does not exist. Can someone confirm that open
cannot be used to create directories?

Another question: if b does exist, then open /a/b/ [O_CREAT] may fail
with ENOTDIR. The clause from the spec is:

[ENOENT] or [ENOTDIR]
O_CREAT is set, and the path argument contains at least one non-
<slash> character and ends with one or more trailing <slash>
characters. If path names an existing file, an [ENOENT] error shall
not occur.

But the error ENOTDIR seems confusing. The problem here seems to be
that the target /a/b/ IS a directory, and that this is not allowed in
combination with the flag O_CREAT. Is there a reason not to allow
EISDIR, or perhaps EINVAL, in this situation?

Thanks
Geoff Clare
2014-06-16 16:07:07 UTC
Permalink
Post by Tom Ridge
Reading the spec for open, it appears that the intention is that open
with O_CREAT cannot be used to create directories. The reasoning is
open /a/b [O_CREAT]
would ordinarily create a non-directory file b in directory a. In
open /a/b/ [O_CREAT]
but this would fail if b does not exist. Can someone confirm that open
cannot be used to create directories?
Yes, open() cannot be used to create directories.
Post by Tom Ridge
Another question: if b does exist, then open /a/b/ [O_CREAT] may fail
[ENOENT] or [ENOTDIR]
O_CREAT is set, and the path argument contains at least one non-
<slash> character and ends with one or more trailing <slash>
characters. If path names an existing file, an [ENOENT] error shall
not occur.
But the error ENOTDIR seems confusing. The problem here seems to be
that the target /a/b/ IS a directory, and that this is not allowed in
combination with the flag O_CREAT. Is there a reason not to allow
EISDIR, or perhaps EINVAL, in this situation?
This looks like an omission in the current EISDIR description.
It doesn't cover the use of O_RDONLY|O_CREAT or O_SEARCH|O_CREAT.
I think we should change:

The named file is a directory and oflag includes O_WRONLY or O_RDWR.

to:

The named file is a directory and oflag includes O_WRONLY, O_RDWR,
or O_CREAT.

In the case of open("/a/b", O_RDONLY|O_CREAT, mode) the EISDIR error
would be required.

In the case of open("/a/b/", O_RDONLY|O_CREAT, mode) the conditions
for EISDIR and ENOTDIR would both be satisfied and implementations
could return either error.

The ENOTDIR is not confusing if you think of it as "you've made an error
by trying to create a non-directory file using a pathname with a trailing
slash". Whether or not the file already exists, and what type it has,
don't affect this. I.e. open() can check for this error without doing
any pathname resolution. All of the functions that create non-directory
files have the same ENOTDIR error.
--
Geoff Clare <g.clare-7882/***@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England
Richard Hansen
2014-06-16 18:39:06 UTC
Permalink
Post by Geoff Clare
Post by Tom Ridge
Reading the spec for open, it appears that the intention is that open
with O_CREAT cannot be used to create directories. The reasoning is
open /a/b [O_CREAT]
would ordinarily create a non-directory file b in directory a. In
open /a/b/ [O_CREAT]
but this would fail if b does not exist. Can someone confirm that open
cannot be used to create directories?
Yes, open() cannot be used to create directories.
Relevant thread:
http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9451

-Richard
Geoff Clare
2014-06-17 08:33:12 UTC
Permalink
Post by Geoff Clare
Post by Tom Ridge
But the error ENOTDIR seems confusing. The problem here seems to be
that the target /a/b/ IS a directory, and that this is not allowed in
combination with the flag O_CREAT. Is there a reason not to allow
EISDIR, or perhaps EINVAL, in this situation?
This looks like an omission in the current EISDIR description.
It doesn't cover the use of O_RDONLY|O_CREAT or O_SEARCH|O_CREAT.
The named file is a directory and oflag includes O_WRONLY or O_RDWR.
The named file is a directory and oflag includes O_WRONLY, O_RDWR,
or O_CREAT.
As Richard pointed out, there was also a recent discussion about
O_CREAT|O_DIRECTORY. If we want to allow implementations to provide
a way create (and open) a directory using O_CREAT|O_DIRECTORY as an
extension, then the new text for the above change should be:

The named file is a directory and oflag includes O_WRONLY or O_RDWR,
or includes O_CREAT without O_DIRECTORY.

This would only make sense if we change the description of O_CREAT to
allow this extension as well. E.g. change:

Otherwise, the file shall be created

to:

Otherwise, if O_DIRECTORY is not set the file shall be created as
a regular file

and add to the end:

If O_CREAT and O_DIRECTORY are set and the requested access mode
is neither O_WRONLY nor O_RDWR, the result is unspecified.
--
Geoff Clare <g.clare-7882/***@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England
Continue reading on narkive:
Loading...