Skip to main content

btrfs_fs/
dir.rs

1//! Directory entries and the file-kind enum.
2//!
3//! [`FileKind`] is the FUSE-independent equivalent of `fuser::FileType`,
4//! and [`Entry`] is what [`crate::Filesystem::readdir`] returns for each
5//! child of a directory.
6
7use crate::Inode;
8use btrfs_disk::items::{DirItem, FileType as BtrfsFileType};
9
10/// Filesystem-level file type, decoupled from any FUSE crate.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum FileKind {
13    RegularFile,
14    Directory,
15    Symlink,
16    BlockDevice,
17    CharDevice,
18    NamedPipe,
19    Socket,
20}
21
22impl FileKind {
23    /// Translate a btrfs on-disk `FileType` into a [`FileKind`].
24    ///
25    /// `Xattr`, `Unknown`, and `Other(_)` are reported as `RegularFile`,
26    /// matching how the kernel surfaces them through `readdir`.
27    #[must_use]
28    pub fn from_btrfs(ft: BtrfsFileType) -> Self {
29        match ft {
30            BtrfsFileType::Dir => FileKind::Directory,
31            BtrfsFileType::Symlink => FileKind::Symlink,
32            BtrfsFileType::Blkdev => FileKind::BlockDevice,
33            BtrfsFileType::Chrdev => FileKind::CharDevice,
34            BtrfsFileType::Fifo => FileKind::NamedPipe,
35            BtrfsFileType::Sock => FileKind::Socket,
36            BtrfsFileType::RegFile
37            | BtrfsFileType::Xattr
38            | BtrfsFileType::Unknown
39            | BtrfsFileType::Other(_) => FileKind::RegularFile,
40        }
41    }
42
43    /// Decode the type bits of a POSIX mode field into a [`FileKind`].
44    #[must_use]
45    pub fn from_mode(mode: u32) -> Self {
46        const S_IFMT: u32 = 0o170_000;
47        const S_IFDIR: u32 = 0o040_000;
48        const S_IFLNK: u32 = 0o120_000;
49        const S_IFBLK: u32 = 0o060_000;
50        const S_IFCHR: u32 = 0o020_000;
51        const S_IFIFO: u32 = 0o010_000;
52        const S_IFSOCK: u32 = 0o140_000;
53        match mode & S_IFMT {
54            S_IFDIR => FileKind::Directory,
55            S_IFLNK => FileKind::Symlink,
56            S_IFBLK => FileKind::BlockDevice,
57            S_IFCHR => FileKind::CharDevice,
58            S_IFIFO => FileKind::NamedPipe,
59            S_IFSOCK => FileKind::Socket,
60            _ => FileKind::RegularFile,
61        }
62    }
63}
64
65/// A single directory entry from [`crate::Filesystem::readdir`].
66#[derive(Debug, Clone)]
67pub struct Entry {
68    pub ino: Inode,
69    pub kind: FileKind,
70    pub name: Vec<u8>,
71    /// Cookie a caller passes back to resume reading strictly after this
72    /// entry. Stable as long as the directory layout doesn't change.
73    pub offset: u64,
74}
75
76impl Entry {
77    pub(crate) fn from_dir_item(
78        subvol: crate::SubvolId,
79        item: &DirItem,
80        next_offset: u64,
81    ) -> Self {
82        Self {
83            ino: Inode {
84                subvol,
85                ino: item.location.objectid,
86            },
87            kind: FileKind::from_btrfs(item.file_type),
88            name: item.name.clone(),
89            offset: next_offset,
90        }
91    }
92}