Skip to content

Some Windows paths fail to .absolutize() #61

@dlenski

Description

@dlenski

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:

  1. \\some.server or \\some.server\share: .is_absolute() is false, but .has_root() is true. Calling .absolutize() returns the path unmodified.
  2. "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:

  1. \\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()

  2. 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!();
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions