mirror of
https://github.com/wez/wezterm.git
synced 2024-11-22 22:42:48 +03:00
Switch to camino::{Utf8PathBuf, Utf8Path}
This commit is contained in:
parent
1ff2a1eb82
commit
2415a44d74
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -550,6 +550,12 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
@ -5364,6 +5370,7 @@ dependencies = [
|
||||
"async_ossl",
|
||||
"base64",
|
||||
"bitflags",
|
||||
"camino",
|
||||
"dirs-next",
|
||||
"filedescriptor",
|
||||
"filenamegen",
|
||||
|
@ -17,6 +17,7 @@ vendored-openssl = ["ssh2/vendored-openssl"]
|
||||
anyhow = "1.0"
|
||||
base64 = "0.13"
|
||||
bitflags = "1.3"
|
||||
camino = "1.0"
|
||||
dirs-next = "2.0"
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
filenamegen = "0.2"
|
||||
|
@ -11,5 +11,6 @@ pub use pty::*;
|
||||
pub use session::*;
|
||||
|
||||
// NOTE: Re-exported as is exposed in a public API of this crate
|
||||
pub use camino::{Utf8Path, Utf8PathBuf};
|
||||
pub use filedescriptor::FileDescriptor;
|
||||
pub use portable_pty::Child;
|
||||
|
@ -3,6 +3,7 @@ use crate::config::ConfigMap;
|
||||
use crate::host::*;
|
||||
use crate::pty::*;
|
||||
use anyhow::{anyhow, Context};
|
||||
use camino::Utf8PathBuf;
|
||||
use filedescriptor::{
|
||||
poll, pollfd, socketpair, AsRawSocketDescriptor, FileDescriptor, POLLIN, POLLOUT,
|
||||
};
|
||||
@ -10,7 +11,8 @@ use portable_pty::{ExitStatus, PtySize};
|
||||
use smol::channel::{bounded, Receiver, Sender, TryRecvError};
|
||||
use ssh2::BlockDirections;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::io::{Read, Write};
|
||||
use std::convert::TryFrom;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::net::TcpStream;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
@ -617,8 +619,6 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Open a handle to a file.
|
||||
///
|
||||
/// See [`Sftp::open_mode`] for more information.
|
||||
pub fn open_with_mode(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
@ -629,7 +629,7 @@ impl SessionInner {
|
||||
let open_type: ssh2::OpenType = msg.opts.ty.into();
|
||||
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.open_mode(msg.filename.as_path(), flags, mode, open_type)
|
||||
sftp.open_mode(msg.filename.as_std_path(), flags, mode, open_type)
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
|
||||
@ -646,11 +646,9 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Helper to open a file in the `Read` mode.
|
||||
///
|
||||
/// See [`Sftp::open`] for more information.
|
||||
pub fn open(&mut self, sess: &ssh2::Session, msg: &sftp::Open) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.open(msg.filename.as_path())
|
||||
sftp.open(msg.filename.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
|
||||
@ -667,11 +665,9 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Helper to create a file in write-only mode with truncation.
|
||||
///
|
||||
/// See [`Sftp::create`] for more information.
|
||||
pub fn create(&mut self, sess: &ssh2::Session, msg: &sftp::Create) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.create(msg.filename.as_path())
|
||||
sftp.create(msg.filename.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
|
||||
@ -688,11 +684,9 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Helper to open a directory for reading its contents.
|
||||
///
|
||||
/// See [`Sftp::opendir`] for more information.
|
||||
pub fn open_dir(&mut self, sess: &ssh2::Session, msg: &sftp::OpenDir) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.opendir(msg.filename.as_path())
|
||||
sftp.opendir(msg.filename.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
|
||||
@ -821,8 +815,14 @@ impl SessionInner {
|
||||
if let Some(file) = self.files.get_mut(&msg.file_id) {
|
||||
let result = file
|
||||
.readdir()
|
||||
.map(|(path, stat)| (path, Metadata::from(stat)))
|
||||
.map_err(SftpChannelError::from);
|
||||
.map_err(SftpChannelError::from)
|
||||
.and_then(|(path, stat)| match Utf8PathBuf::try_from(path) {
|
||||
Ok(path) => Ok((path, Metadata::from(stat))),
|
||||
Err(x) => Err(SftpChannelError::from(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
x,
|
||||
))),
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
}
|
||||
|
||||
@ -844,18 +844,26 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Convenience function to read the files in a directory.
|
||||
///
|
||||
/// See [`Sftp::readdir`] for more information.
|
||||
pub fn read_dir(&mut self, sess: &ssh2::Session, msg: &sftp::ReadDir) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.readdir(msg.filename.as_path())
|
||||
.map(|entries| {
|
||||
entries
|
||||
.into_iter()
|
||||
.map(|(path, stat)| (path, Metadata::from(stat)))
|
||||
.collect()
|
||||
})
|
||||
sftp.readdir(msg.filename.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
.and_then(|entries| {
|
||||
let mut mapped_entries = Vec::new();
|
||||
for (path, stat) in entries {
|
||||
match Utf8PathBuf::try_from(path) {
|
||||
Ok(path) => mapped_entries.push((path, Metadata::from(stat))),
|
||||
Err(x) => {
|
||||
return Err(SftpChannelError::from(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
x,
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mapped_entries)
|
||||
})
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
|
||||
@ -863,15 +871,13 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Create a directory on the remote filesystem.
|
||||
///
|
||||
/// See [`Sftp::rmdir`] for more information.
|
||||
pub fn create_dir(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::CreateDir,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.mkdir(msg.filename.as_path(), msg.mode)
|
||||
sftp.mkdir(msg.filename.as_std_path(), msg.mode)
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
@ -880,15 +886,13 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Remove a directory from the remote filesystem.
|
||||
///
|
||||
/// See [`Sftp::rmdir`] for more information.
|
||||
pub fn remove_dir(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::RemoveDir,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.rmdir(msg.filename.as_path())
|
||||
sftp.rmdir(msg.filename.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
@ -897,15 +901,13 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Get the metadata for a file, performed by stat(2).
|
||||
///
|
||||
/// See [`Sftp::stat`] for more information.
|
||||
pub fn metadata(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::GetMetadata,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.stat(msg.filename.as_path())
|
||||
sftp.stat(msg.filename.as_std_path())
|
||||
.map(Metadata::from)
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
@ -915,15 +917,13 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Get the metadata for a file, performed by lstat(2).
|
||||
///
|
||||
/// See [`Sftp::lstat`] for more information.
|
||||
pub fn symlink_metadata(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::SymlinkMetadata,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.lstat(msg.filename.as_path())
|
||||
sftp.lstat(msg.filename.as_std_path())
|
||||
.map(Metadata::from)
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
@ -933,15 +933,13 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Set the metadata for a file.
|
||||
///
|
||||
/// See [`Sftp::setstat`] for more information.
|
||||
pub fn set_metadata(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::SetMetadata,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.setstat(msg.filename.as_path(), msg.metadata.into())
|
||||
sftp.setstat(msg.filename.as_std_path(), msg.metadata.into())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
@ -950,11 +948,9 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Create symlink at `target` pointing at `path`.
|
||||
///
|
||||
/// See [`Sftp::symlink`] for more information.
|
||||
pub fn symlink(&mut self, sess: &ssh2::Session, msg: &sftp::Symlink) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.symlink(msg.path.as_path(), msg.target.as_path())
|
||||
sftp.symlink(msg.path.as_std_path(), msg.target.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
@ -963,12 +959,15 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Read a symlink at `path`.
|
||||
///
|
||||
/// See [`Sftp::readlink`] for more information.
|
||||
pub fn read_link(&mut self, sess: &ssh2::Session, msg: &sftp::ReadLink) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.readlink(msg.path.as_path())
|
||||
sftp.readlink(msg.path.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
.and_then(|path| {
|
||||
Utf8PathBuf::try_from(path).map_err(|x| {
|
||||
SftpChannelError::from(io::Error::new(io::ErrorKind::InvalidData, x))
|
||||
})
|
||||
})
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
|
||||
@ -976,16 +975,19 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Resolve the real path for `path`.
|
||||
///
|
||||
/// See [`Sftp::realpath`] for more information.
|
||||
pub fn canonicalize(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::Canonicalize,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.realpath(msg.path.as_path())
|
||||
sftp.realpath(msg.path.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
.and_then(|path| {
|
||||
Utf8PathBuf::try_from(path).map_err(|x| {
|
||||
SftpChannelError::from(io::Error::new(io::ErrorKind::InvalidData, x))
|
||||
})
|
||||
})
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
|
||||
@ -993,12 +995,14 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Rename the filesystem object on the remote filesystem.
|
||||
///
|
||||
/// See [`Sftp::rename`] for more information.
|
||||
pub fn rename(&mut self, sess: &ssh2::Session, msg: &sftp::Rename) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.rename(msg.src.as_path(), msg.dst.as_path(), Some(msg.opts.into()))
|
||||
.map_err(SftpChannelError::from)
|
||||
sftp.rename(
|
||||
msg.src.as_std_path(),
|
||||
msg.dst.as_std_path(),
|
||||
Some(msg.opts.into()),
|
||||
)
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
|
||||
@ -1006,15 +1010,13 @@ impl SessionInner {
|
||||
}
|
||||
|
||||
/// Remove a file on the remote filesystem.
|
||||
///
|
||||
/// See [`Sftp::unlink`] for more information.
|
||||
pub fn remove_file(
|
||||
&mut self,
|
||||
sess: &ssh2::Session,
|
||||
msg: &sftp::RemoveFile,
|
||||
) -> anyhow::Result<()> {
|
||||
let result = self.init_sftp(sess).and_then(|sftp| {
|
||||
sftp.unlink(msg.file.as_path())
|
||||
sftp.unlink(msg.file.as_std_path())
|
||||
.map_err(SftpChannelError::from)
|
||||
});
|
||||
msg.reply.try_send(result)?;
|
||||
|
@ -1,6 +1,8 @@
|
||||
use super::{SessionRequest, SessionSender};
|
||||
use camino::Utf8PathBuf;
|
||||
use smol::channel::{bounded, RecvError, Sender};
|
||||
use std::path::PathBuf;
|
||||
use std::convert::TryInto;
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
mod error;
|
||||
@ -18,6 +20,13 @@ pub use types::{
|
||||
FilePermissions, FileType, Metadata, OpenFileType, OpenOptions, RenameOptions, WriteMode,
|
||||
};
|
||||
|
||||
fn into_invalid_data<E>(err: E) -> io::Error
|
||||
where
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
io::Error::new(io::ErrorKind::InvalidData, err)
|
||||
}
|
||||
|
||||
/// Represents the result of some SFTP channel operation
|
||||
pub type SftpChannelResult<T> = Result<T, SftpChannelError>;
|
||||
|
||||
@ -48,17 +57,21 @@ pub struct Sftp {
|
||||
|
||||
impl Sftp {
|
||||
/// Open a handle to a file.
|
||||
pub async fn open_with_mode(
|
||||
pub async fn open_with_mode<T, E>(
|
||||
&self,
|
||||
filename: impl Into<PathBuf>,
|
||||
filename: T,
|
||||
opts: OpenOptions,
|
||||
) -> SftpChannelResult<File> {
|
||||
) -> SftpChannelResult<File>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::OpenWithMode(
|
||||
OpenWithMode {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
opts,
|
||||
reply,
|
||||
},
|
||||
@ -70,11 +83,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Helper to open a file in the `Read` mode.
|
||||
pub async fn open(&self, filename: impl Into<PathBuf>) -> SftpChannelResult<File> {
|
||||
pub async fn open<T, E>(&self, filename: T) -> SftpChannelResult<File>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::Open(Open {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -84,11 +101,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Helper to create a file in write-only mode with truncation.
|
||||
pub async fn create(&self, filename: impl Into<PathBuf>) -> SftpChannelResult<File> {
|
||||
pub async fn create<T, E>(&self, filename: T) -> SftpChannelResult<File>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::Create(Create {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -98,11 +119,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Helper to open a directory for reading its contents.
|
||||
pub async fn open_dir(&self, filename: impl Into<PathBuf>) -> SftpChannelResult<File> {
|
||||
pub async fn open_dir<T, E>(&self, filename: T) -> SftpChannelResult<File>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::OpenDir(OpenDir {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -115,14 +140,18 @@ impl Sftp {
|
||||
///
|
||||
/// The returned paths are all joined with dirname when returned, and the paths . and .. are
|
||||
/// filtered out of the returned list.
|
||||
pub async fn read_dir(
|
||||
pub async fn read_dir<T, E>(
|
||||
&self,
|
||||
filename: impl Into<PathBuf>,
|
||||
) -> SftpChannelResult<Vec<(PathBuf, Metadata)>> {
|
||||
filename: T,
|
||||
) -> SftpChannelResult<Vec<(Utf8PathBuf, Metadata)>>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::ReadDir(ReadDir {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -131,15 +160,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Create a directory on the remote filesystem.
|
||||
pub async fn create_dir(
|
||||
&self,
|
||||
filename: impl Into<PathBuf>,
|
||||
mode: i32,
|
||||
) -> SftpChannelResult<()> {
|
||||
pub async fn create_dir<T, E>(&self, filename: T, mode: i32) -> SftpChannelResult<()>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::CreateDir(CreateDir {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
mode,
|
||||
reply,
|
||||
})))
|
||||
@ -149,11 +178,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Remove a directory from the remote filesystem.
|
||||
pub async fn remove_dir(&self, filename: impl Into<PathBuf>) -> SftpChannelResult<()> {
|
||||
pub async fn remove_dir<T, E>(&self, filename: T) -> SftpChannelResult<()>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::RemoveDir(RemoveDir {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -162,11 +195,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Get the metadata for a file, performed by stat(2).
|
||||
pub async fn metadata(&self, filename: impl Into<PathBuf>) -> SftpChannelResult<Metadata> {
|
||||
pub async fn metadata<T, E>(&self, filename: T) -> SftpChannelResult<Metadata>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::Metadata(GetMetadata {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -175,15 +212,16 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Get the metadata for a file, performed by lstat(2).
|
||||
pub async fn symlink_metadata(
|
||||
&self,
|
||||
filename: impl Into<PathBuf>,
|
||||
) -> SftpChannelResult<Metadata> {
|
||||
pub async fn symlink_metadata<T, E>(&self, filename: T) -> SftpChannelResult<Metadata>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::SymlinkMetadata(
|
||||
SymlinkMetadata {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
},
|
||||
)))
|
||||
@ -193,16 +231,16 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Set the metadata for a file.
|
||||
pub async fn set_metadata(
|
||||
&self,
|
||||
filename: impl Into<PathBuf>,
|
||||
metadata: Metadata,
|
||||
) -> SftpChannelResult<()> {
|
||||
pub async fn set_metadata<T, E>(&self, filename: T, metadata: Metadata) -> SftpChannelResult<()>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::SetMetadata(
|
||||
SetMetadata {
|
||||
filename: filename.into(),
|
||||
filename: filename.try_into().map_err(into_invalid_data)?,
|
||||
metadata,
|
||||
reply,
|
||||
},
|
||||
@ -213,16 +251,18 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Create symlink at `target` pointing at `path`.
|
||||
pub async fn symlink(
|
||||
&self,
|
||||
path: impl Into<PathBuf>,
|
||||
target: impl Into<PathBuf>,
|
||||
) -> SftpChannelResult<()> {
|
||||
pub async fn symlink<T1, T2, E1, E2>(&self, path: T1, target: T2) -> SftpChannelResult<()>
|
||||
where
|
||||
T1: TryInto<Utf8PathBuf, Error = E1>,
|
||||
T2: TryInto<Utf8PathBuf, Error = E2>,
|
||||
E1: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
E2: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::Symlink(Symlink {
|
||||
path: path.into(),
|
||||
target: target.into(),
|
||||
path: path.try_into().map_err(into_invalid_data)?,
|
||||
target: target.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -231,11 +271,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Read a symlink at `path`.
|
||||
pub async fn read_link(&self, path: impl Into<PathBuf>) -> SftpChannelResult<PathBuf> {
|
||||
pub async fn read_link<T, E>(&self, path: T) -> SftpChannelResult<Utf8PathBuf>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::ReadLink(ReadLink {
|
||||
path: path.into(),
|
||||
path: path.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -244,12 +288,16 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Resolve the real path for `path`.
|
||||
pub async fn canonicalize(&self, path: impl Into<PathBuf>) -> SftpChannelResult<PathBuf> {
|
||||
pub async fn canonicalize<T, E>(&self, path: T) -> SftpChannelResult<Utf8PathBuf>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::Canonicalize(
|
||||
Canonicalize {
|
||||
path: path.into(),
|
||||
path: path.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
},
|
||||
)))
|
||||
@ -259,17 +307,23 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Rename the filesystem object on the remote filesystem.
|
||||
pub async fn rename(
|
||||
pub async fn rename<T1, T2, E1, E2>(
|
||||
&self,
|
||||
src: impl Into<PathBuf>,
|
||||
dst: impl Into<PathBuf>,
|
||||
src: T1,
|
||||
dst: T2,
|
||||
opts: RenameOptions,
|
||||
) -> SftpChannelResult<()> {
|
||||
) -> SftpChannelResult<()>
|
||||
where
|
||||
T1: TryInto<Utf8PathBuf, Error = E1>,
|
||||
T2: TryInto<Utf8PathBuf, Error = E2>,
|
||||
E1: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
E2: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::Rename(Rename {
|
||||
src: src.into(),
|
||||
dst: dst.into(),
|
||||
src: src.try_into().map_err(into_invalid_data)?,
|
||||
dst: dst.try_into().map_err(into_invalid_data)?,
|
||||
opts,
|
||||
reply,
|
||||
})))
|
||||
@ -279,11 +333,15 @@ impl Sftp {
|
||||
}
|
||||
|
||||
/// Remove a file on the remote filesystem.
|
||||
pub async fn remove_file(&self, file: impl Into<PathBuf>) -> SftpChannelResult<()> {
|
||||
pub async fn remove_file<T, E>(&self, file: T) -> SftpChannelResult<()>
|
||||
where
|
||||
T: TryInto<Utf8PathBuf, Error = E>,
|
||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
{
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.send(SessionRequest::Sftp(SftpRequest::RemoveFile(RemoveFile {
|
||||
file: file.into(),
|
||||
file: file.try_into().map_err(into_invalid_data)?,
|
||||
reply,
|
||||
})))
|
||||
.await?;
|
||||
@ -316,97 +374,97 @@ pub(crate) enum SftpRequest {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OpenWithMode {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub opts: OpenOptions,
|
||||
pub reply: Sender<SftpChannelResult<File>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Open {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<File>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Create {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<File>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OpenDir {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<File>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadDir {
|
||||
pub filename: PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<Vec<(PathBuf, Metadata)>>>,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<Vec<(Utf8PathBuf, Metadata)>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CreateDir {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub mode: i32,
|
||||
pub reply: Sender<SftpChannelResult<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct RemoveDir {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct GetMetadata {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<Metadata>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SymlinkMetadata {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<Metadata>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SetMetadata {
|
||||
pub filename: PathBuf,
|
||||
pub filename: Utf8PathBuf,
|
||||
pub metadata: Metadata,
|
||||
pub reply: Sender<SftpChannelResult<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Symlink {
|
||||
pub path: PathBuf,
|
||||
pub target: PathBuf,
|
||||
pub path: Utf8PathBuf,
|
||||
pub target: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadLink {
|
||||
pub path: PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<PathBuf>>,
|
||||
pub path: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<Utf8PathBuf>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Canonicalize {
|
||||
pub path: PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<PathBuf>>,
|
||||
pub path: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<Utf8PathBuf>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Rename {
|
||||
pub src: PathBuf,
|
||||
pub dst: PathBuf,
|
||||
pub src: Utf8PathBuf,
|
||||
pub dst: Utf8PathBuf,
|
||||
pub opts: RenameOptions,
|
||||
pub reply: Sender<SftpChannelResult<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct RemoveFile {
|
||||
pub file: PathBuf,
|
||||
pub file: Utf8PathBuf,
|
||||
pub reply: Sender<SftpChannelResult<()>>,
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
use super::{Metadata, SessionRequest, SessionSender, SftpChannelResult, SftpRequest};
|
||||
use camino::Utf8PathBuf;
|
||||
use smol::channel::{bounded, Sender};
|
||||
use smol::future::FutureExt;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{fmt, future::Future, io, path::PathBuf, pin::Pin};
|
||||
use std::{fmt, future::Future, io, pin::Pin};
|
||||
|
||||
pub(crate) type FileId = usize;
|
||||
|
||||
@ -75,7 +76,7 @@ pub(crate) struct MetadataFile {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadDirFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<SftpChannelResult<(PathBuf, Metadata)>>,
|
||||
pub reply: Sender<SftpChannelResult<(Utf8PathBuf, Metadata)>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -170,7 +171,7 @@ impl File {
|
||||
/// files in this directory.
|
||||
///
|
||||
/// See [`ssh2::File::readdir`] for more information.
|
||||
pub async fn read_dir(&self) -> anyhow::Result<(PathBuf, Metadata)> {
|
||||
pub async fn read_dir(&self) -> anyhow::Result<(Utf8PathBuf, Metadata)> {
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.as_ref()
|
||||
|
@ -2,8 +2,8 @@ use crate::sshd::session;
|
||||
use assert_fs::{prelude::*, TempDir};
|
||||
use predicates::prelude::*;
|
||||
use rstest::*;
|
||||
use std::path::PathBuf;
|
||||
use wezterm_ssh::{FileType, Session, SftpChannelError, SftpError};
|
||||
use std::convert::TryInto;
|
||||
use wezterm_ssh::{FileType, Session, SftpChannelError, SftpError, Utf8PathBuf};
|
||||
|
||||
// Sftp file tests
|
||||
mod file;
|
||||
@ -47,23 +47,26 @@ async fn read_dir_should_return_list_of_directories_files_and_symlinks(#[future]
|
||||
|
||||
let mut contents = session
|
||||
.sftp()
|
||||
.read_dir(temp.path())
|
||||
.read_dir(temp.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to read directory")
|
||||
.into_iter()
|
||||
.map(|(p, s)| (p, file_type_to_str(s.ty)))
|
||||
.collect::<Vec<(PathBuf, &'static str)>>();
|
||||
.collect::<Vec<(Utf8PathBuf, &'static str)>>();
|
||||
contents.sort_unstable_by_key(|(p, _)| p.to_path_buf());
|
||||
|
||||
assert_eq!(
|
||||
contents,
|
||||
vec![
|
||||
(dir1.path().to_path_buf(), "dir"),
|
||||
(dir2.path().to_path_buf(), "dir"),
|
||||
(file1.path().to_path_buf(), "file"),
|
||||
(file2.path().to_path_buf(), "file"),
|
||||
(link_dir.path().to_path_buf(), "symlink"),
|
||||
(link_file.path().to_path_buf(), "symlink"),
|
||||
(dir1.path().to_path_buf().try_into().unwrap(), "dir"),
|
||||
(dir2.path().to_path_buf().try_into().unwrap(), "dir"),
|
||||
(file1.path().to_path_buf().try_into().unwrap(), "file"),
|
||||
(file2.path().to_path_buf().try_into().unwrap(), "file"),
|
||||
(link_dir.path().to_path_buf().try_into().unwrap(), "symlink"),
|
||||
(
|
||||
link_file.path().to_path_buf().try_into().unwrap(),
|
||||
"symlink"
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -78,7 +81,7 @@ async fn create_dir_should_create_a_directory_on_the_remote_filesystem(#[future]
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.create_dir(temp.child("dir").path(), 0o644)
|
||||
.create_dir(temp.child("dir").path().to_path_buf(), 0o644)
|
||||
.await
|
||||
.expect("Failed to create directory");
|
||||
|
||||
@ -97,7 +100,7 @@ async fn create_dir_should_return_error_if_unable_to_create_directory(#[future]
|
||||
// Attempt to create a nested directory structure, which is not supported
|
||||
let result = session
|
||||
.sftp()
|
||||
.create_dir(temp.child("dir").child("dir").path(), 0o644)
|
||||
.create_dir(temp.child("dir").child("dir").path().to_path_buf(), 0o644)
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
@ -125,7 +128,7 @@ async fn remove_dir_should_remove_a_remote_directory(#[future] session: Session)
|
||||
dir.create_dir_all().unwrap();
|
||||
session
|
||||
.sftp()
|
||||
.remove_dir(dir.path())
|
||||
.remove_dir(dir.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to remove directory");
|
||||
|
||||
@ -146,7 +149,7 @@ async fn remove_dir_should_return_an_error_if_failed_to_remove_directory(
|
||||
// Attempt to remove a missing path
|
||||
let result = session
|
||||
.sftp()
|
||||
.remove_dir(temp.child("missing-dir").path())
|
||||
.remove_dir(temp.child("missing-dir").path().to_path_buf())
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
@ -159,7 +162,7 @@ async fn remove_dir_should_return_an_error_if_failed_to_remove_directory(
|
||||
dir.create_dir_all().unwrap();
|
||||
dir.child("file").touch().unwrap();
|
||||
|
||||
let result = session.sftp().remove_dir(dir.path()).await;
|
||||
let result = session.sftp().remove_dir(dir.path().to_path_buf()).await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Unexpectedly succeeded in removing non-empty directory: {:?}",
|
||||
@ -172,7 +175,7 @@ async fn remove_dir_should_return_an_error_if_failed_to_remove_directory(
|
||||
// Attempt to remove a file (not a directory)
|
||||
let file = temp.child("file");
|
||||
file.touch().unwrap();
|
||||
let result = session.sftp().remove_dir(file.path()).await;
|
||||
let result = session.sftp().remove_dir(file.path().to_path_buf()).await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Unexpectedly succeeded in removing file: {:?}",
|
||||
@ -195,7 +198,7 @@ async fn metadata_should_return_metadata_about_a_file(#[future] session: Session
|
||||
|
||||
let metadata = session
|
||||
.sftp()
|
||||
.metadata(file.path())
|
||||
.metadata(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for file");
|
||||
|
||||
@ -215,7 +218,7 @@ async fn metadata_should_return_metadata_about_a_directory(#[future] session: Se
|
||||
|
||||
let metadata = session
|
||||
.sftp()
|
||||
.metadata(dir.path())
|
||||
.metadata(dir.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for dir");
|
||||
|
||||
@ -240,7 +243,7 @@ async fn metadata_should_return_metadata_about_the_file_pointed_to_by_a_symlink(
|
||||
|
||||
let metadata = session
|
||||
.sftp()
|
||||
.metadata(link.path())
|
||||
.metadata(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for symlink");
|
||||
|
||||
@ -267,7 +270,7 @@ async fn metadata_should_return_metadata_about_the_dir_pointed_to_by_a_symlink(
|
||||
|
||||
let metadata = session
|
||||
.sftp()
|
||||
.metadata(link.path())
|
||||
.metadata(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for symlink");
|
||||
|
||||
@ -285,7 +288,10 @@ async fn metadata_should_fail_if_path_missing(#[future] session: Session) {
|
||||
|
||||
let temp = TempDir::new().unwrap();
|
||||
|
||||
let result = session.sftp().metadata(temp.child("missing").path()).await;
|
||||
let result = session
|
||||
.sftp()
|
||||
.metadata(temp.child("missing").path().to_path_buf())
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Metadata unexpectedly succeeded: {:?}",
|
||||
@ -305,7 +311,7 @@ async fn symlink_metadata_should_return_metadata_about_a_file(#[future] session:
|
||||
|
||||
let symlink_metadata = session
|
||||
.sftp()
|
||||
.symlink_metadata(file.path())
|
||||
.symlink_metadata(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for file");
|
||||
|
||||
@ -325,7 +331,7 @@ async fn symlink_metadata_should_return_metadata_about_a_directory(#[future] ses
|
||||
|
||||
let symlink_metadata = session
|
||||
.sftp()
|
||||
.symlink_metadata(dir.path())
|
||||
.symlink_metadata(dir.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to metadata for dir");
|
||||
|
||||
@ -350,7 +356,7 @@ async fn symlink_metadata_should_return_metadata_about_symlink_pointing_to_a_fil
|
||||
|
||||
let metadata = session
|
||||
.sftp()
|
||||
.symlink_metadata(link.path())
|
||||
.symlink_metadata(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for symlink");
|
||||
|
||||
@ -377,7 +383,7 @@ async fn symlink_metadata_should_return_metadata_about_symlink_pointing_to_a_dir
|
||||
|
||||
let metadata = session
|
||||
.sftp()
|
||||
.symlink_metadata(link.path())
|
||||
.symlink_metadata(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to get metadata for symlink");
|
||||
|
||||
@ -397,7 +403,7 @@ async fn symlink_metadata_should_fail_if_path_missing(#[future] session: Session
|
||||
|
||||
let result = session
|
||||
.sftp()
|
||||
.symlink_metadata(temp.child("missing").path())
|
||||
.symlink_metadata(temp.child("missing").path().to_path_buf())
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
@ -420,7 +426,7 @@ async fn symlink_should_create_symlink_pointing_to_file(#[future] session: Sessi
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.symlink(file.path(), link.path())
|
||||
.symlink(file.path().to_path_buf(), link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to create symlink");
|
||||
|
||||
@ -451,7 +457,7 @@ async fn symlink_should_create_symlink_pointing_to_directory(#[future] session:
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.symlink(dir.path(), link.path())
|
||||
.symlink(dir.path().to_path_buf(), link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to create symlink");
|
||||
|
||||
@ -471,7 +477,7 @@ async fn symlink_should_succeed_even_if_path_missing(#[future] session: Session)
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.symlink(file.path(), link.path())
|
||||
.symlink(file.path().to_path_buf(), link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to create symlink");
|
||||
|
||||
@ -494,7 +500,7 @@ async fn read_link_should_return_the_target_of_the_symlink(#[future] session: Se
|
||||
|
||||
let path = session
|
||||
.sftp()
|
||||
.read_link(link.path())
|
||||
.read_link(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to read symlink");
|
||||
assert_eq!(path, dir.path());
|
||||
@ -507,7 +513,7 @@ async fn read_link_should_return_the_target_of_the_symlink(#[future] session: Se
|
||||
|
||||
let path = session
|
||||
.sftp()
|
||||
.read_link(link.path())
|
||||
.read_link(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to read symlink");
|
||||
assert_eq!(path, file.path());
|
||||
@ -522,7 +528,10 @@ async fn read_link_should_fail_if_path_is_not_a_symlink(#[future] session: Sessi
|
||||
let temp = TempDir::new().unwrap();
|
||||
|
||||
// Test missing path
|
||||
let result = session.sftp().read_link(temp.child("missing").path()).await;
|
||||
let result = session
|
||||
.sftp()
|
||||
.read_link(temp.child("missing").path().to_path_buf())
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Unexpectedly read link for missing path: {:?}",
|
||||
@ -532,7 +541,7 @@ async fn read_link_should_fail_if_path_is_not_a_symlink(#[future] session: Sessi
|
||||
// Test a directory
|
||||
let dir = temp.child("dir");
|
||||
dir.create_dir_all().unwrap();
|
||||
let result = session.sftp().read_link(dir.path()).await;
|
||||
let result = session.sftp().read_link(dir.path().to_path_buf()).await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Unexpectedly read link for directory: {:?}",
|
||||
@ -542,7 +551,7 @@ async fn read_link_should_fail_if_path_is_not_a_symlink(#[future] session: Sessi
|
||||
// Test a file
|
||||
let file = temp.child("file");
|
||||
file.touch().unwrap();
|
||||
let result = session.sftp().read_link(file.path()).await;
|
||||
let result = session.sftp().read_link(file.path().to_path_buf()).await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Unexpectedly read link for file: {:?}",
|
||||
@ -568,7 +577,7 @@ async fn canonicalize_should_resolve_absolute_path_for_relative_path(#[future] s
|
||||
// on mac the /tmp dir is a symlink to /private/tmp; so, we cannot successfully
|
||||
// check the accuracy of the path itself, meaning that we can only validate
|
||||
// that the operation was okay.
|
||||
let result = session.sftp().canonicalize(rel.path()).await;
|
||||
let result = session.sftp().canonicalize(rel.path().to_path_buf()).await;
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Canonicalize unexpectedly failed: {:?}",
|
||||
@ -596,7 +605,10 @@ async fn canonicalize_should_either_return_resolved_path_or_error_if_missing(
|
||||
// Additionally, this has divergent behavior. On some platforms, this returns
|
||||
// the path as is whereas on others this returns a missing path error. We
|
||||
// have to support both checks.
|
||||
let result = session.sftp().canonicalize(missing.path()).await;
|
||||
let result = session
|
||||
.sftp()
|
||||
.canonicalize(missing.path().to_path_buf())
|
||||
.await;
|
||||
match result {
|
||||
Ok(_) => {}
|
||||
Err(SftpChannelError::Sftp(SftpError::NoSuchFile)) => {}
|
||||
@ -613,7 +625,10 @@ async fn canonicalize_should_fail_if_resolving_missing_path_with_dots(#[future]
|
||||
let temp = TempDir::new().unwrap();
|
||||
let missing = temp.child(".").child("hello").child("..").child("world");
|
||||
|
||||
let result = session.sftp().canonicalize(missing.path()).await;
|
||||
let result = session
|
||||
.sftp()
|
||||
.canonicalize(missing.path().to_path_buf())
|
||||
.await;
|
||||
assert!(result.is_err(), "Canonicalize unexpectedly succeeded");
|
||||
}
|
||||
|
||||
@ -631,7 +646,11 @@ async fn rename_should_support_singular_file(#[future] session: Session) {
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.rename(file.path(), dst.path(), Default::default())
|
||||
.rename(
|
||||
file.path().to_path_buf(),
|
||||
dst.path().to_path_buf(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to rename file");
|
||||
|
||||
@ -658,7 +677,11 @@ async fn rename_should_support_dirtectory(#[future] session: Session) {
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.rename(dir.path(), dst.path(), Default::default())
|
||||
.rename(
|
||||
dir.path().to_path_buf(),
|
||||
dst.path().to_path_buf(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to rename directory");
|
||||
|
||||
@ -684,7 +707,11 @@ async fn rename_should_fail_if_source_path_missing(#[future] session: Session) {
|
||||
|
||||
let result = session
|
||||
.sftp()
|
||||
.rename(missing.path(), dst.path(), Default::default())
|
||||
.rename(
|
||||
missing.path().to_path_buf(),
|
||||
dst.path().to_path_buf(),
|
||||
Default::default(),
|
||||
)
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
@ -705,7 +732,7 @@ async fn remove_file_should_remove_file(#[future] session: Session) {
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.remove_file(file.path())
|
||||
.remove_file(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to remove file");
|
||||
|
||||
@ -726,7 +753,7 @@ async fn remove_file_should_remove_symlink_to_file(#[future] session: Session) {
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.remove_file(link.path())
|
||||
.remove_file(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to remove symlink");
|
||||
|
||||
@ -749,7 +776,7 @@ async fn remove_file_should_remove_symlink_to_directory(#[future] session: Sessi
|
||||
|
||||
session
|
||||
.sftp()
|
||||
.remove_file(link.path())
|
||||
.remove_file(link.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to remove symlink");
|
||||
|
||||
@ -768,7 +795,7 @@ async fn remove_file_should_fail_if_path_to_directory(#[future] session: Session
|
||||
let dir = temp.child("dir");
|
||||
dir.create_dir_all().unwrap();
|
||||
|
||||
let result = session.sftp().remove_file(dir.path()).await;
|
||||
let result = session.sftp().remove_file(dir.path().to_path_buf()).await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Unexpectedly removed directory: {:?}",
|
||||
@ -789,7 +816,7 @@ async fn remove_file_should_fail_if_path_missing(#[future] session: Session) {
|
||||
|
||||
let result = session
|
||||
.sftp()
|
||||
.remove_file(temp.child("missing").path())
|
||||
.remove_file(temp.child("missing").path().to_path_buf())
|
||||
.await;
|
||||
assert!(
|
||||
result.is_err(),
|
||||
|
@ -2,6 +2,7 @@ use crate::sshd::session;
|
||||
use assert_fs::{prelude::*, TempDir};
|
||||
use rstest::*;
|
||||
use smol::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use std::convert::TryInto;
|
||||
use std::path::PathBuf;
|
||||
use wezterm_ssh::Session;
|
||||
|
||||
@ -17,7 +18,7 @@ async fn metadata_should_retrieve_file_stat(#[future] session: Session) {
|
||||
|
||||
let remote_file = session
|
||||
.sftp()
|
||||
.open(file.path())
|
||||
.open(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to open remote file");
|
||||
|
||||
@ -46,7 +47,7 @@ async fn read_dir_should_retrieve_next_dir_entry(#[future] session: Session) {
|
||||
|
||||
let remote_dir = session
|
||||
.sftp()
|
||||
.open_dir(temp.path())
|
||||
.open_dir(temp.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to open remote directory");
|
||||
|
||||
@ -70,11 +71,11 @@ async fn read_dir_should_retrieve_next_dir_entry(#[future] session: Session) {
|
||||
assert_eq!(
|
||||
contents,
|
||||
vec![
|
||||
(PathBuf::from("."), "dir"),
|
||||
(PathBuf::from(".."), "dir"),
|
||||
(PathBuf::from("dir"), "dir"),
|
||||
(PathBuf::from("file"), "file"),
|
||||
(PathBuf::from("link"), "symlink"),
|
||||
(PathBuf::from(".").try_into().unwrap(), "dir"),
|
||||
(PathBuf::from("..").try_into().unwrap(), "dir"),
|
||||
(PathBuf::from("dir").try_into().unwrap(), "dir"),
|
||||
(PathBuf::from("file").try_into().unwrap(), "file"),
|
||||
(PathBuf::from("link").try_into().unwrap(), "symlink"),
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -91,7 +92,7 @@ async fn should_support_async_reading(#[future] session: Session) {
|
||||
|
||||
let mut remote_file = session
|
||||
.sftp()
|
||||
.open(file.path())
|
||||
.open(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to open remote file");
|
||||
|
||||
@ -123,7 +124,7 @@ async fn should_support_async_writing(#[future] session: Session) {
|
||||
|
||||
let mut remote_file = session
|
||||
.sftp()
|
||||
.create(file.path())
|
||||
.create(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to open remote file");
|
||||
|
||||
@ -153,7 +154,7 @@ async fn should_support_async_flush(#[future] session: Session) {
|
||||
|
||||
let mut remote_file = session
|
||||
.sftp()
|
||||
.create(file.path())
|
||||
.create(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to open remote file");
|
||||
|
||||
@ -178,7 +179,7 @@ async fn should_support_async_close(#[future] session: Session) {
|
||||
|
||||
let mut remote_file = session
|
||||
.sftp()
|
||||
.create(file.path())
|
||||
.create(file.path().to_path_buf())
|
||||
.await
|
||||
.expect("Failed to open remote file");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user