Cygwin: mkdir and rmdir: treat drive names specially

If the directory name has the form 'x:' followed by one or more
slashes or backslashes, and if there's at least one backslash, assume
that the user is referring to 'x:\', the root directory of drive x,
and don't strip the backslash.

Previously all trailing slashes and backslashes were stripped, and the
name was treated as a relative file name containing a literal colon.

Addresses https://cygwin.com/ml/cygwin/2019-08/msg00334.html.
This commit is contained in:
Ken Brown 2019-09-27 14:00:52 -04:00
parent e82a0c959a
commit c561a625af
2 changed files with 32 additions and 5 deletions

View File

@ -313,15 +313,27 @@ mkdir (const char *dir, mode_t mode)
/* Following Linux, and intentionally ignoring POSIX, do not
resolve the last component of DIR if it is a symlink, even if
DIR has a trailing slash. Achieve this by stripping trailing
slashes or backslashes. */
slashes or backslashes.
Exception: If DIR == 'x:' followed by one or more slashes or
backslashes, and if there's at least one backslash, assume
that the user is referring to the root directory of drive x.
Retain one backslash in this case. */
if (isdirsep (dir[strlen (dir) - 1]))
{
/* This converts // to /, but since both give EEXIST, we're okay. */
char *buf;
char *p = stpcpy (buf = tp.c_get (), dir) - 1;
bool msdos = false;
dir = buf;
while (p > dir && isdirsep (*p))
*p-- = '\0';
{
if (*p == '\\')
msdos = true;
*p-- = '\0';
}
if (msdos && p == dir + 1 && isdrive (dir))
p[1] = '\\';
}
if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW)))
__leave; /* errno already set */;
@ -360,20 +372,31 @@ rmdir (const char *dir)
set_errno (ENOENT);
__leave;
}
/* Following Linux, and intentionally ignoring POSIX, do not
resolve the last component of DIR if it is a symlink, even if
DIR has a trailing slash. Achieve this by stripping trailing
slashes or backslashes. */
slashes or backslashes.
Exception: If DIR == 'x:' followed by one or more slashes or
backslashes, and if there's at least one backslash, assume
that the user is referring to the root directory of drive x.
Retain one backslash in this case. */
if (isdirsep (dir[strlen (dir) - 1]))
{
/* This converts // to /, but since both give ENOTEMPTY,
we're okay. */
char *buf;
char *p = stpcpy (buf = tp.c_get (), dir) - 1;
bool msdos = false;
dir = buf;
while (p > dir && isdirsep (*p))
*p-- = '\0';
{
if (*p == '\\')
msdos = true;
*p-- = '\0';
}
if (msdos && p == dir + 1 && isdrive (dir))
p[1] = '\\';
}
if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW)))
__leave; /* errno already set */;

View File

@ -87,3 +87,7 @@ Bug Fixes
- Fix an assertion failure on an invalid path.
Addresses: https://cygwin.com/ml/cygwin/2019-09/msg00228.html
- If the argument to mkdir(2) or rmdir(2) is 'x:\', don't strip the
trailing backslash.
Addresses: https://cygwin.com/ml/cygwin/2019-08/msg00334.html