kernel32/profile: Fix cache logic and don't cache new files.

Michael Karcher wine at mkarcher.dialup.fu-berlin.de
Sun Aug 17 12:03:24 CDT 2008


Wine contains logic to detect that the profile file cache "needs
refreshing", but checks only if TRACing of "profile" is on, and does
not act appropriately. This patch activates the check unconditionally
and really refreshes if needed.

Furthermore, the cache-up-to-date condition has reverse logic. Fixing it
breaks the refreshing logic test, as the mtime on ext3 is only on second
granularity and so mtime does not change when changing the profile file.
Limiting caching to files that are at least 2.1 seconds old (granularity on
FAT: 2 seconds) should prevent caching of files that might get modified
without getting a new mtime.
---
 dlls/kernel32/profile.c       |   37 +++++++++++++++++++++++++++++--------
 dlls/kernel32/tests/profile.c |   38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/dlls/kernel32/profile.c b/dlls/kernel32/profile.c
index ac983ff..22d4cb5 100644
--- a/dlls/kernel32/profile.c
+++ b/dlls/kernel32/profile.c
@@ -702,6 +702,25 @@ static void PROFILE_ReleaseFile(void)
     ZeroMemory(&CurProfile->LastWriteTime, sizeof(CurProfile->LastWriteTime));
 }
 
+/***********************************************************************
+ *
+ * Compares a file time with the current time. If the file time is
+ * at least 2.1 seconds in the past, return true.
+ *
+ * Intended as cache safety measure: The time resolution on FAT is
+ * two seconds, so files that are not at least two seconds old might
+ * keep their time even on modification, so don't cache them.
+ */
+static BOOL is_not_current(FILETIME * ft)
+{
+    FILETIME Now;
+    LONGLONG ftll, nowll;
+    GetSystemTimeAsFileTime(&Now);
+    ftll = ((LONGLONG)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
+    nowll = ((LONGLONG)Now.dwHighDateTime << 32) + Now.dwLowDateTime;
+    TRACE("%08x;%08x\n",(unsigned)ftll+21000000,(unsigned)nowll);
+    return ftll + 21000000 < nowll;
+}
 
 /***********************************************************************
  *           PROFILE_Open
@@ -780,15 +799,17 @@ static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access )
 
             if (hFile != INVALID_HANDLE_VALUE)
             {
-                if (TRACE_ON(profile))
+                GetFileTime(hFile, NULL, NULL, &LastWriteTime);
+                if (!memcmp( &CurProfile->LastWriteTime, &LastWriteTime, sizeof(FILETIME) ) &&
+                    is_not_current(&LastWriteTime))
+                    TRACE("(%s): already opened (mru=%d)\n",
+                          debugstr_w(buffer), i);
+                else
                 {
-                    GetFileTime(hFile, NULL, NULL, &LastWriteTime);
-                    if (memcmp(&CurProfile->LastWriteTime, &LastWriteTime, sizeof(FILETIME)))
-                        TRACE("(%s): already opened (mru=%d)\n",
-                              debugstr_w(buffer), i);
-                    else
-                        TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
-                              debugstr_w(buffer), i);
+                    TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
+                          debugstr_w(buffer), i);
+                    CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding);
+                    CurProfile->LastWriteTime = LastWriteTime;
                 }
                 CloseHandle(hFile);
             }
diff --git a/dlls/kernel32/tests/profile.c b/dlls/kernel32/tests/profile.c
index 329ddb2..0f65178 100644
--- a/dlls/kernel32/tests/profile.c
+++ b/dlls/kernel32/tests/profile.c
@@ -362,9 +362,42 @@ static void test_profile_delete_on_close()
     ok( size == sizeof contents - 1, "Test file: partial write\n");
 
     res = GetPrivateProfileInt(SECTION, KEY, 0, testfile);
+    ok( res == 123, "Got %d instead of 123\n", res);
+
+    /* This also deletes the file */
+    CloseHandle(h);
+}
+
+static void test_profile_refresh()
+{
+    static CHAR testfile[] = ".\\winetest4.ini";
+    HANDLE h;
+    DWORD size, res;
+    static const char contents1[] = "[" SECTION "]\n" KEY "=123\n";
+    static const char contents2[] = "[" SECTION "]\n" KEY "=124\n";
+
+    h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                    CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+    ok( WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL ),
+                    "Cannot write test file: %x\n", GetLastError() );
+    ok( size == sizeof contents1 - 1, "Test file: partial write\n");
 
+    res = GetPrivateProfileInt(SECTION, KEY, 0, testfile);
     ok( res == 123, "Got %d instead of 123\n", res);
 
+    CloseHandle(h);
+
+    /* Test proper invalidation of wine's profile file cache */
+
+    h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                    CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+    ok( WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL ),
+                    "Cannot write test file: %x\n", GetLastError() );
+    ok( size == sizeof contents2 - 1, "Test file: partial write\n");
+
+    res = GetPrivateProfileInt(SECTION, KEY, 0, testfile);
+    ok( res == 124, "Got %d instead of 124\n", res);
+
     /* This also deletes the file */
     CloseHandle(h);
 }
@@ -416,6 +449,10 @@ static void test_GetPrivateProfileString(void)
         "[section2]\r\n";
 
     create_test_file(filename, content, sizeof(content));
+
+    /* Run this test series with caching. Wine won't cache profile
+       files younger than 2.1 seconds. */
+    Sleep(2500);
 
     /* lpAppName is NULL */
     lstrcpyA(buf, "kumquat");
@@ -664,5 +701,6 @@ START_TEST(profile)
     test_profile_sections_names();
     test_profile_existing();
     test_profile_delete_on_close();
+    test_profile_refresh();
     test_GetPrivateProfileString();
 }
-- 
1.5.5.4




More information about the wine-patches mailing list