mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Some checks failed
Cachix / Publish Flake (push) Has been cancelled
Check / clippy (push) Has been cancelled
Check / rustfmt (push) Has been cancelled
Check / stylua (push) Has been cancelled
Draft / build-unix (gcc-aarch64-linux-gnu, ubuntu-latest, aarch64-unknown-linux-gnu) (push) Has been cancelled
Draft / build-unix (gcc-i686-linux-gnu, ubuntu-latest, i686-unknown-linux-gnu) (push) Has been cancelled
Draft / build-unix (gcc-riscv64-linux-gnu, ubuntu-latest, riscv64gc-unknown-linux-gnu) (push) Has been cancelled
Draft / build-unix (gcc-sparc64-linux-gnu, ubuntu-latest, sparc64-unknown-linux-gnu) (push) Has been cancelled
Draft / build-unix (macos-latest, aarch64-apple-darwin) (push) Has been cancelled
Draft / build-unix (macos-latest, x86_64-apple-darwin) (push) Has been cancelled
Draft / build-unix (ubuntu-latest, x86_64-unknown-linux-gnu) (push) Has been cancelled
Draft / build-windows (windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
Draft / build-windows (windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
Draft / build-musl (aarch64-unknown-linux-musl) (push) Has been cancelled
Draft / build-musl (x86_64-unknown-linux-musl) (push) Has been cancelled
Draft / build-snap (amd64, ubuntu-latest) (push) Has been cancelled
Draft / build-snap (arm64, ubuntu-24.04-arm) (push) Has been cancelled
Test / test (macos-latest) (push) Has been cancelled
Test / test (ubuntu-latest) (push) Has been cancelled
Test / test (windows-latest) (push) Has been cancelled
Draft / snap (push) Has been cancelled
Draft / draft (push) Has been cancelled
Draft / nightly (push) Has been cancelled
199 lines
4.2 KiB
Rust
199 lines
4.2 KiB
Rust
use std::{fs::Metadata, ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
|
|
|
|
use anyhow::bail;
|
|
use mlua::FromLua;
|
|
use serde::{Deserialize, Serialize};
|
|
use yazi_macro::{unix_either, win_either};
|
|
use yazi_shared::{strand::AsStrand, url::AsUrl};
|
|
|
|
use super::ChaKind;
|
|
use crate::cha::{ChaMode, ChaType};
|
|
|
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, FromLua, PartialEq, Serialize)]
|
|
pub struct Cha {
|
|
pub kind: ChaKind,
|
|
pub mode: ChaMode,
|
|
pub len: u64,
|
|
pub atime: Option<SystemTime>,
|
|
pub btime: Option<SystemTime>,
|
|
pub ctime: Option<SystemTime>,
|
|
pub mtime: Option<SystemTime>,
|
|
pub dev: u64,
|
|
pub uid: u32,
|
|
pub gid: u32,
|
|
pub nlink: u64,
|
|
}
|
|
|
|
impl Deref for Cha {
|
|
type Target = ChaMode;
|
|
|
|
fn deref(&self) -> &Self::Target { &self.mode }
|
|
}
|
|
|
|
impl Default for Cha {
|
|
fn default() -> Self {
|
|
Self {
|
|
kind: ChaKind::DUMMY,
|
|
mode: ChaMode::empty(),
|
|
len: 0,
|
|
atime: None,
|
|
btime: None,
|
|
ctime: None,
|
|
mtime: None,
|
|
dev: 0,
|
|
uid: 0,
|
|
gid: 0,
|
|
nlink: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Cha {
|
|
#[inline]
|
|
pub fn new<T>(name: T, meta: Metadata) -> Self
|
|
where
|
|
T: AsStrand,
|
|
{
|
|
Self::from_bare(&meta).attach(ChaKind::hidden(name, &meta))
|
|
}
|
|
|
|
pub fn from_dummy<U>(_url: U, r#type: Option<ChaType>) -> Self
|
|
where
|
|
U: AsUrl,
|
|
{
|
|
#[allow(unused_mut)]
|
|
let mut kind = ChaKind::DUMMY;
|
|
let mode = r#type.map(ChaMode::from_bare).unwrap_or_default();
|
|
|
|
#[cfg(unix)]
|
|
if _url.as_url().urn().is_hidden() {
|
|
kind |= ChaKind::HIDDEN;
|
|
}
|
|
|
|
Self { kind, mode, ..Default::default() }
|
|
}
|
|
|
|
fn from_bare(m: &Metadata) -> Self {
|
|
#[cfg(unix)]
|
|
use std::os::unix::fs::MetadataExt;
|
|
|
|
#[cfg(unix)]
|
|
let mode = {
|
|
use std::os::unix::fs::PermissionsExt;
|
|
ChaMode::from_bits_retain(m.permissions().mode() as u16)
|
|
};
|
|
|
|
#[cfg(windows)]
|
|
let mut mode = if m.is_file() {
|
|
ChaMode::T_FILE
|
|
} else if m.is_dir() {
|
|
ChaMode::T_DIR
|
|
} else if m.is_symlink() {
|
|
ChaMode::T_LINK
|
|
} else {
|
|
ChaMode::empty()
|
|
};
|
|
#[cfg(windows)]
|
|
if !m.permissions().readonly() {
|
|
mode |= ChaMode::U_WRITE;
|
|
}
|
|
|
|
Self {
|
|
kind: ChaKind::empty(),
|
|
mode,
|
|
len: m.len(),
|
|
atime: m.accessed().ok(),
|
|
btime: m.created().ok(),
|
|
ctime: unix_either!(
|
|
UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32)),
|
|
None
|
|
),
|
|
mtime: m.modified().ok(),
|
|
dev: unix_either!(m.dev(), 0) as _,
|
|
uid: unix_either!(m.uid(), 0) as _,
|
|
gid: unix_either!(m.gid(), 0) as _,
|
|
nlink: unix_either!(m.nlink(), 0) as _,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn hits(self, c: Self) -> bool {
|
|
self.len == c.len
|
|
&& self.mtime == c.mtime
|
|
&& self.ctime == c.ctime
|
|
&& self.btime == c.btime
|
|
&& self.kind == c.kind
|
|
&& self.mode == c.mode
|
|
}
|
|
|
|
#[inline]
|
|
pub fn attach(mut self, kind: ChaKind) -> Self {
|
|
self.kind |= kind;
|
|
self
|
|
}
|
|
|
|
#[inline]
|
|
pub fn follow(self, followed: Option<Self>) -> Self {
|
|
if !self.is_link() {
|
|
return self;
|
|
}
|
|
|
|
let retain = self.kind & (ChaKind::HIDDEN | ChaKind::SYSTEM) | ChaKind::FOLLOW;
|
|
followed.unwrap_or(self).attach(retain)
|
|
}
|
|
}
|
|
|
|
impl Cha {
|
|
#[inline]
|
|
pub fn is_link(self) -> bool {
|
|
self.kind.contains(ChaKind::FOLLOW) || *self.mode == ChaType::Link
|
|
}
|
|
|
|
#[inline]
|
|
pub fn is_orphan(self) -> bool {
|
|
*self.mode == ChaType::Link && self.kind.contains(ChaKind::FOLLOW)
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn is_hidden(self) -> bool {
|
|
win_either!(
|
|
self.kind.contains(ChaKind::HIDDEN) || self.kind.contains(ChaKind::SYSTEM),
|
|
self.kind.contains(ChaKind::HIDDEN)
|
|
)
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn is_dummy(self) -> bool { self.kind.contains(ChaKind::DUMMY) }
|
|
|
|
pub fn atime_dur(self) -> anyhow::Result<Duration> {
|
|
if let Some(atime) = self.atime {
|
|
Ok(atime.duration_since(UNIX_EPOCH)?)
|
|
} else {
|
|
bail!("atime not available");
|
|
}
|
|
}
|
|
|
|
pub fn btime_dur(self) -> anyhow::Result<Duration> {
|
|
if let Some(btime) = self.btime {
|
|
Ok(btime.duration_since(UNIX_EPOCH)?)
|
|
} else {
|
|
bail!("btime not available");
|
|
}
|
|
}
|
|
|
|
pub fn ctime_dur(self) -> anyhow::Result<Duration> {
|
|
if let Some(ctime) = self.ctime {
|
|
Ok(ctime.duration_since(UNIX_EPOCH)?)
|
|
} else {
|
|
bail!("ctime not available");
|
|
}
|
|
}
|
|
|
|
pub fn mtime_dur(self) -> anyhow::Result<Duration> {
|
|
if let Some(mtime) = self.mtime {
|
|
Ok(mtime.duration_since(UNIX_EPOCH)?)
|
|
} else {
|
|
bail!("mtime not available");
|
|
}
|
|
}
|
|
}
|