Index: reactos/dll/appcompat/apphelp/apphelp.h =================================================================== --- reactos/dll/appcompat/apphelp/apphelp.h (revision 75201) +++ reactos/dll/appcompat/apphelp/apphelp.h (working copy) @@ -90,6 +90,7 @@ 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 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: reactos/dll/appcompat/apphelp/hsdb.c =================================================================== --- reactos/dll/appcompat/apphelp/hsdb.c (revision 75201) +++ reactos/dll/appcompat/apphelp/hsdb.c (working copy) @@ -49,31 +49,132 @@ 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; - /* 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)) + RtlInitUnicodeString(&UnicodeDir, dir); + RtlInitBuffer(&FullPathName.ByteBuffer, (PUCHAR)FullPathBuffer, sizeof(FullPathBuffer)); + + 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 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 @@ /* 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 @@ 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: reactos/dll/appcompat/apphelp/sdbfileattr.c =================================================================== --- reactos/dll/appcompat/apphelp/sdbfileattr.c (revision 75201) +++ reactos/dll/appcompat/apphelp/sdbfileattr.c (working copy) @@ -86,7 +86,7 @@ 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)