[PATCH] Cygwin: mkdir and rmdir: treat drive names specially

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] Cygwin: mkdir and rmdir: treat drive names specially

Ken Brown-6
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.
---
 winsup/cygwin/dir.cc | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index 29a9dfa83..3429fe022 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -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 */;
--
2.21.0

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Cygwin: mkdir and rmdir: treat drive names specially

Ken Brown-6
On 9/27/2019 2:44 PM, Ken Brown wrote:

> 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.
> ---
>   winsup/cygwin/dir.cc | 33 ++++++++++++++++++++++++++++-----
>   1 file changed, 28 insertions(+), 5 deletions(-)

No complaints, so I've pushed this.

Ken