ext4_view/
dir.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::Ext4;
10use crate::dir_entry::DirEntryName;
11use crate::dir_htree::get_dir_entry_via_htree;
12use crate::error::Ext4Error;
13use crate::inode::{Inode, InodeFlags};
14use crate::iters::read_dir::ReadDir;
15use crate::path::PathBuf;
16
17/// Search a directory inode for an entry with the given `name`. If
18/// found, return the entry's inode, otherwise return a `NotFound`
19/// error.
20pub(crate) fn get_dir_entry_inode_by_name(
21    fs: &Ext4,
22    dir_inode: &Inode,
23    name: DirEntryName<'_>,
24) -> Result<Inode, Ext4Error> {
25    assert!(dir_inode.metadata.is_dir());
26
27    if dir_inode.flags.contains(InodeFlags::DIRECTORY_ENCRYPTED) {
28        return Err(Ext4Error::Encrypted);
29    }
30
31    if dir_inode.flags.contains(InodeFlags::DIRECTORY_HTREE) {
32        let entry = get_dir_entry_via_htree(fs, dir_inode, name)?;
33        return Inode::read(fs, entry.inode);
34    }
35
36    // The entry's `path()` method is not called, so the value of the
37    // base path does not matter.
38    let path = PathBuf::empty();
39
40    for entry in ReadDir::new(fs.clone(), dir_inode, path)? {
41        let entry = entry?;
42        if entry.file_name() == name {
43            return Inode::read(fs, entry.inode);
44        }
45    }
46
47    Err(Ext4Error::NotFound)
48}
49
50#[cfg(feature = "std")]
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use crate::test_util::load_test_disk1;
55
56    #[test]
57    fn test_get_dir_entry_inode_by_name() {
58        let fs = load_test_disk1();
59        let root_inode = fs.read_root_inode().unwrap();
60
61        let lookup = |name| {
62            get_dir_entry_inode_by_name(
63                &fs,
64                &root_inode,
65                DirEntryName::try_from(name).unwrap(),
66            )
67        };
68
69        // Check for a few expected entries.
70        // '.' always links to self.
71        assert_eq!(lookup(".").unwrap().index, root_inode.index);
72        // '..' is normally parent, but in the root dir it's just the
73        // root dir again.
74        assert_eq!(lookup("..").unwrap().index, root_inode.index);
75        // Don't check specific values of these since they might change
76        // if the test disk is regenerated
77        assert!(lookup("empty_file").is_ok());
78        assert!(lookup("empty_dir").is_ok());
79
80        // Check for something that does not exist.
81        let err = lookup("does_not_exist").unwrap_err();
82        assert!(matches!(err, Ext4Error::NotFound));
83    }
84}