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.