public inbox for binutils-cvs@sourceware.org
 help / color / mirror / Atom feed
From: Nick Clifton <nickc@sourceware.org>
To: binutils-cvs@sourceware.org
Subject: [binutils-gdb] Add support for Windows network paths to the UNC support in _bfd_real_open().
Date: Fri,  5 Apr 2024 08:43:04 +0000 (GMT)	[thread overview]
Message-ID: <20240405084304.CF3E93858C24@sourceware.org> (raw)

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=eac88f3298491fdf2caa0d7dd97a3dde954b8b74

commit eac88f3298491fdf2caa0d7dd97a3dde954b8b74
Author: Zhiqing Xiong <zhiqxion@qti.qualcomm.com>
Date:   Fri Apr 5 09:41:40 2024 +0100

    Add support for Windows network paths to the UNC support in _bfd_real_open().
    
    PR 31527

Diff:
---
 bfd/bfdio.c | 108 ++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 72 insertions(+), 36 deletions(-)

diff --git a/bfd/bfdio.c b/bfd/bfdio.c
index 4ed0eeadc52..718cbe89023 100644
--- a/bfd/bfdio.c
+++ b/bfd/bfdio.c
@@ -29,6 +29,8 @@
 #if defined (_WIN32)
 #include <windows.h>
 #include <locale.h>
+/* FIXME: Do we need a configure time test for the presence of this headers ?  */
+#include <shlwapi.h>  /* Needed for PathIsNetworkPathA().  */
 #endif
 
 #ifndef S_IXUSR
@@ -118,61 +120,95 @@ _bfd_real_fopen (const char *filename, const char *modes)
 
 #elif defined (_WIN32)
   /* PR 25713: Handle extra long path names possibly containing '..' and '.'.  */
-   wchar_t **     lpFilePart = {NULL};
-   const wchar_t  prefix[] = L"\\\\?\\";
-   const size_t   partPathLen = strlen (filename) + 1;
+  wchar_t **      lpFilePart = {NULL};
+  const wchar_t   prefixDOS[] = L"\\\\?\\";
+  const wchar_t   prefixUNC[] = L"\\\\?\\UNC\\";
+  const size_t    partPathLen = strlen (filename) + 1;
+  const wchar_t * prefix;
+  size_t          sizeof_prefix;
+
+  /* PR 31527: Paths that begin with two backslash characters
+     (\\) are interpreted as Universal Naming Convention (UNC)
+     paths.  They use the "\\?\UNC\" prefix for network UNC paths
+     and  the "\\?\" prefix for dos UNC paths.  For more information
+     see: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
+  */
+  bool is_network_path = PathIsNetworkPathA (filename);
+
+  if (is_network_path)
+    {
+      prefix = prefixUNC;
+      sizeof_prefix = sizeof (prefixUNC);
+    }
+  else
+    {
+      prefix = prefixDOS;
+      sizeof_prefix = sizeof (prefixDOS);
+    }
+
 #ifdef __MINGW32__
 #if !HAVE_DECL____LC_CODEPAGE_FUNC
-/* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
-   _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
+  /* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
+  _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
 #endif
-   const unsigned int cp = ___lc_codepage_func ();
+  const unsigned int cp = ___lc_codepage_func ();
 #else
-   const unsigned int cp = CP_UTF8;
+  const unsigned int cp = CP_UTF8;
 #endif
 
-   /* Converting the partial path from ascii to unicode.
-      1) Get the length: Calling with lpWideCharStr set to null returns the length.
-      2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null.  */
-   size_t         partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
-   wchar_t *      partPath = calloc (partPathWSize, sizeof(wchar_t));
-   size_t         ix;
+  /* Converting the partial path from ascii to unicode.
+     1) Get the length: Calling with lpWideCharStr set to null returns the length.
+     2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null.  */
+  size_t     partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0);
+  wchar_t *  partPath = calloc (partPathWSize, sizeof(wchar_t));
+  size_t     ix;
 
-   MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
+  MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize);
 
-   /* Convert any UNIX style path separators into the DOS i.e. backslash separator.  */
-   for (ix = 0; ix < partPathLen; ix++)
-     if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
-       partPath[ix] = '\\';
+  /* Convert any UNIX style path separators into the DOS i.e. backslash separator.  */
+  for (ix = 0; ix < partPathLen; ix++)
+    if (IS_UNIX_DIR_SEPARATOR(filename[ix]))
+      partPath[ix] = '\\';
 
-   /* Getting the full path from the provided partial path.
-      1) Get the length.
-      2) Resolve the path.  */
-   long       fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
-   wchar_t *  fullPath = calloc (fullPathWSize + sizeof(prefix) + 1, sizeof(wchar_t));
+  /* Getting the full path from the provided partial path.
+     1) Get the length.
+     2) Resolve the path.  */
+  long       fullPathWSize = GetFullPathNameW (partPath, 0, NULL, lpFilePart);
+  wchar_t *  fullPath = calloc (fullPathWSize + sizeof_prefix + 1, sizeof(wchar_t));
 
-   wcscpy (fullPath, prefix);
+  wcscpy (fullPath, prefix);
 
-   int        prefixLen = sizeof(prefix) / sizeof(wchar_t);
+  int  prefixLen = sizeof_prefix / sizeof(wchar_t);
 
-   /* Do not add a prefix to the null device.  */
-   if (stricmp (filename, "nul") == 0)
+  /* Do not add a prefix to the null device.  */
+  if (stricmp (filename, "nul") == 0)
     prefixLen = 1;
 
-   wchar_t *  fullPathOffset = fullPath + prefixLen - 1;
+  wchar_t *  fullPathOffset = fullPath + prefixLen - 1;
+
+  GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
+
+  if (is_network_path)
+    {
+      /* Remove begining of the beginning two backslash characters (\\).  */
+      wchar_t *_fullPath = calloc (fullPathWSize + sizeof_prefix + 1, sizeof(wchar_t));
+
+      GetFullPathNameW (fullPath, fullPathWSize + sizeof_prefix + 1, _fullPath, lpFilePart);
+      free (fullPath);
+      fullPath = _fullPath;
+    }
 
-   GetFullPathNameW (partPath, fullPathWSize, fullPathOffset, lpFilePart);
-   free (partPath);
+  free (partPath);
 
-   /* It is non-standard for modes to exceed 16 characters.  */
-   wchar_t    modesW[16];
+  /* It is non-standard for modes to exceed 16 characters.  */
+  wchar_t  modesW[16];
 
-   MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
+  MultiByteToWideChar (cp, 0, modes, -1, modesW, sizeof(modesW));
 
-   FILE *     file = _wfopen (fullPath, modesW);
-   free (fullPath);
+  FILE *  file = _wfopen (fullPath, modesW);
+  free (fullPath);
 
-   return close_on_exec (file);
+  return close_on_exec (file);
 
 #elif defined (HAVE_FOPEN64)
   return close_on_exec (fopen64 (filename, modes));

                 reply	other threads:[~2024-04-05  8:43 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240405084304.CF3E93858C24@sourceware.org \
    --to=nickc@sourceware.org \
    --cc=binutils-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).