This is the mail archive of the
cygwin-patches@cygwin.com
mailing list for the Cygwin project.
Re: cygwin Changes to Rename (Novell and CVS)
- From: Christopher Faylor <cgf at redhat dot com>
- To: cygwin-patches at cygwin dot com
- Date: Mon, 3 Dec 2001 23:31:10 -0500
- Subject: Re: cygwin Changes to Rename (Novell and CVS)
- References: <CAEIIBEHOJELFDAHENHIOEHFCIAA.neil.erskine@jjmackay.ca> <20011002235602.B16572@redhat.com>
- Reply-to: cygwin-patches at cygwin dot com
No feedback at all?
cgf
On Tue, Oct 02, 2001 at 11:56:02PM -0400, Christopher Faylor wrote:
>This patch is almost a month old. Has anyone had a chance to review it?
>
>Obviously there have been some changes to cygwin since this code was
>first introduced (I just made one recently, in fact) but I'd like to know
>if everyone thinks this is an acceptable way to go.
>
>Any thoughts?
>
>cgf
>
>On Fri, Sep 07, 2001 at 12:17:31AM -0300, Neil Erskine wrote:
>>The combination of Novell 5.1 with its current clients does not allow
>>"rename" as included in the 1.3.2 cygwin distribution to work correctly.
>>Unfortunately, different client/OS combinations seem to return different
>>error codes, and invoke different paths through rename, so the work arounds
>>for this are less than elegant. None-the-less, the attached patch to rename
>>is the best I have come up with. It works on NT 4.0, Windows 2000, Windows
>>95 and Windows 98. I have not tried Windows Me.
>>
>>I came up with this while getting cvs to work with Novell. The patch in
>>this message is necessary but insufficient for cvs, which also requires
>>changes to "unlink". I will submit a separate patch for "unlink" once we
>>get some closure on the rename issue. I can get CVS to work on NT 4.0,
>>Windows 2000, Windows 95 and Windows 98, with and without Novell. I have
>>not tried Windows Me. We have been using these changes here for over a
>>month with no obvious side-effects, but then we don't make extensive use of
>>Cygwin.
>>
>>Should anyone be trying to get CVS to work with Novell and be willing to
>>patch their own code, I'll supply it upon request.
>>
>>I added quite a few syscall_printf lines to rename so that I could see what
>>was happening. I have no particular attraction to any of them, but I have
>>not seen reason to remove them.
>>
>>===================================================================
>>RCS file: syscalls.cc,v
>>retrieving revision 1.1
>>diff -u -r1.1 syscalls.cc
>>--- syscalls.cc 2001/05/23 20:09:21 1.1
>>+++ syscalls.cc 2001/07/20 18:53:31
>>@@ -124,7 +124,7 @@
>> {
>> CloseHandle (h);
>> syscall_printf ("CreateFile/CloseHandle succeeded");
>>- if (os_being_run == winNT || GetFileAttributes (win32_name) ==
>>(DWORD) -1)
>>+ if (GetFileAttributes (win32_name) == (DWORD) -1)
>> {
>> res = 0;
>> break;
>>@@ -1234,6 +1234,7 @@
>> sigframe thisframe (mainthread);
>> int res = 0;
>>
>>+ syscall_printf ("rename (%s, %s)", oldpath, newpath);
>> path_conv real_old (oldpath, PC_SYM_NOFOLLOW);
>>
>> if (real_old.error)
>>@@ -1289,43 +1290,112 @@
>> SetFileAttributesA (real_new.get_win32 (), real_new.file_attributes
>>() & ~ FILE_ATTRIBUTE_READONLY);
>> }
>>
>>- if (!MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
>>- res = -1;
>>-
>>- if (res == 0 || (GetLastError () != ERROR_ALREADY_EXISTS
>>- && GetLastError () != ERROR_FILE_EXISTS))
>>- goto done;
>>-
>>- if (os_being_run == winNT)
>>+ if (MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
>> {
>>- if (MoveFileEx (real_old.get_win32 (), real_new.get_win32 (),
>>- MOVEFILE_REPLACE_EXISTING))
>>- res = 0;
>>+ syscall_printf ( "MoveFile worked" );
>> }
>> else
>> {
>>- syscall_printf ("try win95 hack");
>>- for (;;)
>>+ int HackWorked = (1 == 0);
>>+ DWORD LastError = GetLastError();
>>+
>>+ syscall_printf ( "MoveFile failed %x", LastError );
>>+
>>+ /* Normal approach didn't work. Try some hacks that might. */
>>+ switch ( LastError )
>> {
>>- if (!DeleteFileA (real_new.get_win32 ()) &&
>>- GetLastError () != ERROR_FILE_NOT_FOUND)
>>+ case ERROR_ALREADY_EXISTS:
>>+ case ERROR_FILE_EXISTS:
>>+ if (os_being_run == winNT)
>> {
>>- syscall_printf ("deleting %s to be paranoid",
>>- real_new.get_win32 ());
>>- break;
>>+ /* MoveFileEx sometimes works when MoveFile doesn't. Try
>>+ * that for WinNT systems only, as the call doesn't exist on
>>+ * non-WinNT systems. */
>>+ if (MoveFileEx (real_old.get_win32 (), real_new.get_win32 (),
>>+ MOVEFILE_REPLACE_EXISTING))
>>+ {
>>+ syscall_printf ( "MoveFileEx worked" );
>>+ HackWorked = (1 == 1);
>>+ }
>>+ else
>>+ {
>>+ syscall_printf ( "MoveFileEx failed %x", GetLastError() );
>>+ }
>> }
>>- else
>>+ if ( ! HackWorked )
>> {
>>+ /* Try an approach that sometimes works for Win95/98
>>+ * systems using Novell. This is very similar to the
>>+ * "Win95 hack" below, without the loop, and
>>+ * without the assumption that you can delete a
>>+ * read-only file with DeleteFile. */
>>+ chmod ( real_new.get_win32 (), 0777 );
>>+ chmod ( real_old.get_win32 (), 0777 );
>> if (MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
>>+ {
>>+ syscall_printf ( "Novell hack A worked" );
>>+ HackWorked = (1 == 1);
>>+ }
>>+ else
>>+ {
>>+ syscall_printf ( "Novell hack A (%s,%s) didn't work",
>>+ real_old.get_win32 (),
>>+ real_new.get_win32 () );
>>+ }
>>+ }
>>+ break;
>>+
>>+ case ERROR_ACCESS_DENIED:
>>+ chmod ( real_old.get_win32 (), 0777 );
>>+ if (MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
>>+ {
>>+ syscall_printf ("Novell hack B succeeded");
>>+ HackWorked = (1 == 1);
>>+ }
>>+ else
>>+ {
>>+ syscall_printf ("Novell hack B failed");
>>+ }
>>+ break;
>>+
>>+ default:
>>+ syscall_printf ( "No specific solution for problem" );
>>+ break;
>>+ }
>>+
>>+ /* The following loop might help, but so far we have no
>>+ * documentation on why. It would be nice to know why it
>>+ * doesn't loop forever in the Win95 case; it does loop forever
>>+ * in the Win98/Novell case of a read-only file being
>>+ * renamed. */
>>+ if (os_being_run != winNT && ! HackWorked )
>>+ {
>>+ syscall_printf ("win95 hack");
>>+ for (;;)
>>+ {
>>+ if (!DeleteFileA (real_new.get_win32 ()) &&
>>+ GetLastError () != ERROR_FILE_NOT_FOUND)
>> {
>>- res = 0;
>>+ syscall_printf ("deleting %s to be paranoid",
>>+ real_new.get_win32 ());
>> break;
>> }
>>+ else
>>+ {
>>+ if (MoveFile (real_old.get_win32 (), real_new.get_win32 ()))
>>+ {
>>+ HackWorked = (1 == 1);
>>+ break;
>>+ }
>>+ }
>> }
>> }
>>+ if ( ! HackWorked )
>>+ {
>>+ res = -1;
>>+ }
>> }
>>-
>>-done:
>>+
>> if (res)
>> __seterrno ();
>>
>>@@ -1333,6 +1403,14 @@
>> {
>> /* make the new file have the permissions of the old one */
>> SetFileAttributesA (real_new.get_win32 (), real_old.file_attributes
>>());
>>+ }
>>+ else
>>+ {
>>+ /* some of the rename algorithms tried above try to change
>>+ permissions; reset those of the old and new files back to the
>>+ way they were. */
>>+ SetFileAttributesA (real_new.get_win32 (), real_new.file_attributes
>>());
>>+ SetFileAttributesA (real_old.get_win32 (), real_old.file_attributes
>>());
>> }
>>
>> syscall_printf ("%d = rename (%s, %s)", res, real_old.get_win32 (),
>>
>>Neil Erskine
>>Manager, Research and Product Development
>>JJ Mackay Canada Limited
>>1046 Barrington Street, 1st floor
>>Halifax, N.S. B3H 2R1
>>
>>voice 902 423 7727 ext. 230
>>fax 902 422 8108
>
>--
>cgf@cygnus.com Red Hat, Inc.
>http://sources.redhat.com/ http://www.redhat.com/
--
cgf@redhat.com Red Hat, Inc.
http://sources.redhat.com/ http://www.redhat.com/