To: vim_dev@googlegroups.com Subject: Patch 7.4.039 Fcc: outbox From: Bram Moolenaar 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 *** ../vim-7.4.038/src/os_mswin.c 2013-08-30 16:51:15.000000000 +0200 --- src/os_mswin.c 2013-09-25 19:09:53.000000000 +0200 *************** *** 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) *** ../vim-7.4.038/src/os_win32.c 2013-08-30 17:29:10.000000000 +0200 --- src/os_win32.c 2013-09-25 19:09:53.000000000 +0200 *************** *** 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 ---- *** ../vim-7.4.038/src/os_win32.h 2013-07-21 17:53:13.000000000 +0200 --- src/os_win32.h 2013-09-25 19:09:53.000000000 +0200 *************** *** 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? */ *** ../vim-7.4.038/src/version.c 2013-09-25 18:54:20.000000000 +0200 --- src/version.c 2013-09-25 19:08:55.000000000 +0200 *************** *** 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 ///