[newlib-cygwin/main] Cygwin: utils: cygpath: add -r option to emit paths with root-local prefix

Corinna Vinschen corinna@sourceware.org
Tue Dec 10 23:25:27 GMT 2024


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=a0527e37869e8e3e467bbd106d6c77612df617c7

commit a0527e37869e8e3e467bbd106d6c77612df617c7
Author:     Corinna Vinschen <corinna@vinschen.de>
AuthorDate: Tue Dec 10 22:26:50 2024 +0100
Commit:     Corinna Vinschen <corinna@vinschen.de>
CommitDate: Wed Dec 11 00:24:44 2024 +0100

    Cygwin: utils: cygpath: add -r option to emit paths with root-local prefix
    
    cygpath automatically adds the root-local prefix \\?\ automatically
    for paths exceeding 260 bytes.  However, it does not add the root-local
    prefix if the path contains path components invalid in DOS paths, for
    instance path components with trailing dots or spaces.
    
    Add the -r option to always add the root-local prefix to the path.
    
    Add the option to the documentation and improve the help text.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/release/3.6.0 |  3 +++
 winsup/doc/utils.xml        | 35 ++++++++++++++++++++------
 winsup/utils/cygpath.cc     | 60 ++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 82 insertions(+), 16 deletions(-)

diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0
index 8ca91f0c99c1..66f7e73deb8c 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -16,6 +16,9 @@ What's new:
 - New libaio.a provided for projects checking for POSIX aio support
   by looking for this library at configure time.
 
+- cygpath -r option allows to generate all Windows paths with root-local
+  path prefix \\?\.
+
 
 What changed:
 -------------
diff --git a/winsup/doc/utils.xml b/winsup/doc/utils.xml
index fbb39f5f2791..6a55b3a0e790 100644
--- a/winsup/doc/utils.xml
+++ b/winsup/doc/utils.xml
@@ -528,11 +528,15 @@ Output type options:
 Path conversion options:
 
   -a, --absolute        output absolute path
