aboutsummaryrefslogtreecommitdiff
path: root/core/path/filepath
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2026-01-28 15:24:21 +0000
committergingerBill <gingerBill@users.noreply.github.com>2026-01-28 15:24:21 +0000
commit16881e256d5512024dfc85eea2c324cc4241bd99 (patch)
treeb7932bc20760f5d84583201d1ad49a43bfe88de3 /core/path/filepath
parentdb26fb8a216982a4cf7bb7f992e1cf92ad856a02 (diff)
Fix absolute and volume name checks on Windows
Diffstat (limited to 'core/path/filepath')
-rw-r--r--core/path/filepath/path.odin71
-rw-r--r--core/path/filepath/path_windows.odin3
2 files changed, 54 insertions, 20 deletions
diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin
index 14a9181c3..d5ba76342 100644
--- a/core/path/filepath/path.odin
+++ b/core/path/filepath/path.odin
@@ -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
}
diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin
index b3f4eee9e..d7549a42c 100644
--- a/core/path/filepath/path_windows.odin
+++ b/core/path/filepath/path_windows.odin
@@ -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