diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2007-03-02 20:04:26 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2007-03-02 20:04:26 +0000 |
commit | 788e7da136e19ec6e3e5d40872eb728677f9a4cc (patch) | |
tree | b43e12c495987dd926f951918252aa5419f18c14 | |
parent | 35328778895f786e1db88faba245c96a377e0b38 (diff) | |
download | newlib-788e7da136e19ec6e3e5d40872eb728677f9a4cc.zip newlib-788e7da136e19ec6e3e5d40872eb728677f9a4cc.tar.gz newlib-788e7da136e19ec6e3e5d40872eb728677f9a4cc.tar.bz2 |
* ntdll.h (struct _OBJECT_NAME_INFORMATION): Define.
* syscalls.cc (unlink_nt): Check shared directory for being empty
before trying to move and mark for deletion.
-rw-r--r-- | winsup/cygwin/ChangeLog | 6 | ||||
-rw-r--r-- | winsup/cygwin/ntdll.h | 8 | ||||
-rw-r--r-- | winsup/cygwin/syscalls.cc | 53 |
3 files changed, 65 insertions, 2 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 12a48d1..0d5144b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,11 @@ 2007-03-02 Corinna Vinschen <corinna@vinschen.de> + * ntdll.h (struct _OBJECT_NAME_INFORMATION): Define. + * syscalls.cc (unlink_nt): Check shared directory for being empty + before trying to move and mark for deletion. + +2007-03-02 Corinna Vinschen <corinna@vinschen.de> + * security.cc (get_file_attribute): Avoid compiler warning. 2007-03-01 Christopher Faylor <me@cgf.cx> diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 4fc5da5..0bbb5a5 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -79,6 +79,14 @@ typedef enum _FILE_INFORMATION_CLASS FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; +typedef struct _FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; + typedef struct _FILE_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 30a67b8..e564edd 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -283,8 +283,57 @@ unlink_nt (path_conv &win32_name, bool setattrs) if (status == STATUS_SHARING_VIOLATION) { move_to_bin = true; - status = NtOpenFile (&h, DELETE, &attr, &io, FILE_SHARE_VALID_FLAGS, - flags); + if (!win32_name.isdir () || win32_name.isremote ()) + status = NtOpenFile (&h, DELETE, &attr, &io, FILE_SHARE_VALID_FLAGS, + flags); + else + { + /* It's getting tricky. The directory is opened in some process, + so we're supposed to move it to the recycler and mark it for + deletion. But what if the directory is not empty? The move + will work, but the subsequent delete will fail. So we would + have to move it back. That's bad, because the directory would + be moved around which results in a temporary inconsistent state. + So, what we do here is to test if the directory is empty. If + not, we bail out with ERROR_DIR_NOT_EMTPY. The below code + tests for at least three entries in the directory, ".", "..", + and another one. Three entries means, not empty. This doesn't + work for the root directory of a drive, but the root dir can + neither be deleted, nor moved anyway. */ + status = NtOpenFile (&h, DELETE | SYNCHRONIZE | FILE_LIST_DIRECTORY, + &attr, &io, FILE_SHARE_VALID_FLAGS, + flags | FILE_SYNCHRONOUS_IO_NONALERT); + if (NT_SUCCESS (status)) + { + const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION) + + 3 * NAME_MAX * sizeof (WCHAR); + PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION) + alloca (bufsiz); + status = NtQueryDirectoryFile (h, NULL, NULL, 0, &io, pfni, + bufsiz, FileNamesInformation, + FALSE, NULL, TRUE); + if (!NT_SUCCESS (status)) + { + NtClose (h); + syscall_printf ("Checking if directory is empty failed, " + "status = %p", status); + return RtlNtStatusToDosError (status); + } + int cnt = 1; + while (pfni->NextEntryOffset) + { + pfni = (PFILE_NAMES_INFORMATION) + ((caddr_t) pfni + pfni->NextEntryOffset); + ++cnt; + } + if (cnt > 2) + { + NtClose (h); + syscall_printf ("Directory not empty"); + return ERROR_DIR_NOT_EMPTY; + } + } + } } if (!NT_SUCCESS (status)) { |