Skip to main content

intel_crashlog/collateral/
fs.rs

1// Copyright (C) 2025 Intel Corporation
2// SPDX-License-Identifier: MIT
3
4use super::{CollateralManager, CollateralTree, ItemPath, PVSS};
5use crate::Error;
6use std::io::Read;
7use std::path::{Path, PathBuf};
8
9/// Provides access to a collateral tree stored in the file system.
10///
11/// The directories in the collateral tree must follow this structure:
12/// `PRODUCT/VARIANT/STEPPING/SECURITY/crashlog/ITEM_PATH`
13///
14/// A [`CollateralManager`] that uses a collateral tree stored in the file system can be created
15/// using the [`CollateralManager::file_system_tree`] function.
16pub struct FileSystemTree {
17    root: PathBuf,
18}
19
20impl FileSystemTree {
21    fn new(root: &Path) -> Self {
22        Self {
23            root: root.to_path_buf(),
24        }
25    }
26
27    fn build_path(&self, pvss: &PVSS, item: &ItemPath) -> Option<PathBuf> {
28        let mut relative_base = self.root.clone();
29        let pvss: PathBuf = pvss.into();
30        relative_base.extend(&pvss);
31        relative_base.push("crashlog");
32
33        let base = relative_base.canonicalize().ok()?;
34
35        let mut path = base.clone();
36        let item: PathBuf = item.into();
37        path.extend(&item);
38
39        path.canonicalize()
40            .ok()
41            .filter(|path| path.starts_with(&base))
42    }
43}
44
45impl CollateralTree for FileSystemTree {
46    fn get(&self, pvss: &PVSS, item: &ItemPath) -> Result<Vec<u8>, Error> {
47        let Some(path) = self.build_path(pvss, item) else {
48            return Err(Error::MissingCollateral(pvss.clone(), item.clone()));
49        };
50
51        let mut file = std::fs::File::open(path)?;
52        let mut buf = Vec::new();
53        file.read_to_end(&mut buf)?;
54        Ok(buf)
55    }
56
57    fn search(&self, item: &ItemPath) -> Result<Vec<PVSS>, Error> {
58        let mut hits = Vec::new();
59
60        for product in std::fs::read_dir(&self.root)? {
61            let product = product?;
62            for variant in std::fs::read_dir(product.path())? {
63                let variant = variant?;
64                for stepping in std::fs::read_dir(variant.path())? {
65                    let stepping = stepping?;
66                    for security in std::fs::read_dir(stepping.path())? {
67                        let security = security?;
68                        let mut path = security.path();
69                        path.push("crashlog");
70                        path.push::<PathBuf>(item.into());
71                        if path.exists() {
72                            hits.push(PVSS {
73                                product: product.file_name().into_string()?,
74                                variant: variant.file_name().into_string()?,
75                                stepping: stepping.file_name().into_string()?,
76                                security: security.file_name().into_string()?,
77                            });
78                        }
79                    }
80                }
81            }
82        }
83
84        Ok(hits)
85    }
86}
87
88impl CollateralManager<FileSystemTree> {
89    /// Creates a [`CollateralManager`] that uses a collateral tree stored in the file system.
90    /// The collateral items will be loaded at run-time from the collateral tree located at the
91    /// path specified in the `root` argument.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use intel_crashlog::prelude::*;
97    /// use std::path::Path;
98    ///
99    /// let collateral_manager = CollateralManager::file_system_tree(Path::new("collateral"));
100    /// assert!(collateral_manager.is_ok());
101    /// ```
102    pub fn file_system_tree(root: &Path) -> Result<Self, Error> {
103        Self::new(FileSystemTree::new(root))
104    }
105}