From 55bc9f0f2f7886e0196cb7054bc0321b45ca353f Mon Sep 17 00:00:00 2001 From: hamodywe Date: Sun, 9 Aug 2026 01:08:28 +0300 Subject: [PATCH] Fix "invalid path" error for UNC paths on Windows resolve_path() only handled Prefix::Disk and Prefix::VerbatimDisk when initializing the path root on Windows, so any UNC path (\server\share, or its \?\UNC\server\share verbatim form) fell through to the catch-all branch and errored with "invalid path", even though the path itself was perfectly valid. This broke zoxide entirely for anyone whose directories live on a network share. Add a Prefix::UNC / Prefix::VerbatimUNC arm that builds the \server\share root the same way the Disk arms build their drive root, and add resolve_path unit tests covering UNC, verbatim UNC, and a disk-path regression check. Fixes #331 --- src/util.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/util.rs b/src/util.rs index 4c0a27c..4268abb 100644 --- a/src/util.rs +++ b/src/util.rs @@ -332,6 +332,18 @@ pub fn resolve_path(path: impl AsRef) -> Result { base_path = get_drive_path(drive_letter); stack.extend(base_path.components()); } + Prefix::UNC(server, share) | Prefix::VerbatimUNC(server, share) => { + let server = server.to_string_lossy(); + let share = share.to_string_lossy(); + + components.next(); + if components.peek() == Some(&Component::RootDir) { + components.next(); + } + + base_path = format!(r"\\{server}\{share}").into(); + stack.extend(base_path.components()); + } _ => bail!("invalid path: {}", path.display()), }, Some(Component::RootDir) => { @@ -378,3 +390,36 @@ pub fn to_lowercase(s: impl AsRef) -> String { let s = s.as_ref(); if s.is_ascii() { s.to_ascii_lowercase() } else { s.to_lowercase() } } + +#[cfg(all(test, windows))] +mod tests { + use super::*; + + #[test] + fn resolve_path_unc() { + let resolved = resolve_path(r"\\a.network-drive\a-folder").unwrap(); + assert_eq!(resolved, PathBuf::from(r"\\a.network-drive\a-folder")); + } + + #[test] + fn resolve_path_unc_with_subdirs() { + let resolved = resolve_path(r"\\a.network-drive\a-folder\subdir\nested").unwrap(); + assert_eq!(resolved, PathBuf::from(r"\\a.network-drive\a-folder\subdir\nested")); + } + + #[test] + fn resolve_path_verbatim_unc() { + // `\\?\UNC\server\share\...` is the verbatim form Windows APIs produce + // for UNC paths (e.g. via `dunce`/`canonicalize` on paths that were + // already long-path-prefixed). It should resolve to the same + // non-verbatim form as a plain UNC path. + let resolved = resolve_path(r"\\?\UNC\a.network-drive\a-folder\subdir").unwrap(); + assert_eq!(resolved, PathBuf::from(r"\\a.network-drive\a-folder\subdir")); + } + + #[test] + fn resolve_path_disk() { + let resolved = resolve_path(r"C:\Users\test").unwrap(); + assert_eq!(resolved, PathBuf::from(r"C:\Users\test")); + } +}