From c5d2f48aa3eab3d7159b900a66bdc17ed8e29d4e Mon Sep 17 00:00:00 2001 From: bold Date: Mon, 30 Dec 2019 19:21:30 +0100 Subject: add shutdown and close methods This commit exposes the `shutdown` method of `Sft` and `close` method of `File` to free resources. Previously this was done synchronously and therefor not usable in async wrappers. Whith the methods exposed they can be polled until success. If successful a flag is set to notify the destructor that no resources need to be freed anymore. However, if resources were not cleaned up by calling `close` or `shutdown` the destructor will clean up synchronously. --- src/sftp.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/sftp.rs b/src/sftp.rs index e899cf7..6cf6712 100644 --- a/src/sftp.rs +++ b/src/sftp.rs @@ -14,6 +14,7 @@ use {raw, Error, SessionInner}; pub struct Sftp { raw: *mut raw::LIBSSH2_SFTP, _sess: Arc, + closed: bool, } /// A file handle to an SFTP connection. @@ -26,6 +27,7 @@ pub struct Sftp { pub struct File<'sftp> { raw: *mut raw::LIBSSH2_SFTP_HANDLE, sftp: &'sftp Sftp, + closed: bool, } /// Metadata information about a remote file. @@ -113,6 +115,7 @@ impl Sftp { Ok(Self { raw, _sess: Arc::clone(sess), + closed: false, }) } } @@ -371,11 +374,32 @@ impl Sftp { Err(Error::from_errno(rc)) } } + + /// Shuts the sftp connection down. + /// + /// This should not be called manually since the destructor takes care of it. + /// However, it is useful for async wrappers that take care of async destruction. + pub fn shutdown(&mut self) -> Result<(), Error> { + if !self.closed { + self.rc(unsafe { raw::libssh2_sftp_shutdown(self.raw) })?; + // set flag for destructor that we don't need to close the file anymore + self.closed = true; + } + Ok(()) + } } impl Drop for Sftp { fn drop(&mut self) { - unsafe { assert_eq!(raw::libssh2_sftp_shutdown(self.raw), 0) } + if !self.closed { + let rc = loop { + let rc = unsafe { raw::libssh2_sftp_shutdown(self.raw) }; + if rc != raw::LIBSSH2_ERROR_EAGAIN { + break rc; + } + }; + assert_eq!(rc, 0); + } } } @@ -388,6 +412,7 @@ impl<'sftp> File<'sftp> { File { raw: raw, sftp: sftp, + closed: false, } } @@ -470,6 +495,19 @@ impl<'sftp> File<'sftp> { pub fn fsync(&mut self) -> Result<(), Error> { self.sftp.rc(unsafe { raw::libssh2_sftp_fsync(self.raw) }) } + + /// This function closes the file. + /// + /// This should not be called manually since the destructor takes care of it. + /// However, it is useful for async wrappers that take care of async destruction. + pub fn close(&mut self) -> Result<(), Error> { + if !self.closed { + self.sftp.rc(unsafe { raw::libssh2_sftp_close_handle(self.raw) })?; + // set flag for destructor that we don't need to close the file anymore + self.closed = true; + } + Ok(()) + } } impl<'sftp> Read for File<'sftp> { @@ -534,7 +572,15 @@ impl<'sftp> Seek for File<'sftp> { impl<'sftp> Drop for File<'sftp> { fn drop(&mut self) { - unsafe { assert_eq!(raw::libssh2_sftp_close_handle(self.raw), 0) } + if !self.closed { + let rc = loop { + let rc = unsafe { raw::libssh2_sftp_close_handle(self.raw) }; + if rc != raw::LIBSSH2_ERROR_EAGAIN { + break rc; + } + }; + assert_eq!(rc, 0); + } } } -- cgit v1.2.3