From e70dbe774a0c5fe2f8112e06df1e231b1f114560 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 7 Jan 2016 21:07:56 +0100 Subject: [PATCH] cygpath: Try to return system directories with correct case * cygpath.cc (do_sysfolders): Drop lame workaround to fix case of directory returned by GetSystemDirectoryW. Try to fix case of any path returned by this function in case it has to return a POSIX path to support case-sensitivity. Signed-off-by: Corinna Vinschen --- winsup/cygwin/release/2.4.0 | 4 +++ winsup/utils/cygpath.cc | 50 ++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/release/2.4.0 b/winsup/cygwin/release/2.4.0 index 4feff5b80..5953d61ea 100644 --- a/winsup/cygwin/release/2.4.0 +++ b/winsup/cygwin/release/2.4.0 @@ -73,3 +73,7 @@ Bug Fixes - Fix a potential crash reading invalid passwd and group entries from /etc/passwd and /etc/group. Addresses: https://cygwin.com/ml/cygwin/2015-12/msg00170.html + +- Cygpath(1) now tries to correct the case of system directories when + returned as POSIX paths. + Addresses: https://cygwin.com/ml/cygwin/2016-01/msg00002.html diff --git a/winsup/utils/cygpath.cc b/winsup/utils/cygpath.cc index 0fbb2e90e..c0a527631 100644 --- a/winsup/utils/cygpath.cc +++ b/winsup/utils/cygpath.cc @@ -20,6 +20,7 @@ details. */ #include #include #include +#include #include #define _WIN32_WINNT 0x0602 @@ -579,20 +580,7 @@ do_sysfolders (char option) break; case 'S': - { - HANDLE fh; - WIN32_FIND_DATAW w32_fd; - - GetSystemDirectoryW (wbuf, MAX_PATH); - /* The path returned by GetSystemDirectoryW is not case preserving. - The below code is a trick to get the correct case of the system - directory from Windows. */ - if ((fh = FindFirstFileW (wbuf, &w32_fd)) != INVALID_HANDLE_VALUE) - { - FindClose (fh); - wcscpy (wcsrchr (wbuf, L'\\') + 1, w32_fd.cFileName); - } - } + GetSystemDirectoryW (wbuf, MAX_PATH); break; case 'W': @@ -607,9 +595,43 @@ do_sysfolders (char option) { fprintf (stderr, "%s: failed to retrieve special folder path\n", prog_name); + return; } else if (!windows_flag) { + /* The system folders are not necessarily case-correct. To allow + case-sensitivity, try to correct the case. Note that this only + works for local filesystems. */ + if (iswalpha (wbuf[0]) && wbuf[1] == L':' && wbuf[2] == L'\\') + { + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + HANDLE h; + IO_STATUS_BLOCK io; + UNICODE_STRING upath; + const ULONG size = sizeof (FILE_NAME_INFORMATION) + + PATH_MAX * sizeof (WCHAR); + PFILE_NAME_INFORMATION pfni = (PFILE_NAME_INFORMATION) alloca (size); + + /* Avoid another buffer, reuse pfni. */ + wcpcpy (wcpcpy (pfni->FileName, L"\\??\\"), wbuf); + RtlInitUnicodeString (&upath, pfni->FileName); + InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, + NULL, NULL); + status = NtOpenFile (&h, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, FILE_OPEN_REPARSE_POINT); + if (NT_SUCCESS (status)) + { + status = NtQueryInformationFile (h, &io, pfni, size, + FileNameInformation); + if (NT_SUCCESS (status)) + { + pfni->FileName[pfni->FileNameLength / sizeof (WCHAR)] = L'\0'; + wcscpy (wbuf + 2, pfni->FileName); + } + NtClose (h); + } + } if (cygwin_conv_path (CCP_WIN_W_TO_POSIX | cygdrive_flag, wbuf, buf, PATH_MAX)) fprintf (stderr, "%s: error converting \"%ls\" - %s\n",