comparison src/os_mswin.c @ 5376:4dfba3df303c v7.4.039

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)
author Bram Moolenaar <bram@vim.org>
date Wed, 25 Sep 2013 19:13:38 +0200
parents 07737d3aa817
children c0e3990aed3f
comparison
equal deleted inserted replaced
5375:5409c616bfd0 5376:4dfba3df303c
496 *p = psepc; 496 *p = psepc;
497 mb_ptr_adv(p); 497 mb_ptr_adv(p);
498 } 498 }
499 } 499 }
500 500
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
501 593
502 /* 594 /*
503 * stat() can't handle a trailing '/' or '\', remove it first. 595 * stat() can't handle a trailing '/' or '\', remove it first.
504 */ 596 */
505 int 597 int
532 WCHAR *wp = enc_to_utf16(buf, NULL); 624 WCHAR *wp = enc_to_utf16(buf, NULL);
533 int n; 625 int n;
534 626
535 if (wp != NULL) 627 if (wp != NULL)
536 { 628 {
537 n = _wstat(wp, (struct _stat *)stp); 629 n = wstat_symlink_aware(wp, (struct _stat *)stp);
538 vim_free(wp); 630 vim_free(wp);
539 if (n >= 0) 631 if (n >= 0)
540 return n; 632 return n;
541 /* Retry with non-wide function (for Windows 98). Can't use 633 /* Retry with non-wide function (for Windows 98). Can't use
542 * GetLastError() here and it's unclear what errno gets set to if 634 * GetLastError() here and it's unclear what errno gets set to if
543 * the _wstat() fails for missing wide functions. */ 635 * the _wstat() fails for missing wide functions. */
544 } 636 }
545 } 637 }
546 #endif 638 #endif
547 return stat(buf, stp); 639 return stat_symlink_aware(buf, stp);
548 } 640 }
549 641
550 #if defined(FEAT_GUI_MSWIN) || defined(PROTO) 642 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
551 /*ARGSUSED*/ 643 /*ARGSUSED*/
552 void 644 void