Nothing to see here, move along meow
1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub struct FsRights(u16);
3
4impl FsRights {
5 pub const READ: Self = Self(0x01);
6 pub const WRITE: Self = Self(0x02);
7 pub const CREATE: Self = Self(0x04);
8 pub const DELETE: Self = Self(0x08);
9 pub const LIST: Self = Self(0x10);
10 pub const TRAVERSE: Self = Self(0x20);
11 pub const SNAPSHOT: Self = Self(0x40);
12
13 pub const ALL: Self = Self(0x7F);
14 pub const EMPTY: Self = Self(0);
15
16 pub const TRAVERSE_INHERITABLE: Self = Self(
17 Self::READ.0
18 | Self::WRITE.0
19 | Self::CREATE.0
20 | Self::DELETE.0
21 | Self::LIST.0
22 | Self::TRAVERSE.0,
23 );
24
25 pub const fn raw(self) -> u16 {
26 self.0
27 }
28
29 pub const fn from_raw(v: u16) -> Self {
30 Self(v)
31 }
32
33 pub const fn contains(self, other: Self) -> bool {
34 self.0 & other.0 == other.0
35 }
36
37 pub const fn restrict(self, mask: Self) -> Self {
38 Self(self.0 & mask.0)
39 }
40
41 pub const fn is_empty(self) -> bool {
42 self.0 == 0
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub struct FsCap {
48 pub object_id: u64,
49 pub generation: u64,
50 pub rights: FsRights,
51}
52
53impl FsCap {
54 pub const fn new(object_id: u64, generation: u64, rights: FsRights) -> Self {
55 Self {
56 object_id,
57 generation,
58 rights,
59 }
60 }
61
62 pub const fn root(object_id: u64, generation: u64) -> Self {
63 Self {
64 object_id,
65 generation,
66 rights: FsRights::ALL,
67 }
68 }
69
70 pub fn check_rights(&self, required: FsRights) -> Result<(), CapError> {
71 match self.rights.contains(required) {
72 true => Ok(()),
73 false => Err(CapError::InsufficientRights),
74 }
75 }
76
77 pub fn validate_generation(&self, current_generation: u64) -> Result<(), CapError> {
78 match self.generation == current_generation {
79 true => Ok(()),
80 false => Err(CapError::StaleGeneration),
81 }
82 }
83
84 pub const fn derive(&self, child_object_id: u64, child_generation: u64) -> Self {
85 Self {
86 object_id: child_object_id,
87 generation: child_generation,
88 rights: self.rights.restrict(FsRights::TRAVERSE_INHERITABLE),
89 }
90 }
91
92 pub const fn restrict(&self, mode: FsRights) -> Self {
93 Self {
94 object_id: self.object_id,
95 generation: self.generation,
96 rights: self.rights.restrict(mode),
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum CapError {
103 InsufficientRights,
104 StaleGeneration,
105 InvalidHandle,
106 HandleTableFull,
107 NotADirectory,
108 PathTooDeep,
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn rights_contains_subset() {
117 let all = FsRights::ALL;
118 assert!(all.contains(FsRights::READ));
119 assert!(all.contains(FsRights::WRITE));
120 assert!(all.contains(FsRights::TRAVERSE));
121 }
122
123 #[test]
124 fn rights_restrict_narrows() {
125 let rw = FsRights::from_raw(FsRights::READ.raw() | FsRights::WRITE.raw());
126 let restricted = FsRights::ALL.restrict(rw);
127 assert!(restricted.contains(FsRights::READ));
128 assert!(restricted.contains(FsRights::WRITE));
129 assert!(!restricted.contains(FsRights::CREATE));
130 }
131
132 #[test]
133 fn cap_derive_restricts_rights() {
134 let parent = FsCap::root(1, 1);
135 let child = parent.derive(2, 1);
136 assert!(child.rights.contains(FsRights::READ));
137 assert!(child.rights.contains(FsRights::TRAVERSE));
138 assert!(!child.rights.contains(FsRights::SNAPSHOT));
139 }
140
141 #[test]
142 fn cap_check_rights_rejects_missing() {
143 let cap = FsCap::new(1, 1, FsRights::READ);
144 assert!(cap.check_rights(FsRights::WRITE).is_err());
145 }
146
147 #[test]
148 fn cap_validate_generation_stale() {
149 let cap = FsCap::new(1, 1, FsRights::ALL);
150 assert!(cap.validate_generation(2).is_err());
151 }
152
153 #[test]
154 fn cap_restrict_only_decreases() {
155 let cap = FsCap::root(1, 1);
156 let restricted = cap.restrict(FsRights::READ);
157 assert!(restricted.rights.contains(FsRights::READ));
158 assert!(!restricted.rights.contains(FsRights::WRITE));
159 }
160}