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}