| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.039 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 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) |
| Files: src/os_mswin.c, src/os_win32.c, src/os_win32.h |
| |
| |
| |
| |
| |
| *** 498,503 **** |
| --- 498,595 ---- |
| } |
| } |
| |
| + 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,540 **** |
| |
| if (wp != NULL) |
| { |
| ! n = _wstat(wp, (struct _stat *)stp); |
| vim_free(wp); |
| if (n >= 0) |
| return n; |
| --- 626,632 ---- |
| |
| if (wp != NULL) |
| { |
| ! n = wstat_symlink_aware(wp, (struct _stat *)stp); |
| vim_free(wp); |
| if (n >= 0) |
| return n; |
| |
| *** 544,550 **** |
| } |
| } |
| #endif |
| ! return stat(buf, stp); |
| } |
| |
| #if defined(FEAT_GUI_MSWIN) || defined(PROTO) |
| --- 636,642 ---- |
| } |
| } |
| #endif |
| ! return stat_symlink_aware(buf, stp); |
| } |
| |
| #if defined(FEAT_GUI_MSWIN) || defined(PROTO) |
| |
| |
| |
| *** 78,93 **** |
| # 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 */ |
| |
| --- 78,83 ---- |
| |
| |
| |
| *** 130,135 **** |
| --- 130,148 ---- |
| # 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? */ |
| |
| |
| |
| *** 740,741 **** |
| --- 740,743 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 39, |
| /**/ |
| |
| -- |
| A cow comes flying over the battlements, lowing aggressively. The cow |
| lands on GALAHAD'S PAGE, squashing him completely. |
| "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD |
| |
| /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ |
| /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ |
| \\\ an exciting new programming language -- http://www.Zimbu.org /// |
| \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |