]> granicus.if.org Git - vim/commitdiff
updated for version 7.3.1182 v7.3.1182
authorBram Moolenaar <Bram@vim.org>
Wed, 12 Jun 2013 20:41:37 +0000 (22:41 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 12 Jun 2013 20:41:37 +0000 (22:41 +0200)
Problem:    'backupcopy' default on MS-Windows does not work for hard and soft
            links.
Solution:   Check for links. (David Pope, Ken Takata)

src/fileio.c
src/os_win32.c
src/proto/os_win32.pro
src/version.c

index 6665c3a1c4408931a6a501d4edc7340fcc4da609..6c8cba10087e889088b1d3a18b7474b2f54c4964 100644 (file)
@@ -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
 
index e9dbfc5ff1e50dfddcf0f1de0b2da7ac15f41d8e..fd7e57e7f2789757d2a3854174dc259da2451346 100644 (file)
 # 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;
 
@@ -2778,6 +2752,74 @@ mch_is_linked(char_u *fname)
                                                   && info.nNumberOfLinks > 1;
 }
 
+/*
+ * 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.
@@ -2841,6 +2883,92 @@ win32_fileinfo(char_u *fname, BY_HANDLE_FILE_INFORMATION *info)
     return res;
 }
 
+/*
+ * 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
@@ -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;
 }
 
index 2ae24521c37724fd9a9fd0cdf928aba6331fe739..bdefbab568a2c6a00ce389e248d1ee9f93ed3fbe 100644 (file)
@@ -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));
index be1825e38707a97cc8c7fda6fe29195635f955af..9dfef573d003735378d57f82a7e5315bb737d1e4 100644 (file)
@@ -728,6 +728,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1182,
 /**/
     1181,
 /**/