summaryrefslogtreecommitdiffstats
path: root/src/win32
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32')
-rw-r--r--src/win32/environment_win32.c21
-rw-r--r--src/win32/filesystem_win32.c183
-rw-r--r--src/win32/win32_util.c73
-rw-r--r--src/win32/win32_util.h31
4 files changed, 267 insertions, 41 deletions
diff --git a/src/win32/environment_win32.c b/src/win32/environment_win32.c
index 64feee5..ce5f00e 100644
--- a/src/win32/environment_win32.c
+++ b/src/win32/environment_win32.c
@@ -1,6 +1,8 @@
// Copyright 2012-2024 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
+#include "win32_util.h"
+
#include <zix/environment.h>
#include <windows.h>
@@ -9,14 +11,27 @@ char*
zix_expand_environment_strings(ZixAllocator* const allocator,
const char* const string)
{
- const DWORD size = ExpandEnvironmentStrings(string, NULL, 0U);
+ ArgPathChar* const wstring = arg_path_new(allocator, string);
+
+ const DWORD size = ExpandEnvironmentStrings(wstring, NULL, 0U);
if (!size) {
+ arg_path_free(allocator, wstring);
return NULL;
}
- char* const out = (char*)zix_calloc(allocator, (size_t)size + 1U, 1U);
+ TCHAR* const out =
+ (TCHAR*)zix_calloc(allocator, (size_t)size + 1U, sizeof(TCHAR));
if (out) {
- ExpandEnvironmentStrings(string, out, size + 1U);
+ ExpandEnvironmentStrings(wstring, out, size + 1U);
}
+
+ arg_path_free(allocator, wstring);
+
+#ifdef UNICODE
+ char* const result = zix_wchar_to_utf8(allocator, out);
+ zix_free(allocator, out);
+ return result;
+#else
return out;
+#endif
}
diff --git a/src/win32/filesystem_win32.c b/src/win32/filesystem_win32.c
index d311bf8..c88b1ff 100644
--- a/src/win32/filesystem_win32.c
+++ b/src/win32/filesystem_win32.c
@@ -5,6 +5,7 @@
#include "../errno_status.h"
#include "../zix_config.h"
+#include "win32_util.h"
#include <zix/allocator.h>
#include <zix/bump_allocator.h>
@@ -16,6 +17,7 @@
#include <io.h>
#include <limits.h>
#include <sys/stat.h>
+#include <tchar.h>
#include <windows.h>
#include <errno.h>
@@ -25,6 +27,34 @@
#include <stdlib.h>
#include <string.h>
+#ifdef UNICODE
+
+static char*
+path_result(ZixAllocator* const allocator, wchar_t* const path)
+{
+ if (!path) {
+ return NULL;
+ }
+
+ static const wchar_t* const long_prefix = L"\\\\?\\";
+
+ const size_t p = !wcsncmp(path, long_prefix, 4U) ? 4U : 0U;
+ char* const result = zix_wchar_to_utf8(allocator, path + p);
+ zix_free(allocator, path);
+ return result;
+}
+
+#else // !defined(UNICODE)
+
+static char*
+path_result(ZixAllocator* const allocator, char* const path)
+{
+ (void)allocator;
+ return path;
+}
+
+#endif
+
static inline ZixStatus
zix_winerror_status(const DWORD e)
{
@@ -67,8 +97,15 @@ zix_copy_file(ZixAllocator* const allocator,
{
(void)allocator;
- return zix_windows_status(
- CopyFile(src, dst, !(options & ZIX_COPY_OPTION_OVERWRITE_EXISTING)));
+ ArgPathChar* const wsrc = arg_path_new(allocator, src);
+ ArgPathChar* const wdst = arg_path_new(allocator, dst);
+
+ const BOOL ret =
+ CopyFile(wsrc, wdst, !(options & ZIX_COPY_OPTION_OVERWRITE_EXISTING));
+
+ arg_path_free(allocator, wdst);
+ arg_path_free(allocator, wsrc);
+ return zix_windows_status(ret);
}
/// Linear Congruential Generator for making random 32-bit integers
@@ -123,9 +160,15 @@ zix_create_temporary_directory(ZixAllocator* const allocator,
ZixStatus
zix_remove(const char* const path)
{
- return zix_windows_status((zix_file_type(path) == ZIX_FILE_TYPE_DIRECTORY)
- ? RemoveDirectory(path)
- : DeleteFile(path));
+ ArgPathChar* const wpath = arg_path_new(NULL, path);
+ const DWORD attrs = GetFileAttributes(wpath);
+
+ const BOOL success =
+ ((attrs & FILE_ATTRIBUTE_DIRECTORY) ? RemoveDirectory(wpath)
+ : DeleteFile(wpath));
+
+ arg_path_free(NULL, wpath);
+ return zix_windows_status(success);
}
void
@@ -135,9 +178,28 @@ zix_dir_for_each(const char* const path,
const char* name,
void* data))
{
+ static const TCHAR* const dot = TEXT(".");
+ static const TCHAR* const dotdot = TEXT("..");
+
+#ifdef UNICODE
+ const int path_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
+ if (path_size < 1) {
+ return;
+ }
+
+ const size_t path_len = (size_t)path_size - 1U;
+ TCHAR* const pat = (TCHAR*)zix_calloc(NULL, path_len + 4U, sizeof(TCHAR));
+ if (!pat) {
+ return;
+ }
+
+ MultiByteToWideChar(CP_UTF8, 0, path, -1, pat, path_size);
+#else
const size_t path_len = strlen(path);
- char pat[MAX_PATH + 2U];
+ TCHAR* const pat = (TCHAR*)zix_calloc(NULL, path_len + 2U, sizeof(TCHAR));
memcpy(pat, path, path_len + 1U);
+#endif
+
pat[path_len] = '\\';
pat[path_len + 1U] = '*';
pat[path_len + 2U] = '\0';
@@ -146,8 +208,14 @@ zix_dir_for_each(const char* const path,
HANDLE fh = FindFirstFile(pat, &fd);
if (fh != INVALID_HANDLE_VALUE) {
do {
- if (!!strcmp(fd.cFileName, ".") && !!strcmp(fd.cFileName, "..")) {
+ if (!!_tcscmp(fd.cFileName, dot) && !!_tcscmp(fd.cFileName, dotdot)) {
+#ifdef UNICODE
+ char* const name = zix_wchar_to_utf8(NULL, fd.cFileName);
+ f(path, name, data);
+ zix_free(NULL, name);
+#else
f(path, fd.cFileName, data);
+#endif
}
} while (FindNextFile(fh, &fd));
}
@@ -187,10 +255,12 @@ zix_canonical_path(ZixAllocator* const allocator, const char* const path)
return NULL;
}
+ ArgPathChar* const wpath = arg_path_new(allocator, path);
+
#if USE_GETFINALPATHNAMEBYHANDLE // Vista+
const HANDLE h =
- CreateFile(path,
+ CreateFile(wpath,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
@@ -198,37 +268,37 @@ zix_canonical_path(ZixAllocator* const allocator, const char* const path)
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
- if (h == INVALID_HANDLE_VALUE) {
- return NULL;
- }
-
- const DWORD flags = FILE_NAME_NORMALIZED | VOLUME_NAME_DOS;
- const DWORD length = GetFinalPathNameByHandle(h, NULL, 0U, flags);
- TCHAR* final = NULL;
- if (length) {
- final = (TCHAR*)zix_calloc(allocator, (size_t)length + 1U, sizeof(TCHAR));
- if (final) {
- GetFinalPathNameByHandle(h, final, length + 1U, flags);
+ TCHAR* final = NULL;
+ if (h != INVALID_HANDLE_VALUE) {
+ const DWORD flags = FILE_NAME_NORMALIZED | VOLUME_NAME_DOS;
+ const DWORD length = GetFinalPathNameByHandle(h, NULL, 0U, flags);
+ if (length) {
+ final = (TCHAR*)zix_calloc(allocator, (size_t)length + 1U, sizeof(TCHAR));
+ if (final) {
+ GetFinalPathNameByHandle(h, final, length + 1U, flags);
+ }
}
}
CloseHandle(h);
- return final;
+ arg_path_free(allocator, wpath);
+ return path_result(allocator, final);
#else // Fall back to "full path iff it exists" for older Windows
TCHAR* full = NULL;
- if (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES) {
- const DWORD length = GetFullPathName(path, 0U, NULL, NULL);
+ if (GetFileAttributes(wpath) != INVALID_FILE_ATTRIBUTES) {
+ const DWORD length = GetFullPathName(wpath, 0U, NULL, NULL);
if (length) {
full = (TCHAR*)zix_calloc(allocator, (size_t)length + 1U, sizeof(TCHAR));
if (full) {
- GetFullPathName(path, length + 1U, full, NULL);
+ GetFullPathName(wpath, length + 1U, full, NULL);
}
}
}
- return full;
+ arg_path_free(allocator, wpath);
+ return path_result(allocator, full);
#endif
}
@@ -258,7 +328,7 @@ attrs_file_type(const DWORD attrs)
ZixFileType
zix_file_type(const char* const path)
{
- const ZixFileType type = attrs_file_type(GetFileAttributes(path));
+ const ZixFileType type = zix_symlink_type(path);
if (type != ZIX_FILE_TYPE_SYMLINK) {
return type;
}
@@ -267,20 +337,33 @@ zix_file_type(const char* const path)
char buf[MAX_PATH];
ZixBumpAllocator allocator = zix_bump_allocator(sizeof(buf), buf);
char* const canonical = zix_canonical_path(&allocator.base, path);
- return zix_file_type(canonical);
+ return zix_symlink_type(canonical);
}
ZixFileType
zix_symlink_type(const char* const path)
{
- return attrs_file_type(GetFileAttributes(path));
+ ArgPathChar* const wpath = arg_path_new(NULL, path);
+ if (!wpath) {
+ return ZIX_FILE_TYPE_NONE;
+ }
+
+ const ZixFileType type = attrs_file_type(GetFileAttributes(wpath));
+ arg_path_free(NULL, wpath);
+ return type;
}
ZixStatus
zix_create_directory(const char* const dir_path)
{
- return !dir_path[0] ? ZIX_STATUS_BAD_ARG
- : zix_windows_status(CreateDirectory(dir_path, NULL));
+ if (!dir_path[0]) {
+ return ZIX_STATUS_BAD_ARG;
+ }
+
+ ArgPathChar* const wpath = arg_path_new(NULL, dir_path);
+ const ZixStatus st = zix_windows_status(CreateDirectory(wpath, NULL));
+ arg_path_free(NULL, wpath);
+ return st;
}
ZixStatus
@@ -298,7 +381,15 @@ zix_create_symlink(const char* const target_path, const char* const link_path)
#if USE_CREATESYMBOLICLINK
static const DWORD flags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
- return zix_windows_status(CreateSymbolicLink(link_path, target_path, flags));
+ ArgPathChar* const wtarget = arg_path_new(NULL, target_path);
+ ArgPathChar* const wlink = arg_path_new(NULL, link_path);
+
+ const BOOL success = CreateSymbolicLink(wlink, wtarget, flags);
+
+ arg_path_free(NULL, wlink);
+ arg_path_free(NULL, wtarget);
+ return zix_windows_status(success);
+
#else
(void)target_path;
(void)link_path;
@@ -314,7 +405,15 @@ zix_create_directory_symlink(const char* const target_path,
static const DWORD flags =
SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
- return zix_windows_status(CreateSymbolicLink(link_path, target_path, flags));
+ ArgPathChar* const wtarget = arg_path_new(NULL, target_path);
+ ArgPathChar* const wlink = arg_path_new(NULL, link_path);
+
+ const BOOL success = CreateSymbolicLink(wlink, wtarget, flags);
+
+ arg_path_free(NULL, wlink);
+ arg_path_free(NULL, wtarget);
+ return zix_windows_status(success);
+
#else
(void)target_path;
(void)link_path;
@@ -326,7 +425,15 @@ ZixStatus
zix_create_hard_link(const char* const target_path, const char* const link_path)
{
#if USE_CREATEHARDLINK
- return zix_windows_status(CreateHardLink(link_path, target_path, NULL));
+ ArgPathChar* const wtarget = arg_path_new(NULL, target_path);
+ ArgPathChar* const wlink = arg_path_new(NULL, link_path);
+
+ const BOOL success = CreateHardLink(wlink, wtarget, NULL);
+
+ arg_path_free(NULL, wlink);
+ arg_path_free(NULL, wtarget);
+ return zix_windows_status(success);
+
#else
(void)target_path;
(void)link_path;
@@ -337,25 +444,25 @@ zix_create_hard_link(const char* const target_path, const char* const link_path)
char*
zix_temp_directory_path(ZixAllocator* const allocator)
{
- const DWORD size = GetTempPath(0U, NULL);
- char* const buf = (char*)zix_calloc(allocator, size, 1);
+ const DWORD size = GetTempPath(0U, NULL);
+ TCHAR* const buf = (TCHAR*)zix_calloc(allocator, size, sizeof(TCHAR));
if (buf && (GetTempPath(size, buf) != size - 1U)) {
zix_free(allocator, buf);
return NULL;
}
- return buf;
+ return path_result(allocator, buf);
}
char*
zix_current_path(ZixAllocator* const allocator)
{
- const DWORD size = GetCurrentDirectory(0U, NULL);
- char* const buf = (char*)zix_calloc(allocator, size, 1);
+ const DWORD size = GetCurrentDirectory(0U, NULL);
+ TCHAR* const buf = (TCHAR*)zix_calloc(allocator, size, sizeof(TCHAR));
if (buf && (GetCurrentDirectory(size, buf) != size - 1U)) {
zix_free(allocator, buf);
return NULL;
}
- return buf;
+ return path_result(allocator, buf);
}
diff --git a/src/win32/win32_util.c b/src/win32/win32_util.c
new file mode 100644
index 0000000..959867c
--- /dev/null
+++ b/src/win32/win32_util.c
@@ -0,0 +1,73 @@
+// Copyright 2019-2024 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "win32_util.h"
+
+#include <limits.h>
+#include <windows.h>
+
+#ifdef UNICODE
+
+ArgPathChar*
+arg_path_new(ZixAllocator* const allocator, const char* const path)
+{
+ return zix_utf8_to_wchar(allocator, path);
+}
+
+void
+arg_path_free(ZixAllocator* const allocator, ArgPathChar* const path)
+{
+ zix_free(allocator, path);
+}
+
+#else // !defined(UNICODE)
+
+ArgPathChar*
+arg_path_new(ZixAllocator* const allocator, const char* const path)
+{
+ (void)allocator;
+ return path;
+}
+
+void
+arg_path_free(ZixAllocator* const allocator, ArgPathChar* const path)
+{
+ (void)allocator;
+ (void)path;
+}
+
+#endif
+
+wchar_t*
+zix_utf8_to_wchar(ZixAllocator* const allocator, const char* const utf8)
+{
+ const int rc = utf8 ? MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0) : 0;
+ if (rc <= 0 || rc == INT_MAX) {
+ return NULL;
+ }
+
+ wchar_t* const result =
+ (wchar_t*)zix_calloc(allocator, (size_t)rc, sizeof(wchar_t));
+ if (result) {
+ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, rc);
+ }
+
+ return result;
+}
+
+char*
+zix_wchar_to_utf8(ZixAllocator* const allocator, const wchar_t* const wstr)
+{
+ const int rc =
+ wstr ? WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL) : 0;
+ if (rc <= 0 || rc == INT_MAX) {
+ return NULL;
+ }
+
+ char* const result = (char*)zix_calloc(allocator, (size_t)rc, sizeof(char));
+ if (result) {
+ WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, rc, NULL, NULL);
+ }
+
+ return result;
+}
diff --git a/src/win32/win32_util.h b/src/win32/win32_util.h
new file mode 100644
index 0000000..3123ef4
--- /dev/null
+++ b/src/win32/win32_util.h
@@ -0,0 +1,31 @@
+// Copyright 2019-2024 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#ifndef ZIX_WIN32_UTIL_H
+#define ZIX_WIN32_UTIL_H
+
+#include <zix/allocator.h>
+
+#ifdef UNICODE
+typedef wchar_t ArgPathChar;
+#else
+typedef const char ArgPathChar;
+#endif
+
+/// Copy and convert a path argument if necessary
+ArgPathChar*
+arg_path_new(ZixAllocator* const allocator, const char* const path);
+
+/// Free a path from arg_path_new() if necessary
+void
+arg_path_free(ZixAllocator* const allocator, ArgPathChar* const path);
+
+/// Convert from (user) UTF-8 to (Windows) UTF-16
+wchar_t*
+zix_utf8_to_wchar(ZixAllocator* allocator, const char* utf8);
+
+/// Convert from (Windows) UTF-16 to (user) UTF-8
+char*
+zix_wchar_to_utf8(ZixAllocator* allocator, const wchar_t* wstr);
+
+#endif // ZIX_WIN32_UTIL_H