From 5509f23140a635040274ba1ccc1dc233a0d73b71 Mon Sep 17 00:00:00 2001 From: Florian Reimold <11774314+FlorianReimold@users.noreply.github.com> Date: Mon, 10 Jan 2022 10:26:17 +0100 Subject: [PATCH] Added SIZE command (#29) - Added Size Command - Fixed MinGW compile issue - Improved Readme.md Co-authored-by: Bjarne Juul Pasgaard --- README.md | 5 +-- fineftp-server/CMakeLists.txt | 2 +- fineftp-server/src/filesystem.cpp | 2 +- fineftp-server/src/ftp_session.cpp | 50 +++++++++++++++++++++++++- fineftp-server/src/ftp_session.h | 3 +- fineftp-server/src/win_str_convert.cpp | 4 +-- toolchain_mingw.cmake | 24 +++++++++++++ 7 files changed, 82 insertions(+), 8 deletions(-) mode change 100644 => 100755 fineftp-server/src/ftp_session.cpp mode change 100644 => 100755 fineftp-server/src/ftp_session.h create mode 100644 toolchain_mingw.cmake diff --git a/README.md b/README.md index bd3f3e5..0b2809c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ +[![Windows](https://github.com/continental/fineftp-server/actions/workflows/build-windows.yml/badge.svg)](https://github.com/continental/fineftp-server/actions/workflows/build-windows.yml) [![Ubuntu](https://github.com/continental/fineftp-server/actions/workflows/build-ubuntu.yml/badge.svg)](https://github.com/continental/fineftp-server/actions/workflows/build-ubuntu.yml) [![macOS](https://github.com/continental/fineftp-server/actions/workflows/build-macos.yml/badge.svg)](https://github.com/continental/fineftp-server/actions/workflows/build-macos.yml) # fineFTP Server FineFTP is a minimal FTP server library for Windows and Unix flavors. The project is CMake based and only depends on asio, which is integrated as git submodule. No boost is required. -You can easily embed this library into your own project in order to create an embedded FTP Server. It was developed and tested on Windows 10 (Visual Studio 2015 / 2019) and Ubuntu 16.04 - 21.10 (gcc 5.4.0 - 11.2.0). +You can easily embed this library into your own project in order to create an embedded FTP Server. It was developed and tested on Windows 10 (Visual Studio 2015 / 2019, MinGW) and Ubuntu 16.04 - 21.10 (gcc 5.4.0 - 11.2.0). ## Features @@ -14,7 +15,7 @@ You can easily embed this library into your own project in order to create an em - User authentication (and anonymous user without authentication) - Individual local home path for each user - Access control on a per-user-basis -- UTF8 support +- UTF8 support (On Windows MSVC only) *fineFTP does not support any kind of encryption. You should only use fineFTP in trusted networks.* diff --git a/fineftp-server/CMakeLists.txt b/fineftp-server/CMakeLists.txt index 8f5ada0..ee623b5 100644 --- a/fineftp-server/CMakeLists.txt +++ b/fineftp-server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5.1) -project(server VERSION 1.2.0) +project(server VERSION 1.3.0) set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/fineftp-server/src/filesystem.cpp b/fineftp-server/src/filesystem.cpp index aa4d5dc..9f67cf9 100644 --- a/fineftp-server/src/filesystem.cpp +++ b/fineftp-server/src/filesystem.cpp @@ -9,7 +9,7 @@ #define NOMINMAX #define WIN32_LEAN_AND_MEAN -#include +#include #include #else // WIN32 diff --git a/fineftp-server/src/ftp_session.cpp b/fineftp-server/src/ftp_session.cpp old mode 100644 new mode 100755 index e5817ba..8f59091 --- a/fineftp-server/src/ftp_session.cpp +++ b/fineftp-server/src/ftp_session.cpp @@ -197,6 +197,7 @@ namespace fineftp // Modern FTP Commands { "FEAT", std::bind(&FtpSession::handleFtpCommandFEAT, this, std::placeholders::_1) }, { "OPTS", std::bind(&FtpSession::handleFtpCommandOPTS, this, std::placeholders::_1) }, + { "SIZE", std::bind(&FtpSession::handleFtpCommandSIZE, this, std::placeholders::_1) }, }; auto command_it = command_map.find(ftp_command); @@ -485,6 +486,52 @@ namespace fineftp return; } + void FtpSession::handleFtpCommandSIZE(const std::string& param) + { + if (!logged_in_user_) + { + sendFtpMessage(FtpReplyCode::NOT_LOGGED_IN, "Not logged in"); + return; + } + if (static_cast(logged_in_user_->permissions_ & Permission::FileRead) == 0) + { + sendFtpMessage(FtpReplyCode::ACTION_NOT_TAKEN, "Permission denied"); + return; + } + + std::string local_path = toLocalPath(param); + + std::ios::openmode open_mode = + std::ios::ate | (data_type_binary_ ? (std::ios::in | std::ios::binary) : (std::ios::in)); +#if defined(WIN32) && !defined(__GNUG__) + std::ifstream file(StrConvert::Utf8ToWide(local_path), open_mode); +#else + std::ifstream file(local_path, open_mode); +#endif + + if (!file.good()) + { + sendFtpMessage(FtpReplyCode::ACTION_ABORTED_LOCAL_ERROR, "Error opening file for size retrieval"); + return; + } + + // RFC 3659 actually states that the returned size should depend on the STRU, MODE, and TYPE and that + // the returned size should be exact. We don't comply with this here. The size returned is the + // size for TYPE=I. + auto file_size = file.tellg(); + if (std::fstream::pos_type(-1) == file_size) + { + sendFtpMessage(FtpReplyCode::ACTION_ABORTED_LOCAL_ERROR, "Error getting file size"); + return; + } + + // Form reply string + std::stringstream rep; + rep << file_size; + + sendFtpMessage(FtpReplyCode::FILE_STATUS, rep.str()); + } + void FtpSession::handleFtpCommandSTOR(const std::string& param) { if (!logged_in_user_) @@ -1037,8 +1084,9 @@ namespace fineftp std::stringstream ss; ss << "211- Feature List:\r\n"; ss << " UTF8\r\n"; + ss << " SIZE\r\n"; ss << " LANG EN\r\n"; - ss << "211 end\r\n"; + ss << "211 END\r\n"; sendRawFtpMessage(ss.str()); } diff --git a/fineftp-server/src/ftp_session.h b/fineftp-server/src/ftp_session.h old mode 100644 new mode 100755 index e72b25b..66b880f --- a/fineftp-server/src/ftp_session.h +++ b/fineftp-server/src/ftp_session.h @@ -22,7 +22,7 @@ namespace fineftp struct IoFile { IoFile(const std::string& filename, std::ios::openmode mode) -#ifdef WIN32 +#if defined(WIN32) && !defined(__GNUG__) : file_stream_(StrConvert::Utf8ToWide(filename), mode) #else : file_stream_(filename, mode) @@ -88,6 +88,7 @@ namespace fineftp // Ftp service commands void handleFtpCommandRETR(const std::string& param); + void handleFtpCommandSIZE(const std::string& param); void handleFtpCommandSTOR(const std::string& param); void handleFtpCommandSTOU(const std::string& param); void handleFtpCommandAPPE(const std::string& param); diff --git a/fineftp-server/src/win_str_convert.cpp b/fineftp-server/src/win_str_convert.cpp index c688a0c..b6923c3 100644 --- a/fineftp-server/src/win_str_convert.cpp +++ b/fineftp-server/src/win_str_convert.cpp @@ -3,7 +3,7 @@ #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #define NOMINMAX - #include + #include #endif // WIN32 #include @@ -56,4 +56,4 @@ namespace fineftp } #endif } -} \ No newline at end of file +} diff --git a/toolchain_mingw.cmake b/toolchain_mingw.cmake new file mode 100644 index 0000000..d9d9e80 --- /dev/null +++ b/toolchain_mingw.cmake @@ -0,0 +1,24 @@ +set(CMAKE_SYSTEM_NAME Windows) + +set(CMAKE_C_COMPILER /usr/bin/x86_64-w64-mingw32-gcc-posix) +set(CMAKE_CXX_COMPILER /usr/bin/x86_64-w64-mingw32-g++-posix) +set(CMAKE_AR /usr/bin/x86_64-w64-mingw32-ar CACHE FILEPATH "" FORCE) +set(CMAKE_C_COMPILER_AR /usr/bin/x86_64-w64-mingw32-gcc-ar CACHE FILEPATH "" FORCE) +set(CMAKE_CXX_COMPILER_AR /usr/bin/x86_64-w64-mingw32-gcc-ar CACHE FILEPATH "" FORCE) +set(CMAKE_LINKER /usr/bin/x86_64-w64-mingw32-ld CACHE FILEPATH "" FORCE) +set(CMAKE_NM /usr/bin/x86_64-w64-mingw32-nm CACHE FILEPATH "" FORCE) +set(CMAKE_OBJCOPY /usr/bin/x86_64-w64-mingw32-objcopy CACHE FILEPATH "" FORCE) +set(CMAKE_OBJDUMP /usr/bin/x86_64-w64-mingw32-objdump CACHE FILEPATH "" FORCE) +set(CMAKE_RANLIB /usr/bin/x86_64-w64-mingw32-ranlib CACHE FILEPATH "" FORCE) +set(CMAKE_C_COMPILER_RANLIB /usr/bin/x86_64-w64-mingw32-gcc-ranlib CACHE FILEPATH "" FORCE) +set(CMAKE_CXX_COMPILER_RANLIB /usr/bin/x86_64-w64-mingw32-gcc-ranlib CACHE FILEPATH "" FORCE) +set(CMAKE_STRIP /usr/bin/x86_64-w64-mingw32-strip CACHE FILEPATH "" FORCE) + +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32;${PROJECT_SOURCE_DIR}) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_INSTALL_PREFIX ${CMAKE_FIND_ROOT_PATH}/usr CACHE FILEPATH "install path prefix") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-static") +