Alexandre Julliard : kernel32: Attempt to buffer the full directory in FindFirstFile to avoid races.

Alexandre Julliard julliard at winehq.org
Mon Feb 18 13:27:06 CST 2013


Module: wine
Branch: master
Commit: 7ce90cc7198a6dee75a999e9502ff997e5d3a763
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=7ce90cc7198a6dee75a999e9502ff997e5d3a763

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Feb 18 14:50:57 2013 +0100

kernel32: Attempt to buffer the full directory in FindFirstFile to avoid races.

---

 dlls/kernel32/file.c |   63 +++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index 91e8c8c..89e0fad 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -61,11 +61,14 @@ typedef struct
     BOOL              is_root;     /* is directory the root of the drive? */
     UINT              data_pos;    /* current position in dir data */
     UINT              data_len;    /* length of dir data */
-    BYTE              data[8192];  /* directory data */
+    UINT              data_size;   /* size of data buffer, or 0 when everything has been read */
+    BYTE             *data;        /* directory data */
 } FIND_FIRST_INFO;
 
 #define FIND_FIRST_MAGIC  0xc0ffee11
 
+static const UINT max_entry_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] );
+
 static BOOL oem_file_apis;
 
 static const WCHAR wildcardsW[] = { '*','?',0 };
@@ -1930,6 +1933,8 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
     info->magic    = FIND_FIRST_MAGIC;
     info->data_pos = 0;
     info->data_len = 0;
+    info->data_size = 0;
+    info->data      = NULL;
     info->search_op = search_op;
 
     if (device)
@@ -1945,16 +1950,44 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
     else
     {
         IO_STATUS_BLOCK io;
+        BOOL has_wildcard = strpbrkW( info->mask.Buffer, wildcardsW ) != NULL;
+
+        info->data_size = has_wildcard ? 8192 : max_entry_size;
 
-        NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
-                              FileBothDirectoryInformation, FALSE, &info->mask, TRUE );
-        if (io.u.Status)
+        while (info->data_size)
         {
-            FindClose( info );
-            SetLastError( RtlNtStatusToDosError( io.u.Status ) );
-            return INVALID_HANDLE_VALUE;
+            if (!(info->data = HeapAlloc( GetProcessHeap(), 0, info->data_size )))
+            {
+                FindClose( info );
+                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+                return INVALID_HANDLE_VALUE;
+            }
+
+            NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
+                                  FileBothDirectoryInformation, FALSE, &info->mask, TRUE );
+            if (io.u.Status)
+            {
+                FindClose( info );
+                SetLastError( RtlNtStatusToDosError( io.u.Status ) );
+                return INVALID_HANDLE_VALUE;
+            }
+
+            if (io.Information < info->data_size - max_entry_size)
+            {
+                info->data_size = 0;  /* we read everything */
+            }
+            else if (info->data_size < 1024 * 1024)
+            {
+                HeapFree( GetProcessHeap(), 0, info->data );
+                info->data_size *= 2;
+            }
+            else break;
         }
+
         info->data_len = io.Information;
+        if (!info->data_size && has_wildcard)  /* release unused buffer space */
+            HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, info->data, info->data_len );
+
         if (!FindNextFileW( info, data ))
         {
             TRACE( "%s not found\n", debugstr_w(filename) );
@@ -1962,11 +1995,12 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
             SetLastError( ERROR_FILE_NOT_FOUND );
             return INVALID_HANDLE_VALUE;
         }
-        if (!strpbrkW( info->mask.Buffer, wildcardsW ))
+        if (!has_wildcard)  /* we can't find two files with the same name */
         {
-            /* we can't find two files with the same name */
             CloseHandle( info->handle );
+            HeapFree( GetProcessHeap(), 0, info->data );
             info->handle = 0;
+            info->data = NULL;
         }
     }
     return info;
@@ -2010,15 +2044,21 @@ BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
         {
             IO_STATUS_BLOCK io;
 
-            NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
-                                  FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
+            if (info->data_size)
+                NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size,
+                                      FileBothDirectoryInformation, FALSE, &info->mask, FALSE );
+            else
+                io.u.Status = STATUS_NO_MORE_FILES;
+
             if (io.u.Status)
             {
                 SetLastError( RtlNtStatusToDosError( io.u.Status ) );
                 if (io.u.Status == STATUS_NO_MORE_FILES)
                 {
                     CloseHandle( info->handle );
+                    HeapFree( GetProcessHeap(), 0, info->data );
                     info->handle = 0;
+                    info->data = NULL;
                 }
                 break;
             }
@@ -2101,6 +2141,7 @@ BOOL WINAPI FindClose( HANDLE handle )
                 RtlFreeUnicodeString( &info->path );
                 info->data_pos = 0;
                 info->data_len = 0;
+                HeapFree( GetProcessHeap(), 0, info->data );
                 RtlLeaveCriticalSection( &info->cs );
                 info->cs.DebugInfo->Spare[0] = 0;
                 RtlDeleteCriticalSection( &info->cs );




More information about the wine-cvs mailing list