Based on its API (returns std::io::Result), I assumed that the absolutize() method should either convert a non-absolute path to an absolute path, or return a std::io::Error.
With UnixPath, this appears to hold in 100% of cases.
However, with WindowsPath, there are some exceptions: paths which are not absolute, and are neither transformed into absolute paths by absolutize()… but also don't return errors.
What I've found:
\\some.server or \\some.server\share: .is_absolute() is false, but .has_root() is true. Calling .absolutize() returns the path unmodified.
"C:" or "C:whatever" (same for any other drive letter): Windows kinda-sorta has a separate cwd for each drive (a legacy of MS-DOS), but typed-path doesn't seem to use this. Both .is_absolute() and .has_root() are false, and calling .absolutize() returns the path unmodified.
What I think should happen for these:
-
\\some.server\share should be considered equivalent to \\some.server\share\, with .is_absolute() being true regardless of whether or not the final \ is included. In the same way that C:\whatever and C:\whatever\ are equivalent when .joining or .pushing further path components.
On the other hand, \\some.server should return an error when calling .absolutize()
-
A few possibilities:
- Use
GetFullPathNameW to get the per-drive cwd, and use that to absolutize the path…
- Or it should return an error, something like
std::io::Error::other("cannot absolutize a Windows drive without a following backslash")…
- Or it should just ignore this ancient legacy behavior, and insert the backslash (treating
C:foo as equivalent to C:\foo)
#[test]
fn windows_path_absolutize_problem() {
for p in vec!["C:", "D:whatever"] {
let p = WindowsPath::new(p);
let ap = p.absolutize();
if let Ok(ap) = ap {
assert!(!ap.is_absolute() && !ap.has_root());
assert_eq!(ap.as_path(), p);
} else {
panic!();
}
}
for p in vec![r"\\server.com", r"\\server.com\share"] {
let p = WindowsPath::new(p);
let ap = p.absolutize();
if let Ok(ap) = ap {
assert!(!ap.is_absolute() && ap.has_root());
assert_eq!(ap.as_path(), p);
} else {
panic!();
}
}
}
Based on its API (returns
std::io::Result), I assumed that theabsolutize()method should either convert a non-absolute path to an absolute path, or return astd::io::Error.With
UnixPath, this appears to hold in 100% of cases.However, with
WindowsPath, there are some exceptions: paths which are not absolute, and are neither transformed into absolute paths byabsolutize()… but also don't return errors.What I've found:
\\some.serveror\\some.server\share:.is_absolute()isfalse, but.has_root()istrue. Calling.absolutize()returns the path unmodified."C:"or"C:whatever"(same for any other drive letter): Windows kinda-sorta has a separate cwd for each drive (a legacy of MS-DOS), but typed-path doesn't seem to use this. Both.is_absolute()and.has_root()arefalse, and calling.absolutize()returns the path unmodified.What I think should happen for these:
\\some.server\shareshould be considered equivalent to\\some.server\share\, with.is_absolute()beingtrueregardless of whether or not the final\is included. In the same way thatC:\whateverandC:\whatever\are equivalent when.joining or.pushing further path components.On the other hand,
\\some.servershould return an error when calling.absolutize()A few possibilities:
GetFullPathNameWto get the per-drive cwd, and use that to absolutize the path…std::io::Error::other("cannot absolutize a Windows drive without a following backslash")…C:fooas equivalent toC:\foo)