From 0808c8fa3cbd37ecf34fcb288a1d0142f7d40616 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Sun, 22 Dec 2019 11:11:48 +0100 Subject: [PATCH] Refactoring and documentation of check_copy() and copy_file() --- src/libslic3r/Utils.hpp | 5 ++++- src/libslic3r/utils.cpp | 42 +++++++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index bf0fbfa72..06c435809 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -66,9 +66,12 @@ extern std::error_code rename_file(const std::string &from, const std::string &t // Copy a file, adjust the access attributes, so that the target is writable. int copy_file_inner(const std::string &from, const std::string &to); +// Copy file to a temp file first, then rename it to the final file name. +// If with_check is true, then the content of the copied file is compared to the content +// of the source file before renaming. extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false); -// Compares two files, returns 0 if identical. +// Compares two files, returns 0 if identical, -1 if different. extern int check_copy(const std::string& origin, const std::string& copy); // Ignore system and hidden files, which may be created by the DropBox synchronisation process. diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 2b867c8af..b7155ddc8 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -448,31 +448,45 @@ int copy_file(const std::string &from, const std::string &to, const bool with_ch if (with_check) ret_val = check_copy(from, to_temp); - if (ret_val == 0) - rename_file(to_temp, to); + if (ret_val == 0 && rename_file(to_temp, to)) + ret_val = -1; } return ret_val; } int check_copy(const std::string &origin, const std::string ©) { - std::ifstream f1(origin, std::ifstream::binary | std::ifstream::ate); - std::ifstream f2(copy, std::ifstream::binary | std::ifstream::ate); + std::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); + std::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); - if (f1.fail() || f2.fail()) { - return -1; - } + if (f1.fail() || f2.fail()) + return -1; - if (f1.tellg() != f2.tellg()) { - return -1; - } + std::streampos fsize = f1.tellg(); + if (fsize != f2.tellg()) + return -1; f1.seekg(0, std::ifstream::beg); f2.seekg(0, std::ifstream::beg); - bool ident = std::equal(std::istreambuf_iterator(f1.rdbuf()), - std::istreambuf_iterator(), - std::istreambuf_iterator(f2.rdbuf())); - return(ident ? 0 : -1); + + // Compare by reading 8 MiB buffers one at a time. + size_t buffer_size = 8 * 1024 * 1024; + std::vector buffer_origin(buffer_size, 0); + std::vector buffer_copy(buffer_size, 0); + do { + f1.read(buffer_origin.data(), buffer_size); + f2.read(buffer_copy.data(), buffer_size); + std::streampos origin_cnt = f1.gcount(); + std::streampos copy_cnt = f2.gcount(); + if (origin_cnt != copy_cnt || + (origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0)) + // Files are different. + return -1; + fsize -= origin_cnt; + } while (f1.good() && f2.good()); + + // All data has been read and compared equal. + return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -1; } // Ignore system and hidden files, which may be created by the DropBox synchronisation process.