diff --git a/block/file-win32.c b/block/file-win32.c index 2642088bd6..053496afeb 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -337,6 +337,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, QemuOpts *opts; Error *local_err = NULL; const char *filename; + wchar_t *wfilename; bool use_aio; OnOffAuto locking; int ret; @@ -391,9 +392,14 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", buf[0]); } - s->hfile = CreateFile(filename, access_flags, + wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); + if (!filename) { + goto fail; + } + s->hfile = CreateFileW(wfilename, access_flags, FILE_SHARE_READ, NULL, OPEN_EXISTING, overlapped, NULL); + g_free(wfilename); if (s->hfile == INVALID_HANDLE_VALUE) { int err = GetLastError(); @@ -556,27 +562,35 @@ static int64_t raw_getlength(BlockDriverState *bs) static int64_t raw_get_allocated_file_size(BlockDriverState *bs) { - typedef DWORD (WINAPI * get_compressed_t)(const char *filename, + typedef DWORD (WINAPI * get_compressed_t)(const wchar_t *filename, DWORD * high); + int64_t size = -1; get_compressed_t get_compressed; struct _stati64 st; - const char *filename = bs->filename; + wchar_t *wfilename = g_utf8_to_utf16(bs->filename, -1, NULL, NULL, NULL); + if (!wfilename) { + goto done; + } /* WinNT support GetCompressedFileSize to determine allocate size */ get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), - "GetCompressedFileSizeA"); + "GetCompressedFileSizeW"); if (get_compressed) { DWORD high, low; - low = get_compressed(filename, &high); + low = get_compressed(wfilename, &high); if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) { - return (((int64_t) high) << 32) + low; + size = (((int64_t) high) << 32) + low; + goto done; } } - if (_stati64(filename, &st) < 0) { - return -1; + if (_wstati64(wfilename, &st) >= 0) { + size = st.st_size; } - return st.st_size; + +done: + g_free(wfilename); + return size; } static int raw_co_create(BlockdevCreateOptions *options, Error **errp) @@ -752,6 +766,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; const char *filename; + wchar_t *wfilename; bool use_aio; QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, @@ -795,9 +810,14 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, create_flags = OPEN_EXISTING; - s->hfile = CreateFile(filename, access_flags, - FILE_SHARE_READ, NULL, - create_flags, overlapped, NULL); + wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); + if (!filename) { + goto done; + } + s->hfile = CreateFileW(wfilename, access_flags, + FILE_SHARE_READ, NULL, + create_flags, overlapped, NULL); + g_free(wfilename); if (s->hfile == INVALID_HANDLE_VALUE) { int err = GetLastError(); diff --git a/hw/core/loader.c b/hw/core/loader.c index 5b34869a54..12a316ecae 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -70,7 +70,7 @@ int64_t get_image_size(const char *filename) { int fd; int64_t size; - fd = open(filename, O_RDONLY | O_BINARY); + fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd < 0) return -1; size = lseek(fd, 0, SEEK_END); @@ -84,7 +84,7 @@ ssize_t load_image_size(const char *filename, void *addr, size_t size) int fd; ssize_t actsize, l = 0; - fd = open(filename, O_RDONLY | O_BINARY); + fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd < 0) { return -1; } @@ -229,7 +229,7 @@ int load_aout(const char *filename, hwaddr addr, int max_sz, struct exec e; uint32_t magic; - fd = open(filename, O_RDONLY | O_BINARY); + fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd < 0) return -1; @@ -359,7 +359,7 @@ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp) } e_ident = hdr; - fd = open(filename, O_RDONLY | O_BINARY); + fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd < 0) { error_setg_errno(errp, errno, "Failed to open file: %s", filename); return; @@ -456,7 +456,7 @@ int load_elf_ram_sym(const char *filename, int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED; uint8_t e_ident[EI_NIDENT]; - fd = open(filename, O_RDONLY | O_BINARY); + fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd < 0) { perror(filename); return -1; @@ -613,7 +613,7 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, int ret = -1; int do_uncompress = 0; - fd = open(filename, O_RDONLY | O_BINARY); + fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd < 0) return -1; @@ -962,7 +962,7 @@ int rom_add_file(const char *file, const char *fw_dir, rom->path = g_strdup(file); } - fd = open(rom->path, O_RDONLY | O_BINARY); + fd = qemu_open(rom->path, O_RDONLY | O_BINARY, NULL); if (fd == -1) { fprintf(stderr, "Could not open option rom '%s': %s\n", rom->path, strerror(errno)); diff --git a/hw/xbox/eeprom_generation.c b/hw/xbox/eeprom_generation.c index 23319af56e..291e2077dc 100644 --- a/hw/xbox/eeprom_generation.c +++ b/hw/xbox/eeprom_generation.c @@ -241,7 +241,7 @@ bool xbox_eeprom_generate(const char *file, XboxEEPROMVersion ver) { xbox_rc4_crypt(&rctx, e.confounder, 0x1C); // save to file - FILE *fd = fopen(file, "wb"); + FILE *fd = qemu_fopen(file, "wb"); if (fd == NULL) { return false; } diff --git a/hw/xbox/smbus_storage.c b/hw/xbox/smbus_storage.c index 4611450e01..638d776f71 100644 --- a/hw/xbox/smbus_storage.c +++ b/hw/xbox/smbus_storage.c @@ -68,7 +68,7 @@ static void smbus_storage_realize(DeviceState *dev, Error **errp) return; } - int fd = open(s->file, O_RDONLY | O_BINARY); + int fd = qemu_open(s->file, O_RDONLY | O_BINARY, NULL); if (fd < 0) { error_setg(errp, "%s: file '%s' could not be opened\n", __func__, s->file); @@ -109,7 +109,7 @@ static int smbus_storage_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len) } if (changed && s->file && s->persist) { - int fd = open(s->file, O_WRONLY | O_BINARY); + int fd = qemu_open(s->file, O_WRONLY | O_BINARY, NULL); if (fd < 0) { DPRINTF("%s: file '%s' could not be opened\n", __func__, s->file); return -1; diff --git a/hw/xbox/xbox.c b/hw/xbox/xbox.c index 9ace1b79e6..07071b9bcf 100644 --- a/hw/xbox/xbox.c +++ b/hw/xbox/xbox.c @@ -87,7 +87,7 @@ static void xbox_flash_init(MachineState *ms, MemoryRegion *rom_memory) if (!failed_to_load_bios && (filename != NULL)) { /* Read BIOS ROM into memory */ failed_to_load_bios = 1; - int fd = open(filename, O_RDONLY | O_BINARY); + int fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); if (fd >= 0) { int rc = read(fd, bios_data, bios_size); if (rc == bios_size) { @@ -156,7 +156,7 @@ static void xbox_flash_init(MachineState *ms, MemoryRegion *rom_memory) } /* Read in MCPX ROM over last 512 bytes of BIOS data */ - int fd = open(filename, O_RDONLY | O_BINARY); + int fd = qemu_open(filename, O_RDONLY | O_BINARY, NULL); assert(fd >= 0); int rc = read(fd, bios_data + bios_size - bootrom_size, bootrom_size); assert(rc == bootrom_size); diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 60718fc342..eae68bc7ee 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -593,6 +593,21 @@ int qemu_lock_fd_test(int fd, int64_t start, int64_t len, bool exclusive); bool qemu_has_ofd_lock(void); #endif +#ifdef _WIN32 +FILE *qemu_fopen(const char *filename, const char *mode); +int qemu_access(const char *pathname, int mode); +#else +static inline FILE *qemu_fopen(const char *filename, const char *mode) +{ + return fopen(filename, mode); +} + +static inline int qemu_access(const char *pathname, int mode) +{ + return access(pathname, mode); +} +#endif + #if defined(__HAIKU__) && defined(__i386__) #define FMT_pid "%ld" #elif defined(WIN64) diff --git a/softmmu/datadir.c b/softmmu/datadir.c index 504c4665be..de156e4b6f 100644 --- a/softmmu/datadir.c +++ b/softmmu/datadir.c @@ -38,7 +38,7 @@ char *qemu_find_file(int type, const char *name) char *buf; /* Try the name as a straight path first */ - if (access(name, R_OK) == 0) { + if (qemu_access(name, R_OK) == 0) { trace_load_file(name, name); return g_strdup(name); } @@ -56,7 +56,7 @@ char *qemu_find_file(int type, const char *name) for (i = 0; i < data_dir_idx; i++) { buf = g_strdup_printf("%s/%s%s", data_dir[i], subdir, name); - if (access(buf, R_OK) == 0) { + if (qemu_access(buf, R_OK) == 0) { trace_load_file(name, buf); return buf; } diff --git a/softmmu/vl.c b/softmmu/vl.c index 258d11d3ae..0223fb1eb2 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2436,7 +2436,7 @@ static void create_default_memdev(MachineState *ms, const char *path) /* Return 1 if file fails to open */ static int xemu_check_file(const char *path) { - FILE *fd = fopen(path, "rb"); + FILE *fd = qemu_fopen(path, "rb"); if (fd == NULL) { return 1; } @@ -3768,7 +3768,7 @@ void qemu_init(int argc, char **argv, char **envp) if (strcmp(optarg, "-") == 0) { fp = stdout; } else { - fp = fopen(optarg, "w"); + fp = qemu_fopen(optarg, "w"); if (fp == NULL) { error_report("open %s: %s", optarg, strerror(errno)); @@ -3856,7 +3856,7 @@ void qemu_init(int argc, char **argv, char **envp) "option may be given"); exit(1); } - vmstate_dump_file = fopen(optarg, "w"); + vmstate_dump_file = qemu_fopen(optarg, "w"); if (vmstate_dump_file == NULL) { error_report("open %s: %s", optarg, strerror(errno)); exit(1); diff --git a/ui/inih/ini.c b/ui/inih/ini.c index d19d613572..e2c13bea71 100644 --- a/ui/inih/ini.c +++ b/ui/inih/ini.c @@ -18,6 +18,7 @@ https://github.com/benhoyt/inih #include #include #include +#include "qemu/osdep.h" #include "ini.h" @@ -238,7 +239,7 @@ int ini_parse(const char* filename, ini_handler handler, void* user) FILE* file; int error; - file = fopen(filename, "r"); + file = qemu_fopen(filename, "r"); if (!file) return -1; error = ini_parse_file(file, handler, user); diff --git a/ui/noc_file_dialog.h b/ui/noc_file_dialog.h index afb537b27a..93ab4a9c8a 100644 --- a/ui/noc_file_dialog.h +++ b/ui/noc_file_dialog.h @@ -164,48 +164,91 @@ const char *noc_file_dialog_open(int flags, #include #include +#include +#include const char *noc_file_dialog_open(int flags, const char *filters, const char *default_path, const char *default_name) { - OPENFILENAME ofn; // common dialog box structure - char szFile[_MAX_PATH]; // buffer for file name - char initialDir[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; - int ret; + OPENFILENAMEW ofn; // common dialog box structure + wchar_t szFile[_MAX_PATH]; // buffer for file name + wchar_t initialDir[_MAX_PATH]; + wchar_t drive[_MAX_DRIVE]; + wchar_t dir[_MAX_DIR]; + wchar_t fname[_MAX_FNAME]; + wchar_t ext[_MAX_EXT]; + int ret = 0; + wchar_t *wfilters = NULL; + wchar_t *wdefault_path = NULL; + wchar_t *wdefault_name = NULL; + size_t filters_length = 0; + + if (filters) { + // 'filters' is a null-terminated list of null-terminated strings, + // so the buffer length must be provided explicitly + while (filters[filters_length]) { + filters_length += strlen(filters + filters_length) + 1; + } + wfilters = (wchar_t*)g_convert(filters, filters_length + 1, "UTF-16", "UTF-8", NULL, NULL, NULL); + if (!wfilters) { + fprintf(stderr, "Failed to convert UTF-8 string to UTF-16\n"); + goto done; + } + } + if (default_path) { + wdefault_path = g_utf8_to_utf16(default_path, -1, NULL, NULL, NULL); + if (!wdefault_path) { + fprintf(stderr, "Failed to convert UTF-8 string to UTF-16\n"); + goto done; + } + } + if (default_name) { + wdefault_name = g_utf8_to_utf16(default_name, -1, NULL, NULL, NULL); + if (!wdefault_name) { + fprintf(stderr, "Failed to convert UTF-8 string to UTF-16\n"); + goto done; + } + } // init default dir and file name - _splitpath_s(default_path, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, - _MAX_FNAME, ext, _MAX_EXT ); - _makepath_s(initialDir, _MAX_PATH, drive, dir, NULL, NULL); - if (default_name) - strncpy(szFile, default_name, sizeof(szFile) - 1); + _wsplitpath_s(wdefault_path, drive, G_N_ELEMENTS(drive), dir, G_N_ELEMENTS(dir), fname, + G_N_ELEMENTS(fname), ext, G_N_ELEMENTS(ext) ); + _wmakepath_s(initialDir, G_N_ELEMENTS(initialDir), drive, dir, NULL, NULL); + if (wdefault_name) + wcscpy_s(szFile, G_N_ELEMENTS(szFile), wdefault_name); else - _makepath_s(szFile, _MAX_PATH, NULL, NULL, fname, ext); + _wmakepath_s(szFile, G_N_ELEMENTS(szFile), NULL, NULL, fname, ext); ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof(szFile); - ofn.lpstrFilter = filters; + ofn.nMaxFile = G_N_ELEMENTS(szFile); + ofn.lpstrFilter = wfilters; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = initialDir; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - if (flags & NOC_FILE_DIALOG_OPEN) - ret = GetOpenFileName(&ofn); - else - ret = GetSaveFileName(&ofn); + if (flags & NOC_FILE_DIALOG_OPEN) { + ret = GetOpenFileNameW(&ofn); + } else { + ret = GetSaveFileNameW(&ofn); + } - free(g_noc_file_dialog_ret); - g_noc_file_dialog_ret = ret ? strdup(szFile) : NULL; +done: + g_free(wdefault_name); + g_free(wdefault_path); + g_free(wfilters); + + g_free(g_noc_file_dialog_ret); + if (ret) { + g_noc_file_dialog_ret = g_utf16_to_utf8(szFile, -1, NULL, NULL, NULL); + } else { + g_noc_file_dialog_ret = NULL; + } return g_noc_file_dialog_ret; } diff --git a/ui/xemu-settings.c b/ui/xemu-settings.c index 0c0c8ab975..1cdc916714 100644 --- a/ui/xemu-settings.c +++ b/ui/xemu-settings.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include "qemu/osdep.h" #include #include #include @@ -208,7 +209,7 @@ static bool xemu_settings_detect_portable_mode(void) bool val = false; char *portable_path = g_strdup_printf("%s%s", SDL_GetBasePath(), filename); FILE *tmpfile; - if ((tmpfile = fopen(portable_path, "r"))) { + if ((tmpfile = qemu_fopen(portable_path, "r"))) { fclose(tmpfile); val = true; } @@ -392,7 +393,7 @@ void xemu_settings_load(void) int xemu_settings_save(void) { - FILE *fd = fopen(xemu_settings_get_path(), "wb"); + FILE *fd = qemu_fopen(xemu_settings_get_path(), "wb"); assert(fd != NULL); const char *last_section = ""; diff --git a/util/osdep.c b/util/osdep.c index 42a0a4986a..a9ad4c4f89 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -289,13 +289,29 @@ int qemu_lock_fd_test(int fd, int64_t start, int64_t len, bool exclusive) } #endif +static int qemu_open_cloexec_internal(const char *name, int flags, mode_t mode) +{ + int ret; +#ifdef _WIN32 + wchar_t *wname = g_utf8_to_utf16(name, -1, NULL, NULL, NULL); + if (!wname) { + return -1; + } + ret = _wopen(wname, flags, mode); + g_free(wname); +#else + ret = open(name, flags, mode); +#endif + return ret; +} + static int qemu_open_cloexec(const char *name, int flags, mode_t mode) { int ret; #ifdef O_CLOEXEC - ret = open(name, flags | O_CLOEXEC, mode); + ret = qemu_open_cloexec_internal(name, flags | O_CLOEXEC, mode); #else - ret = open(name, flags, mode); + ret = qemu_open_cloexec_internal(name, flags, mode); if (ret >= 0) { qemu_set_cloexec(ret); } diff --git a/util/oslib-win32.c b/util/oslib-win32.c index ec09b622b1..6807355c62 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -294,17 +294,28 @@ char * qemu_get_local_state_pathname(const char *relative_pathname) { HRESULT result; - char base_path[MAX_PATH+1] = ""; + char *ret; + wchar_t wbase_path[MAX_PATH]; + char *base_path; - result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, - /* SHGFP_TYPE_CURRENT */ 0, base_path); + result = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, + /* SHGFP_TYPE_CURRENT */ 0, wbase_path); if (result != S_OK) { /* misconfigured environment */ g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result); abort(); } - return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", base_path, + base_path = g_utf16_to_utf8(wbase_path, -1, NULL, NULL, NULL); + if (!base_path) { + g_critical("Failed to convert local_state_pathname to UTF-8"); + abort(); + } + + ret = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", base_path, relative_pathname); + g_free(base_path); + + return ret; } void qemu_set_tty_echo(int fd, bool echo) @@ -331,27 +342,27 @@ static const char *exec_dir; void qemu_init_exec_dir(const char *argv0) { - char *p; - char buf[MAX_PATH]; + wchar_t *p; + wchar_t buf[MAX_PATH]; DWORD len; if (exec_dir) { return; } - len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); + len = GetModuleFileNameW(NULL, buf, G_N_ELEMENTS(buf) - 1); if (len == 0) { return; } buf[len] = 0; p = buf + len - 1; - while (p != buf && *p != '\\') { + while (p != buf && *p != L'\\') { p--; } *p = 0; - if (access(buf, R_OK) == 0) { - exec_dir = g_strdup(buf); + if (_waccess(buf, R_OK) == 0) { + exec_dir = g_utf16_to_utf8(buf, -1, NULL, NULL, NULL); } else { exec_dir = CONFIG_BINDIR; } @@ -813,11 +824,19 @@ bool qemu_write_pidfile(const char *filename, Error **errp) HANDLE file; OVERLAPPED overlap; BOOL ret; + wchar_t *wfilename; memset(&overlap, 0, sizeof(overlap)); - file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); + if (!wfilename) { + error_setg(errp, "Failed to convert PID file's filename"); + return false; + } + + file = CreateFileW(wfilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + g_free(wfilename); if (file == INVALID_HANDLE_VALUE) { error_setg(errp, "Failed to create PID file"); return false; @@ -856,3 +875,44 @@ size_t qemu_get_host_physmem(void) } return 0; } + +FILE *qemu_fopen(const char *filename, const char *mode) +{ + wchar_t *wfilename; + wchar_t *wmode = NULL; + FILE *file = NULL; + + wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL); + if (!wfilename) { + goto done; + } + + wmode = g_utf8_to_utf16(mode, -1, NULL, NULL, NULL); + if (!wmode) { + goto done; + } + + file = _wfopen(wfilename, wmode); + +done: + g_free(wfilename); + g_free(wmode); + return file; +} + +int qemu_access(const char *pathname, int mode) +{ + wchar_t *wpathname; + int ret = -1; + + wpathname = g_utf8_to_utf16(pathname, -1, NULL, NULL, NULL); + if (!wpathname) { + goto done; + } + + ret = _waccess(wpathname, mode); + +done: + g_free(wpathname); + return ret; +} diff --git a/util/path.c b/util/path.c index 8e174eb436..23f900e8d8 100644 --- a/util/path.c +++ b/util/path.c @@ -53,7 +53,7 @@ const char *path(const char *name) char *full = g_build_filename(base, name, NULL); /* Look for the path; record the result, pass or fail. */ - if (access(full, F_OK) == 0) { + if (qemu_access(full, F_OK) == 0) { /* Exists. */ g_hash_table_insert(hash, save, full); ret = full; diff --git a/util/qemu-config.c b/util/qemu-config.c index 436ab63b16..0d7126df94 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -452,7 +452,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error * int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp) { - FILE *f = fopen(filename, "r"); + FILE *f = qemu_fopen(filename, "r"); int ret; if (f == NULL) {