From 00bca89bfc4220191997de6c61225e90c5330225 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 06:17:21 +0300 Subject: [PATCH] os: fix prebuild release and manual installation crash on windows (fixes #19466) --- v_make.bat | 4 +++- vlib/os/filepath_test.v | 10 ++++++++++ vlib/os/filepath_windows.v | 20 ++++++++++++++++++++ vlib/os/os.c.v | 2 +- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/v_make.bat b/v_make.bat index 489b165c4..76685a9f9 100644 --- a/v_make.bat +++ b/v_make.bat @@ -16,6 +16,8 @@ set V_BOOTSTRAP=./v_win_bootstrap.exe set V_OLD=./v_old.exe set V_UPDATED=./v_up.exe set V_C_FILE=./vc/v_win.c +set where_exe=where.exe +if not ["%SystemRoot%"] == [""] if exist "%SystemRoot%\System32\where.exe" set where_exe=%SystemRoot%\System32\where.exe REM TCC variables set tcc_url=https://github.com/vlang/tccbin @@ -150,7 +152,7 @@ call :move_updated_to_v goto :success :clang_strap -where /q clang +"%where_exe%" /q clang if %ERRORLEVEL% NEQ 0 ( echo ^> Clang not found if not [!compiler!] == [] goto :error diff --git a/vlib/os/filepath_test.v b/vlib/os/filepath_test.v index 1769739de..ddf0eb93f 100644 --- a/vlib/os/filepath_test.v +++ b/vlib/os/filepath_test.v @@ -185,3 +185,13 @@ fn test_windows_volume() { assert windows_volume('/') == '' } } + +fn test_trim_extended_length_path_prefix() { + $if windows { + assert trim_extended_length_path_prefix(r'\\?\C:\path\to\file.v') == r'C:\path\to\file.v' + assert trim_extended_length_path_prefix(r'\\?\UNC\host\share\file.v') == r'\\host\share\file.v' + assert trim_extended_length_path_prefix(r'\\?\Volume{01234567-89ab-cdef-0123-456789abcdef}\file.v') == r'\\?\Volume{01234567-89ab-cdef-0123-456789abcdef}\file.v' + assert trim_extended_length_path_prefix(r'C:\path\to\file.v') == r'C:\path\to\file.v' + assert trim_extended_length_path_prefix('') == '' + } +} diff --git a/vlib/os/filepath_windows.v b/vlib/os/filepath_windows.v index 776c8f3bc..fd6173be2 100644 --- a/vlib/os/filepath_windows.v +++ b/vlib/os/filepath_windows.v @@ -15,3 +15,23 @@ pub fn windows_volume(path string) string { } return path[..volume_len] } + +// trim_extended_length_path_prefix converts Win32 extended-length DOS/UNC +// paths returned by APIs like GetFinalPathNameByHandleW into regular paths. +// Paths that are not standard DOS or UNC paths are left unchanged. +fn trim_extended_length_path_prefix(path string) string { + $if !windows { + return path + } + if path.len < 4 || !starts_w_slash_slash(path) || path[2] != qmark || !is_slash(path[3]) { + return path + } + if path.len >= 8 && (path[4] == `U` || path[4] == `u`) && (path[5] == `N` || path[5] == `n`) + && (path[6] == `C` || path[6] == `c`) && is_slash(path[7]) { + return '\\\\' + path[8..] + } + if path.len >= 7 && path[4].is_letter() && path[5] == `:` && is_slash(path[6]) { + return path[4..] + } + return path +} diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 13ffd4d0e..d496a604c 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -974,7 +974,7 @@ pub fn real_path(fpath string) string { return fpath.clone() } unsafe { res.free() } - res = unsafe { string_from_wide(pu16_fullpath) } + res = normalize_windows_extended_path_prefix(unsafe { string_from_wide(pu16_fullpath) }) } } $else { ret := &char(C.realpath(&char(fpath.str), &char(&fullpath[0]))) -- 2.39.5