mirror of
https://github.com/eza-community/eza.git
synced 2025-08-04 17:08:42 +00:00
Merge cb36411d35
into fa2f3216ad
This commit is contained in:
commit
138bf13d41
6 changed files with 57 additions and 1 deletions
|
@ -410,6 +410,46 @@ impl<'dir> File<'dir> {
|
|||
.is_some_and(|p| all_mounts().contains_key(p))
|
||||
}
|
||||
|
||||
/// Whether the directory represents a Btrfs subvolume
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn is_btrfs_subvolume(&self) -> bool {
|
||||
// Listing all subvolumes with ioctl(BTRFS_IOC_TREE_SEARCH) requires CAP_SYS_ADMIN, normal users can't do that.
|
||||
// So we test the inode number, directory representing a subvolume has always inode number 256
|
||||
const BTRFS_FIRST_FREE_OBJECTID: u64 = 256;
|
||||
|
||||
self.is_directory()
|
||||
&& self.inode().0 == BTRFS_FIRST_FREE_OBJECTID
|
||||
&& self.is_btrfs().unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn is_btrfs_subvolume(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn is_btrfs(&self) -> io::Result<bool> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
const BTRFS_FSTYPE_NAME: &str = "btrfs";
|
||||
|
||||
for part in self.absolute_path().unwrap_or(&self.path).ancestors() {
|
||||
if let Some(mount) = all_mounts().get(part) {
|
||||
return Ok(mount.fstype == BTRFS_FSTYPE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
// /proc/mounts not working? fallback to statfs
|
||||
let file_path = &self.path;
|
||||
let mut out = std::mem::MaybeUninit::<libc::statfs>::uninit();
|
||||
let path = std::ffi::CString::new(file_path.as_os_str().as_bytes()).unwrap();
|
||||
match unsafe { libc::statfs(path.as_ptr(), out.as_mut_ptr()) } {
|
||||
0 => Ok(unsafe { out.assume_init() }.f_type == libc::BTRFS_SUPER_MAGIC),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
// eprintln!("eza: statfs {:?}: {}", self.path, os_err);
|
||||
}
|
||||
}
|
||||
|
||||
/// The filesystem device and type for a mount point
|
||||
pub fn mount_point_info(&self) -> Option<&MountedFs> {
|
||||
if cfg!(any(target_os = "linux", target_os = "macos")) {
|
||||
|
|
|
@ -273,6 +273,7 @@ pub struct FileKindsOverride {
|
|||
pub special: Option<StyleOverride>, // sp
|
||||
pub executable: Option<StyleOverride>, // ex
|
||||
pub mount_point: Option<StyleOverride>, // mp
|
||||
pub btrfs_subvol: Option<StyleOverride>, // sv
|
||||
}
|
||||
|
||||
impl FromOverride<FileKindsOverride> for FileKinds {
|
||||
|
@ -288,6 +289,7 @@ impl FromOverride<FileKindsOverride> for FileKinds {
|
|||
special: FromOverride::from(value.special, default.special),
|
||||
executable: FromOverride::from(value.executable, default.executable),
|
||||
mount_point: FromOverride::from(value.mount_point, default.mount_point),
|
||||
btrfs_subvol: FromOverride::from(value.btrfs_subvol, default.btrfs_subvol),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -477,6 +477,7 @@ impl<C: Colours> FileName<'_, '_, C> {
|
|||
#[rustfmt::skip]
|
||||
return match self.file {
|
||||
f if f.is_mount_point() => self.colours.mount_point(),
|
||||
f if f.is_btrfs_subvolume() => self.colours.btrfs_subvol(),
|
||||
f if f.is_directory() => self.colours.directory(),
|
||||
#[cfg(unix)]
|
||||
f if f.is_executable_file() => self.colours.executable_file(),
|
||||
|
@ -531,6 +532,9 @@ pub trait Colours: FiletypeColours {
|
|||
/// The style to paint a directory that has a filesystem mounted on it.
|
||||
fn mount_point(&self) -> Style;
|
||||
|
||||
/// The style to paint a directory representing a Btrfs subvolume.
|
||||
fn btrfs_subvol(&self) -> Style;
|
||||
|
||||
fn colour_file(&self, file: &File<'_>) -> Style;
|
||||
|
||||
fn style_override(&self, file: &File<'_>) -> Option<FileNameStyle>;
|
||||
|
|
|
@ -40,6 +40,7 @@ impl Default for UiStyles {
|
|||
special: Some(Yellow.normal()),
|
||||
executable: Some(Green.bold()),
|
||||
mount_point: Some(Blue.bold().underline()),
|
||||
btrfs_subvol: Some(Blue.underline()),
|
||||
}),
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
|
@ -471,6 +471,9 @@ impl FileNameColours for Theme {
|
|||
fn broken_control_char(&self) -> Style { apply_overlay(self.ui.control_char(), self.ui.broken_path_overlay()) }
|
||||
fn executable_file(&self) -> Style { self.ui.filekinds.unwrap_or_default().executable() }
|
||||
fn mount_point(&self) -> Style { self.ui.filekinds.unwrap_or_default().mount_point() }
|
||||
fn btrfs_subvol(&self) -> Style {
|
||||
self.ui.filekinds.unwrap_or_default().btrfs_subvol()
|
||||
}
|
||||
|
||||
fn colour_file(&self, file: &File<'_>) -> Style {
|
||||
self.exts
|
||||
|
@ -728,6 +731,7 @@ mod customs_test {
|
|||
test!(exa_bo: ls "", exa "bO=4" => colours c -> { c.broken_path_overlay = Some(Style::default().underline()); });
|
||||
|
||||
test!(exa_mp: ls "", exa "mp=1;34;4" => colours c -> { c.filekinds().mount_point = Some(Blue.bold().underline()); });
|
||||
test!(exa_sv: ls "", exa "sv=0;34;4" => colours c -> { c.filekinds().btrfs_subvol = Some(Blue.underline()); });
|
||||
test!(exa_sp: ls "", exa "sp=1;35;4" => colours c -> { c.filekinds().special = Some(Purple.bold().underline()); });
|
||||
|
||||
test!(exa_im: ls "", exa "im=38;5;128" => colours c -> { c.file_type().image = Some(Fixed(128).normal()); });
|
||||
|
|
|
@ -128,6 +128,7 @@ pub struct FileKinds {
|
|||
pub special: Option<Style>, // sp
|
||||
pub executable: Option<Style>, // ex
|
||||
pub mount_point: Option<Style>, // mp
|
||||
pub btrfs_subvol: Option<Style>, // sv
|
||||
}
|
||||
|
||||
impl Default for FileKinds {
|
||||
|
@ -143,6 +144,7 @@ impl Default for FileKinds {
|
|||
special: Some(Yellow.normal()),
|
||||
executable: Some(Green.bold()),
|
||||
mount_point: Some(Blue.bold().underline()),
|
||||
btrfs_subvol: Some(Blue.underline()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +159,8 @@ field_accessors!(
|
|||
socket: Option<Style>,
|
||||
special: Option<Style>,
|
||||
executable: Option<Style>,
|
||||
mount_point: Option<Style>
|
||||
mount_point: Option<Style>,
|
||||
btrfs_subvol: Option<Style>
|
||||
);
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -402,6 +405,7 @@ impl UiStyles {
|
|||
special: Some(Style::default()),
|
||||
executable: Some(Style::default()),
|
||||
mount_point: Some(Style::default()),
|
||||
btrfs_subvol: Some(Style::default()),
|
||||
}),
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -601,6 +605,7 @@ impl UiStyles {
|
|||
"bO" => self.broken_path_overlay = Some(pair.to_style()),
|
||||
|
||||
"mp" => self.filekinds().mount_point = Some(pair.to_style()),
|
||||
"sv" => self.filekinds().btrfs_subvol = Some(pair.to_style()),
|
||||
"sp" => self.filekinds().special = Some(pair.to_style()), // Catch-all for unrecognized file kind
|
||||
|
||||
"im" => self.file_type().image = Some(pair.to_style()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue