From 77005950f09d2f9ba54962bf5adc3f2bc3a7213f Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 25 Nov 2022 17:47:00 +0100 Subject: [PATCH 1/4] Implement masking in FileType comparison on Unix Fixes: https://github.com/rust-lang/rust/issues/104900 --- library/std/src/sys/unix/fs.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 37a49f2d78acd..382204d689318 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -332,11 +332,16 @@ pub struct FileTimes { modified: Option, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, Eq, Hash, Debug)] pub struct FileType { mode: mode_t, } +impl PartialEq for FileType { + fn eq(&self, other: &Self) -> bool { + self.masked() == other.masked() + } +} #[derive(Debug)] pub struct DirBuilder { mode: mode_t, @@ -550,6 +555,10 @@ impl FileType { pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } + + fn masked(&self) -> mode_t { + self.mode & libc::S_IFMT + } } impl FromInner for FilePermissions { From 62590288621fe9c1fd9b379ed613538f7225f3eb Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Wed, 30 Nov 2022 23:31:42 +0100 Subject: [PATCH 2/4] Add test for regression for FileType equality Cf: https://github.com/rust-lang/rust/issues/104900 --- library/std/src/fs/tests.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index b8959316de170..4748ac9d97ef8 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1551,3 +1551,19 @@ fn hiberfil_sys() { fs::metadata(hiberfil).unwrap(); assert_eq!(true, hiberfil.exists()); } + +/// Test that two different ways of obtaining the FileType give the same result. +/// Cf. https://github.com/rust-lang/rust/issues/104900 +#[test] +fn test_eq_direntry_metadata() { + let tmpdir = tmpdir(); + let file_path = tmpdir.join("file"); + File::create(file_path).unwrap(); + for e in fs::read_dir(tmpdir.path()).unwrap() { + let e = e.unwrap(); + let p = e.path(); + let ft1 = e.file_type().unwrap(); + let ft2 = p.metadata().unwrap().file_type(); + assert_eq!(ft1, ft2); + } +} From 4198d2975dd24322515f8894a3ac06e342aad183 Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Tue, 6 Dec 2022 10:35:34 +0100 Subject: [PATCH 3/4] Implement masking in FileType hashing on Unix Commit 77005950f09d2f9ba54962bf5adc3f2bc3a7213f implemented masking of FileType to fix an issue[^1] in the semantic of FileType comparison. This commit introduces masking to Hash to maintain the invariant that x == y => hash(x) == hash(y). [^1]: https://github.com/rust-lang/rust/issues/104900 --- library/std/src/sys/unix/fs.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 382204d689318..e464388069059 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -332,7 +332,7 @@ pub struct FileTimes { modified: Option, } -#[derive(Copy, Clone, Eq, Hash, Debug)] +#[derive(Copy, Clone, Eq, Debug)] pub struct FileType { mode: mode_t, } @@ -342,6 +342,13 @@ impl PartialEq for FileType { self.masked() == other.masked() } } + +impl core::hash::Hash for FileType { + fn hash(&self, state: &mut H) { + self.masked().hash(state); + } +} + #[derive(Debug)] pub struct DirBuilder { mode: mode_t, From 24cd863a3815f7ae7828c9f161a0b3f863218106 Mon Sep 17 00:00:00 2001 From: Arthur Carcano Date: Fri, 9 Dec 2022 15:04:36 +0100 Subject: [PATCH 4/4] Replace hand-made masking by call to masked() method in FileType --- library/std/src/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index e464388069059..fb8d06c66820c 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -560,7 +560,7 @@ impl FileType { } pub fn is(&self, mode: mode_t) -> bool { - self.mode & libc::S_IFMT == mode + self.masked() == mode } fn masked(&self) -> mode_t {