Rollup merge of #138671 - ChrisDenton:filetype, r=joshtriplett
Fix `FileType` `PartialEq` implementation on Windows Fixes #138668 On Windows the [`FileType`](https://doc.rust-lang.org/stable/std/fs/struct.FileType.html) struct was deriving `PartialEq` which in turn means it was doing a bit-for-bit comparison on the file attributes and reparse point. This is wrong because `attributes` may contain many things unrelated to file type. `FileType` on Windows allows for four possible combinations (see also [`FileTypeExt`](https://doc.rust-lang.org/stable/std/os/windows/fs/trait.FileTypeExt.html)): `file`, `dir`, `symlink_file` and `symlink_dir`. So the new implementation makes sure both symlink and directory information match (and only those things). This could be considered just a bug fix but it is a behaviour change so someone from libs-api might want to FCP this (or might not)...
This commit is contained in:
commit
8e30df7f26
2 changed files with 32 additions and 18 deletions
|
@ -1719,6 +1719,23 @@ fn test_eq_direntry_metadata() {
|
|||
}
|
||||
}
|
||||
|
||||
/// Test that windows file type equality is not affected by attributes unrelated
|
||||
/// to the file type.
|
||||
#[test]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn test_eq_windows_file_type() {
|
||||
let tmpdir = tmpdir();
|
||||
let file1 = File::create(tmpdir.join("file1")).unwrap();
|
||||
let file2 = File::create(tmpdir.join("file2")).unwrap();
|
||||
assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type());
|
||||
|
||||
// Change the readonly attribute of one file.
|
||||
let mut perms = file1.metadata().unwrap().permissions();
|
||||
perms.set_readonly(true);
|
||||
file1.set_permissions(perms).unwrap();
|
||||
assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type());
|
||||
}
|
||||
|
||||
/// Regression test for https://github.com/rust-lang/rust/issues/50619.
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
|
|
|
@ -41,8 +41,8 @@ pub struct FileAttr {
|
|||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct FileType {
|
||||
attributes: u32,
|
||||
reparse_tag: u32,
|
||||
is_directory: bool,
|
||||
is_symlink: bool,
|
||||
}
|
||||
|
||||
pub struct ReadDir {
|
||||
|
@ -1111,32 +1111,29 @@ impl FileTimes {
|
|||
}
|
||||
|
||||
impl FileType {
|
||||
fn new(attrs: u32, reparse_tag: u32) -> FileType {
|
||||
FileType { attributes: attrs, reparse_tag }
|
||||
fn new(attributes: u32, reparse_tag: u32) -> FileType {
|
||||
let is_directory = attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0;
|
||||
let is_symlink = {
|
||||
let is_reparse_point = attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0;
|
||||
let is_reparse_tag_name_surrogate = reparse_tag & 0x20000000 != 0;
|
||||
is_reparse_point && is_reparse_tag_name_surrogate
|
||||
};
|
||||
FileType { is_directory, is_symlink }
|
||||
}
|
||||
pub fn is_dir(&self) -> bool {
|
||||
!self.is_symlink() && self.is_directory()
|
||||
!self.is_symlink && self.is_directory
|
||||
}
|
||||
pub fn is_file(&self) -> bool {
|
||||
!self.is_symlink() && !self.is_directory()
|
||||
!self.is_symlink && !self.is_directory
|
||||
}
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
self.is_reparse_point() && self.is_reparse_tag_name_surrogate()
|
||||
self.is_symlink
|
||||
}
|
||||
pub fn is_symlink_dir(&self) -> bool {
|
||||
self.is_symlink() && self.is_directory()
|
||||
self.is_symlink && self.is_directory
|
||||
}
|
||||
pub fn is_symlink_file(&self) -> bool {
|
||||
self.is_symlink() && !self.is_directory()
|
||||
}
|
||||
fn is_directory(&self) -> bool {
|
||||
self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0
|
||||
}
|
||||
fn is_reparse_point(&self) -> bool {
|
||||
self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0
|
||||
}
|
||||
fn is_reparse_tag_name_surrogate(&self) -> bool {
|
||||
self.reparse_tag & 0x20000000 != 0
|
||||
self.is_symlink && !self.is_directory
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue