Fix hashing for windows paths containing a CurDir component
* the logic only checked for / but not for \ * verbatim paths shouldn't skip items at all since they don't get normalized * the extra branches get optimized out on unix since is_sep_byte is a trivial comparison and is_verbatim is always-false * tests lacked windows coverage for these cases That lead to equal paths not having equal hashes and to unnecessary collisions.
This commit is contained in:
parent
686663a49e
commit
45082b077b
2 changed files with 52 additions and 9 deletions
|
@ -2920,12 +2920,12 @@ impl cmp::PartialEq for Path {
|
||||||
impl Hash for Path {
|
impl Hash for Path {
|
||||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||||
let bytes = self.as_u8_slice();
|
let bytes = self.as_u8_slice();
|
||||||
let prefix_len = match parse_prefix(&self.inner) {
|
let (prefix_len, verbatim) = match parse_prefix(&self.inner) {
|
||||||
Some(prefix) => {
|
Some(prefix) => {
|
||||||
prefix.hash(h);
|
prefix.hash(h);
|
||||||
prefix.len()
|
(prefix.len(), prefix.is_verbatim())
|
||||||
}
|
}
|
||||||
None => 0,
|
None => (0, false),
|
||||||
};
|
};
|
||||||
let bytes = &bytes[prefix_len..];
|
let bytes = &bytes[prefix_len..];
|
||||||
|
|
||||||
|
@ -2933,7 +2933,8 @@ impl Hash for Path {
|
||||||
let mut bytes_hashed = 0;
|
let mut bytes_hashed = 0;
|
||||||
|
|
||||||
for i in 0..bytes.len() {
|
for i in 0..bytes.len() {
|
||||||
if is_sep_byte(bytes[i]) {
|
let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
|
||||||
|
if is_sep {
|
||||||
if i > component_start {
|
if i > component_start {
|
||||||
let to_hash = &bytes[component_start..i];
|
let to_hash = &bytes[component_start..i];
|
||||||
h.write(to_hash);
|
h.write(to_hash);
|
||||||
|
@ -2941,13 +2942,20 @@ impl Hash for Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip over separator and optionally a following CurDir item
|
// skip over separator and optionally a following CurDir item
|
||||||
// since components() would normalize these away
|
// since components() would normalize these away.
|
||||||
component_start = i + match bytes[i..] {
|
component_start = i + 1;
|
||||||
[_, b'.', b'/', ..] | [_, b'.'] => 2,
|
|
||||||
_ => 1,
|
let tail = &bytes[component_start..];
|
||||||
|
|
||||||
|
if !verbatim {
|
||||||
|
component_start += match tail {
|
||||||
|
[b'.'] => 1,
|
||||||
|
[b'.', sep @ _, ..] if is_sep_byte(*sep) => 1,
|
||||||
|
_ => 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if component_start < bytes.len() {
|
if component_start < bytes.len() {
|
||||||
let to_hash = &bytes[component_start..];
|
let to_hash = &bytes[component_start..];
|
||||||
|
|
|
@ -1498,6 +1498,20 @@ pub fn test_compare() {
|
||||||
relative_from: Some("")
|
relative_from: Some("")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
tc!("foo/.", "foo",
|
||||||
|
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",
|
tc!("foo/bar", "foo",
|
||||||
eq: false,
|
eq: false,
|
||||||
starts_with: true,
|
starts_with: true,
|
||||||
|
@ -1541,6 +1555,27 @@ pub fn test_compare() {
|
||||||
ends_with: true,
|
ends_with: true,
|
||||||
relative_from: Some("")
|
relative_from: Some("")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
tc!(r"C:\foo\.\bar.txt", r"C:\foo\bar.txt",
|
||||||
|
eq: true,
|
||||||
|
starts_with: true,
|
||||||
|
ends_with: true,
|
||||||
|
relative_from: Some("")
|
||||||
|
);
|
||||||
|
|
||||||
|
tc!(r"C:\foo\.", r"C:\foo",
|
||||||
|
eq: true,
|
||||||
|
starts_with: true,
|
||||||
|
ends_with: true,
|
||||||
|
relative_from: Some("")
|
||||||
|
);
|
||||||
|
|
||||||
|
tc!(r"\\?\C:\foo\.\bar.txt", r"\\?\C:\foo\bar.txt",
|
||||||
|
eq: false,
|
||||||
|
starts_with: false,
|
||||||
|
ends_with: false,
|
||||||
|
relative_from: None
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue