[APPHELP] Implement SdbpMatchExe, allowing to match applications / files based on...
authorMark Jansen <mark.jansen@reactos.org>
Thu, 29 Jun 2017 17:32:03 +0000 (17:32 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Thu, 29 Jun 2017 17:32:03 +0000 (17:32 +0000)
svn path=/trunk/; revision=75238

reactos/dll/appcompat/apphelp/apphelp.h
reactos/dll/appcompat/apphelp/hsdb.c
reactos/dll/appcompat/apphelp/sdbfileattr.c

index 2e1c4f4..d1897ae 100644 (file)
@@ -90,6 +90,7 @@ PWSTR SdbpStrDup(LPCWSTR string);
 HSDB WINAPI SdbInitDatabase(DWORD, LPCWSTR);
 void WINAPI SdbReleaseDatabase(HSDB);
 BOOL WINAPI SdbGUIDToString(CONST GUID *Guid, PWSTR GuidString, SIZE_T Length);
+LPCWSTR WINAPI SdbTagToString(TAG tag);
 
 PDB WINAPI SdbOpenDatabase(LPCWSTR path, PATH_TYPE type);
 void WINAPI SdbCloseDatabase(PDB);
@@ -105,8 +106,12 @@ TAGID WINAPI SdbFindFirstTag(PDB db, TAGID parent, TAG tag);
 TAGID WINAPI SdbFindNextTag(PDB db, TAGID parent, TAGID prev_child);
 BOOL WINAPI SdbGetDatabaseID(PDB db, GUID* Guid);
 DWORD WINAPI SdbReadDWORDTag(PDB db, TAGID tagid, DWORD ret);
+QWORD WINAPI SdbReadQWORDTag(PDB db, TAGID tagid, QWORD ret);
+TAGID WINAPI SdbGetFirstChild(PDB db, TAGID parent);
+TAGID WINAPI SdbGetNextChild(PDB db, TAGID parent, TAGID prev_child);
 
 /* sdbfileattr.c*/
+BOOL WINAPI SdbGetFileAttributes(LPCWSTR path, PATTRINFO *attr_info_ret, LPDWORD attr_count);
 BOOL WINAPI SdbFreeFileAttributes(PATTRINFO attr_info);
 
 /* layer.c */
index c5b2ac5..63ba796 100644 (file)
@@ -49,31 +49,132 @@ static BOOL WINAPI SdbpFileExists(LPCWSTR path)
     return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
 }
 
