From 70d59218cdb9b063be3e677bece8b30e3cc88411 Mon Sep 17 00:00:00 2001 From: Michael Theall Date: Sun, 24 May 2020 21:21:19 -0500 Subject: [PATCH] Add emulation of /dev/zero for network testing --- include/ftpSession.h | 3 ++ source/fs.cpp | 14 ++++++++ source/ftpSession.cpp | 81 ++++++++++++++++++++++++++----------------- 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/include/ftpSession.h b/include/ftpSession.h index cf8b8b3..6480b8c 100644 --- a/include/ftpSession.h +++ b/include/ftpSession.h @@ -316,6 +316,9 @@ private: /// \brief Whether MLST unix.mode fact is enabled bool m_mlstUnixMode : 1; + /// \brief Whether emulating /dev/zero + bool m_devZero : 1; + /// \brief Abort a transfer /// \param args_ Command arguments void ABOR (char const *args_); diff --git a/source/fs.cpp b/source/fs.cpp index d2ef285..b6cdc08 100644 --- a/source/fs.cpp +++ b/source/fs.cpp @@ -203,9 +203,23 @@ bool fs::File::readAll (void *const buffer_, std::size_t const size_) std::make_signed_t fs::File::write (void const *const buffer_, std::size_t const size_) { + assert (buffer_); + assert (size_ > 0); + return std::fwrite (buffer_, 1, size_, m_fp.get ()); } +std::make_signed_t fs::File::write (IOBuffer &buffer_) +{ + assert (buffer_.usedSize () > 0); + + auto const rc = write (buffer_.usedArea (), buffer_.usedSize ()); + if (rc > 0) + buffer_.markFree (rc); + + return rc; +} + bool fs::File::writeAll (void const *const buffer_, std::size_t const size_) { assert (buffer_); diff --git a/source/ftpSession.cpp b/source/ftpSession.cpp index 2ea9a5b..ca0b44a 100644 --- a/source/ftpSession.cpp +++ b/source/ftpSession.cpp @@ -279,7 +279,8 @@ FtpSession::FtpSession (FtpConfig &config_, UniqueSocket commandSocket_) m_mlstSize (true), m_mlstModify (true), m_mlstPerm (true), - m_mlstUnixMode (false) + m_mlstUnixMode (false), + m_devZero (false) { if (m_config.user ().empty ()) m_authorizedUser = true; @@ -612,6 +613,7 @@ void FtpSession::setState (State const state_, bool const closePasv_, bool const m_workItem.clear (); } + m_devZero = false; m_file.close (); m_dir.close (); } @@ -1055,7 +1057,11 @@ void FtpSession::xferFile (char const *const args_, XferFileMode const mode_) return; } - if (mode_ == XferFileMode::RETR) + if (path == "/devZero") + { + m_devZero = true; + } + else if (mode_ == XferFileMode::RETR) { // stat the file struct stat st; @@ -1709,29 +1715,34 @@ bool FtpSession::retrieveTransfer () { m_xferBuffer.clear (); - auto const buffer = m_xferBuffer.freeArea (); - auto const size = m_xferBuffer.freeSize (); - - // we have sent all the data, so read some more - auto const rc = m_file.read (buffer, size); - if (rc < 0) + if (!m_devZero) { - // failed to read data - sendResponse ("451 %s\r\n", std::strerror (errno)); - setState (State::COMMAND, true, true); - return false; - } + // we have sent all the data, so read some more + auto const rc = m_file.read (m_xferBuffer); + if (rc < 0) + { + // failed to read data + sendResponse ("451 %s\r\n", std::strerror (errno)); + setState (State::COMMAND, true, true); + return false; + } - if (rc == 0) + if (rc == 0) + { + // reached end of file + sendResponse ("226 OK\r\n"); + setState (State::COMMAND, true, true); + return false; + } + } + else { - // reached end of file - sendResponse ("226 OK\r\n"); - setState (State::COMMAND, true, true); - return false; - } + auto const buffer = m_xferBuffer.freeArea (); + auto const size = m_xferBuffer.freeSize (); - // we read some data - m_xferBuffer.markUsed (rc); + std::memset (buffer, 0, size); + m_xferBuffer.markUsed (size); + } } // send any pending data @@ -1780,19 +1791,27 @@ bool FtpSession::storeTransfer () } } - // write any pending data - auto const rc = m_file.write (m_xferBuffer.usedArea (), m_xferBuffer.usedSize ()); - if (rc <= 0) + if (!m_devZero) { - // error writing data - sendResponse ("426 %s\r\n", rc < 0 ? std::strerror (errno) : "Failed to write data"); - setState (State::COMMAND, true, true); - return false; + // write any pending data + auto const rc = m_file.write (m_xferBuffer); + if (rc <= 0) + { + // error writing data + sendResponse ("426 %s\r\n", rc < 0 ? std::strerror (errno) : "Failed to write data"); + setState (State::COMMAND, true, true); + return false; + } + + // we can try to recv/write more data + LOCKED (m_filePosition += rc); + } + else + { + LOCKED (m_filePosition += m_xferBuffer.usedSize ()); + m_xferBuffer.clear (); } - // we can try to recv/write more data - LOCKED (m_filePosition += rc); - m_xferBuffer.markFree (rc); return true; }