2007-08-01 Corinna Vinschen <corinna@vinschen.de>
+ * ntdll.h (STATUS_ACCESS_DENIED): Define.
+ * syscalls.cc (check_dir_not_empty): New static function.
+ (unlink_nt): Move code checking for non-empty dir to check_dir_not_empty
+ and call check_dir_not_empty instead.
+ (rename): Add fault handler. Check oldpath and newpath for trailing
+ . and .. path components and return EINVAL if so. Check oldpath
+ for being on a vrtual file system. If renaming a dir fails with
+ STATUS_ACCESS_DENIED, check if the target dir is non-empty and return
+ ENOTEMPTY if so.
+
+2007-08-01 Corinna Vinschen <corinna@vinschen.de>
+
* localtime.cc (tzsetwall): Don't set TZ.
2007-08-01 Corinna Vinschen <corinna@vinschen.de>
recycler, status);
}
+static NTSTATUS
+check_dir_not_empty (HANDLE dir)
+{
+ IO_STATUS_BLOCK io;
+ const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION)
+ + 3 * NAME_MAX * sizeof (WCHAR);
+ PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION)
+ alloca (bufsiz);
+ NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni,
+ bufsiz, FileNamesInformation,
+ FALSE, NULL, TRUE);
+ if (!NT_SUCCESS (status))
+ {
+ syscall_printf ("Checking if directory is empty failed, "
+ "status = %p", status);
+ return status;
+ }
+ int cnt = 1;
+ while (pfni->NextEntryOffset)
+ {
+ pfni = (PFILE_NAMES_INFORMATION)
+ ((caddr_t) pfni + pfni->NextEntryOffset);
+ ++cnt;
+ }
+ if (cnt > 2)
+ {
+ syscall_printf ("Directory not empty");
+ return STATUS_DIRECTORY_NOT_EMPTY;
+ }
+ return STATUS_SUCCESS;
+}
+
NTSTATUS
unlink_nt (path_conv &pc)
{
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 (fh, NULL, NULL, 0, &io, pfni,
- bufsiz, FileNamesInformation,
- FALSE, NULL, TRUE);
+ status = check_dir_not_empty (fh);
if (!NT_SUCCESS (status))
{
NtClose (fh);
- syscall_printf ("Checking if directory is empty failed, "
- "status = %p", status);
return status;
}
- int cnt = 1;
- while (pfni->NextEntryOffset)
- {
- pfni = (PFILE_NAMES_INFORMATION)
- ((caddr_t) pfni + pfni->NextEntryOffset);
- ++cnt;
- }
- if (cnt > 2)
- {
- NtClose (fh);
- syscall_printf ("Directory not empty");
- return STATUS_DIRECTORY_NOT_EMPTY;
- }
}
}
}
IO_STATUS_BLOCK io;
ULONG size;
PFILE_RENAME_INFORMATION pfri;
-
+
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return -1;
+
+ if (has_dot_last_component (oldpath, true)
+ || has_dot_last_component (newpath, true))
+ {
+ set_errno (EINVAL);
+ goto out;
+ }
+
oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
if (oldpc.error)
{
set_errno (ENOENT);
goto out;
}
+ if (oldpc.isspecial ()) /* No renames from virtual FS */
+ {
+ set_errno (EROFS);
+ goto out;
+ }
olen = strlen (oldpath);
if (oldpc.known_suffix
&& (strcasematch (oldpath + olen - 4, ".lnk")
set_errno (newpc.error);
goto out;
}
- if (newpc.isspecial ()) /* No renames out of the FS */
+ if (newpc.isspecial ()) /* No renames to virtual FSes */
{
set_errno (EROFS);
goto out;
res = 0;
}
else
- __seterrno_from_nt_status (status);
+ {
+ /* Check in case of STATUS_ACCESS_DENIED and pc.isdir(),
+ whether we tried to rename to an existing non-empty dir.
+ In this case we have to set errno to EEXIST. */
+ if (status == STATUS_ACCESS_DENIED && dstpc->isdir ()
+ && NT_SUCCESS (NtOpenFile (&fh, FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ dstpc->get_object_attr (attr, sec_none_nih),
+ &io, FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_FOR_BACKUP_INTENT
+ | FILE_SYNCHRONOUS_IO_NONALERT)))
+ {
+ status = check_dir_not_empty (fh);
+ NtClose (fh);
+ }
+ __seterrno_from_nt_status (status);
+ }
NtClose (fh);
out: