file_system/fundamentals/
metadata.rs

1use users::{GroupIdentifier, UserIdentifier};
2
3use crate::{Kind, Permissions, Time};
4
5use super::Inode;
6
7/// File attributes.
8///
9/// The attributes are metadata associated with the file that stores:
10/// - The file type.
11/// - The file creation time.
12/// - The file modification time.
13/// - The file access time.
14/// - The file permissions.
15/// - The file owner.
16/// - The file group.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct Metadata {
19    /// The file inode.
20    inode: Option<Inode>,
21    /// The file type.
22    r#type: Kind,
23    /// The file creation time.
24    creation_time: Time,
25    /// The file modification time.
26    modification_time: Time,
27    /// The file access time.
28    access_time: Time,
29    /// The file permissions.
30    permissions: Permissions,
31    /// The file owner.
32    user: UserIdentifier,
33    /// The file group.
34    group: GroupIdentifier,
35}
36
37impl Metadata {
38    pub const IDENTIFIER: u8 = 0x01;
39
40    pub fn get_default(
41        type_value: Kind,
42        current_time: Time,
43        user: UserIdentifier,
44        group: GroupIdentifier,
45    ) -> Option<Self> {
46        let permissions = Permissions::new_default(type_value);
47
48        Some(Metadata {
49            inode: None,
50            r#type: type_value,
51            creation_time: current_time,
52            modification_time: current_time,
53            access_time: current_time,
54            permissions,
55            user,
56            group,
57        })
58    }
59
60    pub fn get_inode(&self) -> Option<Inode> {
61        self.inode
62    }
63
64    pub fn get_type(&self) -> Kind {
65        self.r#type
66    }
67
68    pub fn get_creation_time(&self) -> Time {
69        self.creation_time
70    }
71
72    pub fn get_modification_time(&self) -> Time {
73        self.modification_time
74    }
75
76    pub fn get_access_time(&self) -> Time {
77        self.access_time
78    }
79
80    pub fn get_permissions(&self) -> Permissions {
81        self.permissions
82    }
83
84    pub fn get_user(&self) -> UserIdentifier {
85        self.user
86    }
87
88    pub fn get_group(&self) -> GroupIdentifier {
89        self.group
90    }
91
92    pub fn set_inode(&mut self, inode: Inode) {
93        self.inode = Some(inode);
94    }
95
96    pub fn set_type(&mut self, r#type: Kind) {
97        self.r#type = r#type;
98    }
99
100    pub fn set_creation_time(&mut self, time: Time) {
101        self.creation_time = time;
102    }
103
104    pub fn set_modification_time(&mut self, time: Time) {
105        self.modification_time = time;
106    }
107
108    pub fn set_access_time(&mut self, time: Time) {
109        self.access_time = time;
110    }
111
112    pub fn set_permissions(&mut self, permissions: Permissions) {
113        self.permissions = permissions;
114    }
115
116    pub fn set_owner(&mut self, owner: UserIdentifier) {
117        self.user = owner;
118    }
119
120    pub fn set_group(&mut self, group: GroupIdentifier) {
121        self.group = group;
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    fn create_test_metadata() -> Metadata {
130        let current_time = Time::new(1640995200);
131        let user = UserIdentifier::new(1000);
132        let group = GroupIdentifier::new(1000);
133
134        Metadata::get_default(Kind::File, current_time, user, group).unwrap()
135    }
136
137    #[test]
138    fn test_metadata_creation() {
139        let current_time = Time::new(1640995200);
140        let user = UserIdentifier::new(1000);
141        let group = GroupIdentifier::new(1000);
142
143        let metadata = Metadata::get_default(Kind::File, current_time, user, group);
144        assert!(metadata.is_some());
145
146        let metadata = metadata.unwrap();
147        assert_eq!(metadata.get_type(), Kind::File);
148        assert_eq!(metadata.get_creation_time(), current_time);
149        assert_eq!(metadata.get_modification_time(), current_time);
150        assert_eq!(metadata.get_access_time(), current_time);
151        assert_eq!(metadata.get_user(), user);
152        assert_eq!(metadata.get_group(), group);
153        assert!(metadata.get_inode().is_none());
154    }
155
156    #[test]
157    fn test_metadata_identifier() {
158        assert_eq!(Metadata::IDENTIFIER, 0x01);
159    }
160
161    #[test]
162    fn test_metadata_getters() {
163        let metadata = create_test_metadata();
164
165        // Test initial values
166        assert!(metadata.get_inode().is_none());
167        assert_eq!(metadata.get_type(), Kind::File);
168        assert_eq!(metadata.get_creation_time().as_u64(), 1640995200);
169        assert_eq!(metadata.get_modification_time().as_u64(), 1640995200);
170        assert_eq!(metadata.get_access_time().as_u64(), 1640995200);
171        assert_eq!(metadata.get_user().as_u16(), 1000);
172        assert_eq!(metadata.get_group().as_u16(), 1000);
173    }
174
175    #[test]
176    fn test_metadata_setters() {
177        let mut metadata = create_test_metadata();
178
179        // Test setting inode
180        let inode = Inode::new(42);
181        metadata.set_inode(inode);
182        assert_eq!(metadata.get_inode(), Some(inode));
183
184        // Test setting type
185        metadata.set_type(Kind::Directory);
186        assert_eq!(metadata.get_type(), Kind::Directory);
187
188        // Test setting times
189        let new_time = Time::new(1641081600);
190        metadata.set_creation_time(new_time);
191        metadata.set_modification_time(new_time);
192        metadata.set_access_time(new_time);
193
194        assert_eq!(metadata.get_creation_time(), new_time);
195        assert_eq!(metadata.get_modification_time(), new_time);
196        assert_eq!(metadata.get_access_time(), new_time);
197
198        // Test setting owner and group
199        let new_user = UserIdentifier::new(2000);
200        let new_group = GroupIdentifier::new(2000);
201
202        metadata.set_owner(new_user);
203        metadata.set_group(new_group);
204
205        assert_eq!(metadata.get_user(), new_user);
206        assert_eq!(metadata.get_group(), new_group);
207    }
208
209    #[test]
210    fn test_metadata_permissions() {
211        let metadata = create_test_metadata();
212        let _permissions = metadata.get_permissions();
213
214        // Test that we can set new permissions
215        let mut metadata = metadata;
216        let new_permissions = Permissions::new_default(Kind::Directory);
217        metadata.set_permissions(new_permissions);
218
219        assert_eq!(metadata.get_permissions(), new_permissions);
220    }
221
222    #[test]
223    fn test_metadata_clone() {
224        let original = create_test_metadata();
225        let cloned = original.clone();
226
227        assert_eq!(original, cloned);
228        assert_eq!(original.get_type(), cloned.get_type());
229        assert_eq!(original.get_creation_time(), cloned.get_creation_time());
230        assert_eq!(original.get_user(), cloned.get_user());
231        assert_eq!(original.get_group(), cloned.get_group());
232    }
233
234    #[test]
235    fn test_metadata_equality() {
236        let metadata1 = create_test_metadata();
237        let metadata2 = create_test_metadata();
238
239        assert_eq!(metadata1, metadata2);
240
241        // Change one field and verify they're different
242        let mut metadata3 = create_test_metadata();
243        metadata3.set_type(Kind::Directory);
244
245        assert_ne!(metadata1, metadata3);
246    }
247
248    #[test]
249    fn test_metadata_debug() {
250        let metadata = create_test_metadata();
251        let debug_str = alloc::format!("{metadata:?}");
252
253        assert!(debug_str.contains("Metadata_type"));
254        assert!(debug_str.contains("File"));
255        assert!(debug_str.contains("1640995200"));
256    }
257
258    #[test]
259    fn test_metadata_different_types() {
260        let current_time = Time::new(1640995200);
261        let user = UserIdentifier::new(1000);
262        let group = GroupIdentifier::new(1000);
263
264        // Test different file types
265        let file_metadata = Metadata::get_default(Kind::File, current_time, user, group).unwrap();
266        let dir_metadata =
267            Metadata::get_default(Kind::Directory, current_time, user, group).unwrap();
268        let symlink_metadata =
269            Metadata::get_default(Kind::SymbolicLink, current_time, user, group).unwrap();
270
271        assert_eq!(file_metadata.get_type(), Kind::File);
272        assert_eq!(dir_metadata.get_type(), Kind::Directory);
273        assert_eq!(symlink_metadata.get_type(), Kind::SymbolicLink);
274
275        // They should have different permissions based on type
276        assert_ne!(
277            file_metadata.get_permissions(),
278            dir_metadata.get_permissions()
279        );
280    }
281
282    #[test]
283    fn test_metadata_inode_operations() {
284        let mut metadata = create_test_metadata();
285
286        // Initially no inode
287        assert!(metadata.get_inode().is_none());
288
289        // Set an inode
290        let inode1 = Inode::new(42);
291        metadata.set_inode(inode1);
292        assert_eq!(metadata.get_inode(), Some(inode1));
293
294        // Change the inode
295        let inode2 = Inode::new(84);
296        metadata.set_inode(inode2);
297        assert_eq!(metadata.get_inode(), Some(inode2));
298        assert_ne!(metadata.get_inode(), Some(inode1));
299    }
300
301    #[test]
302    fn test_metadata_time_updates() {
303        let mut metadata = create_test_metadata();
304
305        let initial_time = metadata.get_creation_time();
306        let new_time = Time::new(initial_time.as_u64() + 3600); // 1 hour later
307
308        // Test that times can be updated independently
309        metadata.set_creation_time(new_time);
310        assert_eq!(metadata.get_creation_time(), new_time);
311        assert_eq!(metadata.get_modification_time(), initial_time); // Should be unchanged
312        assert_eq!(metadata.get_access_time(), initial_time); // Should be unchanged
313
314        metadata.set_modification_time(new_time);
315        assert_eq!(metadata.get_modification_time(), new_time);
316        assert_eq!(metadata.get_access_time(), initial_time); // Should still be unchanged
317
318        metadata.set_access_time(new_time);
319        assert_eq!(metadata.get_access_time(), new_time);
320    }
321
322    #[test]
323    fn test_metadata_user_group_operations() {
324        let mut metadata = create_test_metadata();
325
326        let _initial_user = metadata.get_user();
327        let initial_group = metadata.get_group();
328
329        let new_user = UserIdentifier::new(5000);
330        let new_group = GroupIdentifier::new(5000);
331
332        // Test user change
333        metadata.set_owner(new_user);
334        assert_eq!(metadata.get_user(), new_user);
335        assert_eq!(metadata.get_group(), initial_group); // Group should be unchanged
336
337        // Test group change
338        metadata.set_group(new_group);
339        assert_eq!(metadata.get_group(), new_group);
340        assert_eq!(metadata.get_user(), new_user); // User should remain changed
341    }
342
343    #[test]
344    fn test_metadata_comprehensive_modification() {
345        let mut metadata = create_test_metadata();
346
347        // Modify all fields
348        let new_inode = Inode::new(999);
349        let new_type = Kind::Socket;
350        let new_time = Time::new(2000000000);
351        let new_user = UserIdentifier::new(9999);
352        let new_group = GroupIdentifier::new(9999);
353        let new_permissions = Permissions::new_default(Kind::Socket);
354
355        metadata.set_inode(new_inode);
356        metadata.set_type(new_type);
357        metadata.set_creation_time(new_time);
358        metadata.set_modification_time(new_time);
359        metadata.set_access_time(new_time);
360        metadata.set_owner(new_user);
361        metadata.set_group(new_group);
362        metadata.set_permissions(new_permissions);
363
364        // Verify all changes
365        assert_eq!(metadata.get_inode(), Some(new_inode));
366        assert_eq!(metadata.get_type(), new_type);
367        assert_eq!(metadata.get_creation_time(), new_time);
368        assert_eq!(metadata.get_modification_time(), new_time);
369        assert_eq!(metadata.get_access_time(), new_time);
370        assert_eq!(metadata.get_user(), new_user);
371        assert_eq!(metadata.get_group(), new_group);
372        assert_eq!(metadata.get_permissions(), new_permissions);
373    }
374}