ntdll: Added support for reading directories using the BSD getdirentries function.
This commit is contained in:
parent
d4796304ad
commit
a9f214cb0d
|
@ -18183,6 +18183,7 @@ fi
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for ac_func in \
|
||||
|
@ -18209,6 +18210,7 @@ for ac_func in \
|
|||
futimes \
|
||||
futimesat \
|
||||
getaddrinfo \
|
||||
getdirentries \
|
||||
gethostbyname \
|
||||
getnameinfo \
|
||||
getnetbyname \
|
||||
|
|
|
@ -1200,6 +1200,7 @@ AC_CHECK_FUNCS(\
|
|||
futimes \
|
||||
futimesat \
|
||||
getaddrinfo \
|
||||
getdirentries \
|
||||
gethostbyname \
|
||||
getnameinfo \
|
||||
getnetbyname \
|
||||
|
|
|
@ -135,6 +135,8 @@ static inline int getdents64( int fd, KERNEL_DIRENT64 *de, unsigned int size )
|
|||
|
||||
#define MAX_DIR_ENTRY_LEN 255 /* max length of a directory entry in chars */
|
||||
|
||||
static const unsigned int max_dir_info_size = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[MAX_DIR_ENTRY_LEN] );
|
||||
|
||||
static int show_dot_files = -1;
|
||||
|
||||
/* at some point we may want to allow Winelib apps to set this */
|
||||
|
@ -971,7 +973,6 @@ static int read_directory_vfat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG
|
|||
size_t len;
|
||||
KERNEL_DIRENT *de;
|
||||
FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL;
|
||||
static const unsigned int max_dir_info_size = sizeof(*info) + (MAX_DIR_ENTRY_LEN-1) * sizeof(WCHAR);
|
||||
|
||||
io->u.Status = STATUS_SUCCESS;
|
||||
|
||||
|
@ -1063,7 +1064,6 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
|
|||
char local_buffer[8192];
|
||||
KERNEL_DIRENT64 *data, *de;
|
||||
FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL;
|
||||
static const unsigned int max_dir_info_size = sizeof(*info) + (MAX_DIR_ENTRY_LEN-1) * sizeof(WCHAR);
|
||||
|
||||
if (size <= sizeof(local_buffer) || !(data = RtlAllocateHeap( GetProcessHeap(), 0, size )))
|
||||
{
|
||||
|
@ -1135,7 +1135,111 @@ done:
|
|||
if ((char *)data != local_buffer) RtlFreeHeap( GetProcessHeap(), 0, data );
|
||||
return res;
|
||||
}
|
||||
#endif /* USE_GETDENTS */
|
||||
|
||||
#elif defined HAVE_GETDIRENTRIES
|
||||
|
||||
/***********************************************************************
|
||||
* read_directory_getdirentries
|
||||
*
|
||||
* Read a directory using the BSD getdirentries system call; helper for NtQueryDirectoryFile.
|
||||
*/
|
||||
static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG length,
|
||||
BOOLEAN single_entry, const UNICODE_STRING *mask,
|
||||
BOOLEAN restart_scan )
|
||||
{
|
||||
long restart_pos;
|
||||
ULONG_PTR restart_info_pos = 0;
|
||||
size_t size, initial_size = length;
|
||||
int res;
|
||||
char *data, local_buffer[8192];
|
||||
struct dirent *de;
|
||||
FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL, *restart_last_info = NULL;
|
||||
|
||||
size = initial_size;
|
||||
data = local_buffer;
|
||||
if (size > sizeof(local_buffer) && !(data = RtlAllocateHeap( GetProcessHeap(), 0, size )))
|
||||
{
|
||||
io->u.Status = STATUS_NO_MEMORY;
|
||||
return io->u.Status;
|
||||
}
|
||||
|
||||
if (restart_scan) lseek( fd, 0, SEEK_SET );
|
||||
|
||||
io->u.Status = STATUS_SUCCESS;
|
||||
|
||||
/* FIXME: should make sure size is larger than filesystem block size */
|
||||
res = getdirentries( fd, data, size, &restart_pos );
|
||||
if (res == -1)
|
||||
{
|
||||
io->u.Status = FILE_GetNtStatus();
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
de = (struct dirent *)data;
|
||||
|
||||
while (res > 0)
|
||||
{
|
||||
res -= de->d_reclen;
|
||||
if (de->d_fileno &&
|
||||
((info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask ))))
|
||||
{
|
||||
last_info = info;
|
||||
if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length)
|
||||
{
|
||||
lseek( fd, (unsigned long)restart_pos, SEEK_SET );
|
||||
if (restart_info_pos) /* if we have a complete read already, return it */
|
||||
{
|
||||
io->Information = restart_info_pos;
|
||||
last_info = restart_last_info;
|
||||
break;
|
||||
}
|
||||
/* otherwise restart from the start with a smaller size */
|
||||
size = (char *)de - data;
|
||||
if (!size)
|
||||
{
|
||||
io->u.Status = STATUS_BUFFER_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
io->Information = 0;
|
||||
last_info = NULL;
|
||||
goto restart;
|
||||
}
|
||||
/* if we have to return but the buffer contains more data, restart with a smaller size */
|
||||
if (res > 0 && (single_entry || io->Information + max_dir_info_size > length))
|
||||
{
|
||||
lseek( fd, (unsigned long)restart_pos, SEEK_SET );
|
||||
size = (char *)de - data;
|
||||
io->Information = restart_info_pos;
|
||||
last_info = restart_last_info;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
/* move on to the next entry */
|
||||
if (res > 0)
|
||||
{
|
||||
de = (struct dirent *)((char *)de + de->d_reclen);
|
||||
continue;
|
||||
}
|
||||
if (size < initial_size) break; /* already restarted once, give up now */
|
||||
size = min( size, length - io->Information );
|
||||
/* if size is too small don't bother to continue */
|
||||
if (size < max_dir_info_size && last_info) break;
|
||||
restart_last_info = last_info;
|
||||
restart_info_pos = io->Information;
|
||||
restart:
|
||||
res = getdirentries( fd, data, size, &restart_pos );
|
||||
de = (struct dirent *)data;
|
||||
}
|
||||
|
||||
if (last_info) last_info->NextEntryOffset = 0;
|
||||
else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
|
||||
res = 0;
|
||||
done:
|
||||
if (data != local_buffer) RtlFreeHeap( GetProcessHeap(), 0, data );
|
||||
return res;
|
||||
}
|
||||
#endif /* HAVE_GETDIRENTRIES */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -1151,7 +1255,6 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U
|
|||
off_t i, old_pos = 0;
|
||||
struct dirent *de;
|
||||
FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL;
|
||||
static const unsigned int max_dir_info_size = sizeof(*info) + (MAX_DIR_ENTRY_LEN-1) * sizeof(WCHAR);
|
||||
|
||||
if (!(dir = opendir( "." )))
|
||||
{
|
||||
|
@ -1326,6 +1429,9 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
|
|||
#ifdef USE_GETDENTS
|
||||
if ((read_directory_getdents( fd, io, buffer, length, single_entry, mask, restart_scan )) != -1)
|
||||
goto done;
|
||||
#elif defined HAVE_GETDIRENTRIES
|
||||
if ((read_directory_getdirentries( fd, io, buffer, length, single_entry, mask, restart_scan )) != -1)
|
||||
goto done;
|
||||
#endif
|
||||
read_directory_readdir( fd, io, buffer, length, single_entry, mask, restart_scan );
|
||||
|
||||
|
|
|
@ -180,6 +180,9 @@
|
|||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define to 1 if you have the `getdirentries' function. */
|
||||
#undef HAVE_GETDIRENTRIES
|
||||
|
||||
/* Define to 1 if you have the `gethostbyname' function. */
|
||||
#undef HAVE_GETHOSTBYNAME
|
||||
|
||||
|
|
Loading…
Reference in New Issue