Files
MusicFS/src/origins/attrs.rs
T
2026-06-29 20:33:32 +02:00

89 lines
2.8 KiB
Rust

use std::{
fs,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use std::os::unix::fs::{MetadataExt, PermissionsExt};
/// Owned, `Clone`-able snapshot of the file attributes that musicfs needs to
/// serve FUSE `getattr` and to compute the per-item identity hash.
///
/// Decoupled from `std::fs::Metadata` so that non-disk origins (e.g. a future
/// `NetworkOrigin` reading a server manifest) can construct equivalent
/// attributes without a real inode on disk. The on-disk origin builds this
/// via `From<&fs::Metadata>`; other origins build it from their own metadata
/// source using the same field types.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FileAttrs {
pub size: u64,
pub blocks: u64,
pub atime: SystemTime,
pub mtime: SystemTime,
pub ctime: SystemTime,
pub crtime: SystemTime,
pub perm: u16,
pub nlink: u32,
pub uid: u32,
pub gid: u32,
pub rdev: u32,
pub blksize: u32,
}
impl From<&fs::Metadata> for FileAttrs {
fn from(metadata: &fs::Metadata) -> Self {
return FileAttrs {
size: metadata.size(),
blocks: metadata.blocks(),
atime: metadata.accessed().unwrap_or(UNIX_EPOCH),
mtime: metadata.modified().unwrap_or(UNIX_EPOCH),
ctime: UNIX_EPOCH + Duration::from_secs(metadata.ctime() as u64),
crtime: metadata.created().unwrap_or(UNIX_EPOCH),
perm: metadata.permissions().mode() as u16,
nlink: metadata.nlink() as u32,
uid: metadata.uid(),
gid: metadata.gid(),
rdev: metadata.rdev() as u32,
blksize: metadata.blksize() as u32,
};
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn file_attrs_from_metadata_copies_size_and_block_fields() {
let tmp = tempfile::tempdir().unwrap();
let metadata = fs::metadata(tmp.path()).unwrap();
let attrs = FileAttrs::from(&metadata);
assert_eq!(attrs.size, metadata.size());
assert_eq!(attrs.blocks, metadata.blocks());
assert_eq!(attrs.blksize, metadata.blksize() as u32);
}
#[test]
fn file_attrs_from_metadata_copies_unix_ownership() {
let tmp = tempfile::tempdir().unwrap();
let metadata = fs::metadata(tmp.path()).unwrap();
let attrs = FileAttrs::from(&metadata);
assert_eq!(attrs.uid, metadata.uid());
assert_eq!(attrs.gid, metadata.gid());
assert_eq!(attrs.perm, metadata.permissions().mode() as u16);
}
#[test]
fn file_attrs_from_metadata_preserves_mtime() {
let tmp = tempfile::tempdir().unwrap();
let metadata = fs::metadata(tmp.path()).unwrap();
let attrs = FileAttrs::from(&metadata);
assert_eq!(attrs.mtime, metadata.modified().unwrap_or(UNIX_EPOCH));
}
}