Defect report from : Don Cragun , Sun Microsystems, Inc.
(Please direct followup comments direct to yyyyyyyyyyyyyy@xxxxxxxxxxxxx)
@ page 102-103 line 3161-3163 section 4.11 objection {dwc:PathnameResolution-1}
Problem:
Edition of Specification (Year): 2003
Defect code : 1. Error
I am requesting a formal interpretation of the meaning of
trailing slashes in the general concept Pathname Resolution in
subclause 4.11 in IEEE Std 1003.1-2001 (2003 edition, pages 102-103,
lines 3161-3163). I do not believe the normative text matches the
intent specified in the rationale. I also believe the normative text
places unneeded restrictions on applications and implementations.
The current POSIX standard finally implemented some changes in
the definition of pathname resolution based on concerns that were
discussed years ago at POSIX meetings about trailing slash characters
in pathnames. I have discussed this issue with several people that
were involved in the original discussions that lead to the text in the
P1003.1a drafts that were incorporated into the definition of the
Pathname Resolution general concept in XBD6 subclause 4.11. All have
agreed that the current wording would have serious side effects if
implementations were written to the letter of these requirements.
(Specifically, things like rmdir("dir/") are required to fail even
though the intent of the changes introduced into P1003.1a drafts was
intended to allow this to succeed in cases where "dir" names an
existing directory. The normative text of the standard is silent on
what happens with rename("dir/", "dir2") when "dir2" names an existing
empty directory or does not name an existing file, but the rationale
clearly states that "dir/." and "dir/.." are not allowed. The intent
of the working group that drafted these changes was to allow a trailing slash
here. We have also discussed whether mkdir("new/") and
rename("dir/", "new/") should succeed or fail when "new" does not name
an existing file.)
The way that this requirement is worded in the current POSIX
standard (POSIX.1, 2003 edition, Base Definitions volume, page 102-103,
lines 3161-3163 is:
"A pathname that contains at least one non-slash
character and that ends with one or more trailing
slash characters shall be resolved as if a single dot
character ('.') were appended to the pathname."
This wording requires failure for these cases:
1. rmdir("dir/.") is required to fail with EINVAL,
2. mkdir("new/.") is required to fail with ENOTDIR, and
3. rename(..., "new/.") is required to fail with ENOTDIR.
As mentioned above, rename() does not explicitly mention
rename("dir/.", ...) in normative text, but the rationale says:
"Renaming dot or dot-dot is prohibited in order to prevent
cyclical file system paths."
(See XSH6, P1216, L37967).
I believe the intent of the working group was that if a
pathname has a trailing slash character, it can only be used to refer
to a directory. The original SVID3 wording (from Volume 1, page 4-11,
top two paragraphs) in the definition of "pathname and path prefix"
includes:
"A pathname is used to identify a file. It consists
of at most, {PATH_MAX} bytes, including a terminating
null character. It has an optional beginning slash,
followed by zero or more filenames separated by
*** slashes. If the pathname refers to a directory, it
*** may also have one or more trailing slashes. Multiple
consecutive slashes may be interpreted in an
implementation-defined manner, although more than two
leading slashes are treated as a single slash.
If a pathname begins with a slash, the path search
begins at the root directory. Otherwise, the search
*** begins from the current working directory. If a
*** pathname refers to a directory, it may also have one
*** or more trailing slashes. Multiple consecutive
slashes are considered the same as a single slash."
(Note that SVID3 was one of the reference documents used frequently in
the development of POSIX.1-1990.) I believe the two complete
sentences on the line marked with *** above cover the same intent, but
System V did not enforce the part about trailing slashes being allowed
only after directories and always threw away trailing slash
characters. (In fact, SVID3 never specified what is supposed to
happen if a pathname that does not refer to a directory has one or
more trailing slashes.)
Unfortunately, the wording from SVID3 is ambiguous. "If a
pathname refers to a directory" could mean "If a pathname refers to aN
EXISTING directory" or could mean "If a pathname refers to SOMETHING
THAT WILL BE USED AS a directory". The unanimous consensus of the
people I have discussed this with so far is that the desired meaning
is the latter, except for a special case for the last argument to
rename(). A short summary of the discussions leading to this
conclusion follows: In these examples "dir" and "dir2" refer to
existing files of type directory and "new" refers to a non-existent
file.
mkdir():
We all believe that mkdir("new") should be equivalent to
mkdir("new/") although there were dissenting opinions at the
start of the discussion.
There are several uses of mkdir("new/") in third party
applications and this is clearly in line with one
interpretation of the SVID3 wording. Many of these
applications are creating a temporary directory and saving the
directory name (with the trailing slash) for later use to
create pathnames for files to be created in that directory.
These applications save a step by including the trailing slash
when the temporary directory is created and did not believe
they were breaking the intended requirements of any standard.
rename():
We all believe that rename("dir", "new") and
rename("dir/", "new") should be equivalent.
We all believe that rename("dir", "new") should not be treated
the same as rename("dir", "new/") although there were
dissenting opinions at the start of the discussion. We
believe that in this case, "new/" should fail if new does not
name an existing directory. The rename() function is very
similar to the mv utility when given two operands that are on
the same file system. For the mv utility, the command:
mv dir dir2/
should always rename dir to be dir2/dir or fail (matching
historic BSD mv behavior). To match this, rename("dir",
"dir2") and rename("dir", "dir2/") should rmdir("dir2") and
rename("dir", "dir2") as an atomic operation, but
rename("dir", "new/") should fail (since "new" is not an
existing directory).
rmdir():
We all believe that rmdir("dir") and rmdir("dir/") should be
equivalent.
Action:
Assuming that the interpretation is that the standard needs to
be changed to match the intent of the working group, I propose the
following changes in the next revision of the standard:
Change XBD6, P102, L3161-3163 from (definition of Pathname Resolution
general concept):
``A pathname that contains at least one non-slash
character and that ends with one or more trailing
slash characters shall be resolved as if a single dot
character ('.') were appended to the pathname.''
to:
``If a pathname contains at least one non-slash
character and ends with one or more trailing slashes
after all symbolic links have been processed, and if
the final component of the pathname before the
trailing slashes names a non-existant file in an
operation that is not attempting to create a directory
or refers to an existing file that is not a directory,
the implementation shall consider this an error.
Otherwise, if a pathname contains at least one
non-slash character and ends with one or more trailing
slashes after all symbolic links have been processed,
the pathname shall be resolved as though all trailing
slashes after the last non-slash character were
removed. Interfaces using pathname resolution may
specify additional constraints when a pathname
contains one or more trailing slashes and does not
name an existing directory.*
__________________
* The only interfaces that further constrain pathnames that do
not name existing directories in this standard are rename()
in the System Interfaces volume of this standard and the rm
utility in the Shell and Utilities volume of this
standard.''
and move this changed text to follow P103, L3180.
Change XRAT6, P37, L1481-1482 from (rationale for Pathname Resolution
general concept):
``IEEE Std 1003.1-2003 requires that a pathname with a
trailing slash character be treated as if it had a
trailing "/." everywhere.''
to:
``An earlier version of this standard required that a
pathname with a trailing slash character be treated as
if it had a trailing "/." everywhere. This
unintentionally broke applications that used
mkdir("newdir/") and rmdir("existing-dir/"). This
standard requires that a pathname with a trailing
slash be rejected unless it refers to a file that is a
directory or to a file that is to be created as a
directory. The rename() function and the mv utility
further specify that a trailing slash cannot be used
on a pathname naming a file that that does not exist
when used as the last argument to rename() or the as
the last operand to mv.''
Add the new sentence (CX shaded):
``If the new argument does not resolve to an existing
file of type directory and the new argument contains
at least one non-slash character and ends with one or
more trailing slashes after all symbolic links have
been processed, rename() shall fail.''
to the end of the paragraph on XSH6, P1214, L37861-37862 (2nd
paragraph of the description of rename()).
Change XSH6, P1215, L37922-37933 (shall fail ENOTDIR error in rename())
from:
``[ENOTDIR] A component of either path prefix is
not a directory; or the old argument
names a directory and the new argument
names a non-directory file.''
to:
``[ENOTDIR] A component of either path prefix is
not a directory; the old argument
names a directory and the new argument
names a non-directory file; or the new
argument names a non-existant file and
ends with a trailing slash
character.''
all CX shaded.
Add the new sentence:
``In this case, if target_file ends with a trailing
slash character, mv shall treat this as an error and
no source_file operands will be processed.''
to the end of the paragraph on XCU6, P655, L25352-25355 (1st paragraph
of the description of mv). (Note that a separate aardvark report has
already been filed to change "target_file" in the second synopsis form
on P655, L25350 to "target_dir".)
To also fix the inconsistency between the normative text and the
rationale in rename()'s handling of pathnames whose last component is
dot or dot-dot, I also suggest changing the EINVAL shall fail error
condition description on XSH6, P1215, L37907-37908 from:
``[EINVAL] The new directory pathname contains a
path prefix that names the old
directory.''
to:
``[EINVAL] The new directory pathname contains a
path prefix that names the old
directory, or the final pathname
component of old or new is dot or
dot-dot.''
If accepted, these changes would allow applications to perform the
following operations successfully (assuming non-existing does not name
any existing file and assuming existing-dir and another-existing-dir
resolve to existing directories upon which the process has permission
to operate):
mkdir("non-existing/", ...)
mkdir("non-existing", ...)
rmdir("existing-dir/")
rmdir("existing-dir")
rename("existing-dir/", "another-existing-dir/")
rename("existing-dir", "another-existing-dir/")
rename("existing-dir/", "another-existing-dir")
rename("existing-dir", "another-existing-dir")
And all of the following would fail (assuming non-dir names an
existing file that is not a directory):
open("non-dir/", ..., ...)
mkdir("non-dir/")
unlink("non-dir/")
rename("non-dir/", ...)
rename(..., "non-dir/")
rename(..., "non-existing/")
|