diff --git a/library/std/src/path.rs b/library/std/src/path.rs index caae8f924d2b1..2c140c1a14f40 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3109,7 +3109,7 @@ impl Hash for Path { bytes_hashed += to_hash.len(); } - // skip over separator and optionally a following CurDir item + // Skip over separators and, optionally, a following CurDir item // since components() would normalize these away. component_start = i + 1; @@ -3117,9 +3117,22 @@ impl Hash for Path { if !verbatim { component_start += match tail { + // At the end of the path, e.g. `foo/` + [] => 0, + // At the end of the path followed by a CurDir component, e.g. `foo/.` [b'.'] => 1, + // Followed by a CurDir component, another separator, and a component e.g. `foo/./bar` [b'.', sep @ _, ..] if is_sep_byte(*sep) => 1, - _ => 0, + // Followed by another separator and a component, e.g. `foo//bar` + [sep @ _, ..] if is_sep_byte(*sep) => 1, + // Otherwise, it's a separator followed by a new component, e.g. `foo/bar` + // and we should hash the separator to distinguish from `foobar` + _ => { + let to_hash = &[b'/' as u8]; + h.write(to_hash); + bytes_hashed += to_hash.len(); + 0 + } }; } } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 92702b395dfe1..87a06a9ea9153 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1545,6 +1545,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo//", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo///", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/.", "foo", eq: true, starts_with: true, @@ -1559,6 +1573,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo/.//bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo//./bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/bar", "foo", eq: false, starts_with: true, @@ -1566,6 +1594,13 @@ pub fn test_compare() { relative_from: Some("bar") ); + tc!("foo/bar", "foobar", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + tc!("foo/bar/baz", "foo/bar", eq: false, starts_with: true,