You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

461 lines
12 KiB

8 years ago
8 years ago
7 years ago
8 years ago
3 years ago
8 years ago
3 years ago
3 years ago
8 years ago
8 years ago
8 years ago
8 years ago
3 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
3 years ago
3 years ago
3 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
7 years ago
3 years ago
7 years ago
2 years ago
2 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. // Windows platform specification
  4. #define WIN32_LEAN_AND_MEAN
  5. #ifndef UNICODE
  6. #define UNICODE
  7. #endif
  8. #define _WIN32_WINNT 0x0600
  9. #include <windows.h>
  10. #define _CRT_RAND_S
  11. #include <stdlib.h>
  12. #include <assert.h>
  13. #include <string.h>
  14. #include <string>
  15. #include <stdexcept>
  16. #include "platform_windows.h"
  17. #include "dynamic_api.h"
  18. #include <fcntl.h>
  19. #include <tchar.h>
  20. #include <sys\stat.h>
  21. #define LOCAL_DB_FILENAME "management.db"
  22. #define SYSTEM_DB_FILENAME "system.db"
  23. #define KEYS_DB "keys.db"
  24. #define USER_FOLDER_PATH _per_user_directory()
  25. #define SYSTEM_FOLDER_PATH _per_machine_directory()
  26. #ifndef WC_ERR_INVALID_CHARS
  27. #define WC_ERR_INVALID_CHARS 0x00000080 // error for invalid chars
  28. #endif
  29. using namespace std;
  30. static string utf8_string(wstring wstr) {
  31. string result;
  32. if (wstr.length()) {
  33. int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
  34. wstr.c_str(), -1, NULL, 0, NULL, NULL);
  35. assert(size);
  36. if (size) {
  37. char *buf = new char[size];
  38. WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr.c_str(),
  39. -1, buf, size, NULL, NULL);
  40. result = buf;
  41. delete[] buf;
  42. } else
  43. throw out_of_range("input wstring is not valid"
  44. " while converting UTF-16 to UTF-8.");
  45. }
  46. return result;
  47. }
  48. static wstring utf16_string(string str) {
  49. wstring result;
  50. if (str.length()) {
  51. int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
  52. str.c_str(), -1, NULL, 0);
  53. assert(size);
  54. if (size) {
  55. wchar_t * buf = new wchar_t[size];
  56. MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
  57. buf, size);
  58. result = buf;
  59. delete[] buf;
  60. } else
  61. throw out_of_range("input string is not valid"
  62. " while converting UTF-8 to UTF-16.");
  63. }
  64. return result;
  65. }
  66. static bool readRegistryString(
  67. HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
  68. DWORD dwSize, LPCTSTR lpDefault
  69. )
  70. {
  71. assert(lpResult);
  72. HKEY theKey;
  73. DWORD type;
  74. DWORD bytesCopied = dwSize;
  75. HRESULT result;
  76. result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
  77. if (result != ERROR_SUCCESS) {
  78. if (lpDefault) {
  79. wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
  80. return true;
  81. }
  82. else
  83. return false;
  84. }
  85. result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
  86. (LPBYTE) lpResult, &bytesCopied);
  87. if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
  88. if (lpDefault) {
  89. wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
  90. RegCloseKey(theKey);
  91. return true;
  92. }
  93. else {
  94. RegCloseKey(theKey);
  95. return false;
  96. }
  97. }
  98. RegCloseKey(theKey);
  99. return true;
  100. }
  101. static const DWORD PATH_BUF_SIZE = 32768;
  102. static inline string managementPath(const char *file_path, const char *file_name)
  103. {
  104. string path;
  105. TCHAR tPath[PATH_BUF_SIZE];
  106. DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
  107. tPath, PATH_BUF_SIZE);
  108. assert(length);
  109. if (length == 0)
  110. throw bad_alloc(); // BUG: there are other errors possible beside out of memory
  111. CreateDirectory(tPath, NULL);
  112. DWORD error = GetLastError();
  113. path = utf8_string(tPath);
  114. path += "\\";
  115. path += file_name;
  116. return path;
  117. }
  118. const char *_per_machine_directory(void)
  119. {
  120. static string path;
  121. if (path.length())
  122. return path.c_str();
  123. TCHAR tPath[PATH_BUF_SIZE];
  124. TCHAR tPath2[PATH_BUF_SIZE];
  125. // Get SystemFolder Registry value and use if available
  126. bool result = readRegistryString(HKEY_CURRENT_USER, TEXT("SOFTWARE\\pEp"),
  127. TEXT("SystemFolder"), tPath2, PATH_BUF_SIZE, NULL);
  128. DWORD length = 0;
  129. // If no Registry value was found, use default
  130. if (!result) {
  131. length = ExpandEnvironmentStringsW(utf16_string(string(PER_MACHINE_DIRECTORY)).c_str(),
  132. tPath, PATH_BUF_SIZE);
  133. }
  134. else {
  135. length = ExpandEnvironmentStringsW(tPath2, tPath, PATH_BUF_SIZE);
  136. }
  137. assert(length);
  138. if (length == 0)
  139. throw bad_alloc(); // BUG: there are other errors possible beside out of memory
  140. path = utf8_string(wstring(tPath, length));
  141. return path.c_str();
  142. }
  143. const char *_per_user_directory(void)
  144. {
  145. static string path;
  146. if (path.length())
  147. return path.c_str();
  148. TCHAR tPath[PATH_BUF_SIZE];
  149. TCHAR tPath2[PATH_BUF_SIZE];
  150. // Get UserFolder Registry value and use if available
  151. bool result = readRegistryString(HKEY_CURRENT_USER, TEXT("SOFTWARE\\pEp"),
  152. TEXT("UserFolder"), tPath2, PATH_BUF_SIZE, NULL);
  153. DWORD length = 0;
  154. // If no Registry value was found, use default
  155. if (!result) {
  156. length = ExpandEnvironmentStringsW(utf16_string(string(PER_USER_DIRECTORY)).c_str(),
  157. tPath, PATH_BUF_SIZE);
  158. }
  159. else {
  160. length = ExpandEnvironmentStringsW(tPath2, tPath, PATH_BUF_SIZE);
  161. }
  162. assert(length);
  163. if (length == 0)
  164. throw bad_alloc(); // BUG: there are other errors possible beside out of memory
  165. path = utf8_string(wstring(tPath));
  166. return path.c_str();
  167. }
  168. extern "C" {
  169. DYNAMIC_API const char *per_user_directory(void)
  170. {
  171. return _per_user_directory();
  172. }
  173. DYNAMIC_API const char *per_machine_directory(void)
  174. {
  175. return _per_machine_directory();
  176. }
  177. void *dlopen(const char *filename, int flag) {
  178. static TCHAR path[PATH_BUF_SIZE];
  179. assert(filename);
  180. assert(flag == RTLD_LAZY); // only lazy binding is implemented
  181. // Look up GnuPG installation in current user scope
  182. bool result = readRegistryString(HKEY_CURRENT_USER,
  183. TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
  184. PATH_BUF_SIZE, NULL);
  185. // If not found in current user, look up in local machine
  186. if (!result)
  187. result = readRegistryString(HKEY_LOCAL_MACHINE,
  188. TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
  189. PATH_BUF_SIZE, NULL);
  190. assert(result);
  191. if (!result)
  192. return NULL;
  193. SetDllDirectory(TEXT(""));
  194. BOOL _result = SetDllDirectory(path);
  195. assert(_result != 0);
  196. if (_result == 0)
  197. return NULL;
  198. HMODULE module = LoadLibrary(utf16_string(filename).c_str());
  199. if (module == NULL) {
  200. SetDllDirectory(NULL);
  201. _tcscat_s(path, TEXT("\\bin"));
  202. SetDllDirectory(TEXT(""));
  203. _result = SetDllDirectory(path);
  204. assert(_result != 0);
  205. if (_result == 0)
  206. return NULL;
  207. module = LoadLibrary(utf16_string(filename).c_str());
  208. }
  209. SetDllDirectory(NULL);
  210. if (module == NULL)
  211. return NULL;
  212. else
  213. return (void *) module;
  214. }
  215. int dlclose(void *handle) {
  216. if (FreeLibrary((HMODULE) handle))
  217. return 0;
  218. else
  219. return 1;
  220. }
  221. void *dlsym(void *handle, const char *symbol) {
  222. return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
  223. }
  224. const char *windoze_keys_db(void) {
  225. static string path;
  226. if (path.length() == 0) {
  227. path = managementPath(USER_FOLDER_PATH, KEYS_DB);
  228. }
  229. return path.c_str();
  230. }
  231. const char *windoze_local_db(void) {
  232. static string path;
  233. if (path.length() == 0)
  234. path = managementPath(USER_FOLDER_PATH, LOCAL_DB_FILENAME);
  235. return path.c_str();
  236. }
  237. const char *windoze_system_db(void) {
  238. static string path;
  239. if (path.length() == 0)
  240. path = managementPath(PER_MACHINE_DIRECTORY, SYSTEM_DB_FILENAME);
  241. return path.c_str();
  242. }
  243. long random(void)
  244. {
  245. unsigned int r;
  246. errno_t e;
  247. assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
  248. do {
  249. e = rand_s(&r);
  250. } while (e);
  251. return (long) (r & ((1U<<31)-1));
  252. }
  253. char *strndup(const char *s1, size_t n)
  254. {
  255. char *str = (char *) calloc(n + 1, 1);
  256. if (str == NULL)
  257. return NULL;
  258. strncpy(str, s1, n);
  259. return str;
  260. }
  261. char *stpcpy(char *dst, const char *src)
  262. {
  263. for (;; ++dst, ++src) {
  264. *dst = *src;
  265. if (*dst == 0)
  266. break;
  267. }
  268. return dst;
  269. }
  270. size_t strlcpy(char* dst, const char* src, size_t size) {
  271. size_t retval = strlen(src);
  272. size_t size_to_copy = (retval < size ? retval : size - 1);
  273. // strlcpy doc says src and dst not allowed to overlap, as
  274. // it's undefined. So this is acceptable:
  275. memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
  276. dst[size_to_copy] = '\0';
  277. return retval;
  278. }
  279. size_t strlcat(char* dst, const char* src, size_t size) {
  280. size_t start_len = strnlen(dst, size);
  281. if (start_len == size)
  282. return size; // no copy, no null termination in size bytes, according to spec
  283. size_t add_len = strlen(src);
  284. size_t retval = start_len + add_len;
  285. size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
  286. // strlcat doc says src and dst not allowed to overlap, as
  287. // it's undefined. So this is acceptable:
  288. memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
  289. dst[start_len + size_to_copy] = '\0';
  290. return retval;
  291. }
  292. char *strnstr(const char *big, const char *little, size_t len) {
  293. if (big == NULL || little == NULL)
  294. return NULL;
  295. if (*little == '\0')
  296. return (char*)big;
  297. const char* curr_big = big;
  298. size_t little_len = strlen(little);
  299. size_t remaining = len;
  300. const char* retval = NULL;
  301. for (remaining = len; remaining >= little_len && *curr_big != '\0'; remaining--, curr_big++) {
  302. // find first-char match
  303. if (*curr_big != *little) {
  304. continue;
  305. }
  306. retval = curr_big;
  307. const char* inner_big = retval + 1;
  308. const char* curr_little = little + 1;
  309. size_t j;
  310. for (j = 1; j < little_len; j++, inner_big++, curr_little++) {
  311. if (*inner_big != *curr_little) {
  312. retval = NULL;
  313. break;
  314. }
  315. }
  316. if (retval)
  317. break;
  318. }
  319. return (char*)retval;
  320. }
  321. int mkstemp(char *templ)
  322. {
  323. char *pathname = _mktemp(templ);
  324. if (!pathname)
  325. return -1;
  326. return _open(pathname, _O_RDWR | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
  327. }
  328. DYNAMIC_API time_t timegm(timestamp *timeptr)
  329. {
  330. assert(timeptr);
  331. if (!timeptr)
  332. return -1;
  333. timeptr->tm_gmtoff = 0;
  334. time_t result = _mkgmtime((struct tm *) timeptr);
  335. if (result == -1)
  336. return -1;
  337. return result;
  338. }
  339. void uuid_generate_random(pEpUUID out)
  340. {
  341. RPC_STATUS rpc_status = UuidCreate(out);
  342. assert(rpc_status == RPC_S_OK);
  343. }
  344. int uuid_parse(char *in, pEpUUID uu)
  345. {
  346. unsigned char *_in = (unsigned char *) in;
  347. RPC_STATUS rpc_status = UuidFromStringA(_in, uu);
  348. assert(rpc_status == RPC_S_OK);
  349. if (rpc_status == RPC_S_INVALID_STRING_UUID)
  350. return -1;
  351. return 0;
  352. }
  353. void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
  354. {
  355. unsigned char *_out = (unsigned char*)out;
  356. RPC_CSTR str;
  357. RPC_STATUS rpc_status = UuidToStringA(uu, &str);
  358. assert(rpc_status == RPC_S_OK);
  359. if (rpc_status == RPC_S_OK) {
  360. memcpy(out, str, 36);
  361. out[36] = 0;
  362. RpcStringFreeA(&str);
  363. }
  364. else { // if (rpc_status == RPC_S_OUT_OF_MEMORY)
  365. memset(out, 0, 37);
  366. }
  367. }
  368. void log_output_debug(const char *title,
  369. const char *entity,
  370. const char *description,
  371. const char *comment)
  372. {
  373. const size_t size = 256;
  374. char str[size];
  375. snprintf(str, size, "*** %s %s %s %s\n", title, entity, description, comment);
  376. OutputDebugStringA(str);
  377. }
  378. } // "C"