If Vim is build by VC10, it can't cd to a symlink of a directory.

E.g.:

>md foo
>mklink /d symlink foo
>gvim
:cd symlink

E344: Can't find directory "symlink" in cdpath
E472: Command failed

This is caused by a bug(?) of VC10's stat(). VC's stat() behaves as follows:

VC8 or earlier: stat() doesn't support symlinks 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. It always returns an error for a symlink to a
directory.
VC11: stat() supports both types of symlinks. It retrieves status of a target.
(I don't know about VC9.)

Attached patch fixes this problem and makes vim_stat() to behave as the same
as VC11's stat().

Regards,
Ken Takata

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
# HG changeset patch
# Parent e4844507d67383dd0a627964241025d606feb496

diff --git a/src/os_mswin.c b/src/os_mswin.c
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -498,6 +498,98 @@
     }
 }
 
+    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.
+     * VC8 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.
+     * VC8 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 @@
 
 	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 @@
 	}
     }
 #endif
-    return stat(buf, stp);
+    return stat_symlink_aware(buf, stp);
 }
 
 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
diff --git a/src/os_win32.c b/src/os_win32.c
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -78,16 +78,6 @@
 # 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 */
 
diff --git a/src/os_win32.h b/src/os_win32.h
--- a/src/os_win32.h
+++ b/src/os_win32.h
@@ -130,6 +132,19 @@
 # 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? */

Raspunde prin e-mail lui