https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4e4328ac8a6c75461a074bd54aa0595eee65b990
commit 4e4328ac8a6c75461a074bd54aa0595eee65b990 Author: Max Korostil <mrmk...@yandex.ru> AuthorDate: Wed Oct 21 23:11:35 2020 +0300 Commit: Mark Jansen <mark.jan...@reactos.org> CommitDate: Sat May 8 14:24:20 2021 +0200 [SDBINST] Add sdbinst uility. It can install sdb to the system --- base/applications/CMakeLists.txt | 1 + base/applications/sdbinst/CMakeLists.txt | 6 + base/applications/sdbinst/sdbinst.c | 482 +++++++++++++++++++++++++++++++ 3 files changed, 489 insertions(+) diff --git a/base/applications/CMakeLists.txt b/base/applications/CMakeLists.txt index 082b2121b35..179d548a07b 100644 --- a/base/applications/CMakeLists.txt +++ b/base/applications/CMakeLists.txt @@ -46,3 +46,4 @@ add_subdirectory(winver) add_subdirectory(wordpad) add_subdirectory(write) add_subdirectory(wusa) +add_subdirectory(sdbinst) diff --git a/base/applications/sdbinst/CMakeLists.txt b/base/applications/sdbinst/CMakeLists.txt new file mode 100644 index 00000000000..682b84117cb --- /dev/null +++ b/base/applications/sdbinst/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${REACTOS_SOURCE_DIR}/dll/appcompat/apphelp) +add_executable(sdbinst sdbinst.c) + +set_module_type(sdbinst win32cui UNICODE) +add_importlibs(sdbinst msvcrt kernel32 ntdll advapi32 apphelp ole32) +add_cd_file(TARGET sdbinst DESTINATION reactos/system32 FOR all) diff --git a/base/applications/sdbinst/sdbinst.c b/base/applications/sdbinst/sdbinst.c new file mode 100644 index 00000000000..530071d1749 --- /dev/null +++ b/base/applications/sdbinst/sdbinst.c @@ -0,0 +1,482 @@ +#define WIN32_NO_STATUS +#include <windef.h> +#include <winbase.h> +#include <tchar.h> +#include <winreg.h> +#include <strsafe.h> +#include <objbase.h> +#include <apphelp.h> + + + +#define APPCOMPAT_REG_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Custom\\" +#define UNINSTALL_REG_PATH L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" + +HRESULT +RegisterSdbEntry( + _In_ PWCHAR sdbEntryName, + _In_ LPCWSTR dbGuid, + _In_ ULONGLONG time) +{ + WCHAR regName[MAX_PATH] = {0}; + HKEY hKey; + + HRESULT hres = StringCchPrintf(regName, sizeof(regName) / sizeof(WCHAR), L"%ls\\%ls", APPCOMPAT_REG_PATH, sdbEntryName); + if (FAILED(hres)) + { + wprintf(L"StringCchPrintfW error: 0x%08X", hres); + goto end; + } + + LSTATUS status = RegCreateKeyEx(HKEY_LOCAL_MACHINE, + regName, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &hKey, + NULL); + + if (status != ERROR_SUCCESS) + { + wprintf(L"RegKeyCreateEx error: 0x%08X", status); + hres = HRESULT_FROM_WIN32(status); + goto end; + } + + status = RegSetValueEx(hKey, + dbGuid, + 0, + REG_QWORD, + (PBYTE)&time, + sizeof(time)); + if (status != ERROR_SUCCESS) + { + wprintf(L"RegSetValueEx error: 0x%08X", status); + hres = HRESULT_FROM_WIN32(status); + goto end; + } + +end: + return hres; +} + +HRESULT +AddUninstallKey( + _In_ LPCWSTR dbName, + _In_ LPCWSTR sdbInstalledPath, + _In_ LPCWSTR guidDbStr) +{ + WCHAR sdbinstPath[MAX_PATH] = {0}; + WCHAR regName[MAX_PATH] = {0}; + WCHAR uninstString[MAX_PATH * 2] = {0}; + HKEY hKey; + HRESULT hres; + + UINT count = GetSystemWindowsDirectory(sdbinstPath, sizeof(sdbinstPath) / sizeof(WCHAR)); + if (sdbinstPath[count - 1] != L'\\') + { + sdbinstPath[count] = L'\\'; + } + + hres = StringCchCat(sdbinstPath, sizeof(sdbinstPath) / sizeof(WCHAR), L"System32\\sdbinst.exe"); + if (FAILED(hres)) + { + wprintf(L"StringCchCat error: 0x%08X", hres); + } + + hres = StringCchPrintf(regName, sizeof(regName) / sizeof(WCHAR), L"%ls\\%ls", UNINSTALL_REG_PATH, guidDbStr); + if (FAILED(hres)) + { + wprintf(L"StringCchPrintfW error: 0x%08X", hres); + goto end; + } + + wprintf(L"%ls\n", sdbinstPath); + wprintf(L"%ls\n", regName); + + LSTATUS status = RegCreateKeyEx(HKEY_LOCAL_MACHINE, + regName, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + &hKey, + NULL); + + if (status != ERROR_SUCCESS) + { + wprintf(L"RegKeyCreateEx error: 0x%08X", status); + hres = HRESULT_FROM_WIN32(status); + goto end; + } + + DWORD length = wcslen(dbName) * sizeof(WCHAR); + status = RegSetValueEx(hKey, + L"DisplayName", + 0, + REG_SZ, + (PBYTE)dbName, + length + sizeof(WCHAR)); + if (status != ERROR_SUCCESS) + { + wprintf(L"RegSetValueEx error: 0x%08X", status); + hres = HRESULT_FROM_WIN32(status); + goto end; + } + + // Uninst string + hres = StringCchPrintf(uninstString, sizeof(uninstString) / sizeof(WCHAR), L"%ls -u \"%ls\"", sdbinstPath, sdbInstalledPath); + if (FAILED(hres)) + { + wprintf(L"StringCchPrintfW error: 0x%08X", hres); + goto end; + } + + //wprintf(L"%ls\n", uninstString); + + length = wcslen(uninstString) * sizeof(WCHAR); + status = RegSetValueEx(hKey, + L"UninstallString", + 0, + REG_SZ, + (PBYTE)uninstString, + length + sizeof(WCHAR)); + if (status != ERROR_SUCCESS) + { + wprintf(L"RegSetValueEx error: 0x%08X", status); + hres = HRESULT_FROM_WIN32(status); + goto end; + } + +end: + + return hres; +} + +// +// Get database guid id +// +BOOL +GetSdbGuid( + _In_ PDB pdb, + _In_ TAGID tagDb, + _Out_ GUID* guid) +{ + TAGID tagDbId; + + tagDbId = SdbFindFirstTag(pdb, tagDb, TAG_DATABASE_ID); + + if (!tagDbId) + { + wprintf(L"Can't find database id tag"); + return FALSE; + } + + if (!SdbReadBinaryTag(pdb, tagDbId, (PBYTE)guid, sizeof(GUID))) + { + wprintf(L"Can't read database id"); + return FALSE; + } + + return TRUE; +} + +HRESULT +ProcessLayers( + _In_ PDB pdb, + _In_ TAGID tagDb, + _In_ LPCWSTR guidDbStr, + _In_ ULONGLONG time) +{ + HRESULT res = ERROR_SUCCESS; + TAGID tagLayerName; + + TAGID tagLayer = SdbFindFirstTag(pdb, tagDb, TAG_LAYER); + + while (tagLayer) + { + tagLayerName = SdbFindFirstTag(pdb, tagLayer, TAG_NAME); + if (!tagLayerName) + { + res = ERROR_NOT_FOUND; + break; + } + + LPWSTR name = SdbGetStringTagPtr(pdb, tagLayerName); + wprintf(L"Layer name %ls", name); + + res = RegisterSdbEntry(name, guidDbStr, time); + if (FAILED(res)) + { + wprintf(L"Can't register layer\n"); + break; + } + + tagLayer = SdbFindNextTag(pdb, tagDb, TAG_LAYER); + } + + return res; +} + +HRESULT +ProcessExe( + _In_ PDB pdb, + _In_ TAGID tagDb, + _In_ LPCWSTR guidDbStr, + _In_ ULONGLONG time +) +{ + HRESULT res = ERROR_SUCCESS; + TAGID tagExeName; + + TAGID tagExe = SdbFindFirstTag(pdb, tagDb, TAG_EXE); + + while (tagExe) + { + tagExeName = SdbFindFirstTag(pdb, tagExe, TAG_NAME); + if (!tagExeName) + { + wprintf(L"Can't find exe tag\n"); + res = ERROR_NOT_FOUND; + break; + } + + LPWSTR name = SdbGetStringTagPtr(pdb, tagExeName); + wprintf(L"Exe name %ls\n", name); + + res = RegisterSdbEntry(name, guidDbStr, time); + if (FAILED(res)) + { + wprintf(L"Can't register exe\n"); + break; + } + + tagExe = SdbFindNextTag(pdb, tagDb, TAG_EXE); + } + + return res; +} + +HRESULT +CopySdbToAppPatch( + _In_ LPCWSTR sourceSdbPath, + _In_ LPCWSTR destSdbPath) +{ + DWORD error = ERROR_SUCCESS; + PWCHAR pTmpSysdir = NULL; + SIZE_T destLen = wcslen(destSdbPath); + PWCHAR sysdirPath = (PWCHAR)HeapAlloc(GetProcessHeap(), 0, destLen * sizeof(WCHAR)); + + if (sysdirPath == NULL) + { + error = ERROR_NOT_ENOUGH_MEMORY; + goto end; + } + + CopyMemory(sysdirPath, destSdbPath, destLen * sizeof(WCHAR)); + pTmpSysdir = sysdirPath + destLen; + + while (*pTmpSysdir != L'\\') + { + *pTmpSysdir = L'\0'; + --pTmpSysdir; + } + + wprintf(L"%ls\n", sysdirPath); + + if (!CreateDirectory(sysdirPath, NULL)) + { + error = GetLastError(); + if (error != ERROR_ALREADY_EXISTS) + { + wprintf(L"Can't create folder %ls\n Error: 0x%08\n", sysdirPath, error); + goto end; + } + error = ERROR_SUCCESS; + } + + if (!CopyFile(sourceSdbPath, destSdbPath, TRUE)) + { + error = GetLastError(); + wprintf(L"Can't copy sdb file"); + } + + HeapFree(GetProcessHeap(), 0, sysdirPath); + +end: + return HRESULT_FROM_WIN32(error); +} + +HRESULT +BuildPathToSdb( + _In_ PWCHAR* buffer, + _In_ SIZE_T bufLen, + _In_ LPCWSTR guidDbStr) +{ + PWCHAR pBuffer = *buffer; + ZeroMemory(pBuffer, bufLen * sizeof(WCHAR)); + + UINT count = GetSystemWindowsDirectory(pBuffer, bufLen); + if (pBuffer[count - 1] != L'\\') + { + pBuffer[count] = L'\\'; + } + + HRESULT res = StringCchCatW(pBuffer, bufLen, L"AppPatch\\Custom\\"); + if (FAILED(res)) + { + goto end; + } + + res = StringCchCatW(pBuffer, bufLen, guidDbStr); + +end: + return res; +} + +BOOL +SdbInstall( + _In_ LPCWSTR sdbPath) +{ + BOOL res = FALSE; + PDB pdb = NULL; + TAGID tagDb; + TAGID tagDbName; + GUID dbGuid = {0}; + FILETIME systemTime = {0}; + ULARGE_INTEGER currentTime = {0}; + PWCHAR sysdirPatchPath = NULL; + WCHAR guidDbStr[MAX_PATH] = {0}; + + GetSystemTimeAsFileTime(&systemTime); + currentTime.LowPart = systemTime.dwLowDateTime; + currentTime.HighPart = systemTime.dwHighDateTime; + + pdb = SdbOpenDatabase(sdbPath, DOS_PATH); + if (pdb == NULL) + { + wprintf(L"Can't open database %ls\n", sdbPath); + goto end; + } + + tagDb = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE); + if (!tagDb) + { + wprintf(L"Can't find database tag\n"); + goto end; + } + + // + if (!GetSdbGuid(pdb, tagDb, &dbGuid)) + { + wprintf(L"GetSdbGuid error\n"); + goto end; + } + + StringFromGUID2(&dbGuid, guidDbStr, MAX_PATH); + HRESULT hres = StringCchCatW(guidDbStr, sizeof(guidDbStr) / sizeof(WCHAR), L".sdb"); + if (FAILED(hres)) + { + wprintf(L"StringCchCatW error 0x%08X\n", hres); + goto end; + } + + wprintf(L"Database guid %wZ\n", &guidDbStr); + + tagDbName = SdbFindFirstTag(pdb, tagDb, TAG_NAME); + if (!tagDbName) + { + wprintf(L"Can't get tag name\n"); + goto end; + } + + LPWSTR dbName = SdbGetStringTagPtr(pdb, tagDbName); + wprintf(L"Database name %ls\n", dbName); + + hres = ProcessExe(pdb, tagDb, guidDbStr, currentTime.QuadPart); + if (FAILED(hres)) + { + wprintf(L"Process exe failed. Status: 0x%08X", res); + goto end; + } + + hres = ProcessLayers(pdb, tagDb, guidDbStr, currentTime.QuadPart); + if (FAILED(hres)) + { + wprintf(L"Process layers failed. Status: 0x%08X", res); + goto end; + } + + SIZE_T bufLen = MAX_PATH * 2; + sysdirPatchPath = (PWCHAR)HeapAlloc(GetProcessHeap(), 0, bufLen * sizeof(WCHAR)); + + hres = BuildPathToSdb(&sysdirPatchPath, bufLen, guidDbStr); + if (FAILED(hres)) + { + wprintf(L"Build path error\n"); + goto end; + } + + wprintf(L"file path %ls\n", sysdirPatchPath); + + res = CopySdbToAppPatch(sdbPath, sysdirPatchPath); + if (FAILED(res)) + { + wprintf(L"Copy sdb error. Status: 0x%08X\n", res); + goto end; + } + + AddUninstallKey(dbName, sysdirPatchPath, guidDbStr); + + if (!SdbRegisterDatabaseEx(sysdirPatchPath, SDB_DATABASE_SHIM, ¤tTime.QuadPart)) + { + wprintf(L"SdbRegisterDatabaseEx UNSUCCESS"); + goto end; + } + + res = TRUE; + +end: + if (pdb) + { + SdbCloseDatabase(pdb); + } + + return res; +} + +void +ShowHelp() +{ + wprintf(L"Using: sdbinst [-?][-q][-u][-g][-n] foo.sdb | {guid} | \"name\" \n" + L"-? - show help\n" + L"-q - silence mode\n" + L"-u - uninstall\n" + L"-g - {guid} file guid (only uninstall)\n" + L"-n - \"name\" - file name (only uninstall)\n"); +} + +int _tmain(int argc, LPCWSTR argv[]) +{ + LPCWSTR sdbPath = NULL; + + if (argc < 2) + { + ShowHelp(); + } + + if (argv[1][0] == L'-' && argv[1][1] == L'?') + { + ShowHelp(); + return ERROR_SUCCESS; + } + + sdbPath = argv[1]; + + SdbInstall(sdbPath); + + return ERROR_SUCCESS; +} \ No newline at end of file