5 #include <c++utilities/conversion/stringbuilder.h> 6 #include <c++utilities/conversion/stringconversion.h> 7 #include <c++utilities/io/catchiofailure.h> 9 #ifdef PLATFORM_WINDOWS 21 using namespace ConversionUtilities;
34 namespace BackupHelper {
55 const std::string &originalPath,
const std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
58 if (originalStream.is_open()) {
59 originalStream.close();
62 backupStream.exceptions(ios_base::goodbit);
65 backupStream.open(backupPath, ios_base::in | ios_base::binary);
66 if (backupStream.is_open()) {
69 throwIoFailure(
"Backup/temporary file has not been created.");
72 std::remove(originalPath.c_str());
73 if (std::rename(backupPath.c_str(), originalPath.c_str())) {
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();
85 throwIoFailure((
"Unable to restore original file from backup file \"" % backupPath +
"\" after failure.").data());
93 static bool isRelative(
const std::string &path)
95 return path.empty() || (path.front() !=
'/' && (path.size() < 2 || path[1] !=
':'));
123 void createBackupFile(
const std::string &backupDir,
const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream,
124 NativeFileStream &backupStream)
127 const auto backupDirRelative(isRelative(backupDir));
128 const auto originalDir(backupDirRelative ? BasicFileInfo::containingDirectory(originalPath) :
string());
131 for (
unsigned int i = 0;; ++i) {
132 if (backupDir.empty()) {
134 backupPath = originalPath %
'.' % i +
".bak";
136 backupPath = originalPath +
".bak";
139 const auto fileName(BasicFileInfo::fileName(originalPath, i));
141 const auto ext(BasicFileInfo::extension(originalPath));
142 if (backupDirRelative) {
143 backupPath = originalDir %
'/' % backupDir %
'/' % fileName %
'.' % i + ext;
145 backupPath = backupDir %
'/' % fileName %
'.' % i + ext;
148 if (backupDirRelative) {
149 backupPath = originalDir %
'/' % backupDir %
'/' + fileName;
151 backupPath = backupDir %
'/' + fileName;
157 #ifdef PLATFORM_WINDOWS 158 if (GetFileAttributes(backupPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
160 struct stat backupStat;
161 if (stat(backupPath.c_str(), &backupStat)) {
168 if (originalStream.is_open()) {
169 originalStream.close();
173 if (std::rename(originalPath.c_str(), backupPath.c_str())) {
176 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
177 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
179 if (backupStream.is_open()) {
180 backupStream.close();
182 backupStream.open(backupPath, ios_base::out | ios_base::binary);
184 originalStream.open(originalPath, ios_base::in | ios_base::binary);
186 backupStream << originalStream.rdbuf();
191 throwIoFailure(
"Unable to rename original file before rewriting it.");
198 if (originalStream.is_open()) {
199 originalStream.close();
202 if (backupStream.is_open()) {
203 backupStream.close();
206 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
207 backupStream.open(backupPath, ios_base::in | ios_base::binary);
212 if (std::rename(backupPath.c_str(), originalPath.c_str())) {
213 throwIoFailure((
"Unable to restore original file from backup file \"" % backupPath +
"\" after failure.").data());
215 throwIoFailure(
"Unable to open backup file.");
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::Information,
"The original file has been restored.", context);
258 diag.emplace_back(DiagLevel::Critical, catchIoFailure(), 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::Information,
"The original file has been restored.", context);
273 diag.emplace_back(DiagLevel::Critical, catchIoFailure(), context);
276 diag.emplace_back(DiagLevel::Critical,
"Applying new tag information failed.", context);
281 const char *what = catchIoFailure();
282 if (!backupPath.empty()) {
284 diag.emplace_back(DiagLevel::Critical,
"An IO error occurred when rewriting the file to apply changed tag information.", context);
287 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
289 diag.emplace_back(DiagLevel::Critical, catchIoFailure(), context);
292 diag.emplace_back(DiagLevel::Critical,
"An IO error occurred when applying tag information.", context);
294 throwIoFailure(what);
const std::string & path() const
Returns the path of the current file.
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.
virtual void reset()
Discards all parsing results.
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 utility classes helping to read and write streams.
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...
Contains all classes and functions of the TagInfo library.
The Diagnostics class is a container for DiagMessage.