-  -l, --long-name       print Windows long form of NAMEs (with -w, -m only)
+  -l, --long-name       print Windows long form of NAMEs (with -w, -m only,
+                        don't mix with -r and -s)
+  -r, --root-local      print Windows path with root-local path prefix (\\?\,
+                        with -w only)
   -p, --path            NAME is a PATH list (i.e., '/bin:/usr/bin')
   -U, --proc-cygdrive   Emit /proc/cygdrive path instead of cygdrive prefix
                         when converting Windows path to UNIX path.
-  -s, --short-name      print DOS (short) form of NAMEs (with -w, -m only)
+  -s, --short-name      print DOS (short) form of NAMEs (with -w, -m only,
+                        don't mix with -l and -r)
   -C, --codepage CP     print DOS, Windows, or mixed pathname in Windows
                         codepage CP.  CP can be a numeric codepage identifier,
                         or one of the reserved words ANSI, OEM, or UTF8.
@@ -574,15 +578,32 @@ Other options:
     <para>The <literal>-u</literal> and <literal>-w</literal> options indicate
       whether you want a conversion to UNIX (POSIX) format
       (<literal>-u</literal>) or to Windows format (<literal>-w</literal>). Use
-      the <literal>-d</literal> to get DOS-style (8.3) file and path names. The
+      the <literal>-d</literal> to get DOS-style 8.3 file and path names. The
       <literal>-m</literal> option will output Windows-style format but with
       forward slashes instead of backslashes. This option is especially useful
       in shell scripts, which use backslashes as an escape character.</para>
 
-    <para> In combination with the <literal>-w</literal> option, you can use
-      the <literal>-l</literal> and <literal>-s</literal> options to use normal
-      (long) or DOS-style (short) form. The <literal>-d</literal> option is
-      identical to <literal>-w</literal> and <literal>-s</literal> together. </para>
+    <para>In combination with the <literal>-w</literal> and
+      <literal>-m</literal> options, you can use the <literal>-l</literal> and
+      <literal>-s</literal> options to use normal (long) or DOS-style 8.3
+      (short) form. The <literal>-d</literal> option is identical to
+      <literal>-w</literal> and <literal>-s</literal> together.</para>
+
+    <para>Note that short DOS-style 8.3 names are not always available.
+      The generation of additional 8.3 filenames is the responsibility of
+      the underlying filesystem.  Modern Windows OS allows to switch off
+      8.3 filename generation and some filesystems never generate 8.3 names.
+      In these cases, using the <literal>-s</literal> option may fail or
+      may be ignored.</para>
+
+    <para>In combination with the <literal>-w</literal> option, you can use
+      the <literal>-r</literal> option to generate root-local paths with
+      leading \\?\ prefix.  This is especially useful if your path contains
+      path components invalid in DOS paths, for instance file or directory
+      names with trailing dot.</para>
+
+    <para>Note that the root-local path prefix is automatically prepended for
+      paths exceeding a length of MAX_PATH (260) bytes.</para>
 
     <para>The <literal>-C</literal> option allows to specify a Windows codepage
       to print DOS and Windows paths created with one of the
diff --git a/winsup/utils/cygpath.cc b/winsup/utils/cygpath.cc
index 10c31f8962a0..4ac1bef94cbf 100644
--- a/winsup/utils/cygpath.cc
+++ b/winsup/utils/cygpath.cc
@@ -33,7 +33,7 @@ details. */
 static char *prog_name;
 static char *file_arg, *output_arg;
 static int path_flag, unix_flag, windows_flag, absolute_flag, cygdrive_flag;
-static int shortname_flag, longname_flag;
+static int shortname_flag, longname_flag, rootlocal_flag;
 static int ignore_flag, allusers_flag, output_flag;
 static int mixed_flag, options_from_file_flag, mode_flag;
 static UINT codepage;
@@ -55,6 +55,7 @@ static struct option long_options[] = {
   {(char *) "proc-cygdrive", no_argument, NULL, 'U'},
   {(char *) "short-name", no_argument, NULL, 's'},
   {(char *) "type", required_argument, NULL, 't'},
+  {(char *) "root-local", no_argument, NULL, 'L'},
   {(char *) "unix", no_argument, NULL, 'u'},
   {(char *) "version", no_argument, NULL, 'V'},
   {(char *) "windows", no_argument, NULL, 'w'},
@@ -70,7 +71,7 @@ static struct option long_options[] = {
   {0, no_argument, 0, 0}
 };
 
-static char options[] = "ac:df:hilmMopst:uUVwAC:DHOPSWF:";
+static char options[] = "ac:df:hilmMoprst:uUVwAC:DHOPSWF:";
 
 static void __attribute__ ((__noreturn__))
 usage (FILE * stream, int status)
@@ -96,11 +97,15 @@ Output type options:\n\
 Path conversion options:\n\
 \n\
   -a, --absolute        output absolute path\n\
-  -l, --long-name       print Windows long form of NAMEs (with -w, -m only)\n\
+  -l, --long-name       print Windows long form of NAMEs (with -w, -m only,\n\
+                        don't mix with -r and -s)\n\
+  -r, --root-local      print Windows path with root-local path prefix (\\\\?\\,\n\
+                        with -w only, don't mix with -l and -s)\n\
   -p, --path            NAME is a PATH list (i.e., '/bin:/usr/bin')\n\
   -U, --proc-cygdrive   Emit /proc/cygdrive path instead of cygdrive prefix\n\
                         when converting Windows path to UNIX path.\n\
-  -s, --short-name      print DOS (short) form of NAMEs (with -w, -m only)\n\
+  -s, --short-name      print DOS (short) form of NAMEs (with -w, -m only,\n\
+                        don't mix with -l and -r)\n\
   -C, --codepage CP     print DOS, Windows, or mixed pathname in Windows\n\
                         codepage CP.  CP can be a numeric codepage identifier,\n\
                         or one of the reserved words ANSI, OEM, or UTF8.\n\
@@ -459,6 +464,29 @@ get_long_name (const char *filename, DWORD& len)
   return sbuf;
 }
 
+static char *
+get_rootlocal_name (const char *filename, DWORD& len)
+{
+  if (!strncmp (filename, "\\\\?\\", 4))
+    return strdup (filename);
+
+  char *buf = (char *) malloc (strlen (filename) + 7);
+  if (!buf)
+    {
+      fprintf (stderr, "%s: out of memory\n", prog_name);
+      exit (1);
+    }
+
+  char *p = stpcpy (buf, "\\\\?\\");
+  if (!strncmp (filename, "\\\\", 2))
+    {
+      p = stpcpy (p, "UNC");
+      ++filename;
+    }
+  stpcpy (p, filename);
+  return buf;
+}
+
 static char *
 get_long_paths (char *path)
 {
@@ -757,8 +785,13 @@ do_pathconv (char *filename)
 	      buf = get_long_name (tmp = buf, len);
 	      free (tmp);
 	    }
+	  if (rootlocal_flag)
+	    {
+	      buf = get_rootlocal_name (tmp = buf, len);
+	      free (tmp);
+	    }
 	  tmp = buf;
-	  if (strncmp (buf, "\\\\?\\", 4) == 0)
+	  if (!rootlocal_flag && strncmp (buf, "\\\\?\\", 4) == 0)
 	    {
 	      len = 0;
 	      if (buf[5] == ':')
@@ -808,6 +841,7 @@ do_options (int argc, char **argv, int from_file)
   windows_flag = 0;
   shortname_flag = 0;
   longname_flag = 0;
+  rootlocal_flag = 0;
   mixed_flag = 0;
   ignore_flag = 0;
   allusers_flag = 0;
@@ -880,6 +914,10 @@ do_options (int argc, char **argv, int from_file)
 	  shortname_flag = 1;
 	  break;
 
+	case 'r':
+	  rootlocal_flag = 1;
+	  break;
+
 	case 't':
 	  if (!optarg)
 	    usage (stderr, 1);
@@ -980,12 +1018,16 @@ do_options (int argc, char **argv, int from_file)
   if (!from_file && options_from_file_flag && !file_arg)
     usage (stderr, 1);
 
-  /* longname and shortname don't play well together. */
-  if (longname_flag && shortname_flag)
+  /* longname, shortname and root-local don't play well together. */
+  if (longname_flag + shortname_flag + rootlocal_flag > 1)
+    usage (stderr, 1);
+
+  /* longname, shortname and root-local only make sense with Windows paths. */
+  if ((longname_flag || shortname_flag || rootlocal_flag) && !windows_flag)
     usage (stderr, 1);
 
-  /* longname and shortname only make sense with Windows paths. */
-  if ((longname_flag || shortname_flag) && !windows_flag)
+  /* root-local with mixed mode doesn't make sense. */
+  if (rootlocal_flag && mixed_flag)
     usage (stderr, 1);
 
   return o;


More information about the Cygwin-cvs mailing list