|Anonymous | Login||2021-03-01 01:01 UTC|
|Main | My View | View Issues | Change Log | Docs|
|Viewing Issue Simple Details|
|ID||Category||Severity||Type||Date Submitted||Last Update|
|0000161||[1003.1(2008)/Issue 7] Shell and Utilities||Objection||Error||2009-10-03 23:17||2013-04-16 13:06|
|Priority||normal||Resolution||Accepted As Marked|
|Final Accepted Text||See Note: 0000247|
|Summary||0000161: mkdir -p through dangling symlink|
The description of mkdir -p in terms of a shell script is incorrect in the presence of whitespace in the directory name. In particular, consider:
mkdir -p "$(printf 'a b\n'/c')"
which in practice creates the parent directory with a trailing newline, but which according to the spec effectively recursively calls mkdir(1) with two arguments and no newline, instead of a single argument.
Furthermore, it seems inconsistent that:
ln -s dir dangling
mkdir -p dangling/sub
is required to fail (since it recurses to 'mkdir -p dangling', but that must fail with EEXIST), while
mkdir -p dangling/
is required to succeed (the recursion sees $(dirname dangling/) which is ".", and that exists; next the code has the same effect as mkdir("dangling/") which is required to follow through the symlink per mkdir(2)). (It doesn't help that GNU/Linux mkdir(2) fails with EEXIST when dealing with a symlink with trailing slash, in violation of the standard as written).
Correctly describing the dirname operation in shell without losing a trailing newline gets rather lengthy. Providing a trailing slash to the recursive mkdir call solves the problem of stripping trailing newline. Furthermore, requiring a trailing slash on all intermediate components will give more predictable behavior, where a directory can be created through a dangling symlink.
Replace lines 96644-5:
mkdir −p −m $(umask −S),u+wx $(dirname dir) &&
mkdir [−m mode] dir
mkdir −p −m $(umask −S),u+wx \
"$(dirname "dir" | head -n -1; printf /)" &&
mkdir [−m mode] "dir"
Typo in the Description:
mkdir -p "$(printf 'a b\n'/c')"
mkdir -p "$(printf 'a b\n/c')"
The desired action also has a typo; 'head -c -1' was intended instead of 'head -n -1'. But unfortunately, even that is not portable (unlike the counterpart of 'tail -c -1'). For that matter, the only portable means I could find for discarding only the trailing newline involves even more processes, including running the dirname command twice:
mkdir −p −m $(umask −S),u+wx "$(dirname "dir" |
dd bs=1 count=$(($(dirname "dir" | wc -c) - 1)) 2>/dev/null; echo /)" &&
mkdir [−m mode] "dir"
edited on: 2009-10-09 08:12
The standard states the requirements for mkdir -p,
and conforming implementations must conform to this. However, concerns
have been raised about this which are being referred to the sponsor.
Notes to the Editor (not part of this interpretation):
Replace the description of -p with:
-p Create any missing intermediate pathname components. For each dir operand that does not name an existing directory, before performing the actions described in the DESCRIPTION above the mkdir utility shall create any pathname components of the path prefix of dir that do not name an existing directory by performing actions equivalent to first calling the mkdir() function with the following arguments: 1. A pathname naming the missing pathname component, ending with a trailing <slash> character, as the path argument. 2. The value zero as the mode argument. and then calling the chmod() function with the following arguments: 1. The same path argument as in the mkdir() call. 2. The value (S_IWUSR|S_IXUSR|~filemask)&0777 as the mode argument, where filemask is the file mode creation mask of the process (see [xref to umask()]). Each dir operand that names an existing directory shall be ignored without error.
|2009-10-03 23:17||eblake||New Issue|
|2009-10-03 23:17||eblake||Status||New => Under Review|
|2009-10-03 23:17||eblake||Assigned To||=> ajosey|
|2009-10-03 23:17||eblake||Name||=> Eric Blake|
|2009-10-03 23:17||eblake||Organization||=> N/A|
|2009-10-03 23:17||eblake||User Reference||=> ebb.mkdir|
|2009-10-03 23:17||eblake||Section||=> mkdir|
|2009-10-03 23:17||eblake||Page Number||=> 2937|
|2009-10-03 23:17||eblake||Line Number||=> 96644|
|2009-10-03 23:24||eblake||Note Added: 0000245|
|2009-10-03 23:38||eblake||Note Added: 0000246|
|2009-10-05 09:59||geoffclare||Note Added: 0000247|
|2009-10-05 10:00||geoffclare||Note Edited: 0000247|
|2009-10-05 10:01||geoffclare||Note Edited: 0000247|
|2009-10-08 16:22||nick||Interp Status||=> Pending|
|2009-10-08 16:22||nick||Final Accepted Text||=> See Note: 0000247|
|2009-10-08 16:22||nick||Note Added: 0000249|
|2009-10-08 16:22||nick||Status||Under Review => Interpretation Required|
|2009-10-08 16:22||nick||Resolution||Open => Accepted As Marked|
|2009-10-08 16:26||nick||Note Edited: 0000247|
|2009-10-08 16:27||nick||Note Deleted: 0000249|
|2009-10-09 08:12||geoffclare||Note Edited: 0000247|
|2009-11-07 07:20||ajosey||Interp Status||Pending => Proposed|
|2009-12-08 10:00||ajosey||Interp Status||Proposed => Approved|
|2010-09-21 11:25||geoffclare||Tag Attached: tc1-2008|
|2013-04-16 13:06||ajosey||Status||Interpretation Required => Closed|
|2013-04-23 17:52||eblake||Relationship added||parent of 0000682|
|Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group|