Skip to content

Commit

Permalink
feat: show files with inaccessible metadata
Browse files Browse the repository at this point in the history
Some broken files cause tokio::fs::DirEntry::metadata to fail. The
previous version would just hide those broken files with no way of
viewing them. This commit shows those files, but marked as inaccessible.
  • Loading branch information
Ape committed Jul 12, 2024
1 parent ac4fd9f commit 884e1b6
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 25 deletions.
5 changes: 5 additions & 0 deletions yazi-config/preset/theme.toml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ rules = [
{ name = "*", is = "orphan", bg = "red" },
{ name = "*", is = "exec" , fg = "green" },

# Inaccessible files
{ name = "*", is = "inaccessible", bg = "red" },
{ name = "*/", is = "inaccessible", bg = "red" },

# Fallback
# { name = "*", fg = "white" },
{ name = "*/", fg = "blue" }
Expand Down Expand Up @@ -765,6 +769,7 @@ exts = [
conds = [
# Special files
{ if = "orphan", text = "" },
{ if = "inaccessible", text = "" },
{ if = "link" , text = "" },
{ if = "block" , text = "" },
{ if = "char" , text = "" },
Expand Down
1 change: 1 addition & 0 deletions yazi-config/src/theme/icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl Icons {
"sock" => file.is_sock(),
"exec" => file.is_exec(),
"sticky" => file.is_sticky(),
"inaccessible" => file.inaccessible,
_ => false,
};
self.conds.iter().find(|(c, _)| c.eval(f) == Some(true)).map(|(_, i)| i)
Expand Down
3 changes: 3 additions & 0 deletions yazi-config/src/theme/is.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum Is {
Orphan,
Sock,
Sticky,
Inaccessible,
}

impl FromStr for Is {
Expand All @@ -32,6 +33,7 @@ impl FromStr for Is {
"orphan" => Self::Orphan,
"sock" => Self::Sock,
"sticky" => Self::Sticky,
"inaccessible" => Self::Inaccessible,
_ => bail!("invalid filetype: {s}"),
})
}
Expand All @@ -56,6 +58,7 @@ impl Is {
Self::Orphan => cha.is_orphan(),
Self::Sock => cha.is_sock(),
Self::Sticky => cha.is_sticky(),
Self::Inaccessible => cha.inaccessible,
}
}
}
6 changes: 6 additions & 0 deletions yazi-core/src/folder/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ impl Files {
result = item.metadata() => {
if let Ok(meta) = result {
tx.send(File::from_meta(Url::from(item.path()), meta).await).ok();
} else {
let file_type = item.file_type().await.ok();
tx.send(File::from_no_meta(Url::from(item.path()), file_type).await).ok();
}
}
}
Expand All @@ -78,6 +81,9 @@ impl Files {
for entry in entities {
if let Ok(meta) = entry.metadata().await {
files.push(File::from_meta(Url::from(entry.path()), meta).await);
} else {
let file_type = entry.file_type().await.ok();
files.push(File::from_no_meta(Url::from(entry.path()), file_type).await);
}
}
files
Expand Down
9 changes: 6 additions & 3 deletions yazi-plugin/preset/components/linemode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ end
function Linemode:permissions(file) return ui.Line(file.cha:permissions() or "") end

function Linemode:owner(file)
if not ya.user_name then
if not ya.user_name or not file.cha.uid or not file.cha.gid then
return ui.Line("")
else
return ui.Line(ya.user_name(file.cha.uid) .. ":" .. ya.group_name(file.cha.gid))
end

user = ya.user_name(file.cha.uid) or file.cha.uid
group = ya.group_name(file.cha.gid) or file.cha.gid

return ui.Line(user .. ":" .. group)
end

function Linemode:render(files)
Expand Down
2 changes: 1 addition & 1 deletion yazi-plugin/preset/components/status.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function Status:permissions()
for i = 1, #perm do
local c = perm:sub(i, i)
local style = THEME.status.permissions_t
if c == "-" then
if c == "-" or c == "?" then
style = THEME.status.permissions_s
elseif c == "r" then
style = THEME.status.permissions_r
Expand Down
9 changes: 5 additions & 4 deletions yazi-plugin/src/cha/cha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ impl Cha {

#[cfg(unix)]
{
reg.add_field_method_get("uid", |_, me| Ok(me.uid));
reg.add_field_method_get("gid", |_, me| Ok(me.gid));
reg.add_field_method_get("nlink", |_, me| Ok(me.nlink));
reg.add_field_method_get("uid", |_, me| Ok((!me.inaccessible).then_some(me.uid)));
reg.add_field_method_get("gid", |_, me| Ok((!me.inaccessible).then_some(me.gid)));
reg.add_field_method_get("nlink", |_, me| Ok((!me.inaccessible).then_some(me.nlink)));
}

reg.add_field_method_get("length", |_, me| Ok(me.len));
Expand All @@ -43,7 +43,7 @@ impl Cha {
reg.add_method("permissions", |_, me, ()| {
Ok(
#[cfg(unix)]
Some(yazi_shared::fs::permissions(me.permissions)),
Some(yazi_shared::fs::permissions(me.permissions, me.inaccessible)),
#[cfg(windows)]
None::<String>,
)
Expand Down Expand Up @@ -75,6 +75,7 @@ impl Cha {
accessed: parse_time(t.raw_get("atime").ok())?,
created: parse_time(t.raw_get("ctime").ok())?,
modified: parse_time(t.raw_get("mtime").ok())?,
inaccessible: t.raw_get("inaccessible").unwrap_or_default(),
#[cfg(unix)]
permissions: t.raw_get("permissions").unwrap_or_default(),
#[cfg(unix)]
Expand Down
93 changes: 78 additions & 15 deletions yazi-shared/src/fs/cha.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fs::Metadata, time::SystemTime};
use std::{fs::{FileType, Metadata}, time::SystemTime};

use bitflags::bitflags;

Expand All @@ -20,19 +20,20 @@ bitflags! {

#[derive(Clone, Copy, Debug, Default)]
pub struct Cha {
pub kind: ChaKind,
pub len: u64,
pub accessed: Option<SystemTime>,
pub created: Option<SystemTime>,
pub modified: Option<SystemTime>,
pub kind: ChaKind,
pub len: u64,
pub accessed: Option<SystemTime>,
pub created: Option<SystemTime>,
pub modified: Option<SystemTime>,
pub inaccessible: bool,
#[cfg(unix)]
pub permissions: libc::mode_t,
pub permissions: libc::mode_t,
#[cfg(unix)]
pub uid: libc::uid_t,
pub uid: libc::uid_t,
#[cfg(unix)]
pub gid: libc::gid_t,
pub gid: libc::gid_t,
#[cfg(unix)]
pub nlink: libc::nlink_t,
pub nlink: libc::nlink_t,
}

impl From<Metadata> for Cha {
Expand Down Expand Up @@ -60,11 +61,12 @@ impl From<Metadata> for Cha {
}

Self {
kind: ck,
len: m.len(),
accessed: m.accessed().ok(),
created: m.created().ok(),
modified: m.modified().ok(),
kind: ck,
len: m.len(),
accessed: m.accessed().ok(),
created: m.created().ok(),
modified: m.modified().ok(),
inaccessible: false,

#[cfg(unix)]
permissions: {
Expand All @@ -90,12 +92,73 @@ impl From<Metadata> for Cha {
}
}

impl From<FileType> for Cha {
fn from(file_type: FileType) -> Self {
let mut kind = ChaKind::empty();
let mut permissions = 0;

if file_type.is_dir() {
kind |= ChaKind::DIR;

#[cfg(unix)]
{
permissions |= libc::S_IFDIR;
}
}

if file_type.is_symlink() {
kind |= ChaKind::LINK;

#[cfg(unix)]
{
permissions |= libc::S_IFLNK;
}
}

#[cfg(unix)]
{
use std::os::unix::prelude::FileTypeExt;
if file_type.is_block_device() {
kind |= ChaKind::BLOCK;
permissions |= libc::S_IFBLK;
}
if file_type.is_char_device() {
kind |= ChaKind::CHAR;
permissions |= libc::S_IFCHR;
}
if file_type.is_fifo() {
kind |= ChaKind::FIFO;
permissions |= libc::S_IFIFO;
}
if file_type.is_socket() {
kind |= ChaKind::SOCKET;
permissions |= libc::S_IFSOCK;
}
}

Self {
kind,

#[cfg(unix)]
permissions,

..Default::default()
}
}
}

impl Cha {
#[inline]
pub fn with_kind(mut self, kind: ChaKind) -> Self {
self.kind |= kind;
self
}

#[inline]
pub fn inaccessible(mut self) -> Self {
self.inaccessible = true;
self
}
}

impl Cha {
Expand Down
10 changes: 9 additions & 1 deletion yazi-shared/src/fs/file.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{cell::Cell, ffi::OsStr, fs::Metadata, ops::Deref};
use std::{cell::Cell, ffi::OsStr, fs::{FileType, Metadata}, ops::Deref};

use anyhow::Result;
use tokio::fs;
Expand Down Expand Up @@ -62,6 +62,14 @@ impl File {
Self { url, cha: Cha::from(meta).with_kind(ck), link_to, icon: Default::default() }
}

pub async fn from_no_meta(url: Url, file_type: Option<FileType>) -> Self {
Self {
url,
cha: file_type.map_or_else(Cha::default, Cha::from).inaccessible(),
..Default::default()
}
}

#[inline]
pub fn from_dummy(url: &Url) -> Self { Self { url: url.to_owned(), ..Default::default() } }
}
Expand Down
10 changes: 9 additions & 1 deletion yazi-shared/src/fs/fns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ pub fn copy_with_progress(
// Convert a file mode to a string representation
#[cfg(unix)]
#[allow(clippy::collapsible_else_if)]
pub fn permissions(m: libc::mode_t) -> String {
pub fn permissions(m: libc::mode_t, inaccessible: bool) -> String {
use libc::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFSOCK, S_IRGRP, S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};
let mut s = String::with_capacity(10);

Expand All @@ -279,6 +279,14 @@ pub fn permissions(m: libc::mode_t) -> String {
_ => '-',
});

if inaccessible {
for _ in 0..9 {
s.push('?');
}

return s;
}

// Owner
s.push(if m & S_IRUSR != 0 { 'r' } else { '-' });
s.push(if m & S_IWUSR != 0 { 'w' } else { '-' });
Expand Down

0 comments on commit 884e1b6

Please sign in to comment.