mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 00:31:04 +00:00
fix: respect hidden status of directory junctions and symlinks themselves on Windows (#2471)
This commit is contained in:
parent
76adb97e22
commit
a0c6842626
21 changed files with 93 additions and 77 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
|
@ -367,9 +367,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.31"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -377,9 +377,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.31"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -418,9 +418,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.28"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
|
@ -1231,9 +1231,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.1"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
|
@ -1767,9 +1767,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ ansi-to-tui = "7.0.0"
|
|||
anyhow = "1.0.97"
|
||||
base64 = "0.22.1"
|
||||
bitflags = "2.9.0"
|
||||
clap = { version = "4.5.31", features = [ "derive" ] }
|
||||
clap = { version = "4.5.32", features = [ "derive" ] }
|
||||
core-foundation-sys = "0.8.7"
|
||||
crossterm = { version = "0.28.1", features = [ "event-stream" ] }
|
||||
dirs = "6.0.0"
|
||||
foldhash = "0.1.4"
|
||||
futures = "0.3.31"
|
||||
globset = "0.4.16"
|
||||
indexmap = { version = "2.7.1", features = [ "serde" ] }
|
||||
indexmap = { version = "2.8.0", features = [ "serde" ] }
|
||||
libc = "0.2.170"
|
||||
lru = "0.13.0"
|
||||
md-5 = "0.10.6"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use serde::Deserialize;
|
||||
use yazi_fs::Cha;
|
||||
use yazi_fs::cha::Cha;
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use parking_lot::RwLock;
|
|||
use tokio::{fs, pin, sync::{mpsc::{self, UnboundedReceiver}, watch}};
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use tracing::error;
|
||||
use yazi_fs::{Cha, File, Files, FilesOp, realname_unchecked};
|
||||
use yazi_fs::{File, Files, FilesOp, cha::Cha, realname_unchecked};
|
||||
use yazi_proxy::WATCHER;
|
||||
use yazi_shared::{RoCell, url::Url};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use tokio::pin;
|
|||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use tracing::error;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_fs::{Cha, FilesOp};
|
||||
use yazi_fs::{FilesOp, cha::Cha};
|
||||
use yazi_plugin::external;
|
||||
use yazi_proxy::{AppProxy, InputProxy, MgrProxy, TabProxy, options::{SearchOpt, SearchOptVia}};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::mem;
|
|||
|
||||
use yazi_config::{LAYOUT, MGR};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{Cha, File, Files, FilesOp, FolderStage, Step};
|
||||
use yazi_fs::{File, Files, FilesOp, FolderStage, Step, cha::Cha};
|
||||
use yazi_proxy::MgrProxy;
|
||||
use yazi_shared::{Id, url::{Url, Urn, UrnBuf}};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
|||
use tokio_util::sync::CancellationToken;
|
||||
use yazi_adapter::ADAPTOR;
|
||||
use yazi_config::PLUGIN;
|
||||
use yazi_fs::{Cha, File, Files, FilesOp};
|
||||
use yazi_fs::{File, Files, FilesOp, cha::Cha};
|
||||
use yazi_macro::render;
|
||||
use yazi_plugin::{external::Highlighter, isolate, utils::PreviewLock};
|
||||
use yazi_shared::{MIME_DIR, url::Url};
|
||||
|
|
|
|||
|
|
@ -1,22 +1,8 @@
|
|||
use std::{fs::{FileType, Metadata}, path::Path, time::SystemTime};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use yazi_macro::{unix_either, win_either};
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ChaKind: u8 {
|
||||
const DIR = 0b00000001;
|
||||
|
||||
const HIDDEN = 0b00000010;
|
||||
const LINK = 0b00000100;
|
||||
const ORPHAN = 0b00001000;
|
||||
|
||||
const DUMMY = 0b00010000;
|
||||
#[cfg(windows)]
|
||||
const SYSTEM = 0b00100000;
|
||||
}
|
||||
}
|
||||
use super::ChaKind;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct Cha {
|
||||
|
|
@ -39,8 +25,8 @@ pub struct Cha {
|
|||
pub nlink: libc::nlink_t,
|
||||
}
|
||||
|
||||
impl From<Metadata> for Cha {
|
||||
fn from(m: Metadata) -> Self {
|
||||
impl From<&Metadata> for Cha {
|
||||
fn from(m: &Metadata) -> Self {
|
||||
let mut kind = ChaKind::empty();
|
||||
if m.is_dir() {
|
||||
kind |= ChaKind::DIR;
|
||||
|
|
@ -89,6 +75,10 @@ impl From<Metadata> for Cha {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Metadata> for Cha {
|
||||
fn from(m: Metadata) -> Self { Self::from(&m) }
|
||||
}
|
||||
|
||||
impl From<FileType> for Cha {
|
||||
fn from(t: FileType) -> Self {
|
||||
let mut kind = ChaKind::DUMMY;
|
||||
|
|
@ -134,9 +124,8 @@ impl From<FileType> for Cha {
|
|||
}
|
||||
|
||||
impl Cha {
|
||||
#[inline]
|
||||
pub async fn new(path: &Path, mut meta: Metadata) -> Self {
|
||||
let mut attached = ChaKind::empty();
|
||||
let mut attached = ChaKind::hidden(path, &meta);
|
||||
|
||||
if meta.is_symlink() {
|
||||
attached |= ChaKind::LINK;
|
||||
|
|
@ -146,35 +135,16 @@ impl Cha {
|
|||
attached |= ChaKind::ORPHAN;
|
||||
}
|
||||
|
||||
let mut cha = Self::new_nofollow(path, meta);
|
||||
cha.kind |= attached;
|
||||
cha
|
||||
let mut me = Self::from(meta);
|
||||
me.kind |= attached;
|
||||
me
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_nofollow(_path: &Path, meta: Metadata) -> Self {
|
||||
let mut attached = ChaKind::empty();
|
||||
|
||||
#[cfg(unix)]
|
||||
if yazi_shared::url::Urn::new(_path).is_hidden() {
|
||||
attached |= ChaKind::HIDDEN;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
|
||||
use windows_sys::Win32::Storage::FileSystem::{FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM};
|
||||
if meta.file_attributes() & FILE_ATTRIBUTE_HIDDEN != 0 {
|
||||
attached |= ChaKind::HIDDEN;
|
||||
}
|
||||
if meta.file_attributes() & FILE_ATTRIBUTE_SYSTEM != 0 {
|
||||
attached |= ChaKind::SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
let mut cha = Self::from(meta);
|
||||
cha.kind |= attached;
|
||||
cha
|
||||
let mut me = Self::from(&meta);
|
||||
me.kind |= ChaKind::hidden(_path, &meta);
|
||||
me
|
||||
}
|
||||
|
||||
#[inline]
|
||||
44
yazi-fs/src/cha/kind.rs
Normal file
44
yazi-fs/src/cha/kind.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
use std::{fs::Metadata, path::Path};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ChaKind: u8 {
|
||||
const DIR = 0b00000001;
|
||||
|
||||
const HIDDEN = 0b00000010;
|
||||
const LINK = 0b00000100;
|
||||
const ORPHAN = 0b00001000;
|
||||
|
||||
const DUMMY = 0b00010000;
|
||||
#[cfg(windows)]
|
||||
const SYSTEM = 0b00100000;
|
||||
}
|
||||
}
|
||||
|
||||
impl ChaKind {
|
||||
#[inline]
|
||||
pub(super) fn hidden(_path: &Path, _meta: &Metadata) -> Self {
|
||||
let mut me = Self::empty();
|
||||
|
||||
#[cfg(unix)]
|
||||
if yazi_shared::url::Urn::new(_path).is_hidden() {
|
||||
me |= Self::HIDDEN;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
|
||||
use windows_sys::Win32::Storage::FileSystem::{FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM};
|
||||
if _meta.file_attributes() & FILE_ATTRIBUTE_HIDDEN != 0 {
|
||||
me |= Self::HIDDEN;
|
||||
}
|
||||
if _meta.file_attributes() & FILE_ATTRIBUTE_SYSTEM != 0 {
|
||||
me |= Self::SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
me
|
||||
}
|
||||
}
|
||||
1
yazi-fs/src/cha/mod.rs
Normal file
1
yazi-fs/src/cha/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(cha kind);
|
||||
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
|||
use tokio::fs;
|
||||
use yazi_shared::{SyncCell, theme::IconCache, url::{Url, Urn, UrnBuf}};
|
||||
|
||||
use crate::Cha;
|
||||
use crate::cha::Cha;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct File {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use tokio::{fs::{self, DirEntry}, select, sync::mpsc::{self, UnboundedReceiver}}
|
|||
use yazi_shared::{Id, url::{Url, Urn, UrnBuf}};
|
||||
|
||||
use super::{FilesSorter, Filter};
|
||||
use crate::{Cha, FILES_TICKET, File, FilesOp, SortBy, maybe_exists, mounts::PARTITIONS};
|
||||
use crate::{FILES_TICKET, File, FilesOp, SortBy, cha::Cha, maybe_exists, mounts::PARTITIONS};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Files {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{borrow::Cow, collections::{HashMap, HashSet, VecDeque}, ffi::{OsStr, O
|
|||
use anyhow::{Result, bail};
|
||||
use tokio::{fs, io::{self, AsyncWriteExt}, select, sync::{mpsc, oneshot}, time};
|
||||
|
||||
use super::Cha;
|
||||
use crate::cha::Cha;
|
||||
|
||||
#[inline]
|
||||
pub async fn must_exists(p: impl AsRef<Path>) -> bool { fs::symlink_metadata(p).await.is_ok() }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#![allow(clippy::if_same_then_else, clippy::option_map_unit_fn)]
|
||||
|
||||
yazi_macro::mod_pub!(mounts);
|
||||
yazi_macro::mod_pub!(cha mounts);
|
||||
|
||||
yazi_macro::mod_flat!(cha cwd file files filter fns op path sorter sorting stage step xdg);
|
||||
yazi_macro::mod_flat!(cwd file files filter fns op path sorter sorting stage step xdg);
|
||||
|
||||
pub fn init() {
|
||||
CWD.init(<_>::default());
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use parking_lot::RwLock;
|
|||
use yazi_shared::RoCell;
|
||||
|
||||
use super::Partition;
|
||||
use crate::Cha;
|
||||
use crate::cha::Cha;
|
||||
|
||||
pub(super) type Locked = Arc<RwLock<Partitions>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ use std::collections::{HashMap, HashSet};
|
|||
|
||||
use yazi_shared::{Id, Ids, event::Cmd, url::{Url, UrnBuf}};
|
||||
|
||||
use super::{Cha, File};
|
||||
use super::File;
|
||||
use crate::cha::Cha;
|
||||
|
||||
pub static FILES_TICKET: Ids = Ids::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
use std::{ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_fs::ChaKind;
|
||||
use yazi_fs::cha::ChaKind;
|
||||
|
||||
#[derive(Clone, Copy, FromLua)]
|
||||
pub struct Cha(yazi_fs::Cha);
|
||||
pub struct Cha(yazi_fs::cha::Cha);
|
||||
|
||||
impl Deref for Cha {
|
||||
type Target = yazi_fs::Cha;
|
||||
type Target = yazi_fs::cha::Cha;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl<T: Into<yazi_fs::Cha>> From<T> for Cha {
|
||||
impl<T: Into<yazi_fs::cha::Cha>> From<T> for Cha {
|
||||
fn from(cha: T) -> Self { Self(cha.into()) }
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ impl Cha {
|
|||
let kind =
|
||||
ChaKind::from_bits(t.raw_get("kind")?).ok_or_else(|| "Invalid kind".into_lua_err())?;
|
||||
|
||||
Self::from(yazi_fs::Cha {
|
||||
Self::from(yazi_fs::cha::Cha {
|
||||
kind,
|
||||
len: t.raw_get("len").unwrap_or_default(),
|
||||
atime: parse_time(t.raw_get("atime").ok())?,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::{elements::{Area, Rect, Renderable, Text, WRAP, WRAP_NO}, external::H
|
|||
#[derive(Debug, Default)]
|
||||
pub struct PreviewLock {
|
||||
pub url: yazi_shared::url::Url,
|
||||
pub cha: yazi_fs::Cha,
|
||||
pub cha: yazi_fs::cha::Cha,
|
||||
pub mime: String,
|
||||
|
||||
pub skip: usize,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::{elements::Renderable, file::FileRef};
|
|||
|
||||
pub struct SpotLock {
|
||||
pub url: yazi_shared::url::Url,
|
||||
pub cha: yazi_fs::Cha,
|
||||
pub cha: yazi_fs::cha::Cha,
|
||||
pub mime: String,
|
||||
|
||||
pub skip: usize,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use anyhow::{Result, anyhow};
|
|||
use tokio::{fs::{self, DirEntry}, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||
use tracing::warn;
|
||||
use yazi_config::TASKS;
|
||||
use yazi_fs::{Cha, calculate_size, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to, skip_path};
|
||||
use yazi_fs::{calculate_size, cha::Cha, copy_with_progress, maybe_exists, ok_or_not_found, path_relative_to, skip_path};
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
use super::{FileOp, FileOpDelete, FileOpHardlink, FileOpLink, FileOpPaste, FileOpTrash};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use yazi_fs::Cha;
|
||||
use yazi_fs::cha::Cha;
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue