v2.0.3-rc (#32)
	
		
			
	
		
	
	
		
	
		
			Some checks reported errors
		
		
	
	
		
			
				
	
				BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
				
			
		
		
	
	
				
					
				
			
		
			Some checks reported errors
		
		
	
	BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
				
			# Changelog ## v2.0.3-rc ### Issues * \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories * \#29 \[bug\] S3 error responses are not being logged * \#30 \[bug\] Sia provider error responses are not logged * \#31 \[bug\] S3 provider should limit max key size to 1024 ### Changes from v2.0.2-rc * Always use direct for read-only providers * Fixed externally removed files not being processed during cleanup * Fixed http headers not being added for requests * Fixed incorrect `stat` values for remote mounts * Fixed invalid directory nullptr error on remote mounts * Fixed memory leak in event system * Refactored application shutdown * Refactored event system * Updated build system to Alpine 3.21.0 * Updated build system to MinGW-w64 12.0.0 * Updated copyright to 2018-2025 Reviewed-on: #32
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -40,8 +40,8 @@ class encrypting_streambuf final : public encrypting_reader::streambuf { | ||||
| public: | ||||
|   encrypting_streambuf(const encrypting_streambuf &) = default; | ||||
|   encrypting_streambuf(encrypting_streambuf &&) = delete; | ||||
|   auto | ||||
|   operator=(const encrypting_streambuf &) -> encrypting_streambuf & = delete; | ||||
|   auto operator=(const encrypting_streambuf &) | ||||
|       -> encrypting_streambuf & = delete; | ||||
|   auto operator=(encrypting_streambuf &&) -> encrypting_streambuf & = delete; | ||||
|  | ||||
|   explicit encrypting_streambuf(const encrypting_reader &reader) | ||||
| @@ -93,9 +93,10 @@ protected: | ||||
|     return encrypting_reader::streambuf::seekoff(off, dir, which); | ||||
|   } | ||||
|  | ||||
|   auto seekpos(pos_type pos, std::ios_base::openmode which = | ||||
|                                  std::ios_base::out | | ||||
|                                  std::ios_base::in) -> pos_type override { | ||||
|   auto seekpos(pos_type pos, | ||||
|                std::ios_base::openmode which = std::ios_base::out | | ||||
|                                                std::ios_base::in) | ||||
|       -> pos_type override { | ||||
|     return seekoff(pos, std::ios_base::beg, which); | ||||
|   } | ||||
|  | ||||
| @@ -177,16 +178,16 @@ const std::size_t encrypting_reader::encrypted_chunk_size_ = | ||||
|  | ||||
| encrypting_reader::encrypting_reader( | ||||
|     std::string_view file_name, std::string_view source_path, | ||||
|     stop_type &stop_requested, std::string_view token, | ||||
|     stop_type_callback stop_requested_cb, std::string_view token, | ||||
|     std::optional<std::string> relative_parent_path, std::size_t error_return) | ||||
|     : key_(utils::encryption::generate_key<utils::encryption::hash_256_t>( | ||||
|           token)), | ||||
|       stop_requested_(stop_requested), | ||||
|       stop_requested_cb_(std::move(stop_requested_cb)), | ||||
|       error_return_(error_return), | ||||
|       source_file_(utils::file::file::open_or_create_file(source_path, true)) { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   if (not *source_file_) { | ||||
|   if (not*source_file_) { | ||||
|     throw utils::error::create_exception(function_name, { | ||||
|                                                             "file open failed", | ||||
|                                                             source_path, | ||||
| @@ -237,17 +238,17 @@ encrypting_reader::encrypting_reader( | ||||
|  | ||||
| encrypting_reader::encrypting_reader(std::string_view encrypted_file_path, | ||||
|                                      std::string_view source_path, | ||||
|                                      stop_type &stop_requested, | ||||
|                                      stop_type_callback stop_requested_cb, | ||||
|                                      std::string_view token, | ||||
|                                      std::size_t error_return) | ||||
|     : key_(utils::encryption::generate_key<utils::encryption::hash_256_t>( | ||||
|           token)), | ||||
|       stop_requested_(stop_requested), | ||||
|       stop_requested_cb_(std::move(stop_requested_cb)), | ||||
|       error_return_(error_return), | ||||
|       source_file_(utils::file::file::open_or_create_file(source_path, true)) { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   if (not *source_file_) { | ||||
|   if (not*source_file_) { | ||||
|     throw utils::error::create_exception(function_name, { | ||||
|                                                             "file open failed", | ||||
|                                                             source_path, | ||||
| @@ -283,19 +284,19 @@ encrypting_reader::encrypting_reader(std::string_view encrypted_file_path, | ||||
|  | ||||
| encrypting_reader::encrypting_reader( | ||||
|     std::string_view encrypted_file_path, std::string_view source_path, | ||||
|     stop_type &stop_requested, std::string_view token, | ||||
|     stop_type_callback stop_requested_cb, std::string_view token, | ||||
|     std::vector< | ||||
|         std::array<unsigned char, crypto_aead_xchacha20poly1305_IETF_NPUBBYTES>> | ||||
|         iv_list, | ||||
|     std::size_t error_return) | ||||
|     : key_(utils::encryption::generate_key<utils::encryption::hash_256_t>( | ||||
|           token)), | ||||
|       stop_requested_(stop_requested), | ||||
|       stop_requested_cb_(std::move(stop_requested_cb)), | ||||
|       error_return_(error_return), | ||||
|       source_file_(utils::file::file::open_or_create_file(source_path, true)) { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   if (not *source_file_) { | ||||
|   if (not*source_file_) { | ||||
|     throw utils::error::create_exception(function_name, { | ||||
|                                                             "file open failed", | ||||
|                                                             source_path, | ||||
| @@ -329,7 +330,7 @@ encrypting_reader::encrypting_reader( | ||||
|  | ||||
| encrypting_reader::encrypting_reader(const encrypting_reader &reader) | ||||
|     : key_(reader.key_), | ||||
|       stop_requested_(reader.stop_requested_), | ||||
|       stop_requested_cb_(reader.stop_requested_cb_), | ||||
|       error_return_(reader.error_return_), | ||||
|       source_file_( | ||||
|           utils::file::file::open_file(reader.source_file_->get_path(), true)), | ||||
| @@ -343,7 +344,7 @@ encrypting_reader::encrypting_reader(const encrypting_reader &reader) | ||||
|       total_size_(reader.total_size_) { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   if (not *source_file_) { | ||||
|   if (not*source_file_) { | ||||
|     throw utils::error::create_exception( | ||||
|         function_name, { | ||||
|                            "file open failed", | ||||
| @@ -403,7 +404,7 @@ auto encrypting_reader::reader_function(char *buffer, size_t size, | ||||
|     try { | ||||
|       ret = true; | ||||
|       auto remain = read_size; | ||||
|       while (not stop_requested_ && ret && (remain != 0U)) { | ||||
|       while (not get_stop_requested() && ret && (remain != 0U)) { | ||||
|         if (chunk_buffers_.find(chunk) == chunk_buffers_.end()) { | ||||
|           auto &chunk_buffer = chunk_buffers_[chunk]; | ||||
|           data_buffer file_data(chunk == last_data_chunk_ | ||||
| @@ -441,9 +442,9 @@ auto encrypting_reader::reader_function(char *buffer, size_t size, | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return stop_requested_ ? static_cast<std::size_t>(CURL_READFUNC_ABORT) | ||||
|          : ret           ? total_read | ||||
|                          : error_return_; | ||||
|   return get_stop_requested() ? static_cast<std::size_t>(CURL_READFUNC_ABORT) | ||||
|          : ret                ? total_read | ||||
|                               : error_return_; | ||||
| } | ||||
| } // namespace repertory::utils::encryption | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -25,26 +25,27 @@ | ||||
|  | ||||
| #include "utils/collection.hpp" | ||||
| #include "utils/encrypting_reader.hpp" | ||||
| #include "utils/path.hpp" | ||||
|  | ||||
| namespace repertory::utils::encryption { | ||||
| auto decrypt_file_path(std::string_view encryption_token, | ||||
|                        std::string &file_path) -> bool { | ||||
|   std::string decrypted_file_path{}; | ||||
|   std::vector<std::string> decrypted_parts; | ||||
|   for (const auto &part : std::filesystem::path(file_path)) { | ||||
|     auto file_name = part.string(); | ||||
|     if (file_name == "/") { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     auto res = decrypt_file_name(encryption_token, file_name); | ||||
|     if (not res) { | ||||
|       return res; | ||||
|     if (not decrypt_file_name(encryption_token, file_name)) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     decrypted_file_path += '/' + file_name; | ||||
|     decrypted_parts.push_back(file_name); | ||||
|   } | ||||
|  | ||||
|   file_path = decrypted_file_path; | ||||
|   file_path = | ||||
|       utils::path::create_api_path(utils::string::join(decrypted_parts, '/')); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| @@ -56,34 +57,27 @@ auto decrypt_file_name(std::string_view encryption_token, | ||||
|   } | ||||
|  | ||||
|   file_name.clear(); | ||||
|   if (not utils::encryption::decrypt_data(encryption_token, buffer, | ||||
|                                           file_name)) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
|   return utils::encryption::decrypt_data(encryption_token, buffer, file_name); | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_CURL) | ||||
| auto read_encrypted_range(const http_range &range, | ||||
|                           const utils::encryption::hash_256_t &key, | ||||
|                           reader_func_t reader_func, std::uint64_t total_size, | ||||
|                           data_buffer &data) -> bool { | ||||
|   const auto encrypted_chunk_size = | ||||
|   auto encrypted_chunk_size = | ||||
|       utils::encryption::encrypting_reader::get_encrypted_chunk_size(); | ||||
|   const auto data_chunk_size = | ||||
|   auto data_chunk_size = | ||||
|       utils::encryption::encrypting_reader::get_data_chunk_size(); | ||||
|  | ||||
|   const auto start_chunk = | ||||
|       static_cast<std::size_t>(range.begin / data_chunk_size); | ||||
|   const auto end_chunk = static_cast<std::size_t>(range.end / data_chunk_size); | ||||
|   auto start_chunk = static_cast<std::size_t>(range.begin / data_chunk_size); | ||||
|   auto end_chunk = static_cast<std::size_t>(range.end / data_chunk_size); | ||||
|   auto remain = range.end - range.begin + 1U; | ||||
|   auto source_offset = static_cast<std::size_t>(range.begin % data_chunk_size); | ||||
|  | ||||
|   for (std::size_t chunk = start_chunk; chunk <= end_chunk; chunk++) { | ||||
|     data_buffer cypher; | ||||
|     const auto start_offset = chunk * encrypted_chunk_size; | ||||
|     const auto end_offset = std::min( | ||||
|     auto start_offset = chunk * encrypted_chunk_size; | ||||
|     auto end_offset = std::min( | ||||
|         start_offset + (total_size - (chunk * data_chunk_size)) + | ||||
|             encryption_header_size - 1U, | ||||
|         static_cast<std::uint64_t>(start_offset + encrypted_chunk_size - 1U)); | ||||
| @@ -98,7 +92,7 @@ auto read_encrypted_range(const http_range &range, | ||||
|     } | ||||
|     cypher.clear(); | ||||
|  | ||||
|     const auto data_size = static_cast<std::size_t>(std::min( | ||||
|     auto data_size = static_cast<std::size_t>(std::min( | ||||
|         remain, static_cast<std::uint64_t>(data_chunk_size - source_offset))); | ||||
|     std::copy(std::next(source_buffer.begin(), | ||||
|                         static_cast<std::int64_t>(source_offset)), | ||||
| @@ -111,7 +105,58 @@ auto read_encrypted_range(const http_range &range, | ||||
|  | ||||
|   return true; | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_CURL) | ||||
|  | ||||
| auto read_encrypted_range(const http_range &range, | ||||
|                           const utils::encryption::hash_256_t &key, | ||||
|                           reader_func_t reader_func, std::uint64_t total_size, | ||||
|                           unsigned char *data, std::size_t size, | ||||
|                           std::size_t &bytes_read) -> bool { | ||||
|   bytes_read = 0U; | ||||
|  | ||||
|   auto encrypted_chunk_size = | ||||
|       utils::encryption::encrypting_reader::get_encrypted_chunk_size(); | ||||
|   auto data_chunk_size = | ||||
|       utils::encryption::encrypting_reader::get_data_chunk_size(); | ||||
|  | ||||
|   auto start_chunk = static_cast<std::size_t>(range.begin / data_chunk_size); | ||||
|   auto end_chunk = static_cast<std::size_t>(range.end / data_chunk_size); | ||||
|   auto remain = range.end - range.begin + 1U; | ||||
|   auto source_offset = static_cast<std::size_t>(range.begin % data_chunk_size); | ||||
|  | ||||
|   std::span dest_buffer(data, size); | ||||
|   for (std::size_t chunk = start_chunk; chunk <= end_chunk; chunk++) { | ||||
|     data_buffer cypher; | ||||
|     auto start_offset = chunk * encrypted_chunk_size; | ||||
|     auto end_offset = std::min( | ||||
|         start_offset + (total_size - (chunk * data_chunk_size)) + | ||||
|             encryption_header_size - 1U, | ||||
|         static_cast<std::uint64_t>(start_offset + encrypted_chunk_size - 1U)); | ||||
|  | ||||
|     if (not reader_func(cypher, start_offset, end_offset)) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     data_buffer source_buffer; | ||||
|     if (not utils::encryption::decrypt_data(key, cypher, source_buffer)) { | ||||
|       return false; | ||||
|     } | ||||
|     cypher.clear(); | ||||
|  | ||||
|     auto data_size = static_cast<std::size_t>(std::min( | ||||
|         remain, static_cast<std::uint64_t>(data_chunk_size - source_offset))); | ||||
|     std::copy( | ||||
|         std::next(source_buffer.begin(), | ||||
|                   static_cast<std::int64_t>(source_offset)), | ||||
|         std::next(source_buffer.begin(), | ||||
|                   static_cast<std::int64_t>(source_offset + data_size)), | ||||
|         std::next(dest_buffer.begin(), static_cast<std::int64_t>(bytes_read))); | ||||
|     remain -= data_size; | ||||
|     bytes_read += data_size; | ||||
|     source_offset = 0U; | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
| } // namespace repertory::utils::encryption | ||||
|  | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined (PROJECT_ENABLE_BOOST) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -23,31 +23,166 @@ | ||||
|  | ||||
| #include "utils/file_enc_file.hpp" | ||||
|  | ||||
| #include "utils/common.hpp" | ||||
| #include "utils/encrypting_reader.hpp" | ||||
| #include "utils/encryption.hpp" | ||||
|  | ||||
| namespace repertory::utils::file { | ||||
| auto enc_file::attach_file(fs_file_t file) -> fs_file_t {} | ||||
| auto enc_file::attach_file(fs_file_t file) -> fs_file_t { | ||||
|   return fs_file_t{ | ||||
|       new enc_file(std::move(file)), | ||||
|   }; | ||||
| } | ||||
|  | ||||
| enc_file::enc_file(fs_file_t file) : file_(std::move(file)) {} | ||||
|  | ||||
| void enc_file::close() {} | ||||
| void enc_file::close() { file_->close(); } | ||||
|  | ||||
| auto enc_file::copy_to(std::string_view new_path, | ||||
|                        bool overwrite) const -> bool {} | ||||
| auto enc_file::copy_to(std::string_view new_path, bool overwrite) const | ||||
|     -> bool { | ||||
|   return file_->copy_to(new_path, overwrite); | ||||
| } | ||||
|  | ||||
| void enc_file::flush() const {} | ||||
| void enc_file::flush() const { return file_->flush(); } | ||||
|  | ||||
| auto enc_file::move_to(std::string_view path) -> bool {} | ||||
| auto enc_file::move_to(std::string_view path) -> bool { | ||||
|   return file_->move_to(path); | ||||
| } | ||||
|  | ||||
| auto enc_file::read(unsigned char *data, std::size_t to_read, | ||||
|                     std::uint64_t offset, std::size_t *total_read) -> bool {} | ||||
|                     std::uint64_t offset, std::size_t *total_read) -> bool { | ||||
|   if (total_read != nullptr) { | ||||
|     *total_read = 0U; | ||||
|   } | ||||
|  | ||||
| auto enc_file::remove() -> bool {} | ||||
|   auto file_size{size()}; | ||||
|   if (not file_size.has_value()) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
| auto enc_file::truncate(std::size_t size) -> bool {} | ||||
|   to_read = utils::calculate_read_size(file_size.value(), to_read, offset); | ||||
|   if (to_read == 0U) { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   std::size_t bytes_read{}; | ||||
|   auto ret{ | ||||
|       utils::encryption::read_encrypted_range( | ||||
|           {offset, offset + to_read - 1U}, | ||||
|           utils::encryption::generate_key<utils::encryption::hash_256_t>( | ||||
|               encryption_token_), | ||||
|           [&](auto &&ct_buffer, auto &&start_offset, | ||||
|               auto &&end_offset) -> bool { | ||||
|             ct_buffer.resize(end_offset - start_offset + 1U); | ||||
|             return file_->read(ct_buffer, start_offset); | ||||
|           }, | ||||
|           file_size.value(), data, to_read, bytes_read), | ||||
|   }; | ||||
|   if (ret && total_read != nullptr) { | ||||
|     *total_read = bytes_read; | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| auto enc_file::remove() -> bool { return file_->remove(); } | ||||
|  | ||||
| auto enc_file::truncate(std::size_t size) -> bool { | ||||
|   if (size == 0U) { | ||||
|     return file_->truncate(size); | ||||
|   } | ||||
|  | ||||
|   auto file_size{this->size()}; | ||||
|   if (not file_size.has_value()) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (size == file_size.value()) { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   auto chunks{ | ||||
|       size / utils::encryption::encrypting_reader::get_data_chunk_size(), | ||||
|   }; | ||||
|   auto real_size{ | ||||
|       (chunks * utils::encryption::encrypting_reader::get_data_chunk_size()) + | ||||
|           (chunks * utils::encryption::encrypting_reader::get_header_size()), | ||||
|   }; | ||||
|   auto remain{ | ||||
|       size % utils::encryption::encrypting_reader::get_data_chunk_size(), | ||||
|   }; | ||||
|   if (remain > 0U) { | ||||
|     real_size += | ||||
|         (remain + utils::encryption::encrypting_reader::get_header_size()); | ||||
|   } | ||||
|  | ||||
|   if (size < file_size.value()) { | ||||
|     if (remain == 0U) { | ||||
|       return file_->truncate(real_size); | ||||
|     } | ||||
|  | ||||
|     auto begin_chunk{ | ||||
|         size / utils::encryption::encrypting_reader::get_data_chunk_size(), | ||||
|     }; | ||||
|  | ||||
|     auto offset{ | ||||
|         begin_chunk * | ||||
|             utils::encryption::encrypting_reader::get_data_chunk_size(), | ||||
|     }; | ||||
|  | ||||
|     std::size_t total_read{}; | ||||
|     data_buffer data( | ||||
|         utils::encryption::encrypting_reader::get_data_chunk_size()); | ||||
|     if (not i_file::read(data, offset, &total_read)) { | ||||
|       return false; | ||||
|     } | ||||
|     data.resize(remain); | ||||
|  | ||||
|     if (not file_->truncate(real_size)) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     return i_file::write(data, offset); | ||||
|   } | ||||
|  | ||||
|   auto begin_chunk{ | ||||
|       file_size.value() / | ||||
|           utils::encryption::encrypting_reader::get_data_chunk_size(), | ||||
|   }; | ||||
|   auto end_chunk{ | ||||
|       utils::divide_with_ceiling( | ||||
|           file_size.value(), | ||||
|           utils::encryption::encrypting_reader::get_data_chunk_size()), | ||||
|   }; | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| auto enc_file::write(const unsigned char *data, std::size_t to_write, | ||||
|                      std::size_t offset, std::size_t *total_written) -> bool {} | ||||
|                      std::size_t offset, std::size_t *total_written) -> bool { | ||||
|   auto file_size{size()}; | ||||
|   if (not file_size.has_value()) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
| auto enc_file::size() const -> std::optional<std::uint64_t> {} | ||||
|   if ((offset + to_write) > file_size.value()) { | ||||
|     if (not truncate((offset + to_write) - file_size.value())) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| auto enc_file::size() const -> std::optional<std::uint64_t> { | ||||
|   auto file_size = file_->size(); | ||||
|   if (not file_size.has_value()) { | ||||
|     return std::nullopt; | ||||
|   } | ||||
|  | ||||
|   return utils::encryption::encrypting_reader::calculate_decrypted_size( | ||||
|       file_size.value()); | ||||
| } | ||||
| } // namespace repertory::utils::file | ||||
|  | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) && defined(PROJECT_ENABLE_BOOST) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -127,7 +127,7 @@ auto smb_directory::open(std::wstring_view host, std::wstring_view user, | ||||
| } | ||||
|  | ||||
| auto smb_directory::copy_to(std::string_view new_path, | ||||
|                             bool overwrite) const -> bool { | ||||
|                             bool /* overwrite */) const -> bool { | ||||
|   REPERTORY_USES_FUNCTION_NAME(); | ||||
|  | ||||
|   try { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -25,41 +25,174 @@ namespace repertory::utils::file { | ||||
| // auto thread_file::attach_file(native_handle handle, | ||||
| //                               bool read_only) -> fs_file_t {} | ||||
|  | ||||
| thread_file::thread_file(std::string_view path) | ||||
|     : file_(new repertory::utils::file::file(path)) {} | ||||
|  | ||||
| thread_file::thread_file(std::wstring_view path) | ||||
|     : file_(new repertory::utils::file::file(utils::string::to_utf8(path))) {} | ||||
|  | ||||
| auto thread_file::attach_file(fs_file_t file) -> fs_file_t {} | ||||
| auto thread_file::attach_file(fs_file_t file) -> fs_file_t { | ||||
|   return fs_file_t{ | ||||
|       new thread_file(std::move(file)), | ||||
|   }; | ||||
| } | ||||
|  | ||||
| auto thread_file::open_file(std::string_view path, | ||||
|                             bool read_only) -> fs_file_t {} | ||||
|                             bool read_only) -> fs_file_t { | ||||
|   return fs_file_t{ | ||||
|       new thread_file(file::open_file(path, read_only)), | ||||
|   }; | ||||
| } | ||||
|  | ||||
| auto thread_file::open_or_create_file(std::string_view path, | ||||
|                                       bool read_only) -> fs_file_t {} | ||||
|                                       bool read_only) -> fs_file_t { | ||||
|   return fs_file_t{ | ||||
|       new thread_file(file::open_or_create_file(path, read_only)), | ||||
|   }; | ||||
| } | ||||
|  | ||||
| void thread_file::io_item::done(bool result) { | ||||
|   unique_mutex_lock lock(*mtx); | ||||
|   complete = true; | ||||
|   success = result; | ||||
|   notify->notify_all(); | ||||
| } | ||||
|  | ||||
| void thread_file::io_item::wait() const { | ||||
|   if (complete) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   unique_mutex_lock lock(*mtx); | ||||
|   while (not complete) { | ||||
|     notify->wait(lock); | ||||
|   } | ||||
|   notify->notify_all(); | ||||
| } | ||||
|  | ||||
| thread_file::thread_file(std::string_view path) : file_(new file(path)) {} | ||||
|  | ||||
| thread_file::thread_file(std::wstring_view path) | ||||
|     : file_(new file(utils::string::to_utf8(path))) {} | ||||
|  | ||||
| thread_file::thread_file(fs_file_t file) : file_(std::move(file)) {} | ||||
|  | ||||
| void thread_file::close() {} | ||||
| thread_file::~thread_file() { | ||||
|   close(); | ||||
|  | ||||
|   if (io_thread_) { | ||||
|     io_thread_->join(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void thread_file::close() { | ||||
|   do_io([this]() -> bool { | ||||
|     file_->close(); | ||||
|     stop_requested_ = true; | ||||
|     return true; | ||||
|   }); | ||||
| } | ||||
|  | ||||
| auto thread_file::copy_to(std::string_view new_path, | ||||
|                           bool overwrite) const -> bool {} | ||||
|                           bool overwrite) const -> bool { | ||||
|   return do_io([this, &new_path, &overwrite]() -> bool { | ||||
|     return file_->copy_to(new_path, overwrite); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| void thread_file::flush() const {} | ||||
| auto thread_file::do_io(action_t action) const -> bool { | ||||
|   unique_mutex_lock lock(*mtx_); | ||||
|   if (stop_requested_) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
| auto thread_file::move_to(std::string_view path) -> bool {} | ||||
|   if (not io_thread_) { | ||||
|     io_thread_ = std::make_unique<std::thread>([this]() { thread_func(); }); | ||||
|   } | ||||
|  | ||||
|   auto item = std::make_shared<io_item>(action); | ||||
|   actions_.emplace_back(item); | ||||
|   notify_->notify_all(); | ||||
|   lock.unlock(); | ||||
|  | ||||
|   item->wait(); | ||||
|  | ||||
|   return item->success; | ||||
| } | ||||
|  | ||||
| void thread_file::flush() const { | ||||
|   do_io([this]() -> bool { | ||||
|     file_->flush(); | ||||
|     return true; | ||||
|   }); | ||||
| } | ||||
|  | ||||
| auto thread_file::move_to(std::string_view path) -> bool { | ||||
|   return do_io([this, &path]() -> bool { return file_->move_to(path); }); | ||||
| } | ||||
|  | ||||
| auto thread_file::read(unsigned char *data, std::size_t to_read, | ||||
|                        std::uint64_t offset, std::size_t *total_read) -> bool {} | ||||
|                        std::uint64_t offset, std::size_t *total_read) -> bool { | ||||
|   return do_io([this, &data, &to_read, &offset, &total_read]() -> bool { | ||||
|     return file_->read(data, to_read, offset, total_read); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| auto thread_file::remove() -> bool {} | ||||
| auto thread_file::remove() -> bool { | ||||
|   return do_io([this]() -> bool { return file_->remove(); }); | ||||
| } | ||||
|  | ||||
| auto thread_file::truncate(std::size_t size) -> bool {} | ||||
| void thread_file::thread_func() const { | ||||
|   unique_mutex_lock lock(*mtx_); | ||||
|   notify_->notify_all(); | ||||
|   lock.unlock(); | ||||
|  | ||||
|   const auto run_actions = [this, &lock]() { | ||||
|     auto actions = actions_; | ||||
|     actions_.clear(); | ||||
|     notify_->notify_all(); | ||||
|     lock.unlock(); | ||||
|  | ||||
|     for (auto &&action : actions) { | ||||
|       action->done(action->action()); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   while (not stop_requested_) { | ||||
|     lock.lock(); | ||||
|     if (stop_requested_) { | ||||
|       lock.unlock(); | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     while (not stop_requested_ && actions_.empty()) { | ||||
|       notify_->wait(lock); | ||||
|     } | ||||
|  | ||||
|     if (stop_requested_) { | ||||
|       lock.unlock(); | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     run_actions(); | ||||
|   } | ||||
|  | ||||
|   lock.lock(); | ||||
|   run_actions(); | ||||
| } | ||||
|  | ||||
| auto thread_file::truncate(std::size_t size) -> bool { | ||||
|   return do_io([this, &size]() -> bool { return file_->truncate(size); }); | ||||
| } | ||||
|  | ||||
| auto thread_file::write(const unsigned char *data, std::size_t to_write, | ||||
|                         std::size_t offset, | ||||
|                         std::size_t *total_written) -> bool {} | ||||
|                         std::size_t *total_written) -> bool { | ||||
|   return do_io([this, &data, &to_write, &offset, &total_written]() -> bool { | ||||
|     return file_->write(data, to_write, offset, total_written); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| auto thread_file::size() const -> std::optional<std::uint64_t> {} | ||||
| auto thread_file::size() const -> std::optional<std::uint64_t> { | ||||
|   std::optional<std::uint64_t> size; | ||||
|   do_io([this, &size]() -> bool { | ||||
|     size = file_->size(); | ||||
|     return size.has_value(); | ||||
|   }); | ||||
|   return size; | ||||
| } | ||||
| } // namespace repertory::utils::file | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|   Copyright <2018-2025> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|   of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
		Reference in New Issue
	
	Block a user