dcaee6
To: vim_dev@googlegroups.com
dcaee6
Subject: Patch 7.4.039
dcaee6
Fcc: outbox
dcaee6
From: Bram Moolenaar <Bram@moolenaar.net>
dcaee6
Mime-Version: 1.0
dcaee6
Content-Type: text/plain; charset=UTF-8
dcaee6
Content-Transfer-Encoding: 8bit
dcaee6
------------
dcaee6
dcaee6
Patch 7.4.039
dcaee6
Problem:    MS-Windows: MSCV10 and earlier can't handle symlinks to a
dcaee6
	    directory properly.
dcaee6
Solution:   Add stat_symlink_aware() and wstat_symlink_aware(). (Ken Takata)
dcaee6
Files:	    src/os_mswin.c, src/os_win32.c, src/os_win32.h
dcaee6
dcaee6
dcaee6
*** ../vim-7.4.038/src/os_mswin.c	2013-08-30 16:51:15.000000000 +0200
dcaee6
--- src/os_mswin.c	2013-09-25 19:09:53.000000000 +0200
dcaee6
***************
dcaee6
*** 498,503 ****
dcaee6
--- 498,595 ----
dcaee6
      }
dcaee6
  }
dcaee6
  
dcaee6
+     static int
dcaee6
+ stat_symlink_aware(const char *name, struct stat *stp)
dcaee6
+ {
dcaee6
+ #if defined(_MSC_VER) && _MSC_VER < 1700
dcaee6
+     /* Work around for VC10 or earlier. stat() can't handle symlinks properly.
dcaee6
+      * VC9 or earlier: stat() doesn't support a symlink at all. It retrieves
dcaee6
+      * status of a symlink itself.
dcaee6
+      * VC10: stat() supports a symlink to a normal file, but it doesn't support
dcaee6
+      * a symlink to a directory (always returns an error). */
dcaee6
+     WIN32_FIND_DATA	findData;
dcaee6
+     HANDLE		hFind, h;
dcaee6
+     DWORD		attr = 0;
dcaee6
+     BOOL		is_symlink = FALSE;
dcaee6
+ 
dcaee6
+     hFind = FindFirstFile(name, &findData);
dcaee6
+     if (hFind != INVALID_HANDLE_VALUE)
dcaee6
+     {
dcaee6
+ 	attr = findData.dwFileAttributes;
dcaee6
+ 	if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
dcaee6
+ 		&& (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
dcaee6
+ 	    is_symlink = TRUE;
dcaee6
+ 	FindClose(hFind);
dcaee6
+     }
dcaee6
+     if (is_symlink)
dcaee6
+     {
dcaee6
+ 	h = CreateFile(name, FILE_READ_ATTRIBUTES,
dcaee6
+ 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
dcaee6
+ 		OPEN_EXISTING,
dcaee6
+ 		(attr & FILE_ATTRIBUTE_DIRECTORY)
dcaee6
+ 					    ? FILE_FLAG_BACKUP_SEMANTICS : 0,
dcaee6
+ 		NULL);
dcaee6
+ 	if (h != INVALID_HANDLE_VALUE)
dcaee6
+ 	{
dcaee6
+ 	    int	    fd, n;
dcaee6
+ 
dcaee6
+ 	    fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
dcaee6
+ 	    n = _fstat(fd, (struct _stat*)stp);
dcaee6
+ 	    _close(fd);
dcaee6
+ 	    return n;
dcaee6
+ 	}
dcaee6
+     }
dcaee6
+ #endif
dcaee6
+     return stat(name, stp);
dcaee6
+ }
dcaee6
+ 
dcaee6
+ #ifdef FEAT_MBYTE
dcaee6
+     static int
dcaee6
+ wstat_symlink_aware(const WCHAR *name, struct _stat *stp)
dcaee6
+ {
dcaee6
+ # if defined(_MSC_VER) && _MSC_VER < 1700
dcaee6
+     /* Work around for VC10 or earlier. _wstat() can't handle symlinks properly.
dcaee6
+      * VC9 or earlier: _wstat() doesn't support a symlink at all. It retrieves
dcaee6
+      * status of a symlink itself.
dcaee6
+      * VC10: _wstat() supports a symlink to a normal file, but it doesn't
dcaee6
+      * support a symlink to a directory (always returns an error). */
dcaee6
+     int			n;
dcaee6
+     BOOL		is_symlink = FALSE;
dcaee6
+     HANDLE		hFind, h;
dcaee6
+     DWORD		attr = 0;
dcaee6
+     WIN32_FIND_DATAW	findDataW;
dcaee6
+ 
dcaee6
+     hFind = FindFirstFileW(name, &findDataW);
dcaee6
+     if (hFind != INVALID_HANDLE_VALUE)
dcaee6
+     {
dcaee6
+ 	attr = findDataW.dwFileAttributes;
dcaee6
+ 	if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
dcaee6
+ 		&& (findDataW.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
dcaee6
+ 	    is_symlink = TRUE;
dcaee6
+ 	FindClose(hFind);
dcaee6
+     }
dcaee6
+     if (is_symlink)
dcaee6
+     {
dcaee6
+ 	h = CreateFileW(name, FILE_READ_ATTRIBUTES,
dcaee6
+ 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
dcaee6
+ 		OPEN_EXISTING,
dcaee6
+ 		(attr & FILE_ATTRIBUTE_DIRECTORY)
dcaee6
+ 					    ? FILE_FLAG_BACKUP_SEMANTICS : 0,
dcaee6
+ 		NULL);
dcaee6
+ 	if (h != INVALID_HANDLE_VALUE)
dcaee6
+ 	{
dcaee6
+ 	    int	    fd;
dcaee6
+ 
dcaee6
+ 	    fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
dcaee6
+ 	    n = _fstat(fd, stp);
dcaee6
+ 	    _close(fd);
dcaee6
+ 	    return n;
dcaee6
+ 	}
dcaee6
+     }
dcaee6
+ # endif
dcaee6
+     return _wstat(name, stp);
dcaee6
+ }
dcaee6
+ #endif
dcaee6
  
dcaee6
  /*
dcaee6
   * stat() can't handle a trailing '/' or '\', remove it first.
dcaee6
***************
dcaee6
*** 534,540 ****
dcaee6
  
dcaee6
  	if (wp != NULL)
dcaee6
  	{
dcaee6
! 	    n = _wstat(wp, (struct _stat *)stp);
dcaee6
  	    vim_free(wp);
dcaee6
  	    if (n >= 0)
dcaee6
  		return n;
dcaee6
--- 626,632 ----
dcaee6
  
dcaee6
  	if (wp != NULL)
dcaee6
  	{
dcaee6
! 	    n = wstat_symlink_aware(wp, (struct _stat *)stp);
dcaee6
  	    vim_free(wp);
dcaee6
  	    if (n >= 0)
dcaee6
  		return n;
dcaee6
***************
dcaee6
*** 544,550 ****
dcaee6
  	}
dcaee6
      }
dcaee6
  #endif
dcaee6
!     return stat(buf, stp);
dcaee6
  }
dcaee6
  
dcaee6
  #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
dcaee6
--- 636,642 ----
dcaee6
  	}
dcaee6
      }
dcaee6
  #endif
dcaee6
!     return stat_symlink_aware(buf, stp);
dcaee6
  }
dcaee6
  
dcaee6
  #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
dcaee6
*** ../vim-7.4.038/src/os_win32.c	2013-08-30 17:29:10.000000000 +0200
dcaee6
--- src/os_win32.c	2013-09-25 19:09:53.000000000 +0200
dcaee6
***************
dcaee6
*** 78,93 ****
dcaee6
  # endif
dcaee6
  #endif
dcaee6
  
dcaee6
- /*
dcaee6
-  * Reparse Point
dcaee6
-  */
dcaee6
- #ifndef FILE_ATTRIBUTE_REPARSE_POINT
dcaee6
- # define FILE_ATTRIBUTE_REPARSE_POINT	0x00000400
dcaee6
- #endif
dcaee6
- #ifndef IO_REPARSE_TAG_SYMLINK
dcaee6
- # define IO_REPARSE_TAG_SYMLINK		0xA000000C
dcaee6
- #endif
dcaee6
- 
dcaee6
  /* Record all output and all keyboard & mouse input */
dcaee6
  /* #define MCH_WRITE_DUMP */
dcaee6
  
dcaee6
--- 78,83 ----
dcaee6
*** ../vim-7.4.038/src/os_win32.h	2013-07-21 17:53:13.000000000 +0200
dcaee6
--- src/os_win32.h	2013-09-25 19:09:53.000000000 +0200
dcaee6
***************
dcaee6
*** 130,135 ****
dcaee6
--- 130,148 ----
dcaee6
  # define DFLT_MAXMEMTOT	(5*1024)    /* use up to 5 Mbyte for Vim */
dcaee6
  #endif
dcaee6
  
dcaee6
+ /*
dcaee6
+  * Reparse Point
dcaee6
+  */
dcaee6
+ #ifndef FILE_ATTRIBUTE_REPARSE_POINT
dcaee6
+ # define FILE_ATTRIBUTE_REPARSE_POINT	0x00000400
dcaee6
+ #endif
dcaee6
+ #ifndef IO_REPARSE_TAG_MOUNT_POINT
dcaee6
+ # define IO_REPARSE_TAG_MOUNT_POINT	0xA0000003
dcaee6
+ #endif
dcaee6
+ #ifndef IO_REPARSE_TAG_SYMLINK
dcaee6
+ # define IO_REPARSE_TAG_SYMLINK		0xA000000C
dcaee6
+ #endif
dcaee6
+ 
dcaee6
  #if defined(_MSC_VER) || defined(__BORLANDC__)
dcaee6
      /* Support for __try / __except.  All versions of MSVC and Borland C are
dcaee6
       * expected to have this.  Any other compilers that support it? */
dcaee6
*** ../vim-7.4.038/src/version.c	2013-09-25 18:54:20.000000000 +0200
dcaee6
--- src/version.c	2013-09-25 19:08:55.000000000 +0200
dcaee6
***************
dcaee6
*** 740,741 ****
dcaee6
--- 740,743 ----
dcaee6
  {   /* Add new patch number below this line */
dcaee6
+ /**/
dcaee6
+     39,
dcaee6
  /**/
dcaee6
dcaee6
-- 
dcaee6
   A cow comes flying over the battlements,  lowing aggressively.  The cow
dcaee6
   lands on GALAHAD'S PAGE, squashing him completely.
dcaee6
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
dcaee6
dcaee6
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
dcaee6
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
dcaee6
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
dcaee6
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///