changeset 16156:602f1888a230 v8.1.1083

patch 8.1.1083: MS-Windows: hang when opening a file on network share commit https://github.com/vim/vim/commit/8bb41b3d062cd315fdd0626dfd6fa68474a96b50 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Mar 30 17:28:16 2019 +0100 patch 8.1.1083: MS-Windows: hang when opening a file on network share Problem: MS-Windows: hang when opening a file on network share. Solution: Avoid using FindFirstFile(), use GetLongPathNameW(). (Ken Takata, closes #3923)
author Bram Moolenaar <Bram@vim.org>
date Sat, 30 Mar 2019 17:30:05 +0100
parents 008036af96aa
children 0062198dc347
files src/os_win32.c src/version.c
diffstat 2 files changed, 19 insertions(+), 239 deletions(-) [+]
line wrap: on
line diff
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -2772,136 +2772,18 @@ mch_check_win(
 #endif
 }
 
-
 /*
- * fname_casew(): Wide version of fname_case().  Set the case of the file name,
- * if it already exists.  When "len" is > 0, also expand short to long
- * filenames.
- * Return FAIL if wide functions are not available, OK otherwise.
- * NOTE: much of this is identical to fname_case(), keep in sync!
- */
-    static int
-fname_casew(
-    WCHAR	*name,
-    int		len)
-{
-    WCHAR		szTrueName[_MAX_PATH + 2];
-    WCHAR		szTrueNameTemp[_MAX_PATH + 2];
-    WCHAR		*ptrue, *ptruePrev;
-    WCHAR		*porig, *porigPrev;
-    int			flen;
-    WIN32_FIND_DATAW	fb;
-    HANDLE		hFind = INVALID_HANDLE_VALUE;
-    int			c;
-    int			slen;
-
-    flen = (int)wcslen(name);
-    if (flen > _MAX_PATH)
-	return OK;
-
-    /* slash_adjust(name) not needed, already adjusted by fname_case(). */
-
-    /* Build the new name in szTrueName[] one component at a time. */
-    porig = name;
-    ptrue = szTrueName;
-
-    if (iswalpha(porig[0]) && porig[1] == L':')
-    {
-	/* copy leading drive letter */
-	*ptrue++ = *porig++;
-	*ptrue++ = *porig++;
-    }
-    *ptrue = NUL;	    /* in case nothing follows */
-
-    while (*porig != NUL)
-    {
-	/* copy \ characters */
-	while (*porig == psepc)
-	    *ptrue++ = *porig++;
-
-	ptruePrev = ptrue;
-	porigPrev = porig;
-	while (*porig != NUL && *porig != psepc)
-	{
-	    *ptrue++ = *porig++;
-	}
-	*ptrue = NUL;
-
-	/* To avoid a slow failure append "\*" when searching a directory,
-	 * server or network share. */
-	wcscpy(szTrueNameTemp, szTrueName);
-	slen = (int)wcslen(szTrueNameTemp);
-	if (*porig == psepc && slen + 2 < _MAX_PATH)
-	    wcscpy(szTrueNameTemp + slen, L"\\*");
-
-	/* Skip "", "." and "..". */
-	if (ptrue > ptruePrev
-		&& (ptruePrev[0] != L'.'
-		    || (ptruePrev[1] != NUL
-			&& (ptruePrev[1] != L'.' || ptruePrev[2] != NUL)))
-		&& (hFind = FindFirstFileW(szTrueNameTemp, &fb))
-						      != INVALID_HANDLE_VALUE)
-	{
-	    c = *porig;
-	    *porig = NUL;
-
-	    /* Only use the match when it's the same name (ignoring case) or
-	     * expansion is allowed and there is a match with the short name
-	     * and there is enough room. */
-	    if (_wcsicoll(porigPrev, fb.cFileName) == 0
-		    || (len > 0
-			&& (_wcsicoll(porigPrev, fb.cAlternateFileName) == 0
-			    && (int)(ptruePrev - szTrueName)
-					   + (int)wcslen(fb.cFileName) < len)))
-	    {
-		wcscpy(ptruePrev, fb.cFileName);
-
-		/* Look for exact match and prefer it if found.  Must be a
-		 * long name, otherwise there would be only one match. */
-		while (FindNextFileW(hFind, &fb))
-		{
-		    if (*fb.cAlternateFileName != NUL
-			    && (wcscoll(porigPrev, fb.cFileName) == 0
-				|| (len > 0
-				    && (_wcsicoll(porigPrev,
-						   fb.cAlternateFileName) == 0
-				    && (int)(ptruePrev - szTrueName)
-					 + (int)wcslen(fb.cFileName) < len))))
-		    {
-			wcscpy(ptruePrev, fb.cFileName);
-			break;
-		    }
-		}
-	    }
-	    FindClose(hFind);
-	    *porig = c;
-	    ptrue = ptruePrev + wcslen(ptruePrev);
-	}
-    }
-
-    wcscpy(name, szTrueName);
-    return OK;
-}
-
-/*
- * fname_case(): Set the case of the file name, if it already exists.
+ * Set the case of the file name, if it already exists.
  * When "len" is > 0, also expand short to long filenames.
- * NOTE: much of this is identical to fname_casew(), keep in sync!
  */
     void
 fname_case(
     char_u	*name,
     int		len)
 {
-    char		szTrueName[_MAX_PATH + 2];
-    char		szTrueNameTemp[_MAX_PATH + 2];
-    char		*ptrue, *ptruePrev;
-    char		*porig, *porigPrev;
-    int			flen;
-    WIN32_FIND_DATA	fb;
-    HANDLE		hFind;
-    int			c;
-    int			slen;
+    int	    flen;
+    WCHAR   *p;
+    WCHAR   buf[_MAX_PATH + 1];
 
     flen = (int)STRLEN(name);
     if (flen == 0)
@@ -2909,126 +2791,22 @@ fname_case(
 
     slash_adjust(name);
 
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-    {
-	WCHAR	*p = enc_to_utf16(name, NULL);
-
-	if (p != NULL)
-	{
-	    char_u	*q;
-	    WCHAR	buf[_MAX_PATH + 1];
-
-	    wcsncpy(buf, p, _MAX_PATH);
-	    buf[_MAX_PATH] = L'\0';
-	    vim_free(p);
-
-	    if (fname_casew(buf, (len > 0) ? _MAX_PATH : 0) == OK)
-	    {
-		q = utf16_to_enc(buf, NULL);
-		if (q != NULL)
-		{
-		    vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
-		    vim_free(q);
-		    return;
-		}
-	    }
-	}
+    p = enc_to_utf16(name, NULL);
+    if (p == NULL)
 	return;
-    }
-
-    /* If 'enc' is utf-8, flen can be larger than _MAX_PATH.
-     * So we should check this after calling wide function. */
-    if (flen > _MAX_PATH)
-	return;
-
-    /* Build the new name in szTrueName[] one component at a time. */
-    porig = (char *)name;
-    ptrue = szTrueName;
-
-    if (isalpha(porig[0]) && porig[1] == ':')
-    {
-	/* copy leading drive letter */
-	*ptrue++ = *porig++;
-	*ptrue++ = *porig++;
-    }
-    *ptrue = NUL;	    /* in case nothing follows */
-
-    while (*porig != NUL)
-    {
-	/* copy \ characters */
-	while (*porig == psepc)
-	    *ptrue++ = *porig++;
-
-	ptruePrev = ptrue;
-	porigPrev = porig;
-	while (*porig != NUL && *porig != psepc)
+
+    if (GetLongPathNameW(p, buf, _MAX_PATH))
+    {
+	char_u	*q = utf16_to_enc(buf, NULL);
+
+	if (q != NULL)
 	{
-	    int l;
-
-	    if (enc_dbcs)
-	    {
-		l = (*mb_ptr2len)((char_u *)porig);
-		while (--l >= 0)
-		    *ptrue++ = *porig++;
-	    }
-	    else
-		*ptrue++ = *porig++;
+	    if (len > 0 || flen >= (int)STRLEN(q))
+		vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
+	    vim_free(q);
 	}
-	*ptrue = NUL;
-
-	/* To avoid a slow failure append "\*" when searching a directory,
-	 * server or network share. */
-	STRCPY(szTrueNameTemp, szTrueName);
-	slen = (int)strlen(szTrueNameTemp);
-	if (*porig == psepc && slen + 2 < _MAX_PATH)
-	    STRCPY(szTrueNameTemp + slen, "\\*");
-
-	/* Skip "", "." and "..". */
-	if (ptrue > ptruePrev
-		&& (ptruePrev[0] != '.'
-		    || (ptruePrev[1] != NUL
-			&& (ptruePrev[1] != '.' || ptruePrev[2] != NUL)))
-		&& (hFind = FindFirstFile(szTrueNameTemp, &fb))
-						      != INVALID_HANDLE_VALUE)
-	{
-	    c = *porig;
-	    *porig = NUL;
-
-	    /* Only use the match when it's the same name (ignoring case) or
-	     * expansion is allowed and there is a match with the short name
-	     * and there is enough room. */
-	    if (_stricoll(porigPrev, fb.cFileName) == 0
-		    || (len > 0
-			&& (_stricoll(porigPrev, fb.cAlternateFileName) == 0
-			    && (int)(ptruePrev - szTrueName)
-					   + (int)strlen(fb.cFileName) < len)))
-	    {
-		STRCPY(ptruePrev, fb.cFileName);
-
-		/* Look for exact match and prefer it if found.  Must be a
-		 * long name, otherwise there would be only one match. */
-		while (FindNextFile(hFind, &fb))
-		{
-		    if (*fb.cAlternateFileName != NUL
-			    && (strcoll(porigPrev, fb.cFileName) == 0
-				|| (len > 0
-				    && (_stricoll(porigPrev,
-						   fb.cAlternateFileName) == 0
-				    && (int)(ptruePrev - szTrueName)
-					 + (int)strlen(fb.cFileName) < len))))
-		    {
-			STRCPY(ptruePrev, fb.cFileName);
-			break;
-		    }
-		}
-	    }
-	    FindClose(hFind);
-	    *porig = c;
-	    ptrue = ptruePrev + strlen(ptruePrev);
-	}
-    }
-
-    STRCPY(name, szTrueName);
+    }
+    vim_free(p);
 }
 
 
--- a/src/version.c
+++ b/src/version.c
@@ -776,6 +776,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1083,
+/**/
     1082,
 /**/
     1081,