* 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.
This commit is contained in:
Corinna Vinschen 2007-08-01 14:46:09 +00:00
parent e9ff75192a
commit 8884a1682a
3 changed files with 80 additions and 25 deletions

View File

@ -1,3 +1,15 @@
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> 2007-08-01 Corinna Vinschen <corinna@vinschen.de>
* localtime.cc (tzsetwall): Don't set TZ. * localtime.cc (tzsetwall): Don't set TZ.

View File

@ -17,6 +17,7 @@
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d) #define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010) #define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010)
#define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xc0000013) #define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xc0000013)
#define STATUS_ACCESS_DENIED ((NTSTATUS) 0xc0000022)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043) #define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)

View File

@ -228,6 +228,38 @@ try_to_bin (path_conv &win32_path, HANDLE h)
recycler, status); 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 NTSTATUS
unlink_nt (path_conv &pc) unlink_nt (path_conv &pc)
{ {
@ -284,33 +316,12 @@ unlink_nt (path_conv &pc)
flags | FILE_SYNCHRONOUS_IO_NONALERT); flags | FILE_SYNCHRONOUS_IO_NONALERT);
if (NT_SUCCESS (status)) if (NT_SUCCESS (status))
{ {
const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION) status = check_dir_not_empty (fh);
+ 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);
if (!NT_SUCCESS (status)) if (!NT_SUCCESS (status))
{ {
NtClose (fh); NtClose (fh);
syscall_printf ("Checking if directory is empty failed, "
"status = %p", status);
return 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;
}
} }
} }
} }
@ -1347,7 +1358,18 @@ rename (const char *oldpath, const char *newpath)
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
ULONG size; ULONG size;
PFILE_RENAME_INFORMATION pfri; 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); oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
if (oldpc.error) if (oldpc.error)
{ {
@ -1359,6 +1381,11 @@ rename (const char *oldpath, const char *newpath)
set_errno (ENOENT); set_errno (ENOENT);
goto out; goto out;
} }
if (oldpc.isspecial ()) /* No renames from virtual FS */
{
set_errno (EROFS);
goto out;
}
olen = strlen (oldpath); olen = strlen (oldpath);
if (oldpc.known_suffix if (oldpc.known_suffix
&& (strcasematch (oldpath + olen - 4, ".lnk") && (strcasematch (oldpath + olen - 4, ".lnk")
@ -1371,7 +1398,7 @@ rename (const char *oldpath, const char *newpath)
set_errno (newpc.error); set_errno (newpc.error);
goto out; goto out;
} }
if (newpc.isspecial ()) /* No renames out of the FS */ if (newpc.isspecial ()) /* No renames to virtual FSes */
{ {
set_errno (EROFS); set_errno (EROFS);
goto out; goto out;
@ -1509,7 +1536,22 @@ rename (const char *oldpath, const char *newpath)
res = 0; res = 0;
} }
else 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); NtClose (fh);
out: out: