Alexandre Julliard : ntdll:
Added support for reading directories using the BSD getdirentries
function .
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Nov 13 09:24:35 CST 2006
Module: wine
Branch: master
Commit: a9f214cb0d99335378688fbaf6f8894ab050fb37
URL: http://source.winehq.org/git/wine.git/?a=commit;h=a9f214cb0d99335378688fbaf6f8894ab050fb37
Author: Alexandre Julliard <julliard at winehq.org>
Date: Mon Nov 13 15:42:48 2006 +0100
ntdll: Added support for reading directories using the BSD getdirentries function.
---
configure | 2 +
configure.ac | 1 +
dlls/ntdll/directory.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++--
include/config.h.in | 3 +
4 files changed, 116 insertions(+), 4 deletions(-)
diff --git a/configure b/configure
index 54e689e..64e16d1 100755
--- a/configure
+++ b/configure
@@ -18185,6 +18185,7 @@ fi
+
for ac_func in \
_pclose \
_popen \
@@ -18209,6 +18210,7 @@ for ac_func in \
futimes \
futimesat \
getaddrinfo \
+ getdirentries \
gethostbyname \
getnameinfo \
getnetbyname \
diff --git a/configure.ac b/configure.ac
index 958a6c8..37cc2ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1200,6 +1200,7 @@ AC_CHECK_FUNCS(\
futimes \
futimesat \
getaddrinfo \
+ getdirentries \
gethostbyname \
getnameinfo \
getnetbyname \
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index d2c0d16..042daef 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -135,6 +135,8 @@ #define INVALID_DOS_CHARS INVALID_NT_CH
#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,
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
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
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 @@ #endif
#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 );
diff --git a/include/config.h.in b/include/config.h.in
index f26735d..69a0af9 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -180,6 +180,9 @@ #undef HAVE_FUTIMESAT
/* 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
More information about the wine-cvs
mailing list