Merge branch 'js/mingw-getcwd'
authorJunio C Hamano <gitster@pobox.com>
Tue, 30 Oct 2018 06:43:48 +0000 (15:43 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Oct 2018 06:43:48 +0000 (15:43 +0900)
The way the Windows port figures out the current directory has been
improved.

* js/mingw-getcwd:
mingw: fix getcwd when the parent directory cannot be queried
mingw: ensure `getcwd()` reports the correct case

1  2 
compat/mingw.c
diff --combined compat/mingw.c
index 44264fe3fd8fd8da4af6f17d7376634a47a92d8f,19addfa5d5925bb65b92962ab38025071167df41..6c3c4ca5a62d9a6498e4c8340983390987ae7680
@@@ -5,7 -5,6 +5,7 @@@
  #include "../strbuf.h"
  #include "../run-command.h"
  #include "../cache.h"
 +#include "win32/lazyload.h"
  
  #define HCAST(type, handle) ((type)(intptr_t)handle)
  
@@@ -203,6 -202,31 +203,31 @@@ static int ask_yes_no_if_possible(cons
        }
  }
  
+ /* Normalizes NT paths as returned by some low-level APIs. */
+ static wchar_t *normalize_ntpath(wchar_t *wbuf)
+ {
+       int i;
+       /* fix absolute path prefixes */
+       if (wbuf[0] == '\\') {
+               /* strip NT namespace prefixes */
+               if (!wcsncmp(wbuf, L"\\??\\", 4) ||
+                   !wcsncmp(wbuf, L"\\\\?\\", 4))
+                       wbuf += 4;
+               else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
+                       wbuf += 12;
+               /* replace remaining '...UNC\' with '\\' */
+               if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
+                       wbuf += 2;
+                       *wbuf = '\\';
+               }
+       }
+       /* convert backslashes to slashes */
+       for (i = 0; wbuf[i]; i++)
+               if (wbuf[i] == '\\')
+                       wbuf[i] = '/';
+       return wbuf;
+ }
  int mingw_unlink(const char *pathname)
  {
        int ret, tries = 0;
@@@ -918,8 -942,29 +943,29 @@@ struct tm *localtime_r(const time_t *ti
  
  char *mingw_getcwd(char *pointer, int len)
  {
-       wchar_t wpointer[MAX_PATH];
-       if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
+       wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
+       DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
+       if (!ret || ret >= ARRAY_SIZE(cwd)) {
+               errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
+               return NULL;
+       }
+       ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
+       if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
+               HANDLE hnd = CreateFileW(cwd, 0,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+               if (hnd == INVALID_HANDLE_VALUE)
+                       return NULL;
+               ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
+               CloseHandle(hnd);
+               if (!ret || ret >= ARRAY_SIZE(wpointer))
+                       return NULL;
+               if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
+                       return NULL;
+               return pointer;
+       }
+       if (!ret || ret >= ARRAY_SIZE(wpointer))
                return NULL;
        if (xwcstoutf(pointer, wpointer, len) < 0)
                return NULL;
@@@ -1799,63 -1844,18 +1845,63 @@@ int mingw_getpagesize(void
        return si.dwAllocationGranularity;
  }
  
 +/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */
 +enum EXTENDED_NAME_FORMAT {
 +      NameDisplay = 3,
 +      NameUserPrincipal = 8
 +};
 +
 +static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type)
 +{
 +      DECLARE_PROC_ADDR(secur32.dll, BOOL, GetUserNameExW,
 +              enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG);
 +      static wchar_t wbuffer[1024];
 +      DWORD len;
 +
 +      if (!INIT_PROC_ADDR(GetUserNameExW))
 +              return NULL;
 +
 +      len = ARRAY_SIZE(wbuffer);
 +      if (GetUserNameExW(type, wbuffer, &len)) {
 +              char *converted = xmalloc((len *= 3));
 +              if (xwcstoutf(converted, wbuffer, len) >= 0)
 +                      return converted;
 +              free(converted);
 +      }
 +
 +      return NULL;
 +}
 +
 +char *mingw_query_user_email(void)
 +{
 +      return get_extended_user_info(NameUserPrincipal);
 +}
 +
  struct passwd *getpwuid(int uid)
  {
 +      static unsigned initialized;
        static char user_name[100];
 -      static struct passwd p;
 +      static struct passwd *p;
 +      DWORD len;
 +
 +      if (initialized)
 +              return p;
  
 -      DWORD len = sizeof(user_name);
 -      if (!GetUserName(user_name, &len))
 +      len = sizeof(user_name);
 +      if (!GetUserName(user_name, &len)) {
 +              initialized = 1;
                return NULL;
 -      p.pw_name = user_name;
 -      p.pw_gecos = "unknown";
 -      p.pw_dir = NULL;
 -      return &p;
 +      }
 +
 +      p = xmalloc(sizeof(*p));
 +      p->pw_name = user_name;
 +      p->pw_gecos = get_extended_user_info(NameDisplay);
 +      if (!p->pw_gecos)
 +              p->pw_gecos = "unknown";
 +      p->pw_dir = NULL;
 +
 +      initialized = 1;
 +      return p;
  }
  
  static HANDLE timer_event;