1
1
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:
Chip Senkbeil 2021-09-25 03:40:09 -05:00 committed by Wez Furlong
parent 50a0372e17
commit 2e19344b22
3 changed files with 279 additions and 59 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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)