emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r115515: Fix copy-file on MS-Windows with file names


From: Eli Zaretskii
Subject: [Emacs-diffs] trunk r115515: Fix copy-file on MS-Windows with file names outside of current locale.
Date: Sat, 14 Dec 2013 08:30:25 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 115515
revision-id: address@hidden
parent: address@hidden
fixes bug: http://debbugs.gnu.org/7100
committer: Eli Zaretskii <address@hidden>
branch nick: trunk
timestamp: Sat 2013-12-14 10:29:42 +0200
message:
  Fix copy-file on MS-Windows with file names outside of current locale.
  
   src/fileio.c (Fcopy_file) [WINDOWSNT]: Move most of the
   Windows-specific code to w32.c.  Change error message text to
   match that of Posix platforms.
   src/w32.c (w32_copy_file): New function, most of the code copied and
   reworked from Fcopy_file.  Improve error handling.  Plug memory
   leak when errors are thrown.  Support file names outside of the
   current codepage.  (Bug#7100)
modified:
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/fileio.c                   fileio.c-20091113204419-o5vbwnq5f7feedwu-210
  src/w32.c                      w32.c-20091113204419-o5vbwnq5f7feedwu-808
  src/w32.h                      w32.h-20091113204419-o5vbwnq5f7feedwu-809
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2013-12-13 22:27:05 +0000
+++ b/src/ChangeLog     2013-12-14 08:29:42 +0000
@@ -1,3 +1,14 @@
+2013-12-14  Eli Zaretskii  <address@hidden>
+
+       * fileio.c (Fcopy_file) [WINDOWSNT]: Move most of the
+       Windows-specific code to w32.c.  Change error message text to
+       match that of Posix platforms.
+
+       * w32.c (w32_copy_file): New function, most of the code copied and
+       reworked from Fcopy_file.  Improve error handling.  Plug memory
+       leak when errors are thrown.  Support file names outside of the
+       current codepage.  (Bug#7100)
+
 2013-12-13  Paul Eggert  <address@hidden>
 
        * lread.c (load_path_default): Prototype.

=== modified file 'src/fileio.c'
--- a/src/fileio.c      2013-12-12 20:52:38 +0000
+++ b/src/fileio.c      2013-12-14 08:29:42 +0000
@@ -1959,7 +1959,7 @@
   int conlength = 0;
 #endif
 #ifdef WINDOWSNT
-  acl_t acl = NULL;
+  int result;
 #endif
 
   encoded_file = encoded_newname = Qnil;
@@ -1996,52 +1996,20 @@
     out_st.st_mode = 0;
 
 #ifdef WINDOWSNT
-  if (!NILP (preserve_extended_attributes))
-    {
-      acl = acl_get_file (SDATA (encoded_file), ACL_TYPE_ACCESS);
-      if (acl == NULL && acl_errno_valid (errno))
-       report_file_error ("Getting ACL", file);
-    }
-  if (!CopyFile (SDATA (encoded_file),
-                SDATA (encoded_newname),
-                FALSE))
-    {
-      /* CopyFile doesn't set errno when it fails.  By far the most
-        "popular" reason is that the target is read-only.  */
-      report_file_errno ("Copying file", list2 (file, newname),
-                        GetLastError () == 5 ? EACCES : EPERM);
-    }
-  /* CopyFile retains the timestamp by default.  */
-  else if (NILP (keep_time))
-    {
-      struct timespec now;
-      DWORD attributes;
-      char * filename;
-
-      filename = SDATA (encoded_newname);
-
-      /* Ensure file is writable while its modified time is set.  */
-      attributes = GetFileAttributes (filename);
-      SetFileAttributes (filename, attributes & ~FILE_ATTRIBUTE_READONLY);
-      now = current_timespec ();
-      if (set_file_times (-1, filename, now, now))
-       {
-         /* Restore original attributes.  */
-         SetFileAttributes (filename, attributes);
-         xsignal2 (Qfile_date_error,
-                   build_string ("Cannot set file date"), newname);
-       }
-      /* Restore original attributes.  */
-      SetFileAttributes (filename, attributes);
-    }
-  if (acl != NULL)
-    {
-      bool fail =
-       acl_set_file (SDATA (encoded_newname), ACL_TYPE_ACCESS, acl) != 0;
-      if (fail && acl_errno_valid (errno))
-       report_file_error ("Setting ACL", newname);
-
-      acl_free (acl);
+  result = w32_copy_file (SSDATA (encoded_file), SSDATA (encoded_newname),
+                         !NILP (keep_time), !NILP (preserve_uid_gid),
+                         !NILP (preserve_extended_attributes));
+  switch (result)
+    {
+    case -1:
+      report_file_error ("Copying file", list2 (file, newname));
+    case -2:
+      report_file_error ("Copying permissions from", file);
+    case -3:
+      xsignal2 (Qfile_date_error,
+               build_string ("Resetting file times"), newname);
+    case -4:
+      report_file_error ("Copying permissions to", newname);
     }
 #else /* not WINDOWSNT */
   immediate_quit = 1;

=== modified file 'src/w32.c'
--- a/src/w32.c 2013-12-12 20:07:40 +0000
+++ b/src/w32.c 2013-12-14 08:29:42 +0000
@@ -140,6 +140,7 @@
 #include <sddl.h>
 
 #include <sys/acl.h>
+#include <acl.h>
 
 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
    define them by hand if not already defined.  */
@@ -6001,6 +6002,116 @@
   return NULL;
 }
 
+int
+w32_copy_file (const char *from, const char *to,
+              int keep_time, int preserve_ownership, int copy_acls)
+{
+  acl_t acl = NULL;
+  BOOL copy_result;
+  wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
+  char from_a[MAX_PATH], to_a[MAX_PATH];
+
+  /* We ignore preserve_ownership for now.  */
+  preserve_ownership = preserve_ownership;
+
+  if (copy_acls)
+    {
+      acl = acl_get_file (from, ACL_TYPE_ACCESS);
+      if (acl == NULL && acl_errno_valid (errno))
+       return -2;
+    }
+  if (w32_unicode_filenames)
+    {
+      filename_to_utf16 (from, from_w);
+      filename_to_utf16 (to, to_w);
+      copy_result = CopyFileW (from_w, to_w, FALSE);
+    }
+  else
+    {
+      filename_to_ansi (from, from_a);
+      filename_to_ansi (to, to_a);
+      copy_result = CopyFileA (from_a, to_a, FALSE);
+    }
+  if (!copy_result)
+    {
+      /* CopyFile doesn't set errno when it fails.  By far the most
+        "popular" reason is that the target is read-only.  */
+      DWORD err = GetLastError ();
+
+      switch (err)
+       {
+       case ERROR_FILE_NOT_FOUND:
+         errno = ENOENT;
+         break;
+       case ERROR_ACCESS_DENIED:
+         errno = EACCES;
+         break;
+       case ERROR_ENCRYPTION_FAILED:
+         errno = EIO;
+         break;
+       default:
+         errno = EPERM;
+         break;
+       }
+
+      if (acl)
+       acl_free (acl);
+      return -1;
+    }
+  /* CopyFile retains the timestamp by default.  However, see
+     "Community Additions" for CopyFile: it sounds like that is not
+     entirely true.  Testing on Windows XP confirms that modified time
+     is copied, but creation and last-access times are not.
+     FIXME?  */
+  else if (!keep_time)
+    {
+      struct timespec now;
+      DWORD attributes;
+
+      if (w32_unicode_filenames)
+       {
+         /* Ensure file is writable while its times are set.  */
+         attributes = GetFileAttributesW (to_w);
+         SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
+         now = current_timespec ();
+         if (set_file_times (-1, to, now, now))
+           {
+             /* Restore original attributes.  */
+             SetFileAttributesW (to_w, attributes);
+             if (acl)
+               acl_free (acl);
+             return -3;
+           }
+         /* Restore original attributes.  */
+         SetFileAttributesW (to_w, attributes);
+       }
+      else
+       {
+         attributes = GetFileAttributesA (to_a);
+         SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
+         now = current_timespec ();
+         if (set_file_times (-1, to, now, now))
+           {
+             SetFileAttributesA (to_a, attributes);
+             if (acl)
+               acl_free (acl);
+             return -3;
+           }
+         SetFileAttributesA (to_a, attributes);
+       }
+    }
+  if (acl != NULL)
+    {
+      bool fail =
+       acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
+      acl_free (acl);
+      if (fail && acl_errno_valid (errno))
+       return -4;
+    }
+
+  return 0;
+}
+
 
 /* Support for browsing other processes and their attributes.  See
    process.c for the Lisp bindings.  */

=== modified file 'src/w32.h'
--- a/src/w32.h 2013-12-03 15:29:48 +0000
+++ b/src/w32.h 2013-12-14 08:29:42 +0000
@@ -185,6 +185,7 @@
 extern int  filename_from_utf16 (const wchar_t *, char *);
 extern int  filename_to_utf16 (const char *, wchar_t *);
 extern Lisp_Object ansi_encode_filename (Lisp_Object);
+extern int  w32_copy_file (const char *, const char *, int, int, int);
 
 extern BOOL init_winsock (int load_now);
 extern void srandom (int);


reply via email to

[Prev in Thread] Current Thread [Next in Thread]