Skip to content

Commit 189d751

Browse files
committed
updated for version 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)
1 parent a03c3d6 commit 189d751

File tree

4 files changed

+109
-12
lines changed

4 files changed

+109
-12
lines changed

src/os_mswin.c

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,98 @@ slash_adjust(p)
498498
}
499499
}
500500

501+
static int
502+
stat_symlink_aware(const char *name, struct stat *stp)
503+
{
504+
#if defined(_MSC_VER) && _MSC_VER < 1700
505+
/* Work around for VC10 or earlier. stat() can't handle symlinks properly.
506+
* VC9 or earlier: stat() doesn't support a symlink at all. It retrieves
507+
* status of a symlink itself.
508+
* VC10: stat() supports a symlink to a normal file, but it doesn't support
509+
* a symlink to a directory (always returns an error). */
510+
WIN32_FIND_DATA findData;
511+
HANDLE hFind, h;
512+
DWORD attr = 0;
513+
BOOL is_symlink = FALSE;
514+
515+
hFind = FindFirstFile(name, &findData);
516+
if (hFind != INVALID_HANDLE_VALUE)
517+
{
518+
attr = findData.dwFileAttributes;
519+
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
520+
&& (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
521+
is_symlink = TRUE;
522+
FindClose(hFind);
523+
}
524+
if (is_symlink)
525+
{
526+
h = CreateFile(name, FILE_READ_ATTRIBUTES,
527+
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
528+
OPEN_EXISTING,
529+
(attr & FILE_ATTRIBUTE_DIRECTORY)
530+
? FILE_FLAG_BACKUP_SEMANTICS : 0,
531+
NULL);
532+
if (h != INVALID_HANDLE_VALUE)
533+
{
534+
int fd, n;
535+
536+
fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
537+
n = _fstat(fd, (struct _stat*)stp);
538+
_close(fd);
539+
return n;
540+
}
541+
}
542+
#endif
543+
return stat(name, stp);
544+
}
545+
546+
#ifdef FEAT_MBYTE
547+
static int
548+
wstat_symlink_aware(const WCHAR *name, struct _stat *stp)
549+
{
550+
# if defined(_MSC_VER) && _MSC_VER < 1700
551+
/* Work around for VC10 or earlier. _wstat() can't handle symlinks properly.
552+
* VC9 or earlier: _wstat() doesn't support a symlink at all. It retrieves
553+
* status of a symlink itself.
554+
* VC10: _wstat() supports a symlink to a normal file, but it doesn't
555+
* support a symlink to a directory (always returns an error). */
556+
int n;
557+
BOOL is_symlink = FALSE;
558+
HANDLE hFind, h;
559+
DWORD attr = 0;
560+
WIN32_FIND_DATAW findDataW;
561+
562+
hFind = FindFirstFileW(name, &findDataW);
563+
if (hFind != INVALID_HANDLE_VALUE)
564+
{
565+
attr = findDataW.dwFileAttributes;
566+
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
567+
&& (findDataW.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
568+
is_symlink = TRUE;
569+
FindClose(hFind);
570+
}
571+
if (is_symlink)
572+
{
573+
h = CreateFileW(name, FILE_READ_ATTRIBUTES,
574+
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
575+
OPEN_EXISTING,
576+
(attr & FILE_ATTRIBUTE_DIRECTORY)
577+
? FILE_FLAG_BACKUP_SEMANTICS : 0,
578+
NULL);
579+
if (h != INVALID_HANDLE_VALUE)
580+
{
581+
int fd;
582+
583+
fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
584+
n = _fstat(fd, stp);
585+
_close(fd);
586+
return n;
587+
}
588+
}
589+
# endif
590+
return _wstat(name, stp);
591+
}
592+
#endif
501593

502594
/*
503595
* stat() can't handle a trailing '/' or '\', remove it first.
@@ -534,7 +626,7 @@ vim_stat(const char *name, struct stat *stp)
534626

535627
if (wp != NULL)
536628
{
537-
n = _wstat(wp, (struct _stat *)stp);
629+
n = wstat_symlink_aware(wp, (struct _stat *)stp);
538630
vim_free(wp);
539631
if (n >= 0)
540632
return n;
@@ -544,7 +636,7 @@ vim_stat(const char *name, struct stat *stp)
544636
}
545637
}
546638
#endif
547-
return stat(buf, stp);
639+
return stat_symlink_aware(buf, stp);
548640
}
549641

550642
#if defined(FEAT_GUI_MSWIN) || defined(PROTO)

src/os_win32.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,6 @@
7878
# endif
7979
#endif
8080

81-
/*
82-
* Reparse Point
83-
*/
84-
#ifndef FILE_ATTRIBUTE_REPARSE_POINT
85-
# define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
86-
#endif
87-
#ifndef IO_REPARSE_TAG_SYMLINK
88-
# define IO_REPARSE_TAG_SYMLINK 0xA000000C
89-
#endif
90-
9181
/* Record all output and all keyboard & mouse input */
9282
/* #define MCH_WRITE_DUMP */
9383

src/os_win32.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@
130130
# define DFLT_MAXMEMTOT (5*1024) /* use up to 5 Mbyte for Vim */
131131
#endif
132132

133+
/*
134+
* Reparse Point
135+
*/
136+
#ifndef FILE_ATTRIBUTE_REPARSE_POINT
137+
# define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
138+
#endif
139+
#ifndef IO_REPARSE_TAG_MOUNT_POINT
140+
# define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
141+
#endif
142+
#ifndef IO_REPARSE_TAG_SYMLINK
143+
# define IO_REPARSE_TAG_SYMLINK 0xA000000C
144+
#endif
145+
133146
#if defined(_MSC_VER) || defined(__BORLANDC__)
134147
/* Support for __try / __except. All versions of MSVC and Borland C are
135148
* expected to have this. Any other compilers that support it? */

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,8 @@ static char *(features[]) =
738738

739739
static int included_patches[] =
740740
{ /* Add new patch number below this line */
741+
/**/
742+
39,
741743
/**/
742744
38,
743745
/**/

0 commit comments

Comments
 (0)