]> git.eshelyaron.com Git - emacs.git/commitdiff
Restore file's original name after a failed rename_replace on Windows 9X
authorPo Lu <luangruo@yahoo.com>
Fri, 14 Jun 2024 02:44:20 +0000 (10:44 +0800)
committerEshel Yaron <me@eshelyaron.com>
Sat, 15 Jun 2024 17:21:13 +0000 (19:21 +0200)
* src/w32.c (sys_rename_replace): If the rename operation fails
and an intermediate name was generated and applied to the input
file, restore the original.

(cherry picked from commit a458dc5dc828cfbe5d74226d6ef45a3d205cb7d8)

src/w32.c

index 6d0b178e9780263a9e525a10cf3eddadd6bf0d02..1c6a56bcbd9bcc9d0f07b94e03bcc0302e951103 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -4740,10 +4740,11 @@ int
 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
 {
   BOOL result;
-  char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
+  char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];
   int newname_dev;
   int oldname_dev;
   bool have_temp_a = false;
+  char oldname_a[MAX_PATH];
 
   /* MoveFile on Windows 95 doesn't correctly change the short file name
      alias in a number of circumstances (it is not easy to predict when
@@ -4768,7 +4769,6 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
       char * o;
       char * p;
       int    i = 0;
-      char oldname_a[MAX_PATH];
 
       oldname = map_w32_filename (oldname, NULL);
       filename_to_ansi (oldname, oldname_a);
@@ -4844,7 +4844,7 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
              DWORD attributes_new;
 
              if (_wchmod (newname_w, 0666) != 0)
-               return result;
+               goto return_result;
              attributes_old = GetFileAttributesW (temp_w);
              attributes_new = GetFileAttributesW (newname_w);
              if (attributes_old != -1 && attributes_new != -1
@@ -4855,15 +4855,16 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
                    errno = ENOTDIR;
                  else
                    errno = EISDIR;
-                 return -1;
+                 result = -1;
+                 goto return_result;
                }
              if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
                {
                  if (_wrmdir (newname_w) != 0)
-                   return result;
+                   goto return_result;
                }
              else if (_wunlink (newname_w) != 0)
-               return result;
+               goto return_result;
              result = _wrename (temp_w, newname_w);
            }
          else if (w32err == ERROR_PRIVILEGE_NOT_HELD
@@ -4902,7 +4903,7 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
              DWORD attributes_new;
 
              if (_chmod (newname_a, 0666) != 0)
-               return result;
+               goto return_result;
              attributes_old = GetFileAttributesA (temp_a);
              attributes_new = GetFileAttributesA (newname_a);
              if (attributes_old != -1 && attributes_new != -1
@@ -4913,15 +4914,16 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
                    errno = ENOTDIR;
                  else
                    errno = EISDIR;
-                 return -1;
+                 result = -1;
+                 goto return_result;
                }
              if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
                {
                  if (_rmdir (newname_a) != 0)
-                   return result;
+                   goto return_result;
                }
              else if (_unlink (newname_a) != 0)
-               return result;
+               goto return_result;
              result = rename (temp_a, newname_a);
            }
          else if (w32err == ERROR_PRIVILEGE_NOT_HELD
@@ -4930,6 +4932,23 @@ sys_rename_replace (const char *oldname, const char *newname, BOOL force)
        }
     }
 
+ return_result:
+  /* This label is also invoked on failure, and on Windows 9X, restores
+     the initial name of files that will have been renamed in
+     preparation for being moved.  It ought to be valid to rename temp_a
+     to its previous name, just as it would, but for the failure, have
+     been renamed to the target.  */
+
+  if (have_temp_a && result)
+    {
+      int save_errno = errno;
+
+      /* XXX: what if a new file has replaced oldname_a in the
+        meantime?  */
+      rename (temp_a, oldname_a);
+      errno = save_errno;
+    }
+
   return result;
 }