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 backupStream.exceptions(ios_base::goodbit);
63 backupStream.open(backupPath, ios_base::in | ios_base::binary);
64 if (backupStream.is_open()) {
67 throw std::ios_base::failure(
"Backup/temporary file has not been created.");
70 std::remove(originalPath.c_str());
71 if (std::rename(BasicFileInfo::pathForOpen(backupPath).data(), BasicFileInfo::pathForOpen(originalPath).data()) == 0) {
77 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
78 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
79 backupStream.open(backupPath, ios_base::in | ios_base::binary);
80 originalStream.open(originalPath, ios_base::out | ios_base::binary);
81 originalStream << backupStream.rdbuf();
82 originalStream.flush();
84 }
catch (
const std::ios_base::failure &failure) {
85 throw std::ios_base::failure(
"Unable to restore original file from backup file \"" % backupPath %
"\" after failure: " + failure.what());
92 static bool isRelative(
const std::string &path)
94 return path.empty() || (path.front() !=
'/' && (path.size() < 2 || path[1] !=
':'));
122 void createBackupFile(
const std::string &backupDir,
const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream,
123 NativeFileStream &backupStream)
126 const auto backupDirRelative(isRelative(backupDir));
127 const auto originalDir(backupDirRelative ? BasicFileInfo::containingDirectory(originalPath) :
string());
130 for (
unsigned int i = 0;; ++i) {
131 if (backupDir.empty()) {
133 backupPath = originalPath %
'.' % i +
".bak";
135 backupPath = originalPath +
".bak";
138 const auto fileName(BasicFileInfo::fileName(originalPath, i));
140 const auto ext(BasicFileInfo::extension(originalPath));
141 if (backupDirRelative) {
142 backupPath = originalDir %
'/' % backupDir %
'/' % fileName %
'.' % i + ext;
144 backupPath = backupDir %
'/' % fileName %
'.' % i + ext;
147 if (backupDirRelative) {
148 backupPath = originalDir %
'/' % backupDir %
'/' + fileName;
150 backupPath = backupDir %
'/' + fileName;
156 #ifdef PLATFORM_WINDOWS
157 if (GetFileAttributes(BasicFileInfo::pathForOpen(backupPath).data()) == INVALID_FILE_ATTRIBUTES) {
159 struct stat backupStat;
160 if (stat(BasicFileInfo::pathForOpen(backupPath).data(), &backupStat)) {
167 if (originalStream.is_open()) {
168 originalStream.close();
172 if (std::rename(BasicFileInfo::pathForOpen(originalPath).data(), BasicFileInfo::pathForOpen(backupPath).data())) {
175 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
176 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
178 if (backupStream.is_open()) {
179 backupStream.close();
181 backupStream.open(BasicFileInfo::pathForOpen(backupPath).data(), ios_base::out | ios_base::binary);
183 originalStream.open(BasicFileInfo::pathForOpen(originalPath).data(), ios_base::in | ios_base::binary);
185 backupStream << originalStream.rdbuf();
186 backupStream.flush();
189 }
catch (
const std::ios_base::failure &failure) {
190 throw std::ios_base::failure(argsToString(
"Unable to rename original file before rewriting it: ", failure.what()));
197 if (originalStream.is_open()) {
198 originalStream.close();
201 if (backupStream.is_open()) {
202 backupStream.close();
205 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
206 backupStream.open(BasicFileInfo::pathForOpen(backupPath).data(), ios_base::in | ios_base::binary);
207 }
catch (
const std::ios_base::failure &failure) {
210 if (std::rename(BasicFileInfo::pathForOpen(backupPath).data(), BasicFileInfo::pathForOpen(originalPath).data())) {
211 throw std::ios_base::failure(
"Unable to restore original file from backup file \"" % backupPath %
"\" after failure: " + failure.what());
213 throw std::ios_base::failure(argsToString(
"Unable to open backup file: ", failure.what()));
238 NativeFileStream &backupStream,
Diagnostics &diag,
const std::string &context)
249 if (!backupPath.empty()) {
251 diag.emplace_back(DiagLevel::Information,
"Rewriting the file to apply changed tag information has been aborted.", context);
254 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
255 }
catch (
const std::ios_base::failure &failure) {
256 diag.emplace_back(DiagLevel::Critical, failure.what(), context);
259 diag.emplace_back(DiagLevel::Information,
"Applying new tag information has been aborted.", context);
264 if (!backupPath.empty()) {
266 diag.emplace_back(DiagLevel::Critical,
"Rewriting the file to apply changed tag information failed.", context);
269 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
270 }
catch (
const std::ios_base::failure &failure) {
271 diag.emplace_back(DiagLevel::Critical, failure.what(), context);
274 diag.emplace_back(DiagLevel::Critical,
"Applying new tag information failed.", context);
278 }
catch (
const std::ios_base::failure &) {
279 if (!backupPath.empty()) {
281 diag.emplace_back(DiagLevel::Critical,
"An IO error occurred when rewriting the file to apply changed tag information.", context);
284 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
285 }
catch (
const std::ios_base::failure &failure) {
286 diag.emplace_back(DiagLevel::Critical, failure.what(), context);
289 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.