use crate::fs_primitive_error::{PrimitiveError, c_path};
use std::os::unix::fs::MetadataExt;
use std::path::Path;
pub const BTRFS_SUBVOLUME_ROOT_INODE: u64 = 256;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FilesystemKind {
Btrfs,
Overlayfs,
Other,
}
pub fn classify_magic(f_type: u64) -> FilesystemKind {
let low: u64 = f_type & 0xffff_ffff;
if low == (libc::BTRFS_SUPER_MAGIC as u64 & 0xffff_ffff) {
return FilesystemKind::Btrfs;
}
if low == (libc::OVERLAYFS_SUPER_MAGIC as u64 & 0xffff_ffff) {
return FilesystemKind::Overlayfs;
}
return FilesystemKind::Other;
}
pub fn filesystem_facts(path: &Path) -> Result<(FilesystemKind, u64), PrimitiveError> {
let name = c_path("statfs", path)?;
let mut buffer: libc::statfs = unsafe { std::mem::zeroed() };
let result: libc::c_int = unsafe { libc::statfs(name.as_ptr(), &mut buffer) };
if result != 0 {
return Err(PrimitiveError::last_os_error("statfs", path));
}
let free: u64 = (buffer.f_bavail as u64).saturating_mul(buffer.f_bsize as u64);
return Ok((classify_magic(buffer.f_type as u64), free));
}
pub fn filesystem_kind(path: &Path) -> Result<FilesystemKind, PrimitiveError> {
return filesystem_facts(path).map(|facts| { return facts.0; });
}
pub fn is_xfs(path: &Path) -> Result<bool, PrimitiveError> {
let name = c_path("statfs", path)?;
let mut buffer: libc::statfs = unsafe { std::mem::zeroed() };
let result: libc::c_int = unsafe { libc::statfs(name.as_ptr(), &mut buffer) };
if result != 0 {
return Err(PrimitiveError::last_os_error("statfs", path));
}
return Ok((buffer.f_type as u64 & 0xffff_ffff) == (libc::XFS_SUPER_MAGIC as u64 & 0xffff_ffff));
}
pub fn is_subvolume_root(path: &Path) -> Result<bool, PrimitiveError> {
if filesystem_kind(path)? != FilesystemKind::Btrfs {
return Ok(false);
}
let metadata = std::fs::metadata(path).map_err(|error| {
return PrimitiveError { operation: "stat", path: path.to_path_buf(), errno: error.raw_os_error().unwrap_or(0) };
})?;
return Ok(metadata.is_dir() && metadata.ino() == BTRFS_SUBVOLUME_ROOT_INODE);
}
#[cfg(test)]
#[path = "fs_kind_tests.rs"]
mod tests;