Make URLSynchronization and HTTPSynchronization download into temporary files and if the download succeeds, transactionally move the temporary file into the correct destination

This commit is contained in:
Alexander Bock
2018-03-10 05:08:14 -05:00
parent 5b6ae62bab
commit 31cdee1fa1
5 changed files with 78 additions and 14 deletions

View File

@@ -22,27 +22,27 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "httpsynchronization.h"
#include <modules/sync/syncs/httpsynchronization.h>
#include <modules/sync/syncmodule.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/util/httprequest.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <openspace/documentation/verifier.h>
#include <sstream>
#include <ghoul/logging/logmanager.h>
#include <cstdio>
#include <fstream>
#include <numeric>
#include <memory>
#include <sstream>
namespace {
constexpr const char* KeyIdentifier = "Identifier";
constexpr const char* KeyVersion = "Version";
constexpr const char* TempSuffix = ".tmp";
constexpr const char* QueryKeyIdentifier = "identifier";
constexpr const char* QueryKeyFileVersion = "file_version";
constexpr const char* QueryKeyApplicationVersion = "application_version";
@@ -214,8 +214,8 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) {
std::string filename = line.substr(lastSlash + 1);
std::string fileDestination = directory() +
ghoul::filesystem::FileSystem::PathSeparator +
filename;
ghoul::filesystem::FileSystem::PathSeparator +
filename + TempSuffix;
downloads.push_back(std::make_unique<AsyncHttpFileDownload>(
line, fileDestination, HttpFileDownload::Overwrite::Yes));
@@ -256,7 +256,31 @@ bool HttpSynchronization::trySyncFromUrl(std::string listUrl) {
bool failed = false;
for (std::unique_ptr<AsyncHttpFileDownload>& d : downloads) {
d->wait();
if (!d->hasSucceeded()) {
if (d->hasSucceeded()) {
// If we are forcing the override, we download to a temporary file
// first, so when we are done here, we need to rename the file to the
// original name
const std::string& tempName = d->destination();
std::string originalName = tempName.substr(
0,
tempName.size() - strlen(TempSuffix)
);
FileSys.deleteFile(originalName);
int success = rename(tempName.c_str(), originalName.c_str());
if (success != 0) {
LERRORC(
"URLSynchronization",
fmt::format(
"Error renaming file {} to {}", tempName, originalName
)
);
failed = true;
}
}
else {
failed = true;
}
}