Mercurial > vim
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 |