ntdll: Remove VFAT_IOCTL_READDIR_BOTH kernel bugs workarounds.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-04-28 12:20:26 +02:00
parent 6b4de51027
commit 69f068bfb1
1 changed files with 27 additions and 76 deletions

View File

@ -1592,46 +1592,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I
#ifdef VFAT_IOCTL_READDIR_BOTH
/***********************************************************************
* start_vfat_ioctl
*
* Wrapper for the VFAT ioctl to work around various kernel bugs.
* dir_section must be held by caller.
*/
static KERNEL_DIRENT *start_vfat_ioctl( int fd )
{
static KERNEL_DIRENT *de;
int res;
if (!de)
{
SIZE_T size = 2 * sizeof(*de) + page_size;
void *addr = NULL;
if (virtual_alloc_aligned( &addr, 0, &size, MEM_RESERVE, PAGE_READWRITE, 1 ))
return NULL;
/* commit only the size needed for the dir entries */
/* this leaves an extra unaccessible page, which should make the kernel */
/* fail with -EFAULT before it stomps all over our memory */
de = addr;
size = 2 * sizeof(*de);
virtual_alloc_aligned( &addr, 0, &size, MEM_COMMIT, PAGE_READWRITE, 1 );
}
/* set d_reclen to 65535 to work around an AFS kernel bug */
de[0].d_reclen = 65535;
res = ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de );
if (res == -1)
{
if (errno != ENOENT) return NULL; /* VFAT ioctl probably not supported */
de[0].d_reclen = 0; /* eof */
}
else if (!res && de[0].d_reclen == 65535) return NULL; /* AFS bug */
return de;
}
/***********************************************************************
* read_directory_vfat
*
@ -1640,40 +1600,42 @@ static KERNEL_DIRENT *start_vfat_ioctl( int fd )
static NTSTATUS read_directory_data_vfat( struct dir_data *data, int fd, const UNICODE_STRING *mask )
{
char *short_name, *long_name;
size_t len;
KERNEL_DIRENT *de;
KERNEL_DIRENT de[2];
NTSTATUS status = STATUS_NO_MEMORY;
off_t old_pos = lseek( fd, 0, SEEK_CUR );
if (!(de = start_vfat_ioctl( fd ))) return STATUS_NOT_SUPPORTED;
lseek( fd, 0, SEEK_SET );
if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) == -1)
{
if (errno != ENOENT)
{
status = STATUS_NOT_SUPPORTED;
goto done;
}
de[0].d_reclen = 0;
}
if (!append_entry( data, ".", NULL, mask )) goto done;
if (!append_entry( data, "..", NULL, mask )) goto done;
while (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) != -1)
while (de[0].d_reclen)
{
if (!de[0].d_reclen) break; /* eof */
/* make sure names are null-terminated to work around an x86-64 kernel bug */
len = min( de[0].d_reclen, sizeof(de[0].d_name) - 1 );
de[0].d_name[len] = 0;
len = min( de[1].d_reclen, sizeof(de[1].d_name) - 1 );
de[1].d_name[len] = 0;
if (!strcmp( de[0].d_name, "." ) || !strcmp( de[0].d_name, ".." )) continue;
if (de[1].d_name[0])
if (strcmp( de[0].d_name, "." ) && strcmp( de[0].d_name, ".." ))
{
short_name = de[0].d_name;
long_name = de[1].d_name;
if (de[1].d_name[0])
{
short_name = de[0].d_name;
long_name = de[1].d_name;
}
else
{
long_name = de[0].d_name;
short_name = NULL;
}
if (!append_entry( data, long_name, short_name, mask )) goto done;
}
else
{
long_name = de[0].d_name;
short_name = NULL;
}
if (!append_entry( data, long_name, short_name, mask )) goto done;
if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) == -1) break;
}
status = STATUS_SUCCESS;
done:
@ -2083,20 +2045,13 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
int fd = open( unix_name, O_RDONLY | O_DIRECTORY );
if (fd != -1)
{
KERNEL_DIRENT *kde;
KERNEL_DIRENT kde[2];
RtlEnterCriticalSection( &dir_section );
if ((kde = start_vfat_ioctl( fd )))
if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)kde ) != -1)
{
unix_name[pos - 1] = '/';
while (kde[0].d_reclen)
{
/* make sure names are null-terminated to work around an x86-64 kernel bug */
size_t len = min(kde[0].d_reclen, sizeof(kde[0].d_name) - 1 );
kde[0].d_name[len] = 0;
len = min(kde[1].d_reclen, sizeof(kde[1].d_name) - 1 );
kde[1].d_name[len] = 0;
if (kde[1].d_name[0])
{
ret = ntdll_umbstowcs( kde[1].d_name, strlen(kde[1].d_name),
@ -2104,7 +2059,6 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
if (ret == length && !RtlCompareUnicodeStrings( buffer, ret, name, ret, TRUE ))
{
strcpy( unix_name + pos, kde[1].d_name );
RtlLeaveCriticalSection( &dir_section );
close( fd );
goto success;
}
@ -2115,19 +2069,16 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
{
strcpy( unix_name + pos,
kde[1].d_name[0] ? kde[1].d_name : kde[0].d_name );
RtlLeaveCriticalSection( &dir_section );
close( fd );
goto success;
}
if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)kde ) == -1)
{
RtlLeaveCriticalSection( &dir_section );
close( fd );
goto not_found;
}
}
}
RtlLeaveCriticalSection( &dir_section );
close( fd );
}
/* fall through to normal handling */