Skip to main content

vfs/posix/
usage.rs

1use super::vfs::{VfsResult, VirtualFileSystem};
2use std::collections::BTreeSet;
3
4pub const DEFAULT_MAX_FILESYSTEM_BYTES: u64 = 64 * 1024 * 1024;
5pub const DEFAULT_MAX_INODE_COUNT: usize = 16_384;
6
7#[derive(Debug, Clone, PartialEq, Eq, Default)]
8pub struct FileSystemUsage {
9    pub total_bytes: u64,
10    pub inode_count: usize,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct FileSystemStats {
15    pub total_bytes: u64,
16    pub used_bytes: u64,
17    pub available_bytes: u64,
18    pub total_inodes: u64,
19    pub free_inodes: u64,
20}
21
22pub trait RootFilesystemResourceLimits {
23    fn max_filesystem_bytes(&self) -> Option<u64>;
24    fn max_inode_count(&self) -> Option<usize>;
25}
26
27pub fn measure_filesystem_usage<F: VirtualFileSystem>(
28    filesystem: &mut F,
29) -> VfsResult<FileSystemUsage> {
30    let mut visited = BTreeSet::new();
31    measure_path_usage(filesystem, "/", &mut visited)
32}
33
34fn measure_path_usage<F: VirtualFileSystem>(
35    filesystem: &mut F,
36    path: &str,
37    visited: &mut BTreeSet<(u64, u64)>,
38) -> VfsResult<FileSystemUsage> {
39    let stat = filesystem.lstat(path)?;
40    let mut usage = FileSystemUsage::default();
41
42    if visited.insert((stat.dev, stat.ino)) {
43        usage.inode_count += 1;
44        if !stat.is_directory {
45            usage.total_bytes = usage.total_bytes.saturating_add(stat.size);
46        }
47    }
48
49    if !stat.is_directory || stat.is_symbolic_link {
50        return Ok(usage);
51    }
52
53    for entry in filesystem.read_dir_with_types(path)? {
54        if matches!(entry.name.as_str(), "." | "..") {
55            continue;
56        }
57
58        let child_path = if path == "/" {
59            format!("/{}", entry.name)
60        } else {
61            format!("{path}/{}", entry.name)
62        };
63        let child_usage = measure_path_usage(filesystem, &child_path, visited)?;
64        usage.total_bytes = usage.total_bytes.saturating_add(child_usage.total_bytes);
65        usage.inode_count = usage.inode_count.saturating_add(child_usage.inode_count);
66    }
67
68    Ok(usage)
69}