InstallationFolder.cpp
1 #include "InstallationFolder.h" 2 3 #include <fstream> 4 #include <set> 5 #include <Windows.h> 6 #include <common/utils/winapi_error.h> 7 8 using namespace std; 9 using std::filesystem::directory_iterator; 10 using std::filesystem::path; 11 12 wstring GetVersion(path filePath) 13 { 14 DWORD verHandle = 0; 15 UINT size = 0; 16 LPVOID lpBuffer = nullptr; 17 DWORD verSize = GetFileVersionInfoSize(filePath.c_str(), &verHandle); 18 wstring version = L"None"; 19 20 if (verSize != 0) 21 { 22 LPSTR verData = new char[verSize]; 23 24 if (GetFileVersionInfo(filePath.c_str(), verHandle, verSize, verData)) 25 { 26 if (VerQueryValue(verData, L"\\", &lpBuffer, &size)) 27 { 28 if (size) 29 { 30 VS_FIXEDFILEINFO* verInfo = static_cast<VS_FIXEDFILEINFO*>(lpBuffer); 31 if (verInfo->dwSignature == 0xfeef04bd) 32 { 33 version = 34 std::to_wstring((verInfo->dwFileVersionMS >> 16) & 0xffff) + L"." + 35 std::to_wstring((verInfo->dwFileVersionMS >> 0) & 0xffff) + L"." + 36 std::to_wstring((verInfo->dwFileVersionLS >> 16) & 0xffff) + L"." + 37 std::to_wstring((verInfo->dwFileVersionLS >> 0) & 0xffff); 38 } 39 } 40 } 41 } 42 43 delete[] verData; 44 } 45 46 return version; 47 } 48 49 optional<path> GetRootPath() 50 { 51 WCHAR modulePath[MAX_PATH]; 52 if (!GetModuleFileName(NULL, modulePath, MAX_PATH)) 53 { 54 return nullopt; 55 } 56 57 path rootPath = path(modulePath); 58 rootPath = rootPath.remove_filename(); 59 rootPath = rootPath.append(".."); 60 return std::filesystem::canonical(rootPath); 61 } 62 63 wstring GetChecksum(path filePath) 64 { 65 BOOL bResult = FALSE; 66 HCRYPTPROV hProv = 0; 67 HCRYPTHASH hHash = 0; 68 HANDLE hFile = NULL; 69 constexpr int bufferSize = 1024; 70 BYTE rgbFile[bufferSize]; 71 DWORD cbRead = 0; 72 constexpr int md5Length = 16; 73 BYTE rgbHash[md5Length]; 74 DWORD cbHash = 0; 75 CHAR rgbDigits[] = "0123456789abcdef"; 76 LPCWSTR filename = filePath.c_str(); 77 hFile = CreateFile(filename, 78 GENERIC_READ, 79 FILE_SHARE_READ, 80 NULL, 81 OPEN_EXISTING, 82 FILE_FLAG_SEQUENTIAL_SCAN, 83 NULL); 84 85 if (INVALID_HANDLE_VALUE == hFile) 86 { 87 return L"CreateFile() failed. " + get_last_error_or_default(GetLastError()); 88 } 89 90 // Get handle to the crypto provider 91 if (!CryptAcquireContext(&hProv, 92 NULL, 93 NULL, 94 PROV_RSA_FULL, 95 CRYPT_VERIFYCONTEXT)) 96 { 97 CloseHandle(hFile); 98 return L"CryptAcquireContext() failed. " + get_last_error_or_default(GetLastError()); 99 } 100 101 if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) 102 { 103 CloseHandle(hFile); 104 CryptReleaseContext(hProv, 0); 105 return L"CryptCreateHash() failed. " + get_last_error_or_default(GetLastError()); 106 } 107 108 bResult = ReadFile(hFile, rgbFile, bufferSize, &cbRead, NULL); 109 while (bResult) 110 { 111 if (0 == cbRead) 112 { 113 break; 114 } 115 116 if (!CryptHashData(hHash, rgbFile, cbRead, 0)) 117 { 118 CryptReleaseContext(hProv, 0); 119 CryptDestroyHash(hHash); 120 CloseHandle(hFile); 121 return L"CryptHashData() failed. " + get_last_error_or_default(GetLastError());; 122 } 123 124 bResult = ReadFile(hFile, rgbFile, bufferSize, &cbRead, NULL); 125 } 126 127 if (!bResult) 128 { 129 CryptReleaseContext(hProv, 0); 130 CryptDestroyHash(hHash); 131 CloseHandle(hFile); 132 return L"ReadFile() failed. " + get_last_error_or_default(GetLastError());; 133 } 134 135 cbHash = md5Length; 136 std::wstring result = L""; 137 if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) 138 { 139 for (DWORD i = 0; i < cbHash; i++) 140 { 141 result += rgbDigits[rgbHash[i] >> 4]; 142 result += rgbDigits[rgbHash[i] & 0xf]; 143 } 144 } 145 else 146 { 147 result = L"CryptGetHashParam() failed. " + get_last_error_or_default(GetLastError());; 148 } 149 150 CryptDestroyHash(hHash); 151 CryptReleaseContext(hProv, 0); 152 CloseHandle(hFile); 153 154 return result; 155 } 156 157 class Reporter 158 { 159 private: 160 std::wofstream os; 161 std::wofstream GetOutputStream(const path& tmpDir) 162 { 163 auto path = tmpDir; 164 path += "installationFolderStructure.txt"; 165 std::wofstream out_s = std::wofstream(path); 166 return out_s; 167 } 168 public: 169 Reporter(const path& tmpDir) 170 { 171 os = GetOutputStream(tmpDir); 172 } 173 174 void Report(path dirPath, int indentation = 0) 175 { 176 set<pair<path, bool>> paths; 177 try 178 { 179 directory_iterator end_it; 180 for (directory_iterator it(dirPath); it != end_it; ++it) 181 { 182 paths.insert({ it->path(), it->is_directory() }); 183 } 184 } 185 catch (filesystem::filesystem_error err) 186 { 187 os << err.what() << endl; 188 } 189 190 for (auto filePair : paths) 191 { 192 auto filePath = filePair.first; 193 auto isDirectory = filePair.second; 194 195 auto fileName = filePath.wstring().substr(dirPath.wstring().size() + 1); 196 os << wstring(indentation, ' ') << fileName << " "; 197 if (!isDirectory) 198 { 199 os << GetVersion(filePath) << " " << GetChecksum(filePath); 200 } 201 202 os << endl; 203 if (isDirectory) 204 { 205 Report(filePath, indentation + 2); 206 } 207 } 208 } 209 }; 210 211 void InstallationFolder::ReportStructure(const path& tmpDir) 212 { 213 auto rootPath = GetRootPath(); 214 if (rootPath) 215 { 216 Reporter(tmpDir).Report(rootPath.value()); 217 } 218 }