mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
fix: paste --force doesn't work on existing read-only files with the same name
This commit is contained in:
parent
463150848d
commit
a79d5e21d0
9 changed files with 71 additions and 20 deletions
|
|
@ -41,9 +41,9 @@ impl Actor for Shell {
|
|||
|
||||
TasksProxy::open_shell_compat(ProcessOpt {
|
||||
cwd,
|
||||
cmd: form.run.to_string().into(),
|
||||
args: selected,
|
||||
block: form.block,
|
||||
cmd: form.run.to_string().into(),
|
||||
args: selected,
|
||||
block: form.block,
|
||||
orphan: form.orphan,
|
||||
spread: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ dirs = { workspace = true }
|
|||
either = { workspace = true }
|
||||
foldhash = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
percent-encoding = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
|
|
@ -38,7 +39,6 @@ tracing = { workspace = true }
|
|||
typed-path = { workspace = true }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = { workspace = true }
|
||||
uzers = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
|
|||
|
|
@ -81,17 +81,19 @@ impl Cha {
|
|||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
let 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()
|
||||
}
|
||||
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(),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{io, path::Path, sync::Arc};
|
|||
use tokio::sync::mpsc;
|
||||
use yazi_shared::{path::{AsPath, PathBufDyn}, scheme::SchemeKind, strand::AsStrand, url::{Url, UrlBuf, UrlCow}};
|
||||
|
||||
use crate::{cha::Cha, provider::{Attrs, Capabilities, Provider}};
|
||||
use crate::{cha::{Cha, ChaMode}, provider::{Attrs, Capabilities, Provider}};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Local<'a> {
|
||||
|
|
@ -125,6 +125,26 @@ impl<'a> Provider for Local<'a> {
|
|||
tokio::fs::rename(self.path, to).await
|
||||
}
|
||||
|
||||
async fn set_mode(&self, mode: ChaMode) -> io::Result<()> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
return tokio::fs::set_permissions(self.path, mode.into()).await;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
|
||||
let path: Vec<u16> = self.path.as_os_str().encode_wide().chain(Some(0)).collect();
|
||||
let perm = if mode.contains(ChaMode::U_WRITE) { libc::S_IWRITE } else { libc::S_IREAD };
|
||||
|
||||
return tokio::task::spawn_blocking(move || {
|
||||
let result = unsafe { libc::_wchmod(path.as_ptr(), perm) };
|
||||
if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn symlink<S, F>(&self, original: S, _is_dir: F) -> io::Result<()>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use tokio::{io::{AsyncRead, AsyncSeek, AsyncWrite, AsyncWriteExt}, sync::mpsc};
|
|||
use yazi_macro::ok_or_not_found;
|
||||
use yazi_shared::{path::{AsPath, PathBufDyn}, strand::{AsStrand, StrandCow}, url::{AsUrl, Url, UrlBuf}};
|
||||
|
||||
use crate::{cha::{Cha, ChaType}, provider::{Attrs, Capabilities}};
|
||||
use crate::{cha::{Cha, ChaMode, ChaType}, provider::{Attrs, Capabilities}};
|
||||
|
||||
pub trait Provider: Sized {
|
||||
type File: AsyncRead + AsyncSeek + AsyncWrite + Unpin;
|
||||
|
|
@ -163,6 +163,8 @@ pub trait Provider: Sized {
|
|||
where
|
||||
P: AsPath;
|
||||
|
||||
fn set_mode(&self, mode: ChaMode) -> impl Future<Output = io::Result<()>>;
|
||||
|
||||
fn symlink<S, F>(&self, original: S, _is_dir: F) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
S: AsStrand,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::{hash::{BuildHasher, Hash, Hasher}, io};
|
||||
|
||||
use yazi_fs::cha::ChaMode;
|
||||
use yazi_macro::ok_or_not_found;
|
||||
use yazi_shared::{timestamp_us, url::{AsUrl, Url, UrlBuf}};
|
||||
use yazi_vfs::{provider, unique_file};
|
||||
|
|
@ -31,8 +32,12 @@ impl Transaction {
|
|||
U: AsUrl,
|
||||
{
|
||||
let url = url.as_url();
|
||||
if ok_or_not_found!(provider::symlink_metadata(url).await, return Ok(())).is_link() {
|
||||
|
||||
let cha = ok_or_not_found!(provider::symlink_metadata(url).await, return Ok(()));
|
||||
if cha.is_link() {
|
||||
provider::rename(Self::tmp(url).await?, url).await?;
|
||||
} else if !cha.contains(ChaMode::U_WRITE) {
|
||||
provider::set_mode(url, cha.mode | ChaMode::U_WRITE).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::io;
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use yazi_fs::{cha::Cha, provider::{Attrs, Capabilities, Provider, local::Local}};
|
||||
use yazi_fs::{cha::{Cha, ChaMode}, provider::{Attrs, Capabilities, Provider, local::Local}};
|
||||
use yazi_shared::{path::PathBufDyn, strand::AsStrand, url::{AsUrl, Url, UrlBuf, UrlCow}};
|
||||
|
||||
use super::{Providers, ReadDir, RwFile};
|
||||
|
|
@ -215,6 +215,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn set_mode<U>(url: U, mode: ChaMode) -> io::Result<()>
|
||||
where
|
||||
U: AsUrl,
|
||||
{
|
||||
Providers::new(url.as_url()).await?.set_mode(mode).await
|
||||
}
|
||||
|
||||
pub async fn symlink<U, S, F>(link: U, original: S, is_dir: F) -> io::Result<()>
|
||||
where
|
||||
U: AsUrl,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::io;
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use yazi_fs::{cha::Cha, provider::{Attrs, Capabilities, Provider}};
|
||||
use yazi_fs::{cha::{Cha, ChaMode}, provider::{Attrs, Capabilities, Provider}};
|
||||
use yazi_shared::{path::{AsPath, PathBufDyn}, strand::AsStrand, url::{Url, UrlBuf, UrlCow}};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -175,6 +175,13 @@ impl<'a> Provider for Providers<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
async fn set_mode(&self, mode: ChaMode) -> io::Result<()> {
|
||||
match self {
|
||||
Self::Local(p) => p.set_mode(mode).await,
|
||||
Self::Sftp(p) => p.set_mode(mode).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn symlink<S, F>(&self, original: S, is_dir: F) -> io::Result<()>
|
||||
where
|
||||
S: AsStrand,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{io, sync::Arc};
|
|||
|
||||
use tokio::{io::{AsyncWriteExt, BufReader, BufWriter}, sync::mpsc::Receiver};
|
||||
use yazi_config::vfs::{ServiceSftp, Vfs};
|
||||
use yazi_fs::provider::{Capabilities, DirReader, FileHolder, Provider};
|
||||
use yazi_fs::{cha::ChaMode, provider::{Capabilities, DirReader, FileHolder, Provider}};
|
||||
use yazi_sftp::fs::{Attrs, Flags};
|
||||
use yazi_shared::{loc::LocBuf, path::{AsPath, PathBufDyn}, pool::InternStr, scheme::SchemeKind, strand::AsStrand, url::{Url, UrlBuf, UrlCow, UrlLike}};
|
||||
|
||||
|
|
@ -193,6 +193,14 @@ impl<'a> Provider for Sftp<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_mode(&self, mode: ChaMode) -> io::Result<()> {
|
||||
let attrs = super::Attrs(yazi_fs::provider::Attrs { mode: Some(mode), ..Default::default() })
|
||||
.try_into()
|
||||
.map_err(|()| io::Error::new(io::ErrorKind::InvalidInput, "Cannot convert mode"))?;
|
||||
|
||||
Ok(self.op().await?.setstat(self.path, attrs).await?)
|
||||
}
|
||||
|
||||
async fn symlink<S, F>(&self, original: S, _is_dir: F) -> io::Result<()>
|
||||
where
|
||||
S: AsStrand,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue