summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <bram@vim.org>2013-06-12 22:41:37 +0200
committerBram Moolenaar <bram@vim.org>2013-06-12 22:41:37 +0200
commit6fb3689471729b7fd9c5288c2b002d50d559805c (patch)
treed6b559fe328c6c7c966881dcb750fbf22022f1ac
parent5c9d527984bbbc0e2c7bd1e203bbd9b32fe65c8a (diff)
downloadvim-6fb3689471729b7fd9c5288c2b002d50d559805c.tar.gz
updated for version 7.3.1182v7.3.1182v7-3-1182
Problem: 'backupcopy' default on MS-Windows does not work for hard and soft links. Solution: Check for links. (David Pope, Ken Takata)
-rw-r--r--src/fileio.c14
-rw-r--r--src/os_win32.c276
-rw-r--r--src/proto/os_win32.pro2
-rw-r--r--src/version.c2
4 files changed, 219 insertions, 75 deletions
diff --git a/src/fileio.c b/src/fileio.c
index 6665c3a1..6c8cba10 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3780,12 +3780,12 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
}
}
-# ifdef UNIX
/*
* 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,8 +3801,18 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
&& 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
#endif
diff --git a/src/os_win32.c b/src/os_win32.c
index e9dbfc5f..fd7e57e7 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -78,6 +78,16 @@
# 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,6 +229,10 @@ static int need_vimrun_warning = FALSE;
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,57 +2637,54 @@ mch_dirname(
/*
* get file permissions for `name'
* -1 : error
- * else FILE_ATTRIBUTE_* defined in winnt.h
+ * else mode_t
*/
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;
+ struct stat st;
+ int 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);
+ 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)
{
- perm |= FILE_ATTRIBUTE_ARCHIVE; /* file has changed, set archive bit */
+ long n;
#ifdef FEAT_MBYTE
+ WCHAR *p;
if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
{
- WCHAR *p = enc_to_utf16(name, NULL);
- long n;
+ p = enc_to_utf16(name, NULL);
if (p != NULL)
{
- n = (long)SetFileAttributesW(p, perm);
+ n = _wchmod(p, perm);
vim_free(p);
- if (n || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return n ? OK : FAIL;
+ if (n == -1 && GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return FAIL;
/* Retry with non-wide function (for Windows 98). */
}
}
+ if (p == NULL)
#endif
- return SetFileAttributes((char *)name, perm) ? OK : FAIL;
+ n = _chmod(name, perm);
+ if (n == -1)
+ return FAIL;
+
+ win32_set_archive(name);
+
+ return OK;
}
/*
@@ -2682,49 +2693,12 @@ mch_setperm(
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
+ int attrs = win32_getattrs(name);
+ if (attrs == -1)
+ return;
-#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
+ attrs |= FILE_ATTRIBUTE_HIDDEN;
+ win32_setattrs(name, attrs);
}
/*
@@ -2734,7 +2708,7 @@ mch_hide(char_u *name)
int
mch_isdir(char_u *name)
{
- int f = mch_getperm(name);
+ int f = win32_getattrs(name);
if (f == -1)
return FALSE; /* file does not exist at all */
@@ -2770,7 +2744,7 @@ mch_mkdir(char_u *name)
* Return TRUE if file "fname" has more than one link.
*/
int
-mch_is_linked(char_u *fname)
+mch_is_hard_link(char_u *fname)
{
BY_HANDLE_FILE_INFORMATION info;
@@ -2779,6 +2753,74 @@ mch_is_linked(char_u *fname)
}
/*
+ * 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,6 +2884,92 @@ win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info)
}
/*
+ * 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,10 +2977,10 @@ win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info)
int
mch_writable(char_u *name)
{
- int perm = mch_getperm(name);
+ int attrs = win32_getattrs(name);
- return (perm != -1 && (!(perm & FILE_ATTRIBUTE_READONLY)
- || (perm & FILE_ATTRIBUTE_DIRECTORY)));
+ return (attrs != -1 && (!(attrs & FILE_ATTRIBUTE_READONLY)
+ || (attrs & FILE_ATTRIBUTE_DIRECTORY)));
}
/*
@@ -5012,13 +5140,16 @@ mch_remove(char_u *name)
#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)
{
- SetFileAttributesW(wn, FILE_ATTRIBUTE_NORMAL);
n = DeleteFileW(wn) ? 0 : -1;
vim_free(wn);
if (n == 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
@@ -5027,7 +5158,6 @@ mch_remove(char_u *name)
}
}
#endif
- SetFileAttributes(name, FILE_ATTRIBUTE_NORMAL);
return DeleteFile(name) ? 0 : -1;
}
diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro
index 2ae24521..bdefbab5 100644
--- a/src/proto/os_win32.pro
+++ b/src/proto/os_win32.pro
@@ -21,6 +21,8 @@ int mch_setperm __ARGS((char_u *name, long perm));
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));
diff --git a/src/version.c b/src/version.c
index be1825e3..9dfef573 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1182,
+/**/
1181,
/**/
1180,