To: vim_dev@googlegroups.com
Subject: Patch 7.3.1182
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
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 ///