To: vim_dev@googlegroups.com Subject: Patch 7.3.1182 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.3.1182 Problem: 'backupcopy' default on MS-Windows does not work for hard and soft links. Solution: Check for links. (David Pope, Ken Takata) Files: src/fileio.c, src/os_win32.c, src/proto/os_win32.pro *** ../vim-7.3.1181/src/fileio.c 2013-06-12 19:52:11.000000000 +0200 --- src/fileio.c 2013-06-12 22:31:34.000000000 +0200 *************** *** 3780,3791 **** } } - # ifdef UNIX /* * Break symlinks and/or hardlinks if we've been asked to. */ if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) { int lstat_res; lstat_res = mch_lstat((char *)fname, &st); --- 3780,3791 ---- } } /* * Break symlinks and/or hardlinks if we've been asked to. */ if ((bkc_flags & BKC_BREAKSYMLINK) || (bkc_flags & BKC_BREAKHARDLINK)) { + # ifdef UNIX int lstat_res; lstat_res = mch_lstat((char *)fname, &st); *************** *** 3801,3808 **** && st_old.st_nlink > 1 && (lstat_res != 0 || st.st_ino == st_old.st_ino)) backup_copy = FALSE; } - #endif #endif --- 3801,3818 ---- && st_old.st_nlink > 1 && (lstat_res != 0 || st.st_ino == st_old.st_ino)) backup_copy = FALSE; + # else + # if defined(WIN32) + /* Symlinks. */ + if ((bkc_flags & BKC_BREAKSYMLINK) && mch_is_symbolic_link(fname)) + backup_copy = FALSE; + + /* Hardlinks. */ + if ((bkc_flags & BKC_BREAKHARDLINK) && mch_is_hard_link(fname)) + backup_copy = FALSE; + # endif + # endif } #endif *** ../vim-7.3.1181/src/os_win32.c 2013-06-07 19:17:12.000000000 +0200 --- src/os_win32.c 2013-06-12 22:39:53.000000000 +0200 *************** *** 78,83 **** --- 78,93 ---- # endif #endif + /* + * Reparse Point + */ + #ifndef FILE_ATTRIBUTE_REPARSE_POINT + # define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 + #endif + #ifndef IO_REPARSE_TAG_SYMLINK + # define IO_REPARSE_TAG_SYMLINK 0xA000000C + #endif + /* Record all output and all keyboard & mouse input */ /* #define MCH_WRITE_DUMP */ *************** *** 219,224 **** --- 229,238 ---- static char *vimrun_path = "vimrun "; #endif + static int win32_getattrs(char_u *name); + static int win32_setattrs(char_u *name, int attrs); + static int win32_set_archive(char_u *name); + #ifndef FEAT_GUI_W32 static int suppress_winsize = 1; /* don't fiddle with console */ #endif *************** *** 2623,2679 **** /* * get file permissions for `name' * -1 : error ! * else FILE_ATTRIBUTE_* defined in winnt.h */ long mch_getperm(char_u *name) { ! #ifdef FEAT_MBYTE ! if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) ! { ! WCHAR *p = enc_to_utf16(name, NULL); ! long n; ! if (p != NULL) ! { ! n = (long)GetFileAttributesW(p); ! vim_free(p); ! if (n >= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) ! return n; ! /* Retry with non-wide function (for Windows 98). */ ! } ! } ! #endif ! return (long)GetFileAttributes((char *)name); } /* * set file permission for `name' to `perm' */ int mch_setperm( char_u *name, long perm) { ! perm |= FILE_ATTRIBUTE_ARCHIVE; /* file has changed, set archive bit */ #ifdef FEAT_MBYTE if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { ! WCHAR *p = enc_to_utf16(name, NULL); ! long n; if (p != NULL) { ! n = (long)SetFileAttributesW(p, perm); vim_free(p); ! if (n || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) ! return n ? OK : FAIL; /* Retry with non-wide function (for Windows 98). */ } } #endif ! return SetFileAttributes((char *)name, perm) ? OK : FAIL; } /* --- 2637,2690 ---- /* * get file permissions for `name' * -1 : error ! * else mode_t */ long mch_getperm(char_u *name) { ! struct stat st; ! int n; ! n = mch_stat(name, &st); ! return n == 0 ? (int)st.st_mode : -1; } /* * set file permission for `name' to `perm' + * + * return FAIL for failure, OK otherwise */ int mch_setperm( char_u *name, long perm) { ! long n; #ifdef FEAT_MBYTE + WCHAR *p; if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { ! p = enc_to_utf16(name, NULL); if (p != NULL) { ! n = _wchmod(p, perm); vim_free(p); ! if (n == -1 && GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) ! return FAIL; /* Retry with non-wide function (for Windows 98). */ } } + if (p == NULL) #endif ! n = _chmod(name, perm); ! if (n == -1) ! return FAIL; ! ! win32_set_archive(name); ! ! return OK; } /* *************** *** 2682,2730 **** void mch_hide(char_u *name) { ! int perm; ! #ifdef FEAT_MBYTE ! WCHAR *p = NULL; ! ! if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) ! p = enc_to_utf16(name, NULL); ! #endif ! #ifdef FEAT_MBYTE ! if (p != NULL) ! { ! perm = GetFileAttributesW(p); ! if (perm < 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ! { ! /* Retry with non-wide function (for Windows 98). */ ! vim_free(p); ! p = NULL; ! } ! } ! if (p == NULL) ! #endif ! perm = GetFileAttributes((char *)name); ! if (perm >= 0) ! { ! perm |= FILE_ATTRIBUTE_HIDDEN; ! #ifdef FEAT_MBYTE ! if (p != NULL) ! { ! if (SetFileAttributesW(p, perm) == 0 ! && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ! { ! /* Retry with non-wide function (for Windows 98). */ ! vim_free(p); ! p = NULL; ! } ! } ! if (p == NULL) ! #endif ! SetFileAttributes((char *)name, perm); ! } ! #ifdef FEAT_MBYTE ! vim_free(p); ! #endif } /* --- 2693,2704 ---- void mch_hide(char_u *name) { ! int attrs = win32_getattrs(name); ! if (attrs == -1) ! return; ! attrs |= FILE_ATTRIBUTE_HIDDEN; ! win32_setattrs(name, attrs); } /* *************** *** 2734,2740 **** int mch_isdir(char_u *name) { ! int f = mch_getperm(name); if (f == -1) return FALSE; /* file does not exist at all */ --- 2708,2714 ---- int mch_isdir(char_u *name) { ! int f = win32_getattrs(name); if (f == -1) return FALSE; /* file does not exist at all */ *************** *** 2770,2776 **** * Return TRUE if file "fname" has more than one link. */ int ! mch_is_linked(char_u *fname) { BY_HANDLE_FILE_INFORMATION info; --- 2744,2750 ---- * Return TRUE if file "fname" has more than one link. */ int ! mch_is_hard_link(char_u *fname) { BY_HANDLE_FILE_INFORMATION info; *************** *** 2779,2784 **** --- 2753,2826 ---- } /* + * Return TRUE if file "fname" is a symbolic link. + */ + int + mch_is_symbolic_link(char_u *fname) + { + HANDLE hFind; + int res = FALSE; + WIN32_FIND_DATAA findDataA; + DWORD fileFlags = 0, reparseTag = 0; + #ifdef FEAT_MBYTE + WCHAR *wn = NULL; + WIN32_FIND_DATAW findDataW; + + if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) + wn = enc_to_utf16(fname, NULL); + if (wn != NULL) + { + hFind = FindFirstFileW(wn, &findDataW); + vim_free(wn); + if (hFind == INVALID_HANDLE_VALUE + && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + /* Retry with non-wide function (for Windows 98). */ + hFind = FindFirstFile(fname, &findDataA); + if (hFind != INVALID_HANDLE_VALUE) + { + fileFlags = findDataA.dwFileAttributes; + reparseTag = findDataA.dwReserved0; + } + } + else + { + fileFlags = findDataW.dwFileAttributes; + reparseTag = findDataW.dwReserved0; + } + } + #else + hFind = FindFirstFile(fname, &findDataA); + if (hFind != INVALID_HANDLE_VALUE) + { + fileFlags = findDataA.dwFileAttributes; + reparseTag = findDataA.dwReserved0; + } + #endif + + if (hFind != INVALID_HANDLE_VALUE) + FindClose(hFind); + + if ((fileFlags & FILE_ATTRIBUTE_REPARSE_POINT) + && reparseTag == IO_REPARSE_TAG_SYMLINK) + res = TRUE; + + return res; + } + + /* + * Return TRUE if file "fname" has more than one link or if it is a symbolic + * link. + */ + int + mch_is_linked(char_u *fname) + { + if (mch_is_hard_link(fname) || mch_is_symbolic_link(fname)) + return TRUE; + return FALSE; + } + + /* * Get the by-handle-file-information for "fname". * Returns FILEINFO_OK when OK. * returns FILEINFO_ENC_FAIL when enc_to_utf16() failed. *************** *** 2842,2847 **** --- 2884,2975 ---- } /* + * get file attributes for `name' + * -1 : error + * else FILE_ATTRIBUTE_* defined in winnt.h + */ + static + int + win32_getattrs(char_u *name) + { + int attr; + #ifdef FEAT_MBYTE + WCHAR *p = NULL; + + if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) + p = enc_to_utf16(name, NULL); + + if (p != NULL) + { + attr = GetFileAttributesW(p); + if (attr < 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + /* Retry with non-wide function (for Windows 98). */ + vim_free(p); + p = NULL; + } + } + if (p == NULL) + #endif + attr = GetFileAttributes((char *)name); + #ifdef FEAT_MBYTE + vim_free(p); + #endif + return attr; + } + + /* + * set file attributes for `name' to `attrs' + * + * return -1 for failure, 0 otherwise + */ + static + int + win32_setattrs(char_u *name, int attrs) + { + int res; + #ifdef FEAT_MBYTE + WCHAR *p = NULL; + + if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) + p = enc_to_utf16(name, NULL); + + if (p != NULL) + { + res = SetFileAttributesW(p, attrs); + if (res == FALSE + && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + /* Retry with non-wide function (for Windows 98). */ + vim_free(p); + p = NULL; + } + } + if (p == NULL) + #endif + res = SetFileAttributes((char *)name, attrs); + #ifdef FEAT_MBYTE + vim_free(p); + #endif + return res ? 0 : -1; + } + + /* + * Set archive flag for "name". + */ + static + int + win32_set_archive(char_u *name) + { + int attrs = win32_getattrs(name); + if (attrs == -1) + return -1; + + attrs |= FILE_ATTRIBUTE_ARCHIVE; + return win32_setattrs(name, attrs); + } + + /* * Return TRUE if file or directory "name" is writable (not readonly). * Strange semantics of Win32: a readonly directory is writable, but you can't * delete a file. Let's say this means it is writable. *************** *** 2849,2858 **** int mch_writable(char_u *name) { ! int perm = mch_getperm(name); ! return (perm != -1 && (!(perm & FILE_ATTRIBUTE_READONLY) ! || (perm & FILE_ATTRIBUTE_DIRECTORY))); } /* --- 2977,2986 ---- int mch_writable(char_u *name) { ! int attrs = win32_getattrs(name); ! return (attrs != -1 && (!(attrs & FILE_ATTRIBUTE_READONLY) ! || (attrs & FILE_ATTRIBUTE_DIRECTORY))); } /* *************** *** 5012,5024 **** #ifdef FEAT_MBYTE WCHAR *wn = NULL; int n; if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { wn = enc_to_utf16(name, NULL); if (wn != NULL) { - SetFileAttributesW(wn, FILE_ATTRIBUTE_NORMAL); n = DeleteFileW(wn) ? 0 : -1; vim_free(wn); if (n == 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) --- 5140,5155 ---- #ifdef FEAT_MBYTE WCHAR *wn = NULL; int n; + #endif + win32_setattrs(name, FILE_ATTRIBUTE_NORMAL); + + #ifdef FEAT_MBYTE if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { wn = enc_to_utf16(name, NULL); if (wn != NULL) { n = DeleteFileW(wn) ? 0 : -1; vim_free(wn); if (n == 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) *************** *** 5027,5033 **** } } #endif - SetFileAttributes(name, FILE_ATTRIBUTE_NORMAL); return DeleteFile(name) ? 0 : -1; } --- 5158,5163 ---- *** ../vim-7.3.1181/src/proto/os_win32.pro 2012-11-20 16:56:49.000000000 +0100 --- src/proto/os_win32.pro 2013-06-12 22:29:53.000000000 +0200 *************** *** 21,26 **** --- 21,28 ---- void mch_hide __ARGS((char_u *name)); int mch_isdir __ARGS((char_u *name)); int mch_mkdir __ARGS((char_u *name)); + int mch_is_hard_link __ARGS((char_u *fname)); + int mch_is_symbolic_link __ARGS((char_u *fname)); int mch_is_linked __ARGS((char_u *fname)); int win32_fileinfo __ARGS((char_u *fname, BY_HANDLE_FILE_INFORMATION *info)); int mch_writable __ARGS((char_u *name)); *** ../vim-7.3.1181/src/version.c 2013-06-12 22:08:54.000000000 +0200 --- src/version.c 2013-06-12 22:40:29.000000000 +0200 *************** *** 730,731 **** --- 730,733 ---- { /* Add new patch number below this line */ + /**/ + 1182, /**/ -- If Microsoft would build a car... ... You'd have to press the "Start" button to turn the engine off. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///