src/platform_windows.cpp
author Krista Bennett <krista@pep-project.org>
Fri, 01 Jun 2018 10:30:19 +0200
branchENGINE-233
changeset 2727 b8b0443804da
parent 1796 51a507ac30e0
child 1860 1975a3b9bc37
child 2195 cf2509784622
permissions -rw-r--r--
close branch
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 // Windows platform specification
     5 
     6 #define WIN32_LEAN_AND_MEAN
     7 #ifndef UNICODE
     8 #define UNICODE
     9 #endif
    10 #define _WIN32_WINNT 0x0600
    11 
    12 #include <windows.h>
    13 #define _CRT_RAND_S
    14 #include <stdlib.h>
    15 #include <assert.h>
    16 #include <string.h>
    17 #include <string>
    18 #include <stdexcept>
    19 #include "platform_windows.h"
    20 #include <fcntl.h>
    21 #include <sys\stat.h>
    22 
    23 #ifndef WC_ERR_INVALID_CHARS
    24 #define WC_ERR_INVALID_CHARS      0x00000080  // error for invalid chars
    25 #endif
    26 
    27 using namespace std;
    28 
    29 static string utf8_string(wstring wstr) {
    30     string result;
    31 
    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 
    47     return result;
    48 }
    49 
    50 static wstring utf16_string(string str) {
    51     wstring result;
    52 
    53     if (str.length()) {
    54         int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
    55                 str.c_str(), -1, NULL, 0);
    56         assert(size);
    57         if (size) {
    58             wchar_t * buf = new wchar_t[size];
    59             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
    60                     buf, size);
    61             result = buf;
    62             delete[] buf;
    63         } else
    64             throw out_of_range("input string is not valid"
    65                     " while converting UTF-8 to UTF-16.");
    66     }
    67 
    68     return result;
    69 }
    70 
    71 static bool readRegistryString(
    72         HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
    73         DWORD dwSize, LPCTSTR lpDefault
    74     )
    75 {
    76     assert(lpResult);
    77 
    78 	HKEY theKey;
    79 	DWORD type;
    80 	DWORD bytesCopied = dwSize;
    81 	HRESULT result;
    82 
    83 	result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
    84 	if (result != ERROR_SUCCESS) {
    85 		if (lpDefault) {
    86 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    87 			return true;
    88 		}
    89 		else
    90 			return false;
    91 	}
    92 
    93 	result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
    94             (LPBYTE) lpResult, &bytesCopied);
    95     if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
    96 		if (lpDefault) {
    97 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    98 			RegCloseKey(theKey);
    99 			return true;
   100 		}
   101 		else {
   102 			RegCloseKey(theKey);
   103 			return false;
   104 		}
   105 	}
   106 
   107 	RegCloseKey(theKey);
   108 	return true;
   109 }
   110 
   111 static const DWORD PATH_BUF_SIZE = 32768;
   112 
   113 static inline string managementPath(const char *file_path, const char *file_name)
   114 {
   115     string path;
   116 	static TCHAR tPath[PATH_BUF_SIZE];
   117 
   118     DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
   119             tPath, PATH_BUF_SIZE);
   120 	assert(length);
   121     if (length == 0)
   122         throw bad_alloc(); // BUG: there are other errors possible beside out of memory
   123 
   124 	CreateDirectory(tPath, NULL);
   125 	DWORD error = GetLastError();
   126 
   127 	path = utf8_string(tPath);
   128 	path += "\\";
   129 	path += file_name;
   130 
   131 	return path;
   132 }
   133 
   134 extern "C" {
   135 
   136 void *dlopen(const char *filename, int flag) {
   137 	static TCHAR path[PATH_BUF_SIZE];
   138 
   139     assert(filename);
   140 	assert(flag == RTLD_LAZY); // only lazy binding is implemented
   141 
   142 	// Look up GnuPG installation in current user scope
   143 	bool result = readRegistryString(HKEY_CURRENT_USER,
   144 		TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   145 		PATH_BUF_SIZE, NULL);
   146 	// If not found in current user, look up in local machine
   147 	if (!result)
   148 		result = readRegistryString(HKEY_LOCAL_MACHINE,
   149 			TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   150 			PATH_BUF_SIZE, NULL);
   151 	assert(result);
   152 	if (!result)
   153 		return NULL;
   154 
   155     SetDllDirectory(TEXT(""));
   156     BOOL _result = SetDllDirectory(path);
   157     assert(_result != 0);
   158     if (_result == 0)
   159         return NULL;
   160 
   161 	HMODULE module = LoadLibrary(utf16_string(filename).c_str());
   162     SetDllDirectory(NULL);
   163 	if (module == NULL)
   164 		return NULL;
   165 	else
   166 		return (void *) module;
   167 }
   168 
   169 int dlclose(void *handle) {
   170 	if (FreeLibrary((HMODULE) handle))
   171 		return 0;
   172 	else
   173 		return 1;
   174 }
   175 
   176 void *dlsym(void *handle, const char *symbol) {
   177 	return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
   178 }
   179 
   180 const char *windoze_local_db(void) {
   181 	static string path;
   182 	if (path.length() == 0)
   183         path = managementPath("%LOCALAPPDATA%\\pEp", "management.db");
   184     return path.c_str();
   185 }
   186 
   187 const char *windoze_system_db(void) {
   188 	static string path;
   189 	if (path.length() == 0)
   190 		path = managementPath("%ALLUSERSPROFILE%\\pEp", "system.db");
   191     return path.c_str();
   192 }
   193 
   194 const char *gpg_conf(void)
   195 {
   196     static string path;
   197     if (path.length() == 0)
   198         path = managementPath("%APPDATA%\\gnupg", "gpg.conf");
   199     return path.c_str();
   200 }
   201 
   202 const char *gpg_agent_conf(void)
   203 {
   204     static string agent_path;
   205     if (agent_path.length() == 0)
   206         agent_path = managementPath("%APPDATA%\\gnupg", "gpg-agent.conf");
   207     return agent_path.c_str();
   208 }
   209 
   210 
   211 long random(void)
   212 {
   213     unsigned int r;
   214     errno_t e;
   215 
   216     assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
   217 
   218     do {
   219         e = rand_s(&r);
   220     } while (e);
   221 
   222     return (long) (r & ((1U<<31)-1));
   223 }
   224 
   225 char *strndup(const char *s1, size_t n)
   226 {
   227     char *str = (char *) calloc(n + 1, 1);
   228     if (str == NULL)
   229         return NULL;
   230 
   231     strncpy(str, s1, n);
   232     return str;
   233 }
   234 
   235 char *stpcpy(char *dst, const char *src)
   236 {
   237     for (;; ++dst, ++src) {
   238         *dst = *src;
   239         if (*dst == 0)
   240             break;
   241     }
   242     return dst;
   243 }
   244 
   245 size_t strlcpy(char* dst, const	char* src, size_t size) {
   246     size_t retval = strlen(src);
   247     size_t size_to_copy = (retval < size ? retval : size - 1);
   248     
   249     // strlcpy doc says src and dst not allowed to overlap, as
   250     // it's undefined. So this is acceptable:
   251     memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   252     dst[size_to_copy] = '\0';
   253     return retval;
   254 }
   255 size_t strlcat(char* dst, const	char* src, size_t size) {
   256     size_t start_len = strnlen(dst, size);
   257     if (start_len == size)
   258         return size; // no copy, no null termination in size bytes, according to spec
   259     
   260     size_t add_len = strlen(src);
   261     size_t retval = start_len + add_len;
   262     size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
   263     
   264     // strlcat doc says src and dst not allowed to overlap, as
   265     // it's undefined. So this is acceptable:
   266     memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   267     dst[start_len + size_to_copy] = '\0';
   268     return retval;
   269 }
   270 
   271 int mkstemp(char *templ)
   272 {
   273     char *pathname = _mktemp(templ);
   274     if (errno)
   275         return -1;
   276     return _open(pathname, _O_RDWR | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
   277 }
   278 
   279 void uuid_generate_random(pEpUUID out)
   280 {
   281     RPC_STATUS rpc_status = UuidCreate(out);
   282     assert(rpc_status == RPC_S_OK);
   283 }
   284 
   285 int uuid_parse(char *in, pEpUUID uu)
   286 {
   287     unsigned char *_in = (unsigned char *) in;
   288     RPC_STATUS rpc_status = UuidFromStringA(_in, uu);
   289     assert(rpc_status == RPC_S_OK);
   290     if (rpc_status == RPC_S_INVALID_STRING_UUID)
   291         return -1;
   292     return 0;
   293 }
   294 
   295 void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
   296 {
   297     unsigned char *_out = (unsigned char*)out;
   298     RPC_CSTR str;
   299     RPC_STATUS rpc_status = UuidToStringA(uu, &str);
   300     assert(rpc_status == RPC_S_OK);
   301     if (rpc_status == RPC_S_OK) {
   302         memcpy(out, str, 36);
   303         out[36] = 0;
   304         RpcStringFreeA(&str);
   305     }
   306     else { // if (rpc_status == RPC_S_OUT_OF_MEMORY)
   307         memset(out, 0, 37);
   308     }
   309 }
   310 
   311 time_t timegm(struct tm* tm) {
   312     return _mkgmtime(tm);
   313 }
   314 
   315 } // "C"