mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01: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 = "exec" , fg = "green" },
|
||||
|
||||
# Dummy files
|
||||
{ name = "*", is = "dummy", bg = "red" },
|
||||
{ name = "*/", is = "dummy", bg = "red" },
|
||||
|
||||
# Fallback
|
||||
# { name = "*", fg = "white" },
|
||||
{ name = "*/", fg = "blue" }
|
||||
|
|
@ -771,6 +775,7 @@ conds = [
|
|||
{ if = "fifo" , text = "" },
|
||||
{ if = "sock" , text = "" },
|
||||
{ if = "sticky", text = "" },
|
||||
{ if = "dummy", text = "" },
|
||||
|
||||
# Fallback
|
||||
{ if = "dir", text = "" },
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ impl Icons {
|
|||
"hidden" => file.is_hidden(),
|
||||
"link" => file.is_link(),
|
||||
"orphan" => file.is_orphan(),
|
||||
"dummy" => file.is_dummy(),
|
||||
"block" => file.is_block(),
|
||||
"char" => file.is_char(),
|
||||
"fifo" => file.is_fifo(),
|
||||
|
|
|
|||
|
|
@ -9,13 +9,14 @@ use yazi_shared::fs::Cha;
|
|||
pub enum Is {
|
||||
#[default]
|
||||
None,
|
||||
Block,
|
||||
Char,
|
||||
Exec,
|
||||
Fifo,
|
||||
Link,
|
||||
Orphan,
|
||||
Dummy,
|
||||
Block,
|
||||
Char,
|
||||
Fifo,
|
||||
Sock,
|
||||
Exec,
|
||||
Sticky,
|
||||
}
|
||||
|
||||
|
|
@ -24,13 +25,14 @@ impl FromStr for Is {
|
|||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"block" => Self::Block,
|
||||
"char" => Self::Char,
|
||||
"exec" => Self::Exec,
|
||||
"fifo" => Self::Fifo,
|
||||
"link" => Self::Link,
|
||||
"orphan" => Self::Orphan,
|
||||
"dummy" => Self::Dummy,
|
||||
"block" => Self::Block,
|
||||
"char" => Self::Char,
|
||||
"fifo" => Self::Fifo,
|
||||
"sock" => Self::Sock,
|
||||
"exec" => Self::Exec,
|
||||
"sticky" => Self::Sticky,
|
||||
_ => bail!("invalid filetype: {s}"),
|
||||
})
|
||||
|
|
@ -48,13 +50,14 @@ impl Is {
|
|||
pub fn check(&self, cha: &Cha) -> bool {
|
||||
match self {
|
||||
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::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::Exec => cha.is_exec(),
|
||||
Self::Sticky => cha.is_sticky(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,9 +54,11 @@ impl Files {
|
|||
select! {
|
||||
_ = tx.closed() => break,
|
||||
result = item.metadata() => {
|
||||
if let Ok(meta) = result {
|
||||
tx.send(File::from_meta(Url::from(item.path()), meta).await).ok();
|
||||
}
|
||||
let url = Url::from(item.path());
|
||||
_ = 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> {
|
||||
let mut files = Vec::with_capacity(entities.len() / 3 + 1);
|
||||
for entry in entities {
|
||||
if let Ok(meta) = entry.metadata().await {
|
||||
files.push(File::from_meta(Url::from(entry.path()), meta).await);
|
||||
}
|
||||
let url = Url::from(entry.path());
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ impl FilesSorter {
|
|||
match self.by {
|
||||
SortBy::None => {}
|
||||
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 }
|
||||
}),
|
||||
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 }
|
||||
}),
|
||||
SortBy::Extension => items.sort_unstable_by(|a, b| {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl Tab {
|
|||
};
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,12 +102,12 @@ impl Preview {
|
|||
*url == lock.url
|
||||
&& self.skip == lock.skip
|
||||
&& cha.len == lock.cha.len
|
||||
&& cha.modified == lock.cha.modified
|
||||
&& cha.mtime == lock.cha.mtime
|
||||
&& cha.kind == lock.cha.kind
|
||||
&& {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
cha.permissions == lock.cha.permissions
|
||||
cha.perm == lock.cha.perm
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,11 +32,9 @@ end
|
|||
function Linemode:permissions(file) return ui.Line(file.cha:permissions() or "") end
|
||||
|
||||
function Linemode:owner(file)
|
||||
if not ya.user_name then
|
||||
return ui.Line("")
|
||||
else
|
||||
return ui.Line(ya.user_name(file.cha.uid) .. ":" .. ya.group_name(file.cha.gid))
|
||||
end
|
||||
local user = file.cha.uid and ya.user_name(file.cha.uid) or file.cha.uid
|
||||
local group = file.cha.gid and ya.group_name(file.cha.gid) or file.cha.gid
|
||||
return ui.Line(string.format("%s:%s", user or "-", group or "-"))
|
||||
end
|
||||
|
||||
function Linemode:render(files)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ impl Cha {
|
|||
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_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_char", |_, me| Ok(me.is_char()));
|
||||
reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo()));
|
||||
|
|
@ -25,25 +26,25 @@ 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.is_dummy()).then_some(me.uid)));
|
||||
reg.add_field_method_get("gid", |_, me| Ok((!me.is_dummy()).then_some(me.gid)));
|
||||
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("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| {
|
||||
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| {
|
||||
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, ()| {
|
||||
Ok(
|
||||
#[cfg(unix)]
|
||||
Some(yazi_shared::fs::permissions(me.permissions)),
|
||||
Some(yazi_shared::fs::permissions(me.perm, me.is_dummy())),
|
||||
#[cfg(windows)]
|
||||
None::<String>,
|
||||
)
|
||||
|
|
@ -72,11 +73,11 @@ impl Cha {
|
|||
Self::cast(lua, yazi_shared::fs::Cha {
|
||||
kind,
|
||||
len: t.raw_get("len").unwrap_or_default(),
|
||||
accessed: parse_time(t.raw_get("atime").ok())?,
|
||||
created: parse_time(t.raw_get("ctime").ok())?,
|
||||
modified: parse_time(t.raw_get("mtime").ok())?,
|
||||
atime: parse_time(t.raw_get("atime").ok())?,
|
||||
ctime: parse_time(t.raw_get("ctime").ok())?,
|
||||
mtime: parse_time(t.raw_get("mtime").ok())?,
|
||||
#[cfg(unix)]
|
||||
permissions: t.raw_get("permissions").unwrap_or_default(),
|
||||
perm: t.raw_get("permissions").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
uid: t.raw_get("uid").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl Utils {
|
|||
|
||||
let hex = {
|
||||
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())
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{fs::Metadata, time::SystemTime};
|
||||
use std::{fs::{FileType, Metadata}, time::SystemTime};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
|
|
@ -11,28 +11,25 @@ bitflags! {
|
|||
const LINK = 0b00000100;
|
||||
const ORPHAN = 0b00001000;
|
||||
|
||||
const BLOCK = 0b00010000;
|
||||
const CHAR = 0b00100000;
|
||||
const FIFO = 0b01000000;
|
||||
const SOCKET = 0b10000000;
|
||||
const DUMMY = 0b00010000;
|
||||
}
|
||||
}
|
||||
|
||||
#[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 atime: Option<SystemTime>,
|
||||
pub ctime: Option<SystemTime>,
|
||||
pub mtime: Option<SystemTime>,
|
||||
#[cfg(unix)]
|
||||
pub permissions: libc::mode_t,
|
||||
pub perm: 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 {
|
||||
|
|
@ -42,47 +39,30 @@ impl From<Metadata> for Cha {
|
|||
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 {
|
||||
kind: ck,
|
||||
len: m.len(),
|
||||
accessed: m.accessed().ok(),
|
||||
created: m.created().ok(),
|
||||
modified: m.modified().ok(),
|
||||
kind: ck,
|
||||
len: m.len(),
|
||||
atime: m.accessed().ok(),
|
||||
ctime: m.created().ok(),
|
||||
mtime: m.modified().ok(),
|
||||
|
||||
#[cfg(unix)]
|
||||
permissions: {
|
||||
perm: {
|
||||
use std::os::unix::prelude::PermissionsExt;
|
||||
m.permissions().mode() as _
|
||||
},
|
||||
#[cfg(unix)]
|
||||
uid: {
|
||||
uid: {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
m.uid() as _
|
||||
},
|
||||
#[cfg(unix)]
|
||||
gid: {
|
||||
gid: {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
m.gid() as _
|
||||
},
|
||||
#[cfg(unix)]
|
||||
nlink: {
|
||||
nlink: {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
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 {
|
||||
#[inline]
|
||||
pub fn with_kind(mut self, kind: ChaKind) -> Self {
|
||||
|
|
@ -100,34 +124,25 @@ impl Cha {
|
|||
|
||||
impl Cha {
|
||||
#[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]
|
||||
pub fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
|
||||
pub const fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
|
||||
|
||||
#[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]
|
||||
pub fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
||||
pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
||||
|
||||
#[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]
|
||||
pub fn is_char(&self) -> bool { self.kind.contains(ChaKind::CHAR) }
|
||||
|
||||
#[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 {
|
||||
pub const fn is_block(&self) -> bool {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
self.permissions & libc::S_IXUSR != 0
|
||||
self.perm & libc::S_IFMT == libc::S_IFBLK
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
|
|
@ -136,10 +151,58 @@ impl Cha {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_sticky(&self) -> bool {
|
||||
pub const fn is_char(&self) -> bool {
|
||||
#[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)]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -63,7 +63,10 @@ impl File {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
|
|
|
|||
|
|
@ -264,11 +264,11 @@ 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, 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};
|
||||
let mut s = String::with_capacity(10);
|
||||
|
||||
// File type
|
||||
// Filetype
|
||||
s.push(match m & S_IFMT {
|
||||
S_IFBLK => 'b',
|
||||
S_IFCHR => 'c',
|
||||
|
|
@ -279,6 +279,11 @@ pub fn permissions(m: libc::mode_t) -> String {
|
|||
_ => '-',
|
||||
});
|
||||
|
||||
if dummy {
|
||||
s.push_str("?????????");
|
||||
return s;
|
||||
}
|
||||
|
||||
// Owner
|
||||
s.push(if m & S_IRUSR != 0 { 'r' } else { '-' });
|
||||
s.push(if m & S_IWUSR != 0 { 'w' } else { '-' });
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue