From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: LynX <_LynX@bk.ru> Newsgroups: gmane.emacs.bugs Subject: bug#10284: "Renaming: permission denied" file-error in Windows Date: Fri, 30 Dec 2011 21:31:26 +0200 Message-ID: <4EFE118E.5040800@bk.ru> References: <4EE3F66D.2050003@bk.ru> <83vcpnllo3.fsf@gnu.org> <4EE46AA1.9010700@cs.ucla.edu> <4EE504C3.3090701@bk.ru> <83obvfkmt6.fsf@gnu.org> <4EE5245E.3090803@bk.ru> <83liqilrs0.fsf@gnu.org> <4EF6D1CE.7020101@bk.ru> <4EFB73C3.7070203@bk.ru> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------030407080800030400040706" X-Trace: dough.gmane.org 1325273596 22883 80.91.229.12 (30 Dec 2011 19:33:16 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Fri, 30 Dec 2011 19:33:16 +0000 (UTC) To: 10284@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Fri Dec 30 20:33:12 2011 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1RgiCU-0004hH-U2 for geb-bug-gnu-emacs@m.gmane.org; Fri, 30 Dec 2011 20:33:11 +0100 Original-Received: from localhost ([::1]:56189 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RgiCU-0000KF-4g for geb-bug-gnu-emacs@m.gmane.org; Fri, 30 Dec 2011 14:33:10 -0500 Original-Received: from eggs.gnu.org ([140.186.70.92]:33648) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RgiCQ-0000Jx-UJ for bug-gnu-emacs@gnu.org; Fri, 30 Dec 2011 14:33:08 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RgiCP-0000tp-Jp for bug-gnu-emacs@gnu.org; Fri, 30 Dec 2011 14:33:06 -0500 Original-Received: from debbugs.gnu.org ([140.186.70.43]:59266) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RgiCP-0000tc-DY for bug-gnu-emacs@gnu.org; Fri, 30 Dec 2011 14:33:05 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.69) (envelope-from ) id 1RgiFG-00063w-2G for bug-gnu-emacs@gnu.org; Fri, 30 Dec 2011 14:36:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: LynX <_LynX@bk.ru> Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 30 Dec 2011 19:36:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 10284 X-GNU-PR-Package: emacs,w32 X-GNU-PR-Keywords: Original-Received: via spool by 10284-submit@debbugs.gnu.org id=B10284.132527372123247 (code B ref 10284); Fri, 30 Dec 2011 19:36:02 +0000 Original-Received: (at 10284) by debbugs.gnu.org; 30 Dec 2011 19:35:21 +0000 Original-Received: from localhost ([127.0.0.1] helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1RgiEa-00062t-Lg for submit@debbugs.gnu.org; Fri, 30 Dec 2011 14:35:20 -0500 Original-Received: from smtp8.mail.ru ([94.100.176.53]) by debbugs.gnu.org with esmtp (Exim 4.69) (envelope-from <_LynX@bk.ru>) id 1RgiEW-00062h-9b for 10284@debbugs.gnu.org; Fri, 30 Dec 2011 14:35:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail; h=Content-Type:In-Reply-To:References:Subject:To:MIME-Version:From:Date:Message-ID; bh=KdsIKEpbzgAS8ttNBPDE5pW1JiyB45dGolbg1z/5ano=; b=MWh8hmp43y5TybYscClIHcggosezx2V6OC0494N0QCs88vWea24w0OW0f2SQnoMc0QpzRWC56PYV2rSffAbZ3b9LPcqc3c6flYRfWdS/u5lftHPHd7F4IC/7GA0m3Tp8; Original-Received: from [213.231.61.71] (port=1371) by smtp8.mail.ru with esmtpa (envelope-from <_LynX@bk.ru>) id 1RgiBd-0005DP-EU for 10284@debbugs.gnu.org; Fri, 30 Dec 2011 23:32:17 +0400 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.8) Gecko/20100227 Thunderbird/3.0.3 In-Reply-To: X-Mru-NR: 1 X-Mru-UID: 10796556 X-Spam: Not detected X-Mras: Ok X-Mru-Karma: 0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.11 Precedence: list Resent-Date: Fri, 30 Dec 2011 14:36:02 -0500 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:55312 Archived-At: This is a multi-part message in MIME format. --------------030407080800030400040706 Content-Type: text/plain; charset=windows-1251; format=flowed Content-Transfer-Encoding: 8bit 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.) > > --------------030407080800030400040706 Content-Type: text/plain; name="w32.c.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="w32.c.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; } --------------030407080800030400040706--