@@ -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 )
0 commit comments