From 85d96fc85721557c8db7c7a5b2e48c2e5e97eac6 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 22 Oct 2026 10:18:22 +0200 Subject: [PATCH] Share UTF-8 Windows path conversion with file workers --- lib/file_io.c | 12 ++++++------ lib/file_io.h | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/file_io.c b/lib/file_io.c index f39496b5..21a05426 100644 --- a/lib/file_io.c +++ b/lib/file_io.c @@ -8,7 +8,7 @@ #ifdef _WIN32 /* Общие пути API — UTF-8; ANSI Win32 API не применяется. */ -static int file_wide(const char *path, wchar_t wide[FILE_IO_PATH_MAX]) { +int file_io_wide(const char *path, wchar_t wide[FILE_IO_PATH_MAX]) { if (path && *path && strlen(path) < FILE_IO_PATH_MAX && MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, wide, FILE_IO_PATH_MAX)) return 0; DEBUG_ERROR(DEBUG_CATEGORY_SYS, "file invalid UTF-8/oversized path winerr=%lu", GetLastError()); @@ -23,7 +23,7 @@ int file_io_inspect(const char *path, int follow, struct file_io_info *info) { struct file_io_info result = {0}; #ifdef _WIN32 wchar_t wide[FILE_IO_PATH_MAX]; - if (file_wide(path, wide)) return -1; + if (file_io_wide(path, wide)) return -1; DWORD attributes = GetFileAttributesW(wide); if (attributes == INVALID_FILE_ATTRIBUTES) { DWORD error = GetLastError(); @@ -74,7 +74,7 @@ FILE *file_io_open_read(const char *path) { } #ifdef _WIN32 wchar_t wide[FILE_IO_PATH_MAX]; - if (file_wide(path, wide)) return NULL; + if (file_io_wide(path, wide)) return NULL; FILE *file = _wfopen(wide, L"rb"); #else FILE *file = fopen(path, "rb"); @@ -109,7 +109,7 @@ int file_io_temp_open(struct file_io_temp *output, const char *destination) { snprintf(output->temporary, sizeof(output->temporary), "%s.tmp.%s", destination, suffix); #ifdef _WIN32 wchar_t wide[FILE_IO_PATH_MAX]; - if (file_wide(output->temporary, wide)) { output->temporary[0] = 0; return -1; } + if (file_io_wide(output->temporary, wide)) { output->temporary[0] = 0; return -1; } int fd = _wopen(wide, _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE); #else int fd = open(output->temporary, O_CREAT | O_EXCL | O_RDWR, 0600); @@ -151,7 +151,7 @@ void file_io_temp_discard(struct file_io_temp *output) { if (!output->temporary[0]) return; #ifdef _WIN32 wchar_t wide[FILE_IO_PATH_MAX]; - int error = file_wide(output->temporary, wide) ? -1 : _wremove(wide); + int error = file_io_wide(output->temporary, wide) ? -1 : _wremove(wide); #else int error = remove(output->temporary); #endif @@ -165,7 +165,7 @@ int file_io_temp_publish(struct file_io_temp *output, const char *source, const } #ifdef _WIN32 wchar_t from[FILE_IO_PATH_MAX], to[FILE_IO_PATH_MAX]; - if (file_wide(output->temporary, from) || file_wide(destination, to)) return -1; + if (file_io_wide(output->temporary, from) || file_io_wide(destination, to)) return -1; if (!MoveFileExW(from, to, MOVEFILE_REPLACE_EXISTING)) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "file publish failed destination=%s winerr=%lu", destination, GetLastError()); return -1; } diff --git a/lib/file_io.h b/lib/file_io.h index f27f3fc5..1ecd1a3a 100644 --- a/lib/file_io.h +++ b/lib/file_io.h @@ -7,6 +7,7 @@ #define FILE_IO_H #include #include +#include #define FILE_IO_PATH_MAX 4096 enum file_io_type { FILE_IO_REGULAR = 1, FILE_IO_DIRECTORY, FILE_IO_LINK, FILE_IO_OTHER }; @@ -22,6 +23,10 @@ struct file_io_temp { // path — UTF-8; follow!=0 разрешает конечную ссылку. info обязателен, заполняется только при успехе. int file_io_inspect(const char *path, int follow, struct file_io_info *info); +#ifdef _WIN32 +// Преобразовать непустой UTF-8 путь в wide[FILE_IO_PATH_MAX]; 0/-1. +int file_io_wide(const char *path, wchar_t wide[FILE_IO_PATH_MAX]); +#endif // Открыть обычный файл для чтения; путь UTF-8. NULL при ошибке, fclose принадлежит вызывающему. FILE *file_io_open_read(const char *path); // Источник должен быть regular; назначение отсутствует или regular без конечной ссылки. 1 — один файл, 0 — разные, -1 — ошибка.