Skip to content

Commit 67833df

Browse files
committed
fix: EntryMode canonicalization (#1259)
This means that `mode.kind()` and `mode.is_*` will also work correctly if the underlying mode wasn't canonicalized, which could happen when looking at trees that were stored with very old versions of Git.
1 parent eb6aa8f commit 67833df

File tree

2 files changed

+38
-15
lines changed

2 files changed

+38
-15
lines changed

gix-object/src/tree/mod.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,46 +72,50 @@ impl std::ops::Deref for EntryMode {
7272
}
7373
}
7474

75+
const IFMT: u16 = 0o170000;
76+
7577
impl EntryMode {
7678
/// Discretize the raw mode into an enum with well-known state while dropping unnecessary details.
7779
pub const fn kind(&self) -> EntryKind {
78-
match self.0 {
79-
0o40000 => EntryKind::Tree,
80-
0o120000 => EntryKind::Link,
81-
0o160000 => EntryKind::Commit,
82-
blob_mode => {
83-
if blob_mode & 0o000100 == 0o000100 {
84-
EntryKind::BlobExecutable
85-
} else {
86-
EntryKind::Blob
87-
}
80+
let etype = self.0 & IFMT;
81+
if etype == 0o100000 {
82+
if self.0 & 0o000100 == 0o000100 {
83+
EntryKind::BlobExecutable
84+
} else {
85+
EntryKind::Blob
8886
}
87+
} else if etype == EntryKind::Link as u16 {
88+
EntryKind::Link
89+
} else if etype == EntryKind::Tree as u16 {
90+
EntryKind::Tree
91+
} else {
92+
EntryKind::Commit
8993
}
9094
}
9195

9296
/// Return true if this entry mode represents a Tree/directory
9397
pub const fn is_tree(&self) -> bool {
94-
self.0 == EntryKind::Tree as u16
98+
self.0 & IFMT == EntryKind::Tree as u16
9599
}
96100

97101
/// Return true if this entry mode represents the commit of a submodule.
98102
pub const fn is_commit(&self) -> bool {
99-
self.0 == EntryKind::Commit as u16
103+
self.0 & IFMT == EntryKind::Commit as u16
100104
}
101105

102106
/// Return true if this entry mode represents a symbolic link
103107
pub const fn is_link(&self) -> bool {
104-
self.0 == EntryKind::Link as u16
108+
self.0 & IFMT == EntryKind::Link as u16
105109
}
106110

107111
/// Return true if this entry mode represents anything BUT Tree/directory
108112
pub const fn is_no_tree(&self) -> bool {
109-
self.0 != EntryKind::Tree as u16
113+
self.0 & IFMT != EntryKind::Tree as u16
110114
}
111115

112116
/// Return true if the entry is any kind of blob.
113117
pub const fn is_blob(&self) -> bool {
114-
matches!(self.kind(), EntryKind::Blob | EntryKind::BlobExecutable)
118+
self.0 & IFMT == 0o100000
115119
}
116120

117121
/// Return true if the entry is an executable blob.

gix-object/tests/tree/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,25 @@ mod entry_mode {
213213
);
214214
}
215215

216+
#[test]
217+
fn is_methods() {
218+
fn mode(kind: EntryKind) -> EntryMode {
219+
kind.into()
220+
}
221+
222+
assert!(mode(EntryKind::Blob).is_blob());
223+
assert!(!mode(EntryKind::Blob).is_link());
224+
assert!(mode(EntryKind::BlobExecutable).is_blob());
225+
assert!(mode(EntryKind::Blob).is_blob_or_symlink());
226+
assert!(mode(EntryKind::BlobExecutable).is_blob_or_symlink());
227+
228+
assert!(!mode(EntryKind::Link).is_blob());
229+
assert!(mode(EntryKind::Link).is_link());
230+
assert!(mode(EntryKind::Link).is_blob_or_symlink());
231+
assert!(mode(EntryKind::Tree).is_tree());
232+
assert!(mode(EntryKind::Commit).is_commit());
233+
}
234+
216235
#[test]
217236
fn as_bytes() {
218237
let mut buf = Default::default();

0 commit comments

Comments
 (0)