Fix absolute and volume name checks on Windows

This commit is contained in:
gingerBill
2026-01-28 15:24:21 +00:00
parent db26fb8a21
commit 16881e256d
3 changed files with 58 additions and 20 deletions

View File

@@ -283,6 +283,10 @@ _is_absolute_path :: proc(path: string) -> bool {
if _is_reserved_name(path) {
return true
}
if len(path) > 0 && _is_path_separator(path[0]) {
return true
}
l := _volume_name_len(path)
if l == 0 {
return false

View File

@@ -49,35 +49,66 @@ volume_name_len :: proc(path: string) -> int {
if len(path) < 2 {
return 0
}
c := path[0]
if path[1] == ':' {
switch c {
switch path[0] {
case 'a'..='z', 'A'..='Z':
return 2
}
}
// URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
if l := len(path); l >= 5 && is_slash(path[0]) && is_slash(path[1]) &&
!is_slash(path[2]) && path[2] != '.' {
for n := 3; n < l-1; n += 1 {
if is_slash(path[n]) {
n += 1
if !is_slash(path[n]) {
if path[n] == '.' {
break
}
}
for ; n < l; n += 1 {
if is_slash(path[n]) {
break
}
}
return n
/*
See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
Further allowed paths can be of the form of:
- \\server\share or \\server\share\more\path
- \\?\C:\...
- \\.\PhysicalDriveX
*/
// Any remaining kind of path has to start with two slashes.
if !is_separator(path[0]) || !is_separator(path[1]) {
return 0
}
// Device path. The volume name is the whole string
if len(path) >= 5 && path[2] == '.' && is_separator(path[3]) {
return len(path)
}
// We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share`
prefix := 2
// File namespace.
if len(path) >= 5 && path[2] == '?' && is_separator(path[3]) {
if is_separator(path[4]) {
// `\\?\\` UNC path in file namespace
prefix = 5
}
if len(path) >= 6 && path[5] == ':' {
switch path[4] {
case 'a'..='z', 'A'..='Z':
return 6
case:
return 0
}
break
}
}
// UNC path, minimum version of the volume is `\\h\s` for host, share.
// Can also contain an IP address in the host position.
slash_count := 0
for i in prefix..<len(path) {
// Host needs to be at least 1 character
if is_separator(path[i]) && i > 0 {
slash_count += 1
if slash_count == 2 {
return i
}
}
}
return len(path)
}
return 0
}

View File

@@ -36,6 +36,9 @@ is_abs :: proc(path: string) -> bool {
if is_reserved_name(path) {
return true
}
if len(path) > 0 && is_slash(path[0]) {
return true
}
l := volume_name_len(path)
if l == 0 {
return false