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