* 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:
parent
e9ff75192a
commit
8884a1682a
|
@ -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>
|
||||
|
||||
* localtime.cc (tzsetwall): Don't set TZ.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
|
||||
#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xc0000010)
|
||||
#define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xc0000013)
|
||||
#define STATUS_ACCESS_DENIED ((NTSTATUS) 0xc0000022)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
|
||||
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
|
||||
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
|
||||
|
|
|
@ -228,6 +228,38 @@ try_to_bin (path_conv &win32_path, HANDLE h)
|
|||
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)
|
||||
{
|
||||
|
@ -284,33 +316,12 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1348,6 +1359,17 @@ rename (const char *oldpath, const char *newpath)
|
|||
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)
|
||||
{
|
||||
|
@ -1359,6 +1381,11 @@ rename (const char *oldpath, const char *newpath)
|
|||
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")
|
||||
|
@ -1371,7 +1398,7 @@ rename (const char *oldpath, const char *newpath)
|
|||
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;
|
||||
|
@ -1509,7 +1536,22 @@ rename (const char *oldpath, const char *newpath)
|
|||
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:
|
||||
|
|
Loading…
Reference in New Issue