summaryrefslogtreecommitdiffstats
path: root/src/win32
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32')
-rw-r--r--src/win32/environment_win32.c37
-rw-r--r--src/win32/filesystem_win32.c298
-rw-r--r--src/win32/sem_win32.c4
-rw-r--r--src/win32/thread_win32.c4
-rw-r--r--src/win32/win32_util.c73
-rw-r--r--src/win32/win32_util.h31
6 files changed, 378 insertions, 69 deletions
diff --git a/src/win32/environment_win32.c b/src/win32/environment_win32.c
new file mode 100644
index 0000000..ce5f00e
--- /dev/null
+++ b/src/win32/environment_win32.c
@@ -0,0 +1,37 @@
+// Copyright 2012-2024 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "win32_util.h"
+
+#include <zix/environment.h>
+
+#include <windows.h>
+
+char*
+zix_expand_environment_strings(ZixAllocator* const allocator,
+ const char* const string)
+{
+ ArgPathChar* const wstring = arg_path_new(allocator, string);
+
+ const DWORD size = ExpandEnvironmentStrings(wstring, NULL, 0U);
+ if (!size) {
+ arg_path_free(allocator, wstring);
+ return NULL;
+ }
+
+ TCHAR* const out =
+ (TCHAR*)zix_calloc(allocator, (size_t)size + 1U, sizeof(TCHAR));
+ if (out) {
+ 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 5dc36a8..fa40cde 100644
--- a/src/win32/filesystem_win32.c
+++ b/src/win32/filesystem_win32.c
@@ -1,21 +1,22 @@
-// Copyright 2007-2022 David Robillard <d@drobilla.net>
+// Copyright 2007-2024 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
-#include "zix/bump_allocator.h"
-#include "zix/filesystem.h"
+#include <zix/filesystem.h>
#include "../errno_status.h"
#include "../zix_config.h"
+#include "win32_util.h"
-#include "zix/allocator.h"
-#include "zix/path.h"
-#include "zix/status.h"
+#include <zix/allocator.h>
+#include <zix/path.h>
+#include <zix/status.h>
#include <direct.h>
#include <fcntl.h>
#include <io.h>
#include <limits.h>
#include <sys/stat.h>
+#include <tchar.h>
#include <windows.h>
#include <errno.h>
@@ -25,6 +26,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 +96,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
@@ -111,7 +147,7 @@ zix_create_temporary_directory(ZixAllocator* const allocator,
suffix[i] = chars[seed % n_chars];
}
- if (!_mkdir(result)) {
+ if (!zix_create_directory(result)) {
return result;
}
}
@@ -123,22 +159,44 @@ zix_create_temporary_directory(ZixAllocator* const allocator,
ZixStatus
zix_remove(const char* const path)
{
- return ((zix_file_type(path) == ZIX_FILE_TYPE_DIRECTORY)
- ? zix_windows_status(RemoveDirectory(path))
- : remove(path) ? zix_errno_status(errno)
- : ZIX_STATUS_SUCCESS);
+ 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
-zix_dir_for_each(const char* const path,
- void* const data,
- void (*const f)(const char* path,
- const char* name,
- void* data))
+zix_dir_for_each(const char* const path,
+ void* const data,
+ const ZixDirEntryVisitFunc f)
{
+ 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';
@@ -147,8 +205,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));
}
@@ -158,6 +222,12 @@ zix_dir_for_each(const char* const path,
ZixStatus
zix_file_lock(FILE* const file, const ZixFileLockMode mode)
{
+#ifdef __clang__
+ (void)file;
+ (void)mode;
+ return ZIX_STATUS_NOT_SUPPORTED;
+#else
+
HANDLE handle = (HANDLE)_get_osfhandle(fileno(file));
OVERLAPPED overlapped = {0};
@@ -167,58 +237,112 @@ zix_file_lock(FILE* const file, const ZixFileLockMode mode)
return zix_windows_status(
LockFileEx(handle, flags, 0, UINT32_MAX, UINT32_MAX, &overlapped));
+#endif
}
ZixStatus
zix_file_unlock(FILE* const file, const ZixFileLockMode mode)
{
(void)mode;
+#ifdef __clang__
+ (void)file;
+ return ZIX_STATUS_NOT_SUPPORTED;
+#else
HANDLE handle = (HANDLE)_get_osfhandle(fileno(file));
OVERLAPPED overlapped = {0};
return zix_windows_status(
UnlockFileEx(handle, 0, UINT32_MAX, UINT32_MAX, &overlapped));
+#endif
}
+#if USE_GETFINALPATHNAMEBYHANDLE && USE_CREATEFILE2
+
+static HANDLE
+open_attribute_handle(const char* const path)
+{
+ wchar_t* const wpath = zix_utf8_to_wchar(NULL, path);
+
+ CREATEFILE2_EXTENDED_PARAMETERS params = {
+ sizeof(CREATEFILE2_EXTENDED_PARAMETERS),
+ 0U,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ 0U,
+ NULL,
+ NULL};
+
+ const HANDLE handle =
+ CreateFile2(wpath, FILE_READ_ATTRIBUTES, 0U, OPEN_EXISTING, &params);
+
+ zix_free(NULL, wpath);
+ return handle;
+}
+
+#elif USE_GETFINALPATHNAMEBYHANDLE
+
+static HANDLE
+open_attribute_handle(const char* const path)
+{
+ ArgPathChar* const wpath = arg_path_new(NULL, path);
+
+ const HANDLE handle = CreateFile(wpath,
+ FILE_READ_ATTRIBUTES,
+ 0U,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ arg_path_free(NULL, wpath);
+ return handle;
+}
+
+#endif
+
char*
zix_canonical_path(ZixAllocator* const allocator, const char* const path)
{
- char full[MAX_PATH] = {0};
- if (!path || !GetFullPathName(path, MAX_PATH, full, NULL)) {
+ if (!path) {
return NULL;
}
- const HANDLE h =
- CreateFile(full,
- FILE_READ_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
-
- const DWORD flags = FILE_NAME_NORMALIZED | VOLUME_NAME_DOS;
- const DWORD final_size = GetFinalPathNameByHandle(h, NULL, 0U, flags);
- if (!final_size) {
- CloseHandle(h);
- return NULL;
+#if USE_GETFINALPATHNAMEBYHANDLE // Vista+
+
+ const HANDLE h = open_attribute_handle(path);
+ 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);
+ }
+ }
}
- char* const final = (char*)zix_calloc(allocator, final_size + 1U, 1U);
- if (!final || !GetFinalPathNameByHandle(h, final, final_size + 1U, flags)) {
- zix_free(allocator, final);
- CloseHandle(h);
- return NULL;
+ CloseHandle(h);
+ return path_result(allocator, final);
+
+#else // Fall back to "full path iff it exists" for older Windows
+
+ ArgPathChar* const wpath = arg_path_new(allocator, path);
+ TCHAR* full = 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(wpath, length + 1U, full, NULL);
+ }
+ }
}
- if (final_size > 4U && !strncmp(final, "\\\\?\\", 4)) {
- memmove(final, final + 4U, final_size - 4U);
- final[final_size - 4U] = '\0';
- }
+ arg_path_free(allocator, wpath);
+ return path_result(allocator, full);
- CloseHandle(h);
- return final;
+#endif
}
static ZixFileType
@@ -246,30 +370,44 @@ 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;
}
// Resolve symlink to find the canonical type
- 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);
+ char* const canonical = zix_canonical_path(NULL, path);
+ const ZixFileType real_type =
+ canonical ? zix_symlink_type(canonical) : ZIX_FILE_TYPE_NONE;
+
+ zix_free(NULL, canonical);
+ return real_type;
}
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
- : _mkdir(dir_path) ? zix_errno_status(errno)
- : ZIX_STATUS_SUCCESS;
+ 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
@@ -287,7 +425,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;
@@ -303,7 +449,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;
@@ -314,31 +468,45 @@ zix_create_directory_symlink(const char* const target_path,
ZixStatus
zix_create_hard_link(const char* const target_path, const char* const link_path)
{
- return zix_windows_status(CreateHardLink(link_path, target_path, NULL));
+#if USE_CREATEHARDLINK
+ 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;
+ return ZIX_STATUS_NOT_SUPPORTED;
+#endif
}
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/sem_win32.c b/src/win32/sem_win32.c
index 979390e..d28f39f 100644
--- a/src/win32/sem_win32.c
+++ b/src/win32/sem_win32.c
@@ -1,9 +1,9 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
-#include "zix/sem.h"
+#include <zix/sem.h>
-#include "zix/status.h"
+#include <zix/status.h>
#include <windows.h>
diff --git a/src/win32/thread_win32.c b/src/win32/thread_win32.c
index e4411b1..dbfe026 100644
--- a/src/win32/thread_win32.c
+++ b/src/win32/thread_win32.c
@@ -1,9 +1,9 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
-#include "zix/thread.h"
+#include <zix/thread.h>
-#include "zix/status.h"
+#include <zix/status.h>
#include <windows.h>
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..3ae2e2b
--- /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* allocator, const char* path);
+
+/// Free a path from arg_path_new() if necessary
+void
+arg_path_free(ZixAllocator* allocator, ArgPathChar* 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