Mercurial > vim
changeset 5376:4dfba3df303c v7.4.039
updated for version 7.4.039
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)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Wed, 25 Sep 2013 19:13:38 +0200 |
parents | 5409c616bfd0 |
children | f894129bfe5b |
files | src/os_mswin.c src/os_win32.c src/os_win32.h src/version.c |
diffstat | 4 files changed, 109 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -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 * 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 * } } #endif - return stat(buf, stp); + return stat_symlink_aware(buf, stp); } #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
--- 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 */
--- a/src/os_win32.h +++ b/src/os_win32.h @@ -130,6 +130,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? */