[impl] Allow to postpone file deletion if file is dll exe file that is still in use

This commit is contained in:
Peter Sykora 2018-03-31 14:51:05 +02:00
parent d142df6366
commit 4e1edd2a33
6 changed files with 95 additions and 14 deletions

View File

@ -15,10 +15,11 @@
class ModuleManager
{
public:
ModuleManager(const std::string& appBaseDir, IModuleDatabase& db, IDownloader& downloader)
ModuleManager(const std::string& appBaseDir, IModuleDatabase& db, IDownloader& downloader, const std::string& tempDir)
: m_appBaseDir(appBaseDir)
, m_db(db)
, m_downloader(downloader)
, m_tempDir(tempDir)
{}
public:
@ -35,4 +36,5 @@ private:
std::string m_appBaseDir;
IModuleDatabase & m_db;
IDownloader& m_downloader;
std::string m_tempDir;
};

View File

@ -177,6 +177,7 @@
<ClInclude Include="api\SystemParamsProvider.h" />
<ClInclude Include="api\SystemParamsProvider_win.h" />
<ClInclude Include="src\HashUtils.h" />
<ClInclude Include="src\SafeFileUtils.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\CachedDownloader.cpp" />
@ -188,6 +189,7 @@
<ClCompile Include="src\LicenseClient.cpp" />
<ClCompile Include="src\ModuleManager.cpp" />
<ClCompile Include="src\ModuleUpdate.cpp" />
<ClCompile Include="src\SafeFileUtils.cpp" />
<ClCompile Include="src\SystemParams.cpp" />
<ClCompile Include="src\SystemParamsProvider_win.cpp" />
</ItemGroup>

View File

@ -60,6 +60,9 @@
<ClInclude Include="api\IDownloader.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="src\SafeFileUtils.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\HashUtils.cpp">
@ -95,5 +98,8 @@
<ClCompile Include="src\CachedDownloader.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\SafeFileUtils.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,6 +1,7 @@
#include "ModuleManager.h"
#include "HashUtils.h"
#include "SafeFileUtils.h"
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
@ -8,6 +9,8 @@
#include <algorithm>
#include <cstdio>
namespace fs = boost::filesystem;
void ModuleManager::applyUpdate(const std::string & moduleId, const ModuleUpdate & update)
{
auto module = m_db.findModule(moduleId).value_or(Module{ moduleId, -1 , {} });
@ -30,10 +33,10 @@ void ModuleManager::applyUpdate(Module & module, const ModuleUpdate & update)
if (!(update.flag & static_cast<uint32_t>(ModuleUpdateFlags::incremental)))
{
// We should remove old files first before extracting new ones
boost::filesystem::path basePath(m_appBaseDir);
std::for_each(module.filePaths.begin(), module.filePaths.end(), [&basePath](const auto& filePath)
fs::path basePath(m_appBaseDir);
std::for_each(module.filePaths.begin(), module.filePaths.end(), [&basePath, this](const auto& filePath)
{
boost::filesystem::remove(basePath / filePath);
safeRemoveFile(basePath / filePath, m_tempDir);
});
module.filePaths.clear();
}
@ -45,7 +48,7 @@ void ModuleManager::applyUpdate(Module & module, const ModuleUpdate & update)
module.filePaths.insert(filePaths.begin(), filePaths.end());
}
boost::filesystem::path ModuleManager::retrieveUpdate(const std::string & updateUrl)
fs::path ModuleManager::retrieveUpdate(const std::string & updateUrl)
{
return m_downloader.download(updateUrl);
}
@ -61,21 +64,21 @@ std::string zipErrorToStr(int err)
return buf;
}
inline std::set<std::string> ModuleManager::extractUpdate(const boost::filesystem::path& archivePath, const std::string & targetPath)
std::set<std::string> ModuleManager::extractUpdate(const fs::path& archivePath, const std::string & targetPath)
{
struct zip_file *zf = nullptr;
struct zip_stat sb;
int err;
boost::filesystem::path basePath(m_appBaseDir);
fs::path basePath(m_appBaseDir);
basePath /= targetPath;
boost::filesystem::path basePathRel(targetPath);
fs::path basePathRel(targetPath);
if (!boost::filesystem::exists(basePath))
if (!fs::exists(basePath))
{
boost::filesystem::create_directories(basePath);
fs::create_directories(basePath);
}
if (!boost::filesystem::is_directory(basePath))
if (!fs::is_directory(basePath))
{
throw std::runtime_error("Target path is not a directory");
}
@ -103,7 +106,7 @@ inline std::set<std::string> ModuleManager::extractUpdate(const boost::filesyste
auto outPathRel = basePathRel / sb.name;
if (sb.name[len - 1] == '/')
{
if (!boost::filesystem::is_directory(outPath) && !boost::filesystem::create_directory(outPath))
if (!fs::is_directory(outPath) && !fs::create_directory(outPath))
{
throw std::runtime_error("Directory can't be extracted");
}
@ -116,8 +119,9 @@ inline std::set<std::string> ModuleManager::extractUpdate(const boost::filesyste
throw std::runtime_error("Can't open file from the archive");
}
auto file = safeCreateFile(outPath, m_tempDir);
{
std::ofstream os(outPath.string(), std::ofstream::binary);
std::ofstream os = std::ofstream(file.path().native(), std::ofstream::binary);
uint64_t sum = 0;
while (sum != sb.size) {
@ -130,7 +134,7 @@ inline std::set<std::string> ModuleManager::extractUpdate(const boost::filesyste
sum += len;
}
}
boost::filesystem::last_write_time(outPath, sb.mtime);
fs::last_write_time(file.path(), sb.mtime);
extractedFiles.insert(outPathRel.string());
zip_fclose(zf);

46
src/SafeFileUtils.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "SafeFileUtils.h"
#include <winerror.h>
namespace fs = boost::filesystem;
void safeRemoveFile(const fs::path& p, const fs::path& tempFolder)
{
try
{
bool result = fs::remove(p);
}
catch (fs::filesystem_error& e)
{
if (e.code().category() == boost::system::system_category()
&& e.code().value() == ERROR_ACCESS_DENIED)
{
auto cleanupFolder = tempFolder;
if (!fs::exists(cleanupFolder))
{
fs::create_directories(cleanupFolder);
}
if (!fs::is_directory(cleanupFolder))
{
throw std::runtime_error(".upd/.remove folder is not directory");
}
auto fileName = fs::unique_path();
fs::rename(p, cleanupFolder / fileName);
}
else
{
throw;
}
}
}
SafeFile safeCreateFile(const fs::path & p, const fs::path& tempFolder)
{
if (fs::exists(p))
{
safeRemoveFile(p, tempFolder);
}
return SafeFile(p);
}

21
src/SafeFileUtils.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <boost/filesystem.hpp>
void safeRemoveFile(const boost::filesystem::path& p, const boost::filesystem::path& tempFolder);
class SafeFile
{
public:
SafeFile(const boost::filesystem::path& p)
: m_path(p)
{}
public:
const boost::filesystem::path& path() { return m_path; }
private:
boost::filesystem::path m_path;
};
SafeFile safeCreateFile(const boost::filesystem::path& p, const boost::filesystem::path& tempFolder);