diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index addb06f6a..0bb91878a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,11 @@ +2007-01-26 Corinna Vinschen + + * fhandler_disk_file.cc (fhandler_disk_file::rmdir): Implement rmdir + on NT by calling unlink_nt. Check for directory here. + * syscalls.cc (try_to_bin): Fix buggy debug_printf statement. + (unlink_nt): Make non-static. Don't use delete-on-close semantics on + directoires. Explain why. + 2007-01-24 Corinna Vinschen * net.cc (if_nametoindex): This time, really free IP_ADAPTER_ADDRESSES diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 43aeff6b4..7de7e56ba 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1447,15 +1447,31 @@ fhandler_disk_file::mkdir (mode_t mode) int fhandler_disk_file::rmdir () { + extern DWORD unlink_nt (path_conv &win32_name, bool setattrs); + int res = -1; + if (!pc.isdir ()) + { + set_errno (ENOTDIR); + return -1; + } /* Even own directories can't be removed if R/O attribute is set. */ if (pc.has_attribute (FILE_ATTRIBUTE_READONLY)) SetFileAttributes (get_win32_name (), (DWORD) pc & ~FILE_ATTRIBUTE_READONLY); DWORD err, att = 0; - int rc = RemoveDirectory (get_win32_name ()); + int rc; + + if (wincap.is_winnt ()) + { + rc = !(err = unlink_nt (pc, pc.has_attribute (FILE_ATTRIBUTE_READONLY))); + if (err) + SetLastError (err); + } + else + rc = RemoveDirectory (get_win32_name ()); if (isremote () && exists ()) att = GetFileAttributes (get_win32_name ()); @@ -1488,7 +1504,7 @@ fhandler_disk_file::rmdir () __seterrno_from_win_error (err); /* Directory still exists, restore its characteristics. */ - if (pc.has_attribute (FILE_ATTRIBUTE_READONLY)) + if (!wincap.is_winnt () && pc.has_attribute (FILE_ATTRIBUTE_READONLY)) SetFileAttributes (get_win32_name (), (DWORD) pc); return res; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 85a43818d..8aec2e649 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -225,7 +225,8 @@ try_to_bin (path_conv &win32_path, HANDLE h) pfri->FileNameLength = uname.Length; status = NtSetInformationFile (h, &io, pfri, size, FileRenameInformation); if (!NT_SUCCESS (status)) - debug_printf ("Move %s to %s failed, status = %p", status); + debug_printf ("Move %s to %s failed, status = %p", win32_path.get_win32 (), + recycler, status); } static DWORD @@ -236,7 +237,7 @@ unlink_9x (path_conv &win32_name) return GetLastError (); } -static DWORD +DWORD unlink_nt (path_conv &win32_name, bool setattrs) { WCHAR wpath[CYG_MAX_PATH + 10]; @@ -247,19 +248,24 @@ unlink_nt (path_conv &win32_name, bool setattrs) HANDLE h; ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT; - /* Don't try "delete on close" if the file is on a remote share. If two - processes have open handles on a file and one of them calls unlink, - then it happens that the file is remove from the remote share even - though the other process still has an open handle. This other process - than gets Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the - file. - That does not happen when using DeleteFile (NtSetInformationFile, class - FileDispositionInformation), which nicely succeeds but still, the file - is available for the other process. - Microsoft KB 837665 describes this problem as a bug in 2K3, but I have - reproduced it on shares on Samba 2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and - 2K3 and in all cases, DeleteFile works, "delete on close" does not. */ - if (!win32_name.isremote ()) + /* Don't open directories with "delete on close", because the NT internal + semantic is apparently different from the file semantic. If a directory + is opened "delete on close", the rename operation in try_to_bin fails + with STATUS_ACCESS_DENIED. So directories must be deleted using + NtSetInformationFile, class FileDispositionInformation, which works fine. + + Don't try "delete on close" if the file is on a remote share. If two + processes have open handles on a file and one of them calls unlink, then + it happens that the file is removed from the remote share even though the + other process still has an open handle. This other process than gets + Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the file. That + does not happen when using NtSetInformationFile, class + FileDispositionInformation, which nicely succeeds but still, the file is + available for the other process. Microsoft KB 837665 describes this + problem as a bug in 2K3, but I have reproduced it on shares on Samba + 2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and 2K3 and in all cases, DeleteFile + works, "delete on close" does not. */ + if (!win32_name.isdir () && !win32_name.isremote ()) flags |= FILE_DELETE_ON_CLOSE; /* Add the reparse point flag to native symlinks, otherwise we remove the target, not the symlink. */ @@ -301,7 +307,7 @@ unlink_nt (path_conv &win32_name, bool setattrs) DWORD lasterr = 0; - if (win32_name.isremote ()) + if (win32_name.isdir () || win32_name.isremote ()) { FILE_DISPOSITION_INFORMATION disp = { TRUE }; status = NtSetInformationFile (h, &io, &disp, sizeof disp,