Skip to content

Commit

Permalink
Highlight btrfs subvolumes and mount points; output mount point info
Browse files Browse the repository at this point in the history
  • Loading branch information
daviessm committed Jul 22, 2019
1 parent 6468095 commit 84726b0
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 18 deletions.
14 changes: 7 additions & 7 deletions src/exa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ mod options;
mod output;
mod style;

lazy_static! {
// A global cache of mount points to enable lookups for each directory
static ref MOUNT_POINTS: Vec<(PathBuf, String, String)> = {
let mount_points = get_mount_points().unwrap();
mount_points
};
}

/// The main program wrapper.
pub struct Exa<'args, 'w, W: Write + 'w> {
Expand Down Expand Up @@ -125,13 +132,6 @@ impl<'args, 'w, W: Write + 'w> Exa<'args, 'w, W> {
let mut dirs = Vec::new();
let mut exit_status = 0;

//Get a vector of all mount points to use later
let mount_points = get_mount_points();
// for test in mount_points.unwrap() {
// println!("entry: {} {}", test.0.to_str().unwrap(), test.1);
// }


for file_path in &self.args {
match File::new(PathBuf::from(file_path), None, None) {
Err(e) => {
Expand Down
55 changes: 52 additions & 3 deletions src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};

use fs::dir::Dir;
use fs::fields as f;

use MOUNT_POINTS;

/// A **File** is a wrapper around one of Rust's Path objects, along with
/// associated data about the file.
Expand Down Expand Up @@ -172,14 +172,63 @@ impl<'dir> File<'dir> {

// Whether this file is a btrfs subvolume
pub fn is_subvolume(&self) -> bool {
if self.is_directory() && (self.metadata.ino() == 2 || self.metadata.ino() == 256) {
// inode numbers look like the file is a subvolume, unwind its
// path to see whether it's on a btrfs volume
let mut ancestors: Vec<PathBuf> = Vec::new();
for ancestor in self.path.ancestors() {
ancestors.push(ancestor.to_path_buf());
}
ancestors.reverse();

let mut is_on_btrfs = false;
// Start at / and work downwards
for ancestor in ancestors {
for mount_point in MOUNT_POINTS.iter() {
let mount_path = &mount_point.0;
let fs_type = &mount_point.1;
if ancestor.eq(mount_path) {
if "btrfs".eq(fs_type) {
is_on_btrfs = true;
} else {
is_on_btrfs = false;
}
}
}
}
return is_on_btrfs;
}
return false;
}

// Whether this file is a mount point
pub fn is_mount_point(&self) -> bool {
if self.is_directory() {
if self.metadata.ino() == 2 || self.metadata.ino() == 256 {
return true;
for mount_point in MOUNT_POINTS.iter() {
let mount_path = &mount_point.0;
if self.path.eq(mount_path) {
return true;
}
}
}
return false;
}

// The filesystem device and type for a mount point
pub fn mount_point_info(&self) -> (Option<PathBuf>, Option<String>, Option<String>) {
if self.is_mount_point() {
for mount_point in MOUNT_POINTS.iter() {
let mount_path = &mount_point.0;
let fs_type = &mount_point.1;
let fs_name = &mount_point.2;
if self.path.eq(mount_path) {
return (Some(mount_path.to_path_buf()), Some(fs_type.to_string()), Some(fs_name.to_string()));
}
}
}
return (None, None, None);
}

/// Re-prefixes the path pointed to by this file, if it’s a symlink, to
/// make it an absolute path that can be accessed from whichever
/// directory exa is being run from.
Expand Down
3 changes: 2 additions & 1 deletion src/fs/get_mounts/bsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ pub fn get_mount_points() -> Result<Vec<(PathBuf,String)>> {
.map(|m| unsafe {(
let bytes = CStr::from_ptr(&m.f_mntonname[0]).to_bytes();
PathBuf::from(OsStr::from_bytes(bytes).to_owned()),
let fstype = CStr::from_ptr(&m.f_fstypename[0]).to_str().unwrap().to_owned()
let fstype = CStr::from_ptr(&m.f_fstypename[0]).to_str().unwrap().to_owned(),
let fsname = CStr::from_ptr(&m.f_mntfromname[0]).to_str().unwrap().to_owned()
}))
.collect();

Expand Down
12 changes: 6 additions & 6 deletions src/fs/get_mounts/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ extern "C" {
fn endmntent(fp: *mut FILE) -> c_int;
}

pub fn get_mount_points() -> Result<Vec<(PathBuf,String)>> {
let mut mount_points: Vec<(PathBuf,String)> = Vec::new();
pub fn get_mount_points() -> Result<Vec<(PathBuf,String, String)>> {
let mut mount_points: Vec<(PathBuf,String, String)> = Vec::new();

// The Linux API is somewhat baroque: rather than exposing the kernel's view of the world
// you are expected to provide it with a mounts file which traditionally might have been
Expand Down Expand Up @@ -66,10 +66,10 @@ pub fn get_mount_points() -> Result<Vec<(PathBuf,String)>> {
let bytes = unsafe { CStr::from_ptr((*mount_entry).mnt_dir).to_bytes() };
let mount_point = PathBuf::from(OsStr::from_bytes(bytes).to_owned());
let str = unsafe { CStr::from_ptr((*mount_entry).mnt_type).to_str().unwrap() };
let fstype = str.to_owned();
// let bytes = unsafe { CStr::from_ptr((*mount_entry).mnt_type).to_bytes() };
// let fstype = String::from(OsStr::from_bytes(bytes).to_owned());
mount_points.push((mount_point, fstype));
let fs_type = str.to_owned();
let str = unsafe { CStr::from_ptr((*mount_entry).mnt_fsname).to_str().unwrap() };
let fs_name = str.to_owned();
mount_points.push((mount_point, fs_type, fs_name));
}

let rc = unsafe { endmntent(mount_file_handle) };
Expand Down
12 changes: 12 additions & 0 deletions src/output/file_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,17 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
bits.push(Style::default().paint(class));
}
}
else if self.file.is_mount_point() {
let mount_point_info = self.file.mount_point_info();
bits.push(Style::default().paint(" "));
bits.push(self.colours.normal_arrow().paint("->"));
bits.push(Style::default().paint(" "));

bits.push(Style::default().paint(mount_point_info.2.unwrap()));
bits.push(Style::default().paint(" ("));
bits.push(Style::default().paint(mount_point_info.1.unwrap()));
bits.push(Style::default().paint(")"));
}

bits.into()
}
Expand Down Expand Up @@ -253,6 +264,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {

fn kind_style(&self) -> Option<Style> {
Some(match self.file {
f if f.is_mount_point() => self.colours.mount_point(),
f if f.is_subvolume() => self.colours.subvolume(),
f if f.is_directory() => self.colours.directory(),
f if f.is_executable_file() => self.colours.executable_file(),
Expand Down
1 change: 1 addition & 0 deletions src/output/render/filetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ pub trait Colours {
fn socket(&self) -> Style;
fn special(&self) -> Style;
fn subvolume(&self) -> Style;
fn mount_point(&self) -> Style;
}
6 changes: 5 additions & 1 deletion src/style/colours.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub struct FileKinds {
pub special: Style,
pub executable: Style,
pub subvolume: Style,
pub mount_point: Style,
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
Expand Down Expand Up @@ -125,7 +126,8 @@ impl Colours {
socket: Red.bold(),
special: Yellow.normal(),
executable: Green.bold(),
subvolume: Blue.bold().underline(),
mount_point: Blue.bold().underline(),
subvolume: Blue.bold().blink(),
},

perms: Permissions {
Expand Down Expand Up @@ -245,6 +247,7 @@ impl Colours {
"ln" => self.filekinds.symlink = pair.to_style(), // LINK
"or" => self.broken_symlink = pair.to_style(), // ORPHAN
"sv" => self.filekinds.subvolume = pair.to_style(), // SUBVOL
"mp" => self.filekinds.mount_point = pair.to_style(), // MNT
_ => return false,
// Codes we don’t do anything with:
// MULTIHARDLINK, DOOR, SETUID, SETGID, CAPABILITY,
Expand Down Expand Up @@ -323,6 +326,7 @@ impl render::FiletypeColours for Colours {
fn socket(&self) -> Style { self.filekinds.socket }
fn special(&self) -> Style { self.filekinds.special }
fn subvolume(&self) -> Style { self.filekinds.subvolume }
fn mount_point(&self) -> Style { self.filekinds.mount_point }
}

impl render::GitColours for Colours {
Expand Down

0 comments on commit 84726b0

Please sign in to comment.