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 34 namespace BackupHelper {
46 static string backupDir;
69 const std::string &originalPath,
const std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
72 if (originalStream.is_open()) {
73 originalStream.close();
76 backupStream.exceptions(ios_base::goodbit);
79 backupStream.open(backupPath, ios_base::in | ios_base::binary);
80 if (backupStream.is_open()) {
83 throwIoFailure(
"Backup/temporary file has not been created.");
86 std::remove(originalPath.c_str());
87 if (std::rename(backupPath.c_str(), originalPath.c_str())) {
91 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
92 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
93 backupStream.open(backupPath, ios_base::in | ios_base::binary);
94 originalStream.open(originalPath, ios_base::out | ios_base::binary);
95 originalStream << backupStream.rdbuf();
99 throwIoFailure((
"Unable to restore original file from backup file \"" % backupPath +
"\" after failure.").data());
107 static bool isRelative(
const std::string &path)
109 return path.empty() || (path.front() !=
'/' && (path.size() < 2 || path[1] !=
':'));
135 void createBackupFile(
const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
139 const auto backupDirRelative(isRelative(backupDir));
140 const auto originalDir(backupDirRelative ? BasicFileInfo::containingDirectory(originalPath) :
string());
143 for (
unsigned int i = 0;; ++i) {
144 if (backupDir.empty()) {
146 backupPath = originalPath %
'.' % i +
".bak";
148 backupPath = originalPath +
".bak";
151 const auto fileName(BasicFileInfo::fileName(originalPath, i));
153 const auto ext(BasicFileInfo::extension(originalPath));
154 if (backupDirRelative) {
155 backupPath = originalDir %
'/' % backupDir %
'/' % fileName %
'.' % i + ext;
157 backupPath = backupDir %
'/' % fileName %
'.' % i + ext;
160 if (backupDirRelative) {
161 backupPath = originalDir %
'/' % backupDir %
'/' + fileName;
163 backupPath = backupDir %
'/' + fileName;
169 #ifdef PLATFORM_WINDOWS 170 if (GetFileAttributes(backupPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
172 struct stat backupStat;
173 if (stat(backupPath.c_str(), &backupStat)) {
180 if (originalStream.is_open()) {
181 originalStream.close();
185 if (std::rename(originalPath.c_str(), backupPath.c_str())) {
188 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
189 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
191 if (backupStream.is_open()) {
192 backupStream.close();
194 backupStream.open(backupPath, ios_base::out | ios_base::binary);
196 originalStream.open(originalPath, ios_base::in | ios_base::binary);
198 backupStream << originalStream.rdbuf();
203 throwIoFailure(
"Unable to rename original file before rewriting it.");
210 if (originalStream.is_open()) {
211 originalStream.close();
214 if (backupStream.is_open()) {
215 backupStream.close();
218 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
219 backupStream.open(backupPath, ios_base::in | ios_base::binary);
224 if (std::rename(backupPath.c_str(), originalPath.c_str())) {
225 throwIoFailure((
"Unable to restore original file from backup file \"" % backupPath +
"\" after failure.").data());
227 throwIoFailure(
"Unable to open backup file.");
251 NativeFileStream &backupStream,
Diagnostics &diag,
const std::string &context)
262 if (!backupPath.empty()) {
264 diag.emplace_back(DiagLevel::Information,
"Rewriting the file to apply changed tag information has been aborted.", context);
267 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
269 diag.emplace_back(DiagLevel::Critical, catchIoFailure(), context);
272 diag.emplace_back(DiagLevel::Information,
"Applying new tag information has been aborted.", context);
277 if (!backupPath.empty()) {
279 diag.emplace_back(DiagLevel::Critical,
"Rewriting the file to apply changed tag information failed.", context);
282 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
284 diag.emplace_back(DiagLevel::Critical, catchIoFailure(), context);
287 diag.emplace_back(DiagLevel::Critical,
"Applying new tag information failed.", context);
292 const char *what = catchIoFailure();
293 if (!backupPath.empty()) {
295 diag.emplace_back(DiagLevel::Critical,
"An IO error occured when rewriting the file to apply changed tag information.", context);
298 diag.emplace_back(DiagLevel::Information,
"The original file has been restored.", context);
300 diag.emplace_back(DiagLevel::Critical, catchIoFailure(), context);
303 diag.emplace_back(DiagLevel::Critical,
"An IO error occured when applying tag information.", context);
305 throwIoFailure(what);
const std::string & path() const
Returns the path of the current file.
void createBackupFile(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.
TAG_PARSER_EXPORT std::string & backupDirectory()
Returns the directory used to store backup files.
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 occured 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.