unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: LynX <_LynX@bk.ru>
To: 10284@debbugs.gnu.org
Subject: bug#10284: "Renaming: permission denied" file-error in Windows
Date: Fri, 30 Dec 2011 21:31:26 +0200	[thread overview]
Message-ID: <4EFE118E.5040800@bk.ru> (raw)
In-Reply-To: <E1Rg9JS-0000mS-8c@fencepost.gnu.org>

[-- Attachment #1: Type: text/plain, Size: 3120 bytes --]

Hello Eli,

Thank you for the clarification.

Please review this patch.

--- w32.c.orig	2011-11-26 05:20:20.000000000 +0200
+++ w32.c	2011-12-30 21:22:56.734375000 +0200
@@ -2857,6 +2857,8 @@
  {
    BOOL result;
    char temp[MAX_PATH];
+  int newname_dev;
+  int oldname_dev;

    /* 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
@@ -2873,6 +2875,9 @@

    strcpy (temp, map_w32_filename (oldname, NULL));

+  /* volume_info is set indirectly by map_w32_filename */
+  oldname_dev = volume_info.serialnum;
+
    if (os_subtype == OS_WIN95)
      {
        char * o;
@@ -2916,13 +2921,36 @@
       all the permutations of shared or subst'd drives, etc.)  */

    newname = map_w32_filename (newname, NULL);
+
+  /* volume_info is set indirectly by map_w32_filename */
+  newname_dev = volume_info.serialnum;
+
    result = rename (temp, newname);

-  if (result < 0
-      && errno == EEXIST
-      && _chmod (newname, 0666) == 0
-      && _unlink (newname) == 0)
-    result = rename (temp, newname);
+  if (result < 0)
+    {
+
+      if (errno == EACCES
+	  && newname_dev != oldname_dev)
+	{
+	  /* The implementation of `rename' on Windows does not return
+	     errno = EXDEV when you are moving a directory to a different
+	     storage device (ex. logical disk). It returns EACCES
+	     instead. So here we handle such situations and return EXDEV. */
+	  DWORD attributes;
+	  if ((attributes = GetFileAttributes(temp)) != -1
+	      && attributes & FILE_ATTRIBUTE_DIRECTORY)
+	    errno = EXDEV;
+	}
+      else if (errno == EEXIST)
+	{
+	  if (_chmod (newname, 0666) != 0)
+	    return result;
+	  if (_unlink (newname) != 0)
+	    return result;
+	  result = rename (temp, newname);
+	}
+    }

    return result;
  }

I've added check whether it is a directory or not, and moved all this 
before the unlink operation.

Regards,
LX

29.12.2011 8:18, Eli Zaretskii пишет:
>> Date: Wed, 28 Dec 2011 21:53:39 +0200
>> From: LynX<_LynX@bk.ru>
>>
>>   >  This first removes the target, and only then compares the device
>>   >  numbers.  Wouldn't it be better to do it the other way around, at
>>   >  least when the target is a directory?  That way, the target is left
>>   >  intact if the caller doesn't want to copy over the target, and also
>>   >  the filesystem is left in the same state as on Posix hosts in this
>>   >  case, i.e. the contract of `rename' is preserved on all systems.
>>
>> You mean that before setting errno to EXDEV we also need to check that
>> target is a directory (since files are moved correctly)?
>
> Yes, but that's not the important part of my comment above.  The
> important part is to move the check for different devices _before_ the
> call to _unlink which removes the target file/directory if it exists.
> In other words, we should fail and report EXDEV without risking the
> removal of the target, and let the caller decide what to do with the
> failure.  (If the caller decides to leave things unchanged, it will
> not be The Right Thing for us to remove the target.)
>
>


[-- Attachment #2: w32.c.patch --]
[-- Type: text/plain, Size: 1748 bytes --]

--- w32.c.orig	2011-11-26 05:20:20.000000000 +0200
+++ w32.c	2011-12-30 21:22:56.734375000 +0200
@@ -2857,6 +2857,8 @@
 {
   BOOL result;
   char temp[MAX_PATH];
+  int newname_dev;
+  int oldname_dev;
 
   /* 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
@@ -2873,6 +2875,9 @@
 
   strcpy (temp, map_w32_filename (oldname, NULL));
 
+  /* volume_info is set indirectly by map_w32_filename */
+  oldname_dev = volume_info.serialnum;
+
   if (os_subtype == OS_WIN95)
     {
       char * o;
@@ -2916,13 +2921,36 @@
      all the permutations of shared or subst'd drives, etc.)  */
 
   newname = map_w32_filename (newname, NULL);
+
+  /* volume_info is set indirectly by map_w32_filename */
+  newname_dev = volume_info.serialnum;
+
   result = rename (temp, newname);
 
-  if (result < 0
-      && errno == EEXIST
-      && _chmod (newname, 0666) == 0
-      && _unlink (newname) == 0)
-    result = rename (temp, newname);
+  if (result < 0)
+    {
+
+      if (errno == EACCES
+	  && newname_dev != oldname_dev)
+	{
+	  /* The implementation of `rename' on Windows does not return 
+	     errno = EXDEV when you are moving a directory to a different 
+	     storage device (ex. logical disk). It returns EACCES
+	     instead. So here we handle such situations and return EXDEV. */
+	  DWORD attributes;
+	  if ((attributes = GetFileAttributes(temp)) != -1
+	      && attributes & FILE_ATTRIBUTE_DIRECTORY)
+	    errno = EXDEV;
+	}
+      else if (errno == EEXIST)
+	{
+	  if (_chmod (newname, 0666) != 0)
+	    return result;
+	  if (_unlink (newname) != 0)
+	    return result;
+	  result = rename (temp, newname);
+	}
+    }
 
   return result;
 }

  reply	other threads:[~2011-12-30 19:31 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <4EE3F66D.2050003@bk.ru>
     [not found] ` <83vcpnllo3.fsf@gnu.org>
     [not found]   ` <4EE46AA1.9010700@cs.ucla.edu>
     [not found]     ` <E1RZisW-0000Ok-0C@fencepost.gnu.org>
     [not found]       ` <4EE504C3.3090701@bk.ru>
     [not found]         ` <83obvfkmt6.fsf@gnu.org>
     [not found]           ` <4EE5245E.3090803@bk.ru>
     [not found]             ` <83liqilrs0.fsf@gnu.org>
     [not found]               ` <4EF6D1CE.7020101@bk.ru>
2011-12-25  9:39                 ` bug#10284: "Renaming: permission denied" file-error in Windows Eli Zaretskii
     [not found]                 ` <E1RekZY-0003jE-FO@fencepost.gnu.org>
2011-12-28 19:53                   ` LynX
2011-12-29  6:18                     ` Eli Zaretskii
2011-12-30 19:31                       ` LynX [this message]
2011-12-30 20:23                         ` Eli Zaretskii
2011-12-30 21:35                           ` LynX
2011-12-31  6:48                             ` Eli Zaretskii
2012-01-06 20:46                               ` LynX
2012-01-07  9:54                                 ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EFE118E.5040800@bk.ru \
    --to=_lynx@bk.ru \
    --cc=10284@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).