5 #include <c++utilities/conversion/stringbuilder.h>
6 #include <c++utilities/conversion/stringconversion.h>
8 #ifdef PLATFORM_WINDOWS
32 namespace BackupHelper {
53 const std::string &originalPath,
const std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
56 if (originalStream.is_open()) {
57 originalStream.close();
60 const auto backupPathForOpen = BasicFileInfo::pathForOpen(backupPath);
61 backupStream.exceptions(ios_base::goodbit);
64 backupStream.open(backupPathForOpen.data(), ios_base::in | ios_base::binary);
65 if (backupStream.is_open()) {
68 throw std::ios_base::failure(
"Backup/temporary file has not been created.");
71 const auto originalPathForOpen = BasicFileInfo::pathForOpen(originalPath);
72 std::remove(originalPathForOpen.data());
73 if (std::rename(backupPathForOpen.data(), originalPathForOpen.data()) == 0) {
79 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
80 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
81 backupStream.open(backupPathForOpen.data(), ios_base::in | ios_base::binary);
82 originalStream.open(originalPathForOpen.data(), ios_base::out | ios_base::binary);
83 originalStream << backupStream.rdbuf();
84 originalStream.flush();
86 }
catch (
const std::ios_base::failure &failure) {
87 throw std::ios_base::failure(
"Unable to restore original file from backup file \"" % backupPath %
"\" after failure: " + failure.what());
94 static bool isRelative(
const std::string &path)
96 return path.empty() || (path.front() !=
'/' && (path.size() < 2 || path[1] !=
':'));
124 void createBackupFile(
const std::string &backupDir,
const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream,
125 NativeFileStream &backupStream)
128 const auto backupDirRelative(isRelative(backupDir));
129 const auto originalDir(backupDirRelative ? BasicFileInfo::containingDirectory(originalPath) :
string());
132 for (
unsigned int i = 0;; ++i) {
133 if (backupDir.empty()) {
135 backupPath = originalPath %
'.' % i +
".bak";
137 backupPath = originalPath +
".bak";
140 const auto fileName(BasicFileInfo::fileName(originalPath, i));
142 const auto ext(BasicFileInfo::extension(originalPath));
143 if (backupDirRelative) {
144 backupPath = originalDir %
'/' % backupDir %
'/' % fileName %
'.' % i + ext;
146 backupPath = backupDir %
'/' % fileName %
'.' % i + ext;
149 if (backupDirRelative) {
150 backupPath = originalDir %
'/' % backupDir %
'/' + fileName;
152 backupPath = backupDir %
'/' + fileName;
158 #ifdef PLATFORM_WINDOWS
159 if (GetFileAttributes(BasicFileInfo::pathForOpen(backupPath).data()) == INVALID_FILE_ATTRIBUTES) {
161 struct stat backupStat;
162 if (stat(BasicFileInfo::pathForOpen(backupPath).data(), &backupStat)) {
169 if (originalStream.is_open()) {
170 originalStream.close();
174 if (std::rename(BasicFileInfo::pathForOpen(originalPath).data(), BasicFileInfo::pathForOpen(backupPath).data())) {
177 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
178 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
180 if (backupStream.is_open()) {
181 backupStream.close();
183 backupStream.open(BasicFileInfo::pathForOpen(backupPath).data(), ios_base::out | ios_base::binary);
185 originalStream.open(BasicFileInfo::pathForOpen(originalPath).data(), ios_base::in | ios_base::binary);
187 backupStream << originalStream.rdbuf();
188 backupStream.flush();
191 }
catch (
const std::ios_base::failure &failure) {
192 throw std::ios_base::failure(argsToString(
"Unable to rename original file before rewriting it: ", failure.what()));
199 if (originalStream.is_open()) {
200 originalStream.close();
203 if (backupStream.is_open()) {
204 backupStream.close();
207 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
208 backupStream.open(BasicFileInfo::pathForOpen(backupPath).data(), ios_base::in | ios_base::binary);
209 }
catch (
const std::ios_base::failure &failure) {
212 if (std::rename(BasicFileInfo::pathForOpen(backupPath).data(), BasicFileInfo::pathForOpen(originalPath).data())) {
213 throw std::ios_base::failure(
"Unable to restore original file from backup file \"" % backupPath %
"\" after failure: " + failure.what());
215 throw std::ios_base::failure(argsToString(
"Unable to open backup file: ", failure.what()));
240 NativeFileStream &backupStream,
Diagnostics &diag,
const std::string &context)
251 if (!backupPath.empty()) {
253 diag.emplace_back(DiagLevel::Information,
"Rewriting the file to apply changed tag information has been aborted.", context);
256 diag.emplace_back(DiagLevel::Warning,
"The original file has been restored.", context);
257 }
catch (
const std::ios_base::failure &failure) {
258 diag.emplace_back(DiagLevel::Critical, argsToString(
"The original file could not be restored: ", failure.what()), context);
261 diag.emplace_back(DiagLevel::Information,
"Applying new tag information has been aborted.", context);
266 if (!backupPath.empty()) {
268 diag.emplace_back(DiagLevel::Critical,
"Rewriting the file to apply changed tag information failed.", context);
271 diag.emplace_back(DiagLevel::Warning,
"The original file has been restored.", context);
272 }
catch (
const std::ios_base::failure &failure) {
273 diag.emplace_back(DiagLevel::Critical, argsToString(
"The original file could not be restored: ", failure.what()), context);
276 diag.emplace_back(DiagLevel::Critical,
"Applying new tag information failed.", context);
280 }
catch (
const std::ios_base::failure &) {
281 if (!backupPath.empty()) {
283 diag.emplace_back(DiagLevel::Critical,
"An IO error occurred when rewriting the file to apply changed tag information.", context);
286 diag.emplace_back(DiagLevel::Warning,
"The original file has been restored.", context);
287 }
catch (
const std::ios_base::failure &failure) {
288 diag.emplace_back(DiagLevel::Critical, argsToString(
"The original file could not be restored: ", failure.what()), context);
291 diag.emplace_back(DiagLevel::Critical,
"An IO error occurred when applying tag information.", context);
virtual void reset()
Discards all parsing results.
const std::string & path() const
Returns the path of the current file.
The Diagnostics class is a container for DiagMessage.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
The exception that is thrown when an operation has been stopped and thus not successfully completed b...
void createBackupFile(const std::string &backupDir, const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
Creates a backup file for the specified file.
void restoreOriginalFileFromBackupFile(const std::string &originalPath, const std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
Restores the original file from the specified backup file.
void handleFailureAfterFileModified(MediaFileInfo &fileInfo, const std::string &backupPath, NativeFileStream &outputStream, NativeFileStream &backupStream, Diagnostics &diag, const std::string &context)
Handles a failure/abort which occurred after the file has been modified.
Contains all classes and functions of the TagInfo library.