diff options
author | Bram Moolenaar <Bram@vim.org> | 2013-09-25 19:13:38 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2013-09-25 19:13:38 +0200 |
commit | 2ee95f7d13566ba393ed70bd4401e7164b0cc2f9 (patch) | |
tree | 9ccfd8c005d3a370675290c759f4dad4ffa4afb3 | |
parent | 134bf07ca0e28addeeb67edc4fceeba00388d7fc (diff) | |
download | vim-git-2ee95f7d13566ba393ed70bd4401e7164b0cc2f9.tar.gz |
updated for version 7.4.039v7.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)
-rw-r--r-- | src/os_mswin.c | 96 | ||||
-rw-r--r-- | src/os_win32.c | 10 | ||||
-rw-r--r-- | src/os_win32.h | 13 | ||||
-rw-r--r-- | src/version.c | 2 |
4 files changed, 109 insertions, 12 deletions
diff --git a/src/os_mswin.c b/src/os_mswin.c index 67b796097..8b507f6fb 100644 --- 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 *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) diff --git a/src/os_win32.c b/src/os_win32.c index f36dfb3db..cd29b8738 100644 --- 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 index 58b179ff8..29fe5e4fb 100644 --- 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? */ diff --git a/src/version.c b/src/version.c index c7b73329a..3495b0ee8 100644 --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 39, +/**/ 38, /**/ 37, |