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.
This commit is contained in:
parent
937adfdcbb
commit
a82e3a0ae5
@ -260,7 +260,7 @@ get_gpgconf_item (int what)
|
|||||||
char *pgmname;
|
char *pgmname;
|
||||||
|
|
||||||
pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
|
pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
|
||||||
if (pgmname && access (pgmname, F_OK))
|
if (pgmname && _gpgme_access (pgmname, F_OK))
|
||||||
{
|
{
|
||||||
_gpgme_debug (DEBUG_INIT, -1, NULL, NULL, NULL,
|
_gpgme_debug (DEBUG_INIT, -1, NULL, NULL, NULL,
|
||||||
"gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
|
"gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
|
||||||
|
@ -157,3 +157,10 @@ _gpgme_allow_set_foreground_window (pid_t pid)
|
|||||||
(void)pid;
|
(void)pid;
|
||||||
/* Not needed. */
|
/* Not needed. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See w32-util.c */
|
||||||
|
int
|
||||||
|
_gpgme_access (const char *path, int mode)
|
||||||
|
{
|
||||||
|
return access (path, mode);
|
||||||
|
}
|
||||||
|
@ -28,9 +28,22 @@ int _gpgme_set_override_inst_dir (const char *dir);
|
|||||||
char *_gpgme_get_gpg_path (void);
|
char *_gpgme_get_gpg_path (void);
|
||||||
char *_gpgme_get_gpgconf_path (void);
|
char *_gpgme_get_gpgconf_path (void);
|
||||||
|
|
||||||
|
int _gpgme_access (const char *path_utf8, int mode);
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
const char *_gpgme_get_inst_dir (void);
|
const char *_gpgme_get_inst_dir (void);
|
||||||
void _gpgme_w32_cancel_synchronous_io (HANDLE thread);
|
void _gpgme_w32_cancel_synchronous_io (HANDLE thread);
|
||||||
|
/* See CreateProcessA returns true on success */
|
||||||
|
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);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* SYS_UTIL_H */
|
#endif /* SYS_UTIL_H */
|
||||||
|
@ -1481,7 +1481,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
|
|||||||
free (tmp_name);
|
free (tmp_name);
|
||||||
return TRACE_SYSRES (-1);
|
return TRACE_SYSRES (-1);
|
||||||
}
|
}
|
||||||
if (!CreateProcessA (spawnhelper,
|
if (!_gpgme_create_process_utf8 (spawnhelper,
|
||||||
arg_string,
|
arg_string,
|
||||||
&sec_attr, /* process security attributes */
|
&sec_attr, /* process security attributes */
|
||||||
&sec_attr, /* thread security attributes */
|
&sec_attr, /* thread security attributes */
|
||||||
|
105
src/w32-util.c
105
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. */
|
/* Replace all forward slashes by backslashes. */
|
||||||
static void
|
static void
|
||||||
replace_slashes (char *string)
|
replace_slashes (char *string)
|
||||||
@ -395,7 +437,7 @@ find_program_in_dir (const char *dir, const char *name)
|
|||||||
if (!result)
|
if (!result)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (access (result, F_OK))
|
if (_gpgme_access (result, F_OK))
|
||||||
{
|
{
|
||||||
free (result);
|
free (result);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -408,7 +450,7 @@ find_program_in_dir (const char *dir, const char *name)
|
|||||||
static char *
|
static char *
|
||||||
find_program_at_standard_place (const char *name)
|
find_program_at_standard_place (const char *name)
|
||||||
{
|
{
|
||||||
char path[MAX_PATH];
|
wchar_t path[MAX_PATH];
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
|
|
||||||
/* See https://wiki.tcl-lang.org/page/Getting+Windows+%22special+folders%22+with+Ffidl for details on compatibility.
|
/* 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
|
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
|
(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. */
|
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);
|
char *utf8_path = wchar_to_utf8 (path);
|
||||||
if (result && access (result, F_OK))
|
result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
|
||||||
|
free (utf8_path);
|
||||||
|
if (result && _gpgme_access (result, F_OK))
|
||||||
{
|
{
|
||||||
free (result);
|
free (result);
|
||||||
result = NULL;
|
result = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result
|
if (!result
|
||||||
&& SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
|
&& SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
|
||||||
{
|
{
|
||||||
result = _gpgme_strconcat (path, "\\", name, NULL);
|
char *utf8_path = wchar_to_utf8 (path);
|
||||||
if (result && access (result, F_OK))
|
result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
|
||||||
|
free (utf8_path);
|
||||||
|
if (result && _gpgme_access (result, F_OK))
|
||||||
{
|
{
|
||||||
free (result);
|
free (result);
|
||||||
result = NULL;
|
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. */
|
/* Entry point called by the DLL loader. */
|
||||||
#ifdef DLL_EXPORT
|
#ifdef DLL_EXPORT
|
||||||
|
Loading…
Reference in New Issue
Block a user