-static BOOL WINAPI SdbpMatchExe(PDB db, TAGID exe, WCHAR* dir)
+static BOOL SdbpMatchFileAttributes(PDB pdb, TAGID matching_file, PATTRINFO attribs, DWORD attr_count)
 {
-    static const WCHAR fmt[] = {'%','s','%','s',0};
-    WCHAR buffer[256];  /* FIXME: rewrite using a buffer that can grow if needed, f.e. RtlInitBuffer stuff! */
+    TAGID child;
+
+    for (child = SdbGetFirstChild(pdb, matching_file);
+         child != TAGID_NULL; child = SdbGetNextChild(pdb, matching_file, child))
+    {
+        TAG tag = SdbGetTagFromTagID(pdb, child);
+        DWORD n;
+
+        /* Already handled! */
+        if (tag == TAG_NAME)
+            continue;
+
+        if (tag == TAG_UPTO_BIN_FILE_VERSION ||
+            tag == TAG_UPTO_BIN_PRODUCT_VERSION ||
+            tag == TAG_UPTO_LINK_DATE)
+        {
+            SHIM_WARN("Unimplemented TAG_UPTO_XXXXX\n");
+            continue;
+        }
+
+        for (n = 0; n < attr_count; ++n)
+        {
+            PATTRINFO attr = attribs + n;
+            if (attr->flags == ATTRIBUTE_AVAILABLE && attr->type == tag)
+            {
+                DWORD dwval;
+                WCHAR* lpval;
+                QWORD qwval;
+                switch (tag & TAG_TYPE_MASK)
+                {
+                case TAG_TYPE_DWORD:
+                    dwval = SdbReadDWORDTag(pdb, child, 0);
+                    if (dwval != attr->dwattr)
+                        return FALSE;
+                    break;
+                case TAG_TYPE_STRINGREF:
+                    lpval = SdbGetStringTagPtr(pdb, child);
+                    if (!lpval || wcsicmp(attr->lpattr, lpval))
+                        return FALSE;
+                    break;
+                case TAG_TYPE_QWORD:
+                    qwval = SdbReadQWORDTag(pdb, child, 0);
+                    if (qwval != attr->qwattr)
+                        return FALSE;
+                    break;
+                default:
+                    SHIM_WARN("Unhandled type 0x%x MATCHING_FILE\n", (tag & TAG_TYPE_MASK));
+                    return FALSE;
+                }
+            }
+        }
+        if (n == attr_count)
+            SHIM_WARN("Unhandled tag %ws in MACHING_FILE\n", SdbTagToString(tag));
+    }
+    return TRUE;
+}
+
+static BOOL WINAPI SdbpMatchExe(PDB pdb, TAGID exe, const WCHAR* dir, PATTRINFO main_attribs, DWORD main_attr_count)
+{
+    RTL_UNICODE_STRING_BUFFER FullPathName = { { 0 } };
+    WCHAR FullPathBuffer[MAX_PATH];
+    UNICODE_STRING UnicodeDir;
     TAGID matching_file;
+    PATTRINFO attribs = NULL;
+    DWORD attr_count;
+    BOOL IsMatch = FALSE;
+
+    RtlInitUnicodeString(&UnicodeDir, dir);
+    RtlInitBuffer(&FullPathName.ByteBuffer, (PUCHAR)FullPathBuffer, sizeof(FullPathBuffer));
 
-    /* TODO: check size/checksum from the main exe as well as from the extra files */
-    for (matching_file = SdbFindFirstTag(db, exe, TAG_MATCHING_FILE);
-            matching_file != TAGID_NULL; matching_file = SdbFindNextTag(db, exe, matching_file))
+    for (matching_file = SdbFindFirstTag(pdb, exe, TAG_MATCHING_FILE);
+            matching_file != TAGID_NULL; matching_file = SdbFindNextTag(pdb, exe, matching_file))
     {
-        TAGID tagName = SdbFindFirstTag(db, matching_file, TAG_NAME);
-        LPWSTR name = SdbGetStringTagPtr(db, tagName);
+        TAGID tagName = SdbFindFirstTag(pdb, matching_file, TAG_NAME);
+        UNICODE_STRING Name;
+        USHORT Len;
 
-        if (!wcscmp(name, L"*"))
+        RtlInitUnicodeString(&Name, SdbGetStringTagPtr(pdb, tagName));
+
+        if (!Name.Buffer)
+            goto Cleanup;
+
+        if (!wcscmp(Name.Buffer, L"*"))
         {
-            // if attributes dont match main file, return FALSE!
+            if (!SdbpMatchFileAttributes(pdb, matching_file, main_attribs, main_attr_count))
+                goto Cleanup;
             continue;
         }
 
-        snprintfW(buffer, _countof(buffer), fmt, dir, name);
-        if (!SdbpFileExists(buffer))
-            return FALSE;
+        /* Technically, one UNICODE_NULL and one path separator. */
+        Len = UnicodeDir.Length + Name.Length + sizeof(UNICODE_NULL) + sizeof(UNICODE_NULL);
+        if (!NT_SUCCESS(RtlEnsureBufferSize(RTL_SKIP_BUFFER_COPY, &FullPathName.ByteBuffer, Len)))
+            goto Cleanup;
+
+        if (Len > FullPathName.ByteBuffer.Size)
+            goto Cleanup;
+
+        RtlInitEmptyUnicodeString(&FullPathName.String, (PWCHAR)FullPathName.ByteBuffer.Buffer, FullPathName.ByteBuffer.Size);
+
+        RtlCopyUnicodeString(&FullPathName.String, &UnicodeDir);
+        RtlAppendUnicodeToString(&FullPathName.String, L"\\");
+        RtlAppendUnicodeStringToString(&FullPathName.String, &Name);
+
+        if (!SdbpFileExists(FullPathName.String.Buffer))
+            goto Cleanup;
+
+        if (attribs)
+            SdbFreeFileAttributes(attribs);
+
+        if (!SdbGetFileAttributes(FullPathName.String.Buffer, &attribs, &attr_count))
+            goto Cleanup;
+
+        if (!SdbpMatchFileAttributes(pdb, matching_file, attribs, attr_count))
+            goto Cleanup;
     }
 
-    return TRUE;
+    IsMatch = TRUE;
+
+Cleanup:
+    RtlFreeBuffer(&FullPathName.ByteBuffer);
+    if (attribs)
+        SdbFreeFileAttributes(attribs);
+
+    return IsMatch;
 }
 
 static void SdbpAddDatabaseGuid(PDB db, PSDBQUERYRESULT result)
@@ -331,7 +432,7 @@ BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
     BOOL ret = FALSE;
     TAGID database, iter, name;
     PATTRINFO attribs = NULL;
-    /*DWORD attr_count;*/
+    DWORD attr_count;
     RTL_UNICODE_STRING_BUFFER DosApplicationName = { { 0 } };
     WCHAR DosPathBuffer[MAX_PATH];
     ULONG PathType = 0;
@@ -390,10 +491,6 @@ BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
     /* We will use the buffer for exe name and directory. */
     *(file_name++) = UNICODE_NULL;
 
-    /* Get information about executable required to match it with database entry */
-    /*if (!SdbGetFileAttributes(path, &attribs, &attr_count))
-        return FALSE;*/
-
     /* DATABASE is list TAG which contains all executables */
     database = SdbFindFirstTag(db, TAGID_ROOT, TAG_DATABASE);
     if (database == TAGID_NULL)
@@ -414,8 +511,16 @@ BOOL WINAPI SdbGetMatchingExe(HSDB hsdb, LPCWSTR path, LPCWSTR module_name,
         foundName = SdbGetStringTagPtr(db, name);
         if (foundName && !lstrcmpiW(foundName, file_name))
         {
+            /* Get information about executable required to match it with database entry */
+            if (!attribs)
+            {
+                if (!SdbGetFileAttributes(path, &attribs, &attr_count))
+                    goto Cleanup;
+            }
+
+
             /* We have a null terminator before the application name, so DosApplicationName only contains the path. */
-            if (SdbpMatchExe(db, iter, DosApplicationName.String.Buffer))
+            if (SdbpMatchExe(db, iter, DosApplicationName.String.Buffer, attribs, attr_count))
             {
                 ret = TRUE;
                 SdbpAddExeMatch(hsdb, db, iter, result);
index 349501c..2032e11 100644 (file)
@@ -86,7 +86,7 @@ static WCHAR* WINAPI SdbpGetStringAttr(LPWSTR translation, LPCWSTR attr, PVOID f
     return NULL;
 }
 
-static void WINAPI SdbpSetStringAttrFromAnsiString(PATTRINFO attr, TAG tag, PBYTE string, BYTE len)
+static void WINAPI SdbpSetStringAttrFromAnsiString(PATTRINFO attr, TAG tag, PBYTE string, size_t len)
 {
     WCHAR* dest;
     if (!string)