rename() removes file when 'from' and 'to' are same file with different path.

Steps to reproduce:

   > echo hello > a.txt
   > vim
   :echo rename('a.txt', '.\a.txt')
   -1
   (a.txt is removed)

   > mkdir dir1
   > mklink /d dir2 dir1
   > echo hello > dir1\a.txt
   > vim
   :echo rename('dir1\a.txt', 'dir2\a.txt')
   -1
   (dir1\a.txt is removed)


The attached patch fixes this problem.
Changed to use GetFileInformationByHandle() to obtain file identifier
and compare it to check if 'from' and 'to' are same file.
Additional clean.diff removes duplicate code.

--
Yukihiro Nakadaira - [email protected]

--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff --git a/src/if_cscope.c b/src/if_cscope.c
--- a/src/if_cscope.c
+++ b/src/if_cscope.c
@@ -1412,17 +1412,17 @@
 {
     short	i, j;
 #ifndef UNIX
-    HANDLE	hFile;
     BY_HANDLE_FILE_INFORMATION bhfi;
+    int		r;
 
-    vim_memset(&bhfi, 0, sizeof(bhfi));
     /* On windows 9x GetFileInformationByHandle doesn't work, so skip it */
     if (!mch_windows95())
     {
-	hFile = CreateFile(fname, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
-						 FILE_ATTRIBUTE_NORMAL, NULL);
-	if (hFile == INVALID_HANDLE_VALUE)
-	{
+	/* FIXME: magic number */
+	r = win32_fileinfo(fname, &bhfi);
+	switch (r) {
+	case -3:    /* enc_to_utf16() failed */
+	case -2:    /* CreateFile() failed */
 	    if (p_csverbose)
 	    {
 		char *cant_msg = _("E625: cannot open cscope database: %s");
@@ -1438,15 +1438,11 @@
 		    (void)EMSG2(cant_msg, fname);
 	    }
 	    return -1;
-	}
-	if (!GetFileInformationByHandle(hFile, &bhfi))
-	{
-	    CloseHandle(hFile);
+	case -1:    /* GetFileInformationByHandle() failed */
 	    if (p_csverbose)
 		(void)EMSG(_("E626: cannot get cscope database information"));
 	    return -1;
 	}
-	CloseHandle(hFile);
     }
 #endif
 
diff --git a/src/os_win32.c b/src/os_win32.c
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -2645,53 +2645,9 @@
     int
 mch_is_linked(char_u *fname)
 {
-    HANDLE	hFile;
-    int		res = 0;
-    BY_HANDLE_FILE_INFORMATION inf;
-#ifdef FEAT_MBYTE
-    WCHAR	*wn = NULL;
-
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	wn = enc_to_utf16(fname, NULL);
-    if (wn != NULL)
-    {
-	hFile = CreateFileW(wn,		/* file name */
-		    GENERIC_READ,	/* access mode */
-		    0,			/* share mode */
-		    NULL,		/* security descriptor */
-		    OPEN_EXISTING,	/* creation disposition */
-		    0,			/* file attributes */
-		    NULL);		/* handle to template file */
-	if (hFile == INVALID_HANDLE_VALUE
-		&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
-	{
-	    /* Retry with non-wide function (for Windows 98). */
-	    vim_free(wn);
-	    wn = NULL;
-	}
-    }
-    if (wn == NULL)
-#endif
-	hFile = CreateFile(fname,	/* file name */
-		    GENERIC_READ,	/* access mode */
-		    0,			/* share mode */
-		    NULL,		/* security descriptor */
-		    OPEN_EXISTING,	/* creation disposition */
-		    0,			/* file attributes */
-		    NULL);		/* handle to template file */
-
-    if (hFile != INVALID_HANDLE_VALUE)
-    {
-	if (GetFileInformationByHandle(hFile, &inf) != 0
-		&& inf.nNumberOfLinks > 1)
-	    res = 1;
-	CloseHandle(hFile);
-    }
-
-#ifdef FEAT_MBYTE
-    vim_free(wn);
-#endif
-    return res;
+    BY_HANDLE_FILE_INFORMATION info;
+
+    return win32_fileinfo(fname, &info) == 0 && info.nNumberOfLinks > 1;
 }
 
 /*

diff --git a/src/fileio.c b/src/fileio.c
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6556,6 +6556,19 @@
     }
 #endif
 
+#ifdef WIN3264
+    {
+	BY_HANDLE_FILE_INFORMATION info1, info2;
+
+	if (win32_fileinfo(from, &info1) == 0
+		&& win32_fileinfo(to, &info2) == 0
+		&& info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
+		&& info1.nFileIndexHigh == info2.nFileIndexHigh
+		&& info1.nFileIndexLow == info2.nFileIndexLow)
+	    use_tmp_file = TRUE;
+    }
+#endif
+
 #if defined(UNIX) || defined(CASE_INSENSITIVE_FILENAME)
     if (use_tmp_file)
     {
diff --git a/src/os_win32.c b/src/os_win32.c
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5236,3 +5236,44 @@
     set_alist_count();
 }
 #endif
+
+/*
+ * Get file information.
+ * Return 0 for success, non-zero for failure.
+ */
+    int
+win32_fileinfo(char *name, LPBY_HANDLE_FILE_INFORMATION lpFileInfo)
+{
+    HANDLE h;
+    BOOL ok;
+
+#ifdef FEAT_MBYTE
+    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+    {
+	WCHAR *wname;
+
+	wname = enc_to_utf16(name, NULL);
+	if (wname == NULL)
+	    return -3;
+	h = CreateFileW(wname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+		(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
+		FILE_FLAG_BACKUP_SEMANTICS, /* for directory */
+		(HANDLE)NULL);
+	vim_free(wname);
+    }
+    else
+#endif
+    {
+	h = CreateFile(name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+		(LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
+		FILE_FLAG_BACKUP_SEMANTICS, /* for directory */
+		(HANDLE)NULL);
+    }
+
+    if (h == INVALID_HANDLE_VALUE)
+	return -2;
+    ok = GetFileInformationByHandle(h, lpFileInfo);
+    CloseHandle(h);
+    return ok ? 0 : -1;
+}
+
diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro
--- a/src/proto/os_win32.pro
+++ b/src/proto/os_win32.pro
@@ -52,4 +52,5 @@
 void used_file_arg __ARGS((char *name, int literal, int full_path, int diff_mode));
 void set_alist_count __ARGS((void));
 void fix_arg_enc __ARGS((void));
+int win32_fileinfo __ARGS((char *name, LPBY_HANDLE_FILE_INFORMATION lpFileInfo));
 /* vim: set ft=c : */

Raspunde prin e-mail lui