mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: support displaying files with inaccessible metadata (#1275)
This commit is contained in:
parent
2cf722ed48
commit
ab88588c0e
15 changed files with 187 additions and 104 deletions
|
|
@ -1 +1 @@
|
||||||
{"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","subsec"],"version":"0.2"}
|
{"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink"],"flagWords":[]}
|
||||||
|
|
@ -189,6 +189,10 @@ rules = [
|
||||||
{ name = "*", is = "orphan", bg = "red" },
|
{ name = "*", is = "orphan", bg = "red" },
|
||||||
{ name = "*", is = "exec" , fg = "green" },
|
{ name = "*", is = "exec" , fg = "green" },
|
||||||
|
|
||||||
|
# Dummy files
|
||||||
|
{ name = "*", is = "dummy", bg = "red" },
|
||||||
|
{ name = "*/", is = "dummy", bg = "red" },
|
||||||
|
|
||||||
# Fallback
|
# Fallback
|
||||||
# { name = "*", fg = "white" },
|
# { name = "*", fg = "white" },
|
||||||
{ name = "*/", fg = "blue" }
|
{ name = "*/", fg = "blue" }
|
||||||
|
|
@ -771,6 +775,7 @@ conds = [
|
||||||
{ if = "fifo" , text = "" },
|
{ if = "fifo" , text = "" },
|
||||||
{ if = "sock" , text = "" },
|
{ if = "sock" , text = "" },
|
||||||
{ if = "sticky", text = "" },
|
{ if = "sticky", text = "" },
|
||||||
|
{ if = "dummy", text = "" },
|
||||||
|
|
||||||
# Fallback
|
# Fallback
|
||||||
{ if = "dir", text = "" },
|
{ if = "dir", text = "" },
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ impl Icons {
|
||||||
"hidden" => file.is_hidden(),
|
"hidden" => file.is_hidden(),
|
||||||
"link" => file.is_link(),
|
"link" => file.is_link(),
|
||||||
"orphan" => file.is_orphan(),
|
"orphan" => file.is_orphan(),
|
||||||
|
"dummy" => file.is_dummy(),
|
||||||
"block" => file.is_block(),
|
"block" => file.is_block(),
|
||||||
"char" => file.is_char(),
|
"char" => file.is_char(),
|
||||||
"fifo" => file.is_fifo(),
|
"fifo" => file.is_fifo(),
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,14 @@ use yazi_shared::fs::Cha;
|
||||||
pub enum Is {
|
pub enum Is {
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
Block,
|
|
||||||
Char,
|
|
||||||
Exec,
|
|
||||||
Fifo,
|
|
||||||
Link,
|
Link,
|
||||||
Orphan,
|
Orphan,
|
||||||
|
Dummy,
|
||||||
|
Block,
|
||||||
|
Char,
|
||||||
|
Fifo,
|
||||||
Sock,
|
Sock,
|
||||||
|
Exec,
|
||||||
Sticky,
|
Sticky,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,13 +25,14 @@ impl FromStr for Is {
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(match s {
|
Ok(match s {
|
||||||
"block" => Self::Block,
|
|
||||||
"char" => Self::Char,
|
|
||||||
"exec" => Self::Exec,
|
|
||||||
"fifo" => Self::Fifo,
|
|
||||||
"link" => Self::Link,
|
"link" => Self::Link,
|
||||||
"orphan" => Self::Orphan,
|
"orphan" => Self::Orphan,
|
||||||
|
"dummy" => Self::Dummy,
|
||||||
|
"block" => Self::Block,
|
||||||
|
"char" => Self::Char,
|
||||||
|
"fifo" => Self::Fifo,
|
||||||
"sock" => Self::Sock,
|
"sock" => Self::Sock,
|
||||||
|
"exec" => Self::Exec,
|
||||||
"sticky" => Self::Sticky,
|
"sticky" => Self::Sticky,
|
||||||
_ => bail!("invalid filetype: {s}"),
|
_ => bail!("invalid filetype: {s}"),
|
||||||
})
|
})
|
||||||
|
|
@ -48,13 +50,14 @@ impl Is {
|
||||||
pub fn check(&self, cha: &Cha) -> bool {
|
pub fn check(&self, cha: &Cha) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::None => true,
|
Self::None => true,
|
||||||
Self::Block => cha.is_block(),
|
|
||||||
Self::Char => cha.is_char(),
|
|
||||||
Self::Exec => cha.is_exec(),
|
|
||||||
Self::Fifo => cha.is_fifo(),
|
|
||||||
Self::Link => cha.is_link(),
|
Self::Link => cha.is_link(),
|
||||||
Self::Orphan => cha.is_orphan(),
|
Self::Orphan => cha.is_orphan(),
|
||||||
|
Self::Dummy => cha.is_dummy(),
|
||||||
|
Self::Block => cha.is_block(),
|
||||||
|
Self::Char => cha.is_char(),
|
||||||
|
Self::Fifo => cha.is_fifo(),
|
||||||
Self::Sock => cha.is_sock(),
|
Self::Sock => cha.is_sock(),
|
||||||
|
Self::Exec => cha.is_exec(),
|
||||||
Self::Sticky => cha.is_sticky(),
|
Self::Sticky => cha.is_sticky(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,11 @@ impl Files {
|
||||||
select! {
|
select! {
|
||||||
_ = tx.closed() => break,
|
_ = tx.closed() => break,
|
||||||
result = item.metadata() => {
|
result = item.metadata() => {
|
||||||
if let Ok(meta) = result {
|
let url = Url::from(item.path());
|
||||||
tx.send(File::from_meta(Url::from(item.path()), meta).await).ok();
|
_ = tx.send(match result {
|
||||||
}
|
Ok(meta) => File::from_meta(url, meta).await,
|
||||||
|
Err(_) => File::from_dummy(url, item.file_type().await.ok())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,9 +78,11 @@ impl Files {
|
||||||
async fn go(entities: &[DirEntry]) -> Vec<File> {
|
async fn go(entities: &[DirEntry]) -> Vec<File> {
|
||||||
let mut files = Vec::with_capacity(entities.len() / 3 + 1);
|
let mut files = Vec::with_capacity(entities.len() / 3 + 1);
|
||||||
for entry in entities {
|
for entry in entities {
|
||||||
if let Ok(meta) = entry.metadata().await {
|
let url = Url::from(entry.path());
|
||||||
files.push(File::from_meta(Url::from(entry.path()), meta).await);
|
files.push(match entry.metadata().await {
|
||||||
}
|
Ok(meta) => File::from_meta(url, meta).await,
|
||||||
|
Err(_) => File::from_dummy(url, entry.file_type().await.ok()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
files
|
files
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,11 @@ impl FilesSorter {
|
||||||
match self.by {
|
match self.by {
|
||||||
SortBy::None => {}
|
SortBy::None => {}
|
||||||
SortBy::Modified => items.sort_unstable_by(|a, b| {
|
SortBy::Modified => items.sort_unstable_by(|a, b| {
|
||||||
let ord = self.cmp(a.modified, b.modified, self.promote(a, b));
|
let ord = self.cmp(a.mtime, b.mtime, self.promote(a, b));
|
||||||
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
|
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
|
||||||
}),
|
}),
|
||||||
SortBy::Created => items.sort_unstable_by(|a, b| {
|
SortBy::Created => items.sort_unstable_by(|a, b| {
|
||||||
let ord = self.cmp(a.created, b.created, self.promote(a, b));
|
let ord = self.cmp(a.ctime, b.ctime, self.promote(a, b));
|
||||||
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
|
if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord }
|
||||||
}),
|
}),
|
||||||
SortBy::Extension => items.sort_unstable_by(|a, b| {
|
SortBy::Extension => items.sort_unstable_by(|a, b| {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ impl Tab {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cd(parent.clone());
|
self.cd(parent.clone());
|
||||||
FilesOp::Creating(parent, vec![File::from_dummy(&opt.target)]).emit();
|
FilesOp::Creating(parent, vec![File::from_dummy(opt.target.clone(), None)]).emit();
|
||||||
ManagerProxy::hover(Some(opt.target));
|
ManagerProxy::hover(Some(opt.target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,12 +102,12 @@ impl Preview {
|
||||||
*url == lock.url
|
*url == lock.url
|
||||||
&& self.skip == lock.skip
|
&& self.skip == lock.skip
|
||||||
&& cha.len == lock.cha.len
|
&& cha.len == lock.cha.len
|
||||||
&& cha.modified == lock.cha.modified
|
&& cha.mtime == lock.cha.mtime
|
||||||
&& cha.kind == lock.cha.kind
|
&& cha.kind == lock.cha.kind
|
||||||
&& {
|
&& {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
cha.permissions == lock.cha.permissions
|
cha.perm == lock.cha.perm
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,9 @@ end
|
||||||
function Linemode:permissions(file) return ui.Line(file.cha:permissions() or "") end
|
function Linemode:permissions(file) return ui.Line(file.cha:permissions() or "") end
|
||||||
|
|
||||||
function Linemode:owner(file)
|
function Linemode:owner(file)
|
||||||
if not ya.user_name then
|
local user = file.cha.uid and ya.user_name(file.cha.uid) or file.cha.uid
|
||||||
return ui.Line("")
|
local group = file.cha.gid and ya.group_name(file.cha.gid) or file.cha.gid
|
||||||
else
|
return ui.Line(string.format("%s:%s", user or "-", group or "-"))
|
||||||
return ui.Line(ya.user_name(file.cha.uid) .. ":" .. ya.group_name(file.cha.gid))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Linemode:render(files)
|
function Linemode:render(files)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ function Status:permissions()
|
||||||
for i = 1, #perm do
|
for i = 1, #perm do
|
||||||
local c = perm:sub(i, i)
|
local c = perm:sub(i, i)
|
||||||
local style = THEME.status.permissions_t
|
local style = THEME.status.permissions_t
|
||||||
if c == "-" then
|
if c == "-" or c == "?" then
|
||||||
style = THEME.status.permissions_s
|
style = THEME.status.permissions_s
|
||||||
elseif c == "r" then
|
elseif c == "r" then
|
||||||
style = THEME.status.permissions_r
|
style = THEME.status.permissions_r
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ impl Cha {
|
||||||
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
||||||
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
||||||
reg.add_field_method_get("is_orphan", |_, me| Ok(me.is_orphan()));
|
reg.add_field_method_get("is_orphan", |_, me| Ok(me.is_orphan()));
|
||||||
|
reg.add_field_method_get("is_dummy", |_, me| Ok(me.is_dummy()));
|
||||||
reg.add_field_method_get("is_block", |_, me| Ok(me.is_block()));
|
reg.add_field_method_get("is_block", |_, me| Ok(me.is_block()));
|
||||||
reg.add_field_method_get("is_char", |_, me| Ok(me.is_char()));
|
reg.add_field_method_get("is_char", |_, me| Ok(me.is_char()));
|
||||||
reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo()));
|
reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo()));
|
||||||
|
|
@ -25,25 +26,25 @@ impl Cha {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
reg.add_field_method_get("uid", |_, me| Ok(me.uid));
|
reg.add_field_method_get("uid", |_, me| Ok((!me.is_dummy()).then_some(me.uid)));
|
||||||
reg.add_field_method_get("gid", |_, me| Ok(me.gid));
|
reg.add_field_method_get("gid", |_, me| Ok((!me.is_dummy()).then_some(me.gid)));
|
||||||
reg.add_field_method_get("nlink", |_, me| Ok(me.nlink));
|
reg.add_field_method_get("nlink", |_, me| Ok((!me.is_dummy()).then_some(me.nlink)));
|
||||||
}
|
}
|
||||||
|
|
||||||
reg.add_field_method_get("length", |_, me| Ok(me.len));
|
reg.add_field_method_get("length", |_, me| Ok(me.len));
|
||||||
reg.add_field_method_get("created", |_, me| {
|
reg.add_field_method_get("created", |_, me| {
|
||||||
Ok(me.created.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||||
});
|
});
|
||||||
reg.add_field_method_get("modified", |_, me| {
|
reg.add_field_method_get("modified", |_, me| {
|
||||||
Ok(me.modified.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||||
});
|
});
|
||||||
reg.add_field_method_get("accessed", |_, me| {
|
reg.add_field_method_get("accessed", |_, me| {
|
||||||
Ok(me.accessed.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||||
});
|
});
|
||||||
reg.add_method("permissions", |_, me, ()| {
|
reg.add_method("permissions", |_, me, ()| {
|
||||||
Ok(
|
Ok(
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
Some(yazi_shared::fs::permissions(me.permissions)),
|
Some(yazi_shared::fs::permissions(me.perm, me.is_dummy())),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
None::<String>,
|
None::<String>,
|
||||||
)
|
)
|
||||||
|
|
@ -72,11 +73,11 @@ impl Cha {
|
||||||
Self::cast(lua, yazi_shared::fs::Cha {
|
Self::cast(lua, yazi_shared::fs::Cha {
|
||||||
kind,
|
kind,
|
||||||
len: t.raw_get("len").unwrap_or_default(),
|
len: t.raw_get("len").unwrap_or_default(),
|
||||||
accessed: parse_time(t.raw_get("atime").ok())?,
|
atime: parse_time(t.raw_get("atime").ok())?,
|
||||||
created: parse_time(t.raw_get("ctime").ok())?,
|
ctime: parse_time(t.raw_get("ctime").ok())?,
|
||||||
modified: parse_time(t.raw_get("mtime").ok())?,
|
mtime: parse_time(t.raw_get("mtime").ok())?,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
permissions: t.raw_get("permissions").unwrap_or_default(),
|
perm: t.raw_get("permissions").unwrap_or_default(),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
uid: t.raw_get("uid").unwrap_or_default(),
|
uid: t.raw_get("uid").unwrap_or_default(),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ impl Utils {
|
||||||
|
|
||||||
let hex = {
|
let hex = {
|
||||||
let mut digest = Md5::new_with_prefix(file.url.as_os_str().as_encoded_bytes());
|
let mut digest = Md5::new_with_prefix(file.url.as_os_str().as_encoded_bytes());
|
||||||
digest.update(&format!("//{:?}//{}", file.cha.modified, t.raw_get("skip").unwrap_or(0)));
|
digest.update(&format!("//{:?}//{}", file.cha.mtime, t.raw_get("skip").unwrap_or(0)));
|
||||||
format!("{:x}", digest.finalize())
|
format!("{:x}", digest.finalize())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fs::Metadata, time::SystemTime};
|
use std::{fs::{FileType, Metadata}, time::SystemTime};
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
|
@ -11,28 +11,25 @@ bitflags! {
|
||||||
const LINK = 0b00000100;
|
const LINK = 0b00000100;
|
||||||
const ORPHAN = 0b00001000;
|
const ORPHAN = 0b00001000;
|
||||||
|
|
||||||
const BLOCK = 0b00010000;
|
const DUMMY = 0b00010000;
|
||||||
const CHAR = 0b00100000;
|
|
||||||
const FIFO = 0b01000000;
|
|
||||||
const SOCKET = 0b10000000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Cha {
|
pub struct Cha {
|
||||||
pub kind: ChaKind,
|
pub kind: ChaKind,
|
||||||
pub len: u64,
|
pub len: u64,
|
||||||
pub accessed: Option<SystemTime>,
|
pub atime: Option<SystemTime>,
|
||||||
pub created: Option<SystemTime>,
|
pub ctime: Option<SystemTime>,
|
||||||
pub modified: Option<SystemTime>,
|
pub mtime: Option<SystemTime>,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub permissions: libc::mode_t,
|
pub perm: libc::mode_t,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub uid: libc::uid_t,
|
pub uid: libc::uid_t,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub gid: libc::gid_t,
|
pub gid: libc::gid_t,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub nlink: libc::nlink_t,
|
pub nlink: libc::nlink_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Metadata> for Cha {
|
impl From<Metadata> for Cha {
|
||||||
|
|
@ -42,47 +39,30 @@ impl From<Metadata> for Cha {
|
||||||
ck |= ChaKind::DIR;
|
ck |= ChaKind::DIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
use std::os::unix::prelude::FileTypeExt;
|
|
||||||
if m.file_type().is_block_device() {
|
|
||||||
ck |= ChaKind::BLOCK;
|
|
||||||
}
|
|
||||||
if m.file_type().is_char_device() {
|
|
||||||
ck |= ChaKind::CHAR;
|
|
||||||
}
|
|
||||||
if m.file_type().is_fifo() {
|
|
||||||
ck |= ChaKind::FIFO;
|
|
||||||
}
|
|
||||||
if m.file_type().is_socket() {
|
|
||||||
ck |= ChaKind::SOCKET;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
kind: ck,
|
kind: ck,
|
||||||
len: m.len(),
|
len: m.len(),
|
||||||
accessed: m.accessed().ok(),
|
atime: m.accessed().ok(),
|
||||||
created: m.created().ok(),
|
ctime: m.created().ok(),
|
||||||
modified: m.modified().ok(),
|
mtime: m.modified().ok(),
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
permissions: {
|
perm: {
|
||||||
use std::os::unix::prelude::PermissionsExt;
|
use std::os::unix::prelude::PermissionsExt;
|
||||||
m.permissions().mode() as _
|
m.permissions().mode() as _
|
||||||
},
|
},
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
uid: {
|
uid: {
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
m.uid() as _
|
m.uid() as _
|
||||||
},
|
},
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
gid: {
|
gid: {
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
m.gid() as _
|
m.gid() as _
|
||||||
},
|
},
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
nlink: {
|
nlink: {
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
m.nlink() as _
|
m.nlink() as _
|
||||||
},
|
},
|
||||||
|
|
@ -90,6 +70,50 @@ impl From<Metadata> for Cha {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<FileType> for Cha {
|
||||||
|
fn from(t: FileType) -> Self {
|
||||||
|
let mut kind = ChaKind::DUMMY;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
let perm = {
|
||||||
|
use std::os::unix::fs::FileTypeExt;
|
||||||
|
if t.is_dir() {
|
||||||
|
kind |= ChaKind::DIR;
|
||||||
|
libc::S_IFDIR
|
||||||
|
} else if t.is_symlink() {
|
||||||
|
kind |= ChaKind::LINK;
|
||||||
|
libc::S_IFLNK
|
||||||
|
} else if t.is_block_device() {
|
||||||
|
libc::S_IFBLK
|
||||||
|
} else if t.is_char_device() {
|
||||||
|
libc::S_IFCHR
|
||||||
|
} else if t.is_fifo() {
|
||||||
|
libc::S_IFIFO
|
||||||
|
} else if t.is_socket() {
|
||||||
|
libc::S_IFSOCK
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
if t.is_dir() {
|
||||||
|
kind |= ChaKind::DIR;
|
||||||
|
} else if t.is_symlink() {
|
||||||
|
kind |= ChaKind::LINK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
kind,
|
||||||
|
#[cfg(unix)]
|
||||||
|
perm,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Cha {
|
impl Cha {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_kind(mut self, kind: ChaKind) -> Self {
|
pub fn with_kind(mut self, kind: ChaKind) -> Self {
|
||||||
|
|
@ -100,34 +124,25 @@ impl Cha {
|
||||||
|
|
||||||
impl Cha {
|
impl Cha {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) }
|
pub const fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
|
pub const fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) }
|
pub const fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_block(&self) -> bool { self.kind.contains(ChaKind::BLOCK) }
|
pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_char(&self) -> bool { self.kind.contains(ChaKind::CHAR) }
|
pub const fn is_block(&self) -> bool {
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_fifo(&self) -> bool { self.kind.contains(ChaKind::FIFO) }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_sock(&self) -> bool { self.kind.contains(ChaKind::SOCKET) }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_exec(&self) -> bool {
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
self.permissions & libc::S_IXUSR != 0
|
self.perm & libc::S_IFMT == libc::S_IFBLK
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
|
|
@ -136,10 +151,58 @@ impl Cha {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sticky(&self) -> bool {
|
pub const fn is_char(&self) -> bool {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
self.permissions & libc::S_ISVTX != 0
|
self.perm & libc::S_IFMT == libc::S_IFCHR
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_fifo(&self) -> bool {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
self.perm & libc::S_IFMT == libc::S_IFIFO
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_sock(&self) -> bool {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
self.perm & libc::S_IFMT == libc::S_IFSOCK
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_exec(&self) -> bool {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
self.perm & libc::S_IXUSR != 0
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_sticky(&self) -> bool {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
self.perm & libc::S_ISVTX != 0
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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 anyhow::Result;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
@ -63,7 +63,10 @@ impl File {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_dummy(url: &Url) -> Self { Self { url: url.to_owned(), ..Default::default() } }
|
pub fn from_dummy(url: Url, ft: Option<FileType>) -> Self {
|
||||||
|
// TODO: set dummy=true
|
||||||
|
Self { url: url.to_owned(), cha: ft.map_or_else(Cha::default, Cha::from), ..Default::default() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
|
|
|
||||||
|
|
@ -264,11 +264,11 @@ pub fn copy_with_progress(
|
||||||
// Convert a file mode to a string representation
|
// Convert a file mode to a string representation
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[allow(clippy::collapsible_else_if)]
|
#[allow(clippy::collapsible_else_if)]
|
||||||
pub fn permissions(m: libc::mode_t) -> String {
|
pub fn permissions(m: libc::mode_t, dummy: 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};
|
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);
|
let mut s = String::with_capacity(10);
|
||||||
|
|
||||||
// File type
|
// Filetype
|
||||||
s.push(match m & S_IFMT {
|
s.push(match m & S_IFMT {
|
||||||
S_IFBLK => 'b',
|
S_IFBLK => 'b',
|
||||||
S_IFCHR => 'c',
|
S_IFCHR => 'c',
|
||||||
|
|
@ -279,6 +279,11 @@ pub fn permissions(m: libc::mode_t) -> String {
|
||||||
_ => '-',
|
_ => '-',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if dummy {
|
||||||
|
s.push_str("?????????");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
// Owner
|
// Owner
|
||||||
s.push(if m & S_IRUSR != 0 { 'r' } else { '-' });
|
s.push(if m & S_IRUSR != 0 { 'r' } else { '-' });
|
||||||
s.push(if m & S_IWUSR != 0 { 'w' } else { '-' });
|
s.push(if m & S_IWUSR != 0 { 'w' } else { '-' });
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue