diff --git a/td/telegram/files/FileGenerateManager.cpp b/td/telegram/files/FileGenerateManager.cpp index b823f74c3..562c283e4 100644 --- a/td/telegram/files/FileGenerateManager.cpp +++ b/td/telegram/files/FileGenerateManager.cpp @@ -412,7 +412,7 @@ static Status check_mtime(std::string &conversion, CSlice original_path) { conversion = parser.read_all().str(); auto r_stat = stat(original_path); uint64 actual_mtime = r_stat.is_ok() ? r_stat.ok().mtime_nsec_ : 0; - if (FileManager::are_modification_times_equal(expected_mtime, actual_mtime)) { + if (are_modification_times_equal(expected_mtime, actual_mtime)) { LOG(DEBUG) << "File \"" << original_path << "\" modification time " << actual_mtime << " matches"; return Status::OK(); } diff --git a/td/telegram/files/FileLoaderUtils.cpp b/td/telegram/files/FileLoaderUtils.cpp index 41b0f8a5b..c45d4f529 100644 --- a/td/telegram/files/FileLoaderUtils.cpp +++ b/td/telegram/files/FileLoaderUtils.cpp @@ -257,4 +257,100 @@ string get_files_dir(FileType file_type) { return PSTRING() << get_files_base_dir(file_type) << get_file_type_name(file_type) << TD_DIR_SLASH; } +bool are_modification_times_equal(int64 old_mtime, int64 new_mtime) { + if (old_mtime == new_mtime) { + return true; + } + if (old_mtime < new_mtime) { + return false; + } + if (old_mtime - new_mtime == 1000000000 && old_mtime % 1000000000 == 0 && new_mtime % 2000000000 == 0) { + // FAT32 has 2 seconds mtime resolution, but file system sometimes reports odd modification time + return true; + } + return false; +} + +Result check_full_local_location(FullLocalLocationInfo local_info, bool skip_file_size_checks) { + constexpr int64 MAX_FILE_SIZE = static_cast(4000) << 20 /* 4000 MB */; + constexpr int64 MAX_THUMBNAIL_SIZE = 200 * (1 << 10) - 1 /* 200 KB - 1 B */; + constexpr int64 MAX_PHOTO_SIZE = 10 * (1 << 20) /* 10 MB */; + constexpr int64 DEFAULT_VIDEO_NOTE_SIZE_MAX = 12 * (1 << 20) /* 12 MB */; + + FullLocalFileLocation &location = local_info.location_; + int64 &size = local_info.size_; + if (location.path_.empty()) { + return Status::Error(400, "File must have non-empty path"); + } + auto r_path = realpath(location.path_, true); + if (r_path.is_error()) { + return Status::Error(400, "Can't find real file path"); + } + location.path_ = r_path.move_as_ok(); + + auto r_stat = stat(location.path_); + if (r_stat.is_error()) { + return Status::Error(400, "Can't get stat about the file"); + } + auto stat = r_stat.move_as_ok(); + if (!stat.is_reg_) { + return Status::Error(400, "File must be a regular file"); + } + if (stat.size_ < 0) { + // TODO is it possible? + return Status::Error(400, "File is too big"); + } + if (stat.size_ == 0) { + return Status::Error(400, "File must be non-empty"); + } + + if (size == 0) { + size = stat.size_; + } + if (location.mtime_nsec_ == 0) { + VLOG(file_loader) << "Set file \"" << location.path_ << "\" modification time to " << stat.mtime_nsec_; + location.mtime_nsec_ = stat.mtime_nsec_; + } else if (!are_modification_times_equal(location.mtime_nsec_, stat.mtime_nsec_)) { + VLOG(file_loader) << "File \"" << location.path_ << "\" was modified: old mtime = " << location.mtime_nsec_ + << ", new mtime = " << stat.mtime_nsec_; + return Status::Error(400, PSLICE() << "File \"" << utf8_encode(location.path_) << "\" was modified"); + } + if (skip_file_size_checks) { + return std::move(local_info); + } + + auto get_file_size_error = [&](Slice reason) { + return Status::Error(400, PSLICE() << "File \"" << utf8_encode(location.path_) << "\" of size " << size + << " bytes is too big" << reason); + }; + if ((location.file_type_ == FileType::Thumbnail || location.file_type_ == FileType::EncryptedThumbnail) && + size > MAX_THUMBNAIL_SIZE && !begins_with(PathView(location.path_).file_name(), "map") && + !begins_with(PathView(location.path_).file_name(), "Album cover for ")) { + return get_file_size_error(" for a thumbnail"); + } + if (size > MAX_FILE_SIZE) { + return get_file_size_error(""); + } + if (location.file_type_ == FileType::Photo && size > MAX_PHOTO_SIZE) { + return get_file_size_error(" for a photo"); + } + if (location.file_type_ == FileType::VideoNote && + size > G()->get_option_integer("video_note_size_max", DEFAULT_VIDEO_NOTE_SIZE_MAX)) { + return get_file_size_error(" for a video note"); + } + return std::move(local_info); +} + +Status check_partial_local_location(const PartialLocalFileLocation &location) { + TRY_RESULT(stat, stat(location.path_)); + if (!stat.is_reg_) { + if (stat.is_dir_) { + return Status::Error(PSLICE() << "Can't use directory \"" << location.path_ << "\" as a file path"); + } + return Status::Error("File must be a regular file"); + } + // can't check mtime. Hope nobody will mess with this files in our temporary dir. + return Status::OK(); +} + } // namespace td diff --git a/td/telegram/files/FileLoaderUtils.h b/td/telegram/files/FileLoaderUtils.h index 5fb1c1e02..f7e4a3ae4 100644 --- a/td/telegram/files/FileLoaderUtils.h +++ b/td/telegram/files/FileLoaderUtils.h @@ -38,4 +38,15 @@ string get_files_temp_dir(FileType file_type); string get_files_dir(FileType file_type); +bool are_modification_times_equal(int64 old_mtime, int64 new_mtime); + +struct FullLocalLocationInfo { + FullLocalFileLocation location_; + int64 size_ = 0; +}; + +Result check_full_local_location(FullLocalLocationInfo local_info, bool skip_file_size_checks); + +Status check_partial_local_location(const PartialLocalFileLocation &location); + } // namespace td diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index a551985d0..b0cf7591c 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -916,106 +916,10 @@ string FileManager::get_file_name(FileType file_type, Slice path) { return file_name.str(); } -bool FileManager::are_modification_times_equal(int64 old_mtime, int64 new_mtime) { - if (old_mtime == new_mtime) { - return true; - } - if (old_mtime < new_mtime) { - return false; - } - if (old_mtime - new_mtime == 1000000000 && old_mtime % 1000000000 == 0 && new_mtime % 2000000000 == 0) { - // FAT32 has 2 seconds mtime resolution, but file system sometimes reports odd modification time - return true; - } - return false; -} - bool FileManager::is_remotely_generated_file(Slice conversion) { return begins_with(conversion, "#map#") || begins_with(conversion, "#audio_t#"); } -Result FileManager::check_local_location(FullLocalLocationInfo local_info, - bool skip_file_size_checks) { - constexpr int64 MAX_THUMBNAIL_SIZE = 200 * (1 << 10) - 1 /* 200 KB - 1 B */; - constexpr int64 MAX_PHOTO_SIZE = 10 * (1 << 20) /* 10 MB */; - constexpr int64 DEFAULT_VIDEO_NOTE_SIZE_MAX = 12 * (1 << 20) /* 12 MB */; - - FullLocalFileLocation &location = local_info.location_; - int64 &size = local_info.size_; - if (location.path_.empty()) { - return Status::Error(400, "File must have non-empty path"); - } - auto r_path = realpath(location.path_, true); - if (r_path.is_error()) { - return Status::Error(400, "Can't find real file path"); - } - location.path_ = r_path.move_as_ok(); - - auto r_stat = stat(location.path_); - if (r_stat.is_error()) { - return Status::Error(400, "Can't get stat about the file"); - } - auto stat = r_stat.move_as_ok(); - if (!stat.is_reg_) { - return Status::Error(400, "File must be a regular file"); - } - if (stat.size_ < 0) { - // TODO is it possible? - return Status::Error(400, "File is too big"); - } - if (stat.size_ == 0) { - return Status::Error(400, "File must be non-empty"); - } - - if (size == 0) { - size = stat.size_; - } - if (location.mtime_nsec_ == 0) { - VLOG(file_loader) << "Set file \"" << location.path_ << "\" modification time to " << stat.mtime_nsec_; - location.mtime_nsec_ = stat.mtime_nsec_; - } else if (!are_modification_times_equal(location.mtime_nsec_, stat.mtime_nsec_)) { - VLOG(file_loader) << "File \"" << location.path_ << "\" was modified: old mtime = " << location.mtime_nsec_ - << ", new mtime = " << stat.mtime_nsec_; - return Status::Error(400, PSLICE() << "File \"" << utf8_encode(location.path_) << "\" was modified"); - } - if (skip_file_size_checks) { - return std::move(local_info); - } - - auto get_file_size_error = [&](Slice reason) { - return Status::Error(400, PSLICE() << "File \"" << utf8_encode(location.path_) << "\" of size " << size - << " bytes is too big" << reason); - }; - if ((location.file_type_ == FileType::Thumbnail || location.file_type_ == FileType::EncryptedThumbnail) && - size > MAX_THUMBNAIL_SIZE && !begins_with(PathView(location.path_).file_name(), "map") && - !begins_with(PathView(location.path_).file_name(), "Album cover for ")) { - return get_file_size_error(" for a thumbnail"); - } - if (size > MAX_FILE_SIZE) { - return get_file_size_error(""); - } - if (location.file_type_ == FileType::Photo && size > MAX_PHOTO_SIZE) { - return get_file_size_error(" for a photo"); - } - if (location.file_type_ == FileType::VideoNote && - size > G()->get_option_integer("video_note_size_max", DEFAULT_VIDEO_NOTE_SIZE_MAX)) { - return get_file_size_error(" for a video note"); - } - return std::move(local_info); -} - -static Status check_partial_local_location(const PartialLocalFileLocation &location) { - TRY_RESULT(stat, stat(location.path_)); - if (!stat.is_reg_) { - if (stat.is_dir_) { - return Status::Error(PSLICE() << "Can't use directory \"" << location.path_ << "\" as a file path"); - } - return Status::Error("File must be a regular file"); - } - // can't check mtime. Hope nobody will mess with this file in our temporary dir. - return Status::OK(); -} - void FileManager::check_local_location(FileId file_id, bool skip_file_size_checks) { auto node = get_sync_file_node(file_id); if (node) { @@ -1026,7 +930,7 @@ void FileManager::check_local_location(FileId file_id, bool skip_file_size_check Status FileManager::check_local_location(FileNodePtr node, bool skip_file_size_checks) { Status status; if (node->local_.type() == LocalFileLocation::Type::Full) { - auto r_info = check_local_location({node->local_.full(), node->size_}, skip_file_size_checks); + auto r_info = check_full_local_location({node->local_.full(), node->size_}, skip_file_size_checks); if (r_info.is_error()) { status = r_info.move_as_error(); } else if (bad_paths_.count(r_info.ok().location_.path_) != 0) { @@ -1212,7 +1116,7 @@ Result FileManager::register_file(FileData &&data, FileLocationSource fi if (!is_from_database) { Status status; - auto r_info = check_local_location({data.local_.full(), data.size_}, skip_file_size_checks); + auto r_info = check_full_local_location({data.local_.full(), data.size_}, skip_file_size_checks); if (r_info.is_error()) { status = r_info.move_as_error(); } else if (bad_paths_.count(r_info.ok().location_.path_) != 0) { diff --git a/td/telegram/files/FileManager.h b/td/telegram/files/FileManager.h index 92494b213..8bb08bf41 100644 --- a/td/telegram/files/FileManager.h +++ b/td/telegram/files/FileManager.h @@ -416,8 +416,6 @@ class FileManager final : public FileLoadManager::Callback { FileManager &operator=(FileManager &&other) = delete; ~FileManager() final; - static bool are_modification_times_equal(int64 old_mtime, int64 new_mtime); - static bool is_remotely_generated_file(Slice conversion); void init_actor(); @@ -618,13 +616,6 @@ class FileManager final : public FileLoadManager::Callback { void load_from_pmc_result(FileId file_id, Result &&result); FileId register_pmc_file_data(FileData &&data); - struct FullLocalLocationInfo { - FullLocalFileLocation location_; - int64 size_ = 0; - }; - static Result check_local_location(FullLocalLocationInfo local_info, - bool skip_file_size_checks); - Status check_local_location(FileNodePtr node, bool skip_file_size_checks); static bool try_fix_partial_local_location(FileNodePtr node); void try_flush_node_full(FileNodePtr node, bool new_remote, bool new_local, bool new_generate, FileDbId other_pmc_id); diff --git a/td/telegram/files/FileStats.cpp b/td/telegram/files/FileStats.cpp index b391ec7bc..c231783f7 100644 --- a/td/telegram/files/FileStats.cpp +++ b/td/telegram/files/FileStats.cpp @@ -6,7 +6,6 @@ // #include "td/telegram/files/FileStats.h" -#include "td/telegram/files/FileLoaderUtils.h" #include "td/telegram/td_api.h" #include "td/utils/algorithm.h"