diff options
author | Andre Heinecke <[email protected]> | 2019-04-09 11:42:58 +0000 |
---|---|---|
committer | Andre Heinecke <[email protected]> | 2019-04-09 11:42:58 +0000 |
commit | a82e3a0ae57a48ba173e282a050680751006c074 (patch) | |
tree | 5afef85afbfa0052ff5aa84b51a2d25aa0c72762 /src/w32-util.c | |
parent | core,w32: Show w32-spawn warning only once (diff) | |
download | gpgme-a82e3a0ae57a48ba173e282a050680751006c074.tar.gz gpgme-a82e3a0ae57a48ba173e282a050680751006c074.zip |
core,w32: Improve handling of Unicode paths
* src/dirinfo.c (get_gpgconf_item): Use _gpgme_access.
* src/posix-util.c (_gpgme_access): Add forward to normal access.
* src/sys-util.h (_gpgme_access): New for posix and w32.
* src/w32-io.c (_gpgme_io_spawn): Use _gpgme_crate_process_utf8.
* src/w32-util.c (utf8_to_wchar, utf8_to_wchar0): The usual w32 conv.
(find_program_in_dir): Use _gpgme_access.
(find_program_at_standard_place): Use wchar API and convert to UTF-8.
(_gpgme_access): Convert UTF-8 to wchar and use wchar API.
(_gpgme_create_process_utf8): Convert UTF-8 to wchar and use wchar API.
--
While we should not say that we have full support for unicode path
installations of GnuPG, this ensures that GPGME works if GPGME
itself is installed in a unicode path. e.g.: Libreoffice supports
this.
GnuPG-Bug-Id: T4453
Based on a patch provided by Egor Pugin. Thanks.
Diffstat (limited to 'src/w32-util.c')
-rw-r--r-- | src/w32-util.c | 105 |
1 files changed, 97 insertions, 8 deletions
diff --git a/src/w32-util.c b/src/w32-util.c index 9802d9cc..eced1396 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -168,6 +168,48 @@ wchar_to_utf8 (const wchar_t *string) } +/* Return a malloced wide char string from an UTF-8 encoded input + string STRING. Caller must free this value. On failure returns + NULL; caller may use GetLastError to get the actual error number. + Calling this function with STRING set to NULL is not defined. */ +static wchar_t * +utf8_to_wchar (const char *string) +{ + int n; + wchar_t *result; + + + n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0); + if (n < 0) + return NULL; + + result = (wchar_t *) malloc ((n+1) * sizeof *result); + if (!result) + return NULL; + + n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n); + if (n < 0) + { + free (result); + return NULL; + } + return result; +} + + +/* Same as utf8_to_wchar but calling it with NULL returns + NULL. So a return value of NULL only indicates failure + if STRING is not set to NULL. */ +static wchar_t * +utf8_to_wchar0 (const char *string) +{ + if (!string) + return NULL; + + return utf8_to_wchar (string); +} + + /* Replace all forward slashes by backslashes. */ static void replace_slashes (char *string) @@ -395,7 +437,7 @@ find_program_in_dir (const char *dir, const char *name) if (!result) return NULL; - if (access (result, F_OK)) + if (_gpgme_access (result, F_OK)) { free (result); return NULL; @@ -408,7 +450,7 @@ find_program_in_dir (const char *dir, const char *name) static char * find_program_at_standard_place (const char *name) { - char path[MAX_PATH]; + wchar_t path[MAX_PATH]; char *result = NULL; /* See https://wiki.tcl-lang.org/page/Getting+Windows+%22special+folders%22+with+Ffidl for details on compatibility. @@ -416,20 +458,24 @@ find_program_at_standard_place (const char *name) We First try the generic place and then fallback to the x86 (i.e. 32 bit) place. This will prefer a 64 bit of the program over a 32 bit version on 64 bit Windows if installed. */ - if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0)) + if (SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILES, 0)) { - result = _gpgme_strconcat (path, "\\", name, NULL); - if (result && access (result, F_OK)) + char *utf8_path = wchar_to_utf8 (path); + result = _gpgme_strconcat (utf8_path, "\\", name, NULL); + free (utf8_path); + if (result && _gpgme_access (result, F_OK)) { free (result); result = NULL; } } if (!result - && SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0)) + && SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILESX86, 0)) { - result = _gpgme_strconcat (path, "\\", name, NULL); - if (result && access (result, F_OK)) + char *utf8_path = wchar_to_utf8 (path); + result = _gpgme_strconcat (utf8_path, "\\", name, NULL); + free (utf8_path); + if (result && _gpgme_access (result, F_OK)) { free (result); result = NULL; @@ -781,6 +827,49 @@ _gpgme_mkstemp (int *fd, char **name) } +/* Like access but using windows _waccess */ +int +_gpgme_access (const char *path, int mode) +{ + wchar_t *u16 = utf8_to_wchar0 (path); + int r = _waccess (u16, F_OK); + + free(u16); + return r; +} + +/* Like CreateProcessA but mapping the arguments to wchar API */ +int _gpgme_create_process_utf8 (const char *application_name_utf8, + char *command_line_utf8, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + void *lpEnvironment, + char *working_directory_utf8, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) +{ + BOOL ret; + wchar_t *application_name = utf8_to_wchar0 (application_name_utf8); + wchar_t *command_line = utf8_to_wchar0 (command_line_utf8); + wchar_t *working_directory = utf8_to_wchar0 (working_directory_utf8); + + ret = CreateProcessW (application_name, + command_line, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + working_directory, + lpStartupInfo, + lpProcessInformation); + free (application_name); + free (command_line); + free (working_directory); + return ret; +} /* Entry point called by the DLL loader. */ #ifdef DLL_EXPORT |