]> granicus.if.org Git - vim/commitdiff
updated for version 7.4.039 v7.4.039
authorBram Moolenaar <Bram@vim.org>
Wed, 25 Sep 2013 17:13:38 +0000 (19:13 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 25 Sep 2013 17:13:38 +0000 (19:13 +0200)
Problem:    MS-Windows: MSCV10 and earlier can't handle symlinks to a
            directory properly.
Solution:   Add stat_symlink_aware() and wstat_symlink_aware(). (Ken Takata)

src/os_mswin.c
src/os_win32.c
src/os_win32.h
src/version.c

index 67b7960978388ed482f33066e640222715f772ab..8b507f6fbd0d6e30ad991442e3ef151fbf80949b 100644 (file)
@@ -498,6 +498,98 @@ slash_adjust(p)
     }
 }
 
+    static int
+stat_symlink_aware(const char *name, struct stat *stp)
+{
+#if defined(_MSC_VER) && _MSC_VER < 1700
+    /* Work around for VC10 or earlier. stat() can't handle symlinks properly.
+     * VC9 or earlier: stat() doesn't support a symlink at all. It retrieves
+     * status of a symlink itself.
+     * VC10: stat() supports a symlink to a normal file, but it doesn't support
+     * a symlink to a directory (always returns an error). */
+    WIN32_FIND_DATA    findData;
+    HANDLE             hFind, h;
+    DWORD              attr = 0;
+    BOOL               is_symlink = FALSE;
+
+    hFind = FindFirstFile(name, &findData);
+    if (hFind != INVALID_HANDLE_VALUE)
+    {
+       attr = findData.dwFileAttributes;
+       if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
+               && (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
+           is_symlink = TRUE;
+       FindClose(hFind);
+    }
+    if (is_symlink)
+    {
+       h = CreateFile(name, FILE_READ_ATTRIBUTES,
+               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+               OPEN_EXISTING,
+               (attr & FILE_ATTRIBUTE_DIRECTORY)
+                                           ? FILE_FLAG_BACKUP_SEMANTICS : 0,
+               NULL);
+       if (h != INVALID_HANDLE_VALUE)
+       {
+           int     fd, n;
+
+           fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
+           n = _fstat(fd, (struct _stat*)stp);
+           _close(fd);
+           return n;
+       }
+    }
+#endif
+    return stat(name, stp);
+}
+
+#ifdef FEAT_MBYTE
+    static int
+wstat_symlink_aware(const WCHAR *name, struct _stat *stp)
+{
+# if defined(_MSC_VER) && _MSC_VER < 1700
+    /* Work around for VC10 or earlier. _wstat() can't handle symlinks properly.
+     * VC9 or earlier: _wstat() doesn't support a symlink at all. It retrieves
+     * status of a symlink itself.
+     * VC10: _wstat() supports a symlink to a normal file, but it doesn't
+     * support a symlink to a directory (always returns an error). */
+    int                        n;
+    BOOL               is_symlink = FALSE;
+    HANDLE             hFind, h;
+    DWORD              attr = 0;
+    WIN32_FIND_DATAW   findDataW;
+
+    hFind = FindFirstFileW(name, &findDataW);
+    if (hFind != INVALID_HANDLE_VALUE)
+    {
+       attr = findDataW.dwFileAttributes;
+       if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
+               && (findDataW.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
+           is_symlink = TRUE;
+       FindClose(hFind);
+    }
+    if (is_symlink)
+    {
+       h = CreateFileW(name, FILE_READ_ATTRIBUTES,
+               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+               OPEN_EXISTING,
+               (attr & FILE_ATTRIBUTE_DIRECTORY)
+                                           ? FILE_FLAG_BACKUP_SEMANTICS : 0,
+               NULL);
+       if (h != INVALID_HANDLE_VALUE)
+       {
+           int     fd;
+
+           fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
+           n = _fstat(fd, stp);
+           _close(fd);
+           return n;
+       }
+    }
+# endif
+    return _wstat(name, stp);
+}
+#endif
 
 /*
  * stat() can't handle a trailing '/' or '\', remove it first.
@@ -534,7 +626,7 @@ vim_stat(const char *name, struct stat *stp)
 
        if (wp != NULL)
        {
-           n = _wstat(wp, (struct _stat *)stp);
+           n = wstat_symlink_aware(wp, (struct _stat *)stp);
            vim_free(wp);
            if (n >= 0)
                return n;
@@ -544,7 +636,7 @@ vim_stat(const char *name, struct stat *stp)
        }
     }
 #endif
-    return stat(buf, stp);
+    return stat_symlink_aware(buf, stp);
 }
 
 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
index f36dfb3db903160a2cd2644a6a0ce8bda82d9688..cd29b8738a131bb5dac877522cd164ddef5e5fa2 100644 (file)
 # endif
 #endif
 
-/*
- * Reparse Point
- */
-#ifndef FILE_ATTRIBUTE_REPARSE_POINT
-# define FILE_ATTRIBUTE_REPARSE_POINT  0x00000400
-#endif
-#ifndef IO_REPARSE_TAG_SYMLINK
-# define IO_REPARSE_TAG_SYMLINK                0xA000000C
-#endif
-
 /* Record all output and all keyboard & mouse input */
 /* #define MCH_WRITE_DUMP */
 
index 58b179ff87de5742b4dc2e316b52bacf08235dea..29fe5e4fb835fdfc72607870cda8de33e8a6cc76 100644 (file)
 # define DFLT_MAXMEMTOT        (5*1024)    /* use up to 5 Mbyte for Vim */
 #endif
 
+/*
+ * Reparse Point
+ */
+#ifndef FILE_ATTRIBUTE_REPARSE_POINT
+# define FILE_ATTRIBUTE_REPARSE_POINT  0x00000400
+#endif
+#ifndef IO_REPARSE_TAG_MOUNT_POINT
+# define IO_REPARSE_TAG_MOUNT_POINT    0xA0000003
+#endif
+#ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK                0xA000000C
+#endif
+
 #if defined(_MSC_VER) || defined(__BORLANDC__)
     /* Support for __try / __except.  All versions of MSVC and Borland C are
      * expected to have this.  Any other compilers that support it? */
index c7b73329a16ac0cf93b6d8496d7ff140e060ec22..3495b0ee8e0b17eb1a4e7ec48462d3fa9f4a8f30 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    39,
 /**/
     38,
 /**/