mirror of
https://github.com/wez/wezterm.git
synced 2024-11-23 15:04:36 +03:00
Add drop impl to file struct; add missing file methods (untested)
This commit is contained in:
parent
50a0372e17
commit
2e19344b22
@ -17,7 +17,7 @@ use std::time::Duration;
|
||||
|
||||
mod sftp;
|
||||
pub use sftp::{File, Sftp};
|
||||
use sftp::{FileId, SftpRequest};
|
||||
use sftp::{FileId, FileRequest, SftpRequest};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SessionEvent {
|
||||
@ -415,30 +415,54 @@ impl SessionInner {
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::WriteFile(write_file)) => {
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Write(write_file))) => {
|
||||
if let Err(err) = self.write_file(&sess, &write_file) {
|
||||
log::error!("{:?} -> error: {:#}", write_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::ReadFile(read_file)) => {
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Read(read_file))) => {
|
||||
if let Err(err) = self.read_file(&sess, &read_file) {
|
||||
log::error!("{:?} -> error: {:#}", read_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::CloseFile(close_file)) => {
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Close(close_file))) => {
|
||||
if let Err(err) = self.close_file(&sess, &close_file) {
|
||||
log::error!("{:?} -> error: {:#}", close_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::FlushFile(flush_file)) => {
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Flush(flush_file))) => {
|
||||
if let Err(err) = self.flush_file(&sess, &flush_file) {
|
||||
log::error!("{:?} -> error: {:#}", flush_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Setstat(setstat_file))) => {
|
||||
if let Err(err) = self.setstat_file(&sess, &setstat_file) {
|
||||
log::error!("{:?} -> error: {:#}", setstat_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Stat(stat_file))) => {
|
||||
if let Err(err) = self.stat_file(&sess, &stat_file) {
|
||||
log::error!("{:?} -> error: {:#}", stat_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Readdir(readdir_file))) => {
|
||||
if let Err(err) = self.readdir_file(&sess, &readdir_file) {
|
||||
log::error!("{:?} -> error: {:#}", readdir_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::File(FileRequest::Fsync(fsync_file))) => {
|
||||
if let Err(err) = self.fsync_file(&sess, &fsync_file) {
|
||||
log::error!("{:?} -> error: {:#}", fsync_file, err);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
SessionRequest::Sftp(SftpRequest::Readdir(readdir)) => {
|
||||
if let Err(err) = self.readdir(&sess, &readdir) {
|
||||
log::error!("{:?} -> error: {:#}", readdir, err);
|
||||
@ -729,6 +753,68 @@ impl SessionInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets file stat.
|
||||
fn setstat_file(
|
||||
&mut self,
|
||||
_sess: &ssh2::Session,
|
||||
setstat_file: &sftp::SetstatFile,
|
||||
) -> anyhow::Result<()> {
|
||||
let sftp::SetstatFile {
|
||||
file_id,
|
||||
stat,
|
||||
reply,
|
||||
} = setstat_file;
|
||||
|
||||
if let Some(file) = self.files.get_mut(file_id) {
|
||||
file.setstat(stat.clone())?;
|
||||
}
|
||||
reply.try_send(())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets file stat.
|
||||
fn stat_file(
|
||||
&mut self,
|
||||
_sess: &ssh2::Session,
|
||||
stat_file: &sftp::StatFile,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(file) = self.files.get_mut(&stat_file.file_id) {
|
||||
let stat = file.stat()?;
|
||||
stat_file.reply.try_send(stat)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Performs readdir for file.
|
||||
fn readdir_file(
|
||||
&mut self,
|
||||
_sess: &ssh2::Session,
|
||||
readdir_file: &sftp::ReaddirFile,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(file) = self.files.get_mut(&readdir_file.file_id) {
|
||||
let result = file.readdir()?;
|
||||
readdir_file.reply.try_send(result)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fsync file.
|
||||
fn fsync_file(
|
||||
&mut self,
|
||||
_sess: &ssh2::Session,
|
||||
fsync_file: &sftp::FsyncFile,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(file) = self.files.get_mut(&fsync_file.file_id) {
|
||||
file.fsync()?;
|
||||
}
|
||||
fsync_file.reply.try_send(())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Convenience function to read the files in a directory.
|
||||
///
|
||||
/// See [`Sftp::readdir`] for more information.
|
||||
|
@ -5,7 +5,10 @@ use std::{fmt, path::PathBuf};
|
||||
|
||||
mod file;
|
||||
pub use file::File;
|
||||
pub(crate) use file::FileId;
|
||||
pub(crate) use file::{
|
||||
CloseFile, FileId, FileRequest, FlushFile, FsyncFile, ReadFile, ReaddirFile, SetstatFile,
|
||||
StatFile, WriteFile,
|
||||
};
|
||||
|
||||
/// Represents an open sftp channel for performing filesystem operations
|
||||
#[derive(Clone, Debug)]
|
||||
@ -276,7 +279,6 @@ impl Sftp {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum SftpRequest {
|
||||
// Below are standard SFTP operations
|
||||
OpenMode(OpenMode),
|
||||
Open(Open),
|
||||
Create(Create),
|
||||
@ -293,11 +295,8 @@ pub(crate) enum SftpRequest {
|
||||
Rename(Rename),
|
||||
Unlink(Unlink),
|
||||
|
||||
// Below are specialized SFTP operations for files
|
||||
WriteFile(WriteFile),
|
||||
ReadFile(ReadFile),
|
||||
CloseFile(CloseFile),
|
||||
FlushFile(FlushFile),
|
||||
/// Specialized type for file-based operations
|
||||
File(FileRequest),
|
||||
}
|
||||
|
||||
pub(crate) struct OpenMode {
|
||||
@ -345,32 +344,6 @@ pub(crate) struct Opendir {
|
||||
pub reply: Sender<File>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WriteFile {
|
||||
pub file_id: FileId,
|
||||
pub data: Vec<u8>,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadFile {
|
||||
pub file_id: FileId,
|
||||
pub max_bytes: usize,
|
||||
pub reply: Sender<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CloseFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FlushFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Readdir {
|
||||
pub filename: PathBuf,
|
||||
|
@ -1,11 +1,13 @@
|
||||
use super::{
|
||||
CloseFile, FlushFile, ReadFile, SessionRequest, SessionSender, SftpRequest, WriteFile,
|
||||
use super::{FileStat, SessionRequest, SessionSender, SftpRequest};
|
||||
use smol::{
|
||||
channel::{bounded, Sender},
|
||||
future::FutureExt,
|
||||
};
|
||||
use smol::{channel::bounded, future::FutureExt};
|
||||
use std::{
|
||||
fmt,
|
||||
future::Future,
|
||||
io,
|
||||
path::PathBuf,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
@ -27,6 +29,69 @@ struct FileState {
|
||||
f_close: Option<Pin<Box<dyn Future<Output = io::Result<()>> + Send + Sync + 'static>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FileRequest {
|
||||
Write(WriteFile),
|
||||
Read(ReadFile),
|
||||
Close(CloseFile),
|
||||
Flush(FlushFile),
|
||||
Setstat(SetstatFile),
|
||||
Stat(StatFile),
|
||||
Readdir(ReaddirFile),
|
||||
Fsync(FsyncFile),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WriteFile {
|
||||
pub file_id: FileId,
|
||||
pub data: Vec<u8>,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReadFile {
|
||||
pub file_id: FileId,
|
||||
pub max_bytes: usize,
|
||||
pub reply: Sender<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CloseFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FlushFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SetstatFile {
|
||||
pub file_id: FileId,
|
||||
pub stat: FileStat,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StatFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<FileStat>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ReaddirFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<(PathBuf, FileStat)>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FsyncFile {
|
||||
pub file_id: FileId,
|
||||
pub reply: Sender<()>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for File {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("File")
|
||||
@ -35,6 +100,21 @@ impl fmt::Debug for File {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for File {
|
||||
/// Attempts to close the file that exists in the dedicated ssh2 thread
|
||||
fn drop(&mut self) {
|
||||
if let Some(tx) = self.tx.take() {
|
||||
let (reply, _) = bounded(1);
|
||||
let _ = tx.try_send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Close(
|
||||
CloseFile {
|
||||
file_id: self.file_id,
|
||||
reply,
|
||||
},
|
||||
))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub(crate) fn new(file_id: FileId) -> Self {
|
||||
Self {
|
||||
@ -47,6 +127,85 @@ impl File {
|
||||
pub(crate) fn initialize_sender(&mut self, sender: SessionSender) {
|
||||
self.tx.replace(sender);
|
||||
}
|
||||
|
||||
/// Set the metadata for this handle.
|
||||
///
|
||||
/// See [`ssh2::File::setstat`] for more information.
|
||||
pub async fn setstat(&self, stat: FileStat) -> anyhow::Result<()> {
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send(SessionRequest::Sftp(SftpRequest::File(
|
||||
FileRequest::Setstat(SetstatFile {
|
||||
file_id: self.file_id,
|
||||
stat,
|
||||
reply,
|
||||
}),
|
||||
)))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get the metadata for this handle.
|
||||
///
|
||||
/// See [`ssh2::File::stat`] for more information.
|
||||
pub async fn stat(&self) -> anyhow::Result<FileStat> {
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Stat(
|
||||
StatFile {
|
||||
file_id: self.file_id,
|
||||
reply,
|
||||
},
|
||||
))))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Reads a block of data from a handle and returns file entry information for the next entry,
|
||||
/// if any.
|
||||
///
|
||||
/// See [`ssh2::File::readdir`] for more information.
|
||||
pub async fn readdir(&self) -> anyhow::Result<(PathBuf, FileStat)> {
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send(SessionRequest::Sftp(SftpRequest::File(
|
||||
FileRequest::Readdir(ReaddirFile {
|
||||
file_id: self.file_id,
|
||||
reply,
|
||||
}),
|
||||
)))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// This function causes the remote server to synchronize the file data and metadata to disk
|
||||
/// (like fsync(2)).
|
||||
///
|
||||
/// See [`ssh2::File::fsync`] for more information.
|
||||
pub async fn fsync(&self) -> anyhow::Result<()> {
|
||||
let (reply, rx) = bounded(1);
|
||||
self.tx
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Fsync(
|
||||
FsyncFile {
|
||||
file_id: self.file_id,
|
||||
reply,
|
||||
},
|
||||
))))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl smol::io::AsyncRead for File {
|
||||
@ -165,11 +324,13 @@ impl smol::io::AsyncWrite for File {
|
||||
/// Writes some bytes to the file.
|
||||
async fn inner_write(tx: SessionSender, file_id: usize, data: Vec<u8>) -> anyhow::Result<()> {
|
||||
let (reply, rx) = bounded(1);
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::WriteFile(WriteFile {
|
||||
file_id,
|
||||
data,
|
||||
reply,
|
||||
})))
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Write(
|
||||
WriteFile {
|
||||
file_id,
|
||||
data,
|
||||
reply,
|
||||
},
|
||||
))))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
@ -185,11 +346,13 @@ async fn inner_read(
|
||||
max_bytes: usize,
|
||||
) -> anyhow::Result<Vec<u8>> {
|
||||
let (reply, rx) = bounded(1);
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::ReadFile(ReadFile {
|
||||
file_id,
|
||||
max_bytes,
|
||||
reply,
|
||||
})))
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Read(
|
||||
ReadFile {
|
||||
file_id,
|
||||
max_bytes,
|
||||
reply,
|
||||
},
|
||||
))))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
@ -198,10 +361,9 @@ async fn inner_read(
|
||||
/// Flushes the remote file
|
||||
async fn inner_flush(tx: SessionSender, file_id: usize) -> anyhow::Result<()> {
|
||||
let (reply, rx) = bounded(1);
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::FlushFile(FlushFile {
|
||||
file_id,
|
||||
reply,
|
||||
})))
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Flush(
|
||||
FlushFile { file_id, reply },
|
||||
))))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
@ -210,10 +372,9 @@ async fn inner_flush(tx: SessionSender, file_id: usize) -> anyhow::Result<()> {
|
||||
/// Closes the handle to the remote file
|
||||
async fn inner_close(tx: SessionSender, file_id: usize) -> anyhow::Result<()> {
|
||||
let (reply, rx) = bounded(1);
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::CloseFile(CloseFile {
|
||||
file_id,
|
||||
reply,
|
||||
})))
|
||||
tx.send(SessionRequest::Sftp(SftpRequest::File(FileRequest::Close(
|
||||
CloseFile { file_id, reply },
|
||||
))))
|
||||
.await?;
|
||||
let result = rx.recv().await?;
|
||||
Ok(result)
|
||||
|
Loading…
Reference in New Issue
Block a user