]> granicus.if.org Git - vim/commitdiff
patch 8.1.1083: MS-Windows: hang when opening a file on network share v8.1.1083
authorBram Moolenaar <Bram@vim.org>
Sat, 30 Mar 2019 16:28:16 +0000 (17:28 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 30 Mar 2019 16:28:16 +0000 (17:28 +0100)
Problem:    MS-Windows: hang when opening a file on network share.
Solution:   Avoid using FindFirstFile(), use GetLongPathNameW(). (Ken Takata,
            closes #3923)

src/os_win32.c
src/version.c

index 81cf737827d2418af582dc5c762710f54c578e1d..2912b0df75a30c1af352786b1eb5f1528fe6281f 100644 (file)
@@ -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;
-               }
-           }
-       }
-       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)
+    p = enc_to_utf16(name, NULL);
+    if (p == NULL)
        return;
 
-    /* Build the new name in szTrueName[] one component at a time. */
-    porig = (char *)name;
-    ptrue = szTrueName;
-
-    if (isalpha(porig[0]) && porig[1] == ':')
+    if (GetLongPathNameW(p, buf, _MAX_PATH))
     {
-       /* copy leading drive letter */
-       *ptrue++ = *porig++;
-       *ptrue++ = *porig++;
-    }
-    *ptrue = NUL;          /* in case nothing follows */
+       char_u  *q = utf16_to_enc(buf, NULL);
 
-    while (*porig != NUL)
-    {
-       /* copy \ characters */
-       while (*porig == psepc)
-           *ptrue++ = *porig++;
-
-       ptruePrev = ptrue;
-       porigPrev = porig;
-       while (*porig != NUL && *porig != psepc)
+       if (q != NULL)
        {
-           int l;
-
-           if (enc_dbcs)
-           {
-               l = (*mb_ptr2len)((char_u *)porig);
-               while (--l >= 0)
-                   *ptrue++ = *porig++;
-           }
-           else
-               *ptrue++ = *porig++;
-       }
-       *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);
+           if (len > 0 || flen >= (int)STRLEN(q))
+               vim_strncpy(name, q, (len > 0) ? len - 1 : flen);
+           vim_free(q);
        }
     }
-
-    STRCPY(name, szTrueName);
+    vim_free(p);
 }
 
 
index 98f09b3fb4b2756d5324d36ed5b0f37a7247aa1d..c267a20daf308615a821e106bfa8e27e7771ad87 100644 (file)
@@ -775,6 +775,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1083,
 /**/
     1082,
 /**/