This is the mail archive of the cygwin-developers@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

rename() is sometimes unsafe on remote drives.


rename() simply deletes a file on remote drives when its source
and destination are identical without distinction of their case.
The following session illustrates this problem.

/jizai/tmp $ touch aa    (A remote drive is mounted on /jizai)
/jizai/tmp $ ls -l aa
-rw-r--r--   1 fujieda  Domain U        0 Apr 17 13:18 aa
/jizai/tmp $ mv aa AA
mv: cannot move `aa' to `AA': No such file or directory
/jizai/tmp $ ls -l aa
ls: aa: No such file or directory
/jizai/tmp $ ls -l AA
ls: AA: No such file or directory

It is caused by MoveFileEx(..., MOVEFILE_REPLACE_EXISTING) in
_rename().

The following patch modify _rename() so that it tries MoveFile()
at first, then tries MoveFileEx(..., MOVEFILE_REPLACE_EXISTING)
on WinNT or the loop of DeleteFileA() and MoveFile() on Win9x.

ChangeLog:
Mon Apr 17 12:08:47 2000  Kazuhiro Fujieda <fujieda@jaist.ac.jp>
	* syscalls.cc (_rename): Try MoveFile() at first before
        MoveFileEx(..., MOVEFILE_REPLACE_EXISTING).

Index: syscalls.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/syscalls.cc,v
retrieving revision 1.14
diff -u -p -r1.14 syscalls.cc
--- syscalls.cc	2000/04/16 22:57:05	1.14
+++ syscalls.cc	2000/04/17 03:58:43
@@ -1200,42 +1200,44 @@ _rename (const char *oldpath, const char
       SetFileAttributesA (real_new.get_win32 (), newatts & ~ FILE_ATTRIBUTE_READONLY);
     }
 
-  /* First make sure we have the permissions */
-  if (!MoveFileEx (real_old.get_win32 (), real_new.get_win32 (), MOVEFILE_REPLACE_EXISTING))
-    {
-      res = -1;
+  if (!MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
+    res = -1;
+
+  if (res == 0 || GetLastError () != ERROR_ALREADY_EXISTS)
+    goto done;
 
-      /* !!! fixme, check for windows version before trying this.. */
-      if (GetLastError () == ERROR_CALL_NOT_IMPLEMENTED)
+  if (os_being_run == winNT)
+    {
+      if (MoveFileEx (real_old.get_win32 (), real_new.get_win32 (),
+		      MOVEFILE_REPLACE_EXISTING))
+	res = 0;
+    }
+  else
+    {
+      syscall_printf ("try win95 hack");
+      for (;;)
 	{
-	  /* How sad, we must be on win95, try it the stupid way */
-	  syscall_printf ("try win95 hack");
-	  for (;;)
+	  if (!DeleteFileA (real_new.get_win32 ()) &&
+	      GetLastError () != ERROR_FILE_NOT_FOUND)
+	    {
+	      syscall_printf ("deleting %s to be paranoid",
+			      real_new.get_win32 ());
+	      break;
+	    }
+	  else
 	    {
 	      if (MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
 		{
 		  res = 0;
 		  break;
 		}
-
-	      if (GetLastError () != ERROR_ALREADY_EXISTS)
-		{
-		  syscall_printf ("%s already_exists", real_new.get_win32 ());
-		  break;
-		}
-
-	      if (!DeleteFileA (real_new.get_win32 ()) &&
-		  GetLastError () != ERROR_FILE_NOT_FOUND)
-		{
-		  syscall_printf ("deleting %s to be paranoid",
-				  real_new.get_win32 ());
-		  break;
-		}
 	    }
 	}
-      if (res)
-	__seterrno ();
     }
+
+done:
+  if (res)
+    __seterrno ();
 
   if (res == 0)
     {

____
  | AIST      Kazuhiro Fujieda <fujieda@jaist.ac.jp>
  | HOKURIKU  School of Information Science
o_/ 1990      Japan Advanced Institute of Science and Technology

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]