Bug 795134 - Improper handle of unicode character in username

Part 1: gnc-filename-utils didn't manage the encoding differences
between Windows (UTF16) and GLib (UTF-8).
This commit is contained in:
John Ralls 2018-04-20 14:09:53 -07:00
parent 451bbd53d9
commit 35cd165bec
3 changed files with 61 additions and 60 deletions

View File

@ -81,7 +81,11 @@ static int gnucash_show_version = 0;
static int debugging = 0; static int debugging = 0;
static int extra = 0; static int extra = 0;
static gchar **log_flags = NULL; static gchar **log_flags = NULL;
static gchar *log_to_filename = NULL; #ifdef __MINGW64__
static wchar_t *log_to_filename = NULL;
#else
static char *log_to_filename = NULL;
#endif
static int nofile = 0; static int nofile = 0;
static const gchar *gsettings_prefix = NULL; static const gchar *gsettings_prefix = NULL;
static const char *add_quotes_file = NULL; static const char *add_quotes_file = NULL;
@ -679,7 +683,12 @@ gnc_log_init()
{ {
if (log_to_filename != NULL) if (log_to_filename != NULL)
{ {
qof_log_init_filename_special(log_to_filename); #ifdef __MINGW64__
char* filename = g_utf16_to_utf8(log_to_filename, -1, NULL, NULL, NULL);
#else
char* filename = log_to_filename;
#endif
qof_log_init_filename_special(filename);
} }
else else
{ {

View File

@ -66,14 +66,19 @@ extern "C" {
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/locale.hpp> #include <boost/locale.hpp>
#include <codecvt>
#include <iostream> #include <iostream>
#if PLATFORM(WINDOWS) #if PLATFORM(WINDOWS)
#include <codecvt> using codecvt = std::codecvt_utf8<wchar_t, 0x10FFFF, std::little_endian>;
#include <locale> using string = std::wstring;
#else
using codecvt = std::codecvt;
using string = std::string;
#endif #endif
static codecvt cvt;
static std::locale bfs_locale(std::locale(), new codecvt);
namespace bfs = boost::filesystem; namespace bfs = boost::filesystem;
namespace bst = boost::system; namespace bst = boost::system;
@ -366,7 +371,8 @@ gnc_validate_directory (const bfs::path &dirname)
* we need to overrule it during build (when guile interferes) * we need to overrule it during build (when guile interferes)
* and testing. * and testing.
*/ */
auto home_dir = bfs::path (g_get_home_dir ()); bfs::path home_dir(g_get_home_dir(), cvt);
home_dir.imbue(bfs_locale);
auto homedir_exists = bfs::exists(home_dir); auto homedir_exists = bfs::exists(home_dir);
auto is_descendant = dir_is_descendant (dirname, home_dir); auto is_descendant = dir_is_descendant (dirname, home_dir);
if (!homedir_exists && is_descendant) if (!homedir_exists && is_descendant)
@ -432,11 +438,16 @@ copy_recursive(const bfs::path& src, const bfs::path& dest)
for(auto direntry = bfs::recursive_directory_iterator(src); for(auto direntry = bfs::recursive_directory_iterator(src);
direntry != bfs::recursive_directory_iterator(); ++direntry) direntry != bfs::recursive_directory_iterator(); ++direntry)
{ {
auto cur_str = direntry->path().string(); #ifdef G_OS_WIN32
string cur_str = direntry->path().wstring();
#else
string cur_str = direntry->path().string();
#endif
auto cur_len = cur_str.size(); auto cur_len = cur_str.size();
auto rel_str = std::string(cur_str, old_len, cur_len - old_len); string rel_str(cur_str, old_len, cur_len - old_len);
auto relpath = bfs::path(rel_str).relative_path(); bfs::path relpath(rel_str, cvt);
auto newpath = bfs::absolute (relpath, dest); auto newpath = bfs::absolute (relpath.relative_path(), dest);
newpath.imbue(bfs_locale);
bfs::copy(direntry->path(), newpath); bfs::copy(direntry->path(), newpath);
} }
} }
@ -458,31 +469,27 @@ copy_recursive(const bfs::path& src, const bfs::path& dest)
* So this function is a copy of glib's internal get_special_folder * So this function is a copy of glib's internal get_special_folder
* and minimally adjusted to fetch CSIDL_APPDATA * and minimally adjusted to fetch CSIDL_APPDATA
*/ */
static char * static bfs::path
win32_get_userdata_home (void) get_user_data_dir ()
{ {
wchar_t path[MAX_PATH+1]; wchar_t path[MAX_PATH+1];
HRESULT hr; HRESULT hr;
LPITEMIDLIST pidl = NULL; LPITEMIDLIST pidl = NULL;
BOOL b; BOOL b;
char *retval = NULL;
hr = SHGetSpecialFolderLocation (NULL, CSIDL_APPDATA, &pidl); hr = SHGetSpecialFolderLocation (NULL, CSIDL_APPDATA, &pidl);
if (hr == S_OK) if (hr == S_OK)
{ {
b = SHGetPathFromIDListW (pidl, path); b = SHGetPathFromIDListW (pidl, path);
if (b)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
retval = g_strdup(utf8_conv.to_bytes(path).c_str());
}
CoTaskMemFree (pidl); CoTaskMemFree (pidl);
} }
bfs::path retval(path, cvt);
retval.imbue(bfs_locale);
return retval; return retval;
} }
#elif defined MAC_INTEGRATION #elif defined MAC_INTEGRATION
static char* static bfs::path
quarz_get_userdata_home(void) get_user_data_dir()
{ {
char *retval = NULL; char *retval = NULL;
NSFileManager*fm = [NSFileManager defaultManager]; NSFileManager*fm = [NSFileManager defaultManager];
@ -492,9 +499,14 @@ quarz_get_userdata_home(void)
{ {
NSURL* dirUrl = [appSupportDir objectAtIndex:0]; NSURL* dirUrl = [appSupportDir objectAtIndex:0];
NSString* dirPath = [dirUrl path]; NSString* dirPath = [dirUrl path];
retval = g_strdup([dirPath UTF8String]);
} }
return retval; return [dirPath UTF8String];
}
#else
static bfs::path
get_user_data_dir()
{
return g_get_user_data_dir();
} }
#endif #endif
@ -508,22 +520,8 @@ static bfs::path
get_userdata_home(void) get_userdata_home(void)
{ {
auto try_tmp_dir = true; auto try_tmp_dir = true;
gchar *data_dir = NULL; auto userdata_home = get_user_data_dir();
auto userdata_home = bfs::path();
#ifdef G_OS_WIN32
data_dir = win32_get_userdata_home ();
#elif defined MAC_INTEGRATION
data_dir = quarz_get_userdata_home ();
#endif
if (data_dir)
{
userdata_home = data_dir;
g_free(data_dir);
}
else
userdata_home = g_get_user_data_dir();
/* g_get_user_data_dir doesn't check whether the path exists nor attempts to /* g_get_user_data_dir doesn't check whether the path exists nor attempts to
* create it. So while it may return an actual path we may not be able to use it. * create it. So while it may return an actual path we may not be able to use it.
@ -548,7 +546,9 @@ get_userdata_home(void)
Hopefully we can always write there. */ Hopefully we can always write there. */
if (try_tmp_dir) if (try_tmp_dir)
{ {
userdata_home = bfs::path (g_get_tmp_dir ()) / g_get_user_name (); bfs::path newpath(g_get_tmp_dir (), cvt);
newpath.imbue(bfs_locale);
userdata_home = std::move(newpath);
} }
g_assert(!userdata_home.empty()); g_assert(!userdata_home.empty());
@ -564,33 +564,21 @@ get_userdata_home(void)
static bfs::path static bfs::path
get_userconfig_home(void) get_userconfig_home(void)
{ {
gchar *config_dir = NULL;
auto userconfig_home = bfs::path();
#ifdef G_OS_WIN32
config_dir = win32_get_userdata_home ();
#elif defined MAC_INTEGRATION
config_dir = quarz_get_userdata_home ();
#endif
/* On Windows and Macs the data directory is used, for Linux /* On Windows and Macs the data directory is used, for Linux
$HOME/.config is used */ $HOME/.config is used */
if (config_dir) #if defined (G_OS_WIN32) || defined (MAC_INTEGRATION)
{ return get_user_data_dir();
userconfig_home = config_dir; #else
g_free(config_dir); return g_get_user_config_dir();
} #endif
else
userconfig_home = g_get_user_config_dir();
return userconfig_home;
} }
static std::string migrate_gnc_datahome() static std::string migrate_gnc_datahome()
{ {
auto success = false; auto success = false;
// Specify location of dictionaries // Specify location of dictionaries
auto old_dir = bfs::path(g_get_home_dir()) / ".gnucash"; bfs::path old_dir(g_get_home_dir(), cvt);
old_dir += ".gnucash";
bl::generator gen; bl::generator gen;
gen.add_messages_path(gnc_path_get_datadir()); gen.add_messages_path(gnc_path_get_datadir());
@ -760,7 +748,9 @@ gnc_filepath_init (void)
* issues when the build environment is not a complete environment (like * issues when the build environment is not a complete environment (like
* it could be missing a valid home directory). */ * it could be missing a valid home directory). */
auto env_build_dir = g_getenv ("GNC_BUILDDIR"); auto env_build_dir = g_getenv ("GNC_BUILDDIR");
build_dir = bfs::path(env_build_dir ? env_build_dir : ""); bfs::path new_dir(env_build_dir ? env_build_dir : "", cvt);
new_dir.imbue(bfs_locale);
build_dir = std::move(new_dir);
auto running_uninstalled = (g_getenv ("GNC_UNINSTALLED") != NULL); auto running_uninstalled = (g_getenv ("GNC_UNINSTALLED") != NULL);
if (running_uninstalled && !build_dir.empty()) if (running_uninstalled && !build_dir.empty())
{ {
@ -787,7 +777,9 @@ gnc_filepath_init (void)
auto gnc_userdata_home_env = g_getenv ("GNC_DATA_HOME"); auto gnc_userdata_home_env = g_getenv ("GNC_DATA_HOME");
if (gnc_userdata_home_env) if (gnc_userdata_home_env)
{ {
gnc_userdata_home = bfs::path (gnc_userdata_home_env); bfs::path newdir(gnc_userdata_home_env, cvt);
newdir.imbue(bfs_locale);
gnc_userdata_home = std::move(newdir);
try try
{ {
gnc_userdata_home_exists = bfs::exists (gnc_userdata_home); gnc_userdata_home_exists = bfs::exists (gnc_userdata_home);

View File

@ -166,7 +166,7 @@ qof_log_init_filename(const gchar* log_filename)
#if PLATFORM(WINDOWS) #if PLATFORM(WINDOWS)
/* MSVC compiler: Somehow the OS thinks file descriptor from above /* MSVC compiler: Somehow the OS thinks file descriptor from above
* still isn't open. So we open normally with the file name and that's it. */ * still isn't open. So we open normally with the file name and that's it. */
fout = fopen(fname, "wb"); fout = g_fopen(fname, "wb");
#else #else
/* We must not overwrite /dev/null */ /* We must not overwrite /dev/null */
g_assert(g_strcmp0(log_filename, "/dev/null") != 0); g_assert(g_strcmp0(log_filename, "/dev/null") != 0);