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 extra = 0;
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 const gchar *gsettings_prefix = NULL;
static const char *add_quotes_file = NULL;
@ -679,7 +683,12 @@ gnc_log_init()
{
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
{

View File

@ -66,14 +66,19 @@ extern "C" {
#include <boost/filesystem.hpp>
#include <boost/locale.hpp>
#include <codecvt>
#include <iostream>
#if PLATFORM(WINDOWS)
#include <codecvt>
#include <locale>
using codecvt = std::codecvt_utf8<wchar_t, 0x10FFFF, std::little_endian>;
using string = std::wstring;
#else
using codecvt = std::codecvt;
using string = std::string;
#endif
static codecvt cvt;
static std::locale bfs_locale(std::locale(), new codecvt);
namespace bfs = boost::filesystem;
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)
* 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 is_descendant = dir_is_descendant (dirname, home_dir);
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);
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 rel_str = std::string(cur_str, old_len, cur_len - old_len);
auto relpath = bfs::path(rel_str).relative_path();
auto newpath = bfs::absolute (relpath, dest);
string rel_str(cur_str, old_len, cur_len - old_len);
bfs::path relpath(rel_str, cvt);
auto newpath = bfs::absolute (relpath.relative_path(), dest);
newpath.imbue(bfs_locale);
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
* and minimally adjusted to fetch CSIDL_APPDATA
*/
static char *
win32_get_userdata_home (void)
static bfs::path
get_user_data_dir ()
{
wchar_t path[MAX_PATH+1];
HRESULT hr;
LPITEMIDLIST pidl = NULL;
BOOL b;
char *retval = NULL;
hr = SHGetSpecialFolderLocation (NULL, CSIDL_APPDATA, &pidl);
if (hr == S_OK)
{
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);
}
bfs::path retval(path, cvt);
retval.imbue(bfs_locale);
return retval;
}
#elif defined MAC_INTEGRATION
static char*
quarz_get_userdata_home(void)
static bfs::path
get_user_data_dir()
{
char *retval = NULL;
NSFileManager*fm = [NSFileManager defaultManager];
@ -492,9 +499,14 @@ quarz_get_userdata_home(void)
{
NSURL* dirUrl = [appSupportDir objectAtIndex:0];
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
@ -508,22 +520,8 @@ static bfs::path
get_userdata_home(void)
{
auto try_tmp_dir = true;
gchar *data_dir = NULL;
auto userdata_home = bfs::path();
auto userdata_home = get_user_data_dir();
#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
* 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. */
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());
@ -564,33 +564,21 @@ get_userdata_home(void)
static bfs::path
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
$HOME/.config is used */
if (config_dir)
{
userconfig_home = config_dir;
g_free(config_dir);
}
else
userconfig_home = g_get_user_config_dir();
return userconfig_home;
#if defined (G_OS_WIN32) || defined (MAC_INTEGRATION)
return get_user_data_dir();
#else
return g_get_user_config_dir();
#endif
}
static std::string migrate_gnc_datahome()
{
auto success = false;
// 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;
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
* it could be missing a valid home directory). */
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);
if (running_uninstalled && !build_dir.empty())
{
@ -787,7 +777,9 @@ gnc_filepath_init (void)
auto gnc_userdata_home_env = g_getenv ("GNC_DATA_HOME");
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
{
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)
/* 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. */
fout = fopen(fname, "wb");
fout = g_fopen(fname, "wb");
#else
/* We must not overwrite /dev/null */
g_assert(g_strcmp0(log_filename, "/dev/null") != 0);