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