file_system/fundamentals/entry.rs
1//! Directory entry representation for file system operations.
2
3//!
4//! This module provides the [`Entry`] structure which represents individual
5//! entries within directories, such as files, subdirectories, and other file system objects.
6
7use alloc::string::String;
8
9use crate::{Kind, Path, PathOwned};
10
11use super::{Inode, Size};
12
13/// Represents a single entry within a directory.
14///
15/// A directory entry contains metadata about a file system object including its
16/// inode number, name, type, and size. This structure is used when reading directory
17/// contents to provide information about each item within the directory.
18#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct Entry {
20 /// The inode number identifying this file system object
21 pub inode: Inode,
22 /// The name of this directory entry
23 pub name: String,
24 /// The type of file system object (file, directory, etc.)
25 pub kind: Kind,
26 /// The size of the file system object in bytes
27 pub size: Size,
28}
29
30impl Entry {
31 /// Create a new directory entry with the specified metadata.
32 ///
33 /// # Arguments
34 ///
35 /// * `Inode` - Unique inode number for this file system object
36 /// * `Name` - Name of the file or directory
37 /// * `Type` - Type of the file system object
38 /// * `Size` - Size in bytes (for files) or entry count (for directories)
39 ///
40 /// # Examples
41 ///
42 /// ```rust
43 /// # extern crate alloc;
44 /// use file_system::{Entry, Inode, Kind, Size};
45 /// use alloc::string::String;
46 ///
47 /// let entry = Entry::new(
48 /// 123,
49 /// String::from("example.txt"),
50 /// Kind::File,
51 /// 2048
52 /// );
53 /// ```
54 pub fn new(inode: Inode, name: String, r#type: Kind, size: Size) -> Self {
55 Self {
56 inode,
57 name,
58 kind: r#type,
59 size,
60 }
61 }
62
63 pub fn join_path(&self, base_path: impl AsRef<Path>) -> Option<PathOwned> {
64 base_path.as_ref().join(Path::from_str(&self.name))
65 }
66}
67
68impl AsMut<[u8]> for Entry {
69 fn as_mut(&mut self) -> &mut [u8] {
70 unsafe {
71 core::slice::from_raw_parts_mut(
72 self as *mut Entry as *mut u8,
73 core::mem::size_of::<Entry>(),
74 )
75 }
76 }
77}
78
79impl TryFrom<&mut [u8]> for &mut Entry {
80 type Error = ();
81
82 fn try_from(value: &mut [u8]) -> Result<Self, Self::Error> {
83 if value.len() != core::mem::size_of::<Entry>() {
84 return Err(());
85 }
86 if !(value.as_ptr() as usize).is_multiple_of(core::mem::align_of::<Entry>()) {
87 return Err(());
88 }
89
90 #[allow(clippy::transmute_ptr_to_ref)]
91 Ok(unsafe { core::mem::transmute::<*mut u8, &mut Entry>(value.as_mut_ptr()) })
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use alloc::string::String;
99
100 #[test]
101 fn test_entry_as_mut_slice() {
102 let mut entry = Entry::new(42, String::from("test"), Kind::File, 100);
103
104 let slice = entry.as_mut();
105 assert_eq!(slice.len(), core::mem::size_of::<Entry>());
106 }
107
108 #[test]
109 fn test_entry_from_slice_invalid_size() {
110 let mut buffer = [0u8; 10]; // Too small
111 let result = <&mut Entry>::try_from(buffer.as_mut_slice());
112 assert!(result.is_err());
113 }
114
115 #[test]
116 fn test_entry_from_slice_valid() {
117 // Create a properly sized and aligned buffer
118 let mut buffer = alloc::vec![0u8; core::mem::size_of::<Entry>()];
119
120 // Ensure proper alignment by using Vec which should be properly aligned for any type
121 let result = <&mut Entry>::try_from(buffer.as_mut_slice());
122
123 // This might fail due to alignment requirements, which is expected behavior
124 // The important thing is that we're testing the code path
125 let _ = result; // We don't assert success since alignment isn't guaranteed
126 }
127}