5#include <c++utilities/conversion/stringbuilder.h>
6#include <c++utilities/conversion/stringconversion.h>
7#include <c++utilities/io/path.h>
28namespace BackupHelper {
49 const std::string &originalPath,
const std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
52 originalStream.exceptions(ios_base::goodbit);
53 backupStream.exceptions(ios_base::goodbit);
54 originalStream.close();
56 originalStream.clear();
60 originalStream.exceptions(ios_base::badbit | ios_base::failbit);
61 backupStream.exceptions(ios_base::badbit | ios_base::failbit);
66 auto ec = std::error_code();
67 if (!std::filesystem::exists(backupPathForOpen, ec) && !ec) {
68 throw std::ios_base::failure(
"Backup/temporary file has not been created.");
72 std::filesystem::remove(originalPathForOpen, ec);
74 throw std::ios_base::failure(
"Unable to remove original file: " + ec.message());
76 std::filesystem::rename(backupPathForOpen, originalPathForOpen, ec);
79 std::filesystem::copy_file(backupPathForOpen, originalPathForOpen, ec);
82 throw std::ios_base::failure(
"Unable to restore original file from backup file \"" % backupPath %
"\" after failure: " + ec.message());
111void createBackupFile(
const std::string &backupDir,
const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream,
112 NativeFileStream &backupStream)
115 const auto backupDirRelative = std::filesystem::path(makeNativePath(backupDir)).is_relative();
119 auto ec = std::error_code();
120 for (
unsigned int i = 0;; ++i) {
121 if (backupDir.empty()) {
123 backupPath = originalPath %
'.' % i +
".bak";
125 backupPath = originalPath +
".bak";
131 if (backupDirRelative) {
132 backupPath = originalDir %
'/' % backupDir %
'/' % fileName %
'.' % i + ext;
134 backupPath = backupDir %
'/' % fileName %
'.' % i + ext;
137 if (backupDirRelative) {
138 backupPath = originalDir %
'/' % backupDir %
'/' + fileName;
140 backupPath = backupDir %
'/' + fileName;
152 if (originalStream.is_open()) {
153 originalStream.close();
157 const auto u8originalPath = std::filesystem::path(makeNativePath(originalPath));
159 std::filesystem::rename(u8originalPath, backupPathForOpen, ec);
162 std::filesystem::copy_file(u8originalPath, backupPathForOpen, ec);
165 throw std::ios_base::failure(argsToString(
"Unable to create backup file \"",
BasicFileInfo::pathForOpen(backupPath),
"\" of \"", originalPath,
166 "\" before rewriting it: " + ec.message()));
172 if (originalStream.is_open()) {
173 originalStream.close();
176 if (backupStream.is_open()) {
177 backupStream.close();
180 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
182 }
catch (
const std::ios_base::failure &failure) {
186 }
catch (
const std::ios_base::failure &) {
187 throw std::ios_base::failure(
"Unable to restore original file from backup file \"" % backupPath %
"\" after failure: " + failure.what());
189 throw std::ios_base::failure(argsToString(
"Unable to open backup file: ", failure.what()));
200 CppUtilities::NativeFileStream &originalStream, CppUtilities::NativeFileStream &backupStream)
202 auto ec = std::error_code();
203 if (
const auto canonicalPath = std::filesystem::canonical(makeNativePath(
BasicFileInfo::pathForOpen(originalPath)), ec); !ec) {
204 originalPath = canonicalPath.string();
206 throw std::ios_base::failure(
"Unable to canonicalize path of original file before rewriting it: " + ec.message());
208 createBackupFile(backupDir, originalPath, backupPath, originalStream, backupStream);
231 NativeFileStream &backupStream,
Diagnostics &diag,
const std::string &context)
242 CppUtilities::NativeFileStream &outputStream, CppUtilities::NativeFileStream &backupStream,
Diagnostics &diag,
const std::string &context)
253 if (!backupPath.empty()) {
255 diag.emplace_back(
DiagLevel::Information,
"Rewriting the file to apply changed tag information has been aborted.", context);
258 diag.emplace_back(
DiagLevel::Warning,
"The original file has been restored.", context);
259 }
catch (
const std::ios_base::failure &failure) {
260 diag.emplace_back(
DiagLevel::Critical, argsToString(
"The original file could not be restored: ", failure.what()), context);
268 if (!backupPath.empty()) {
270 diag.emplace_back(
DiagLevel::Critical,
"Rewriting the file to apply changed tag information failed.", context);
273 diag.emplace_back(
DiagLevel::Warning,
"The original file has been restored.", context);
274 }
catch (
const std::ios_base::failure &failure) {
275 diag.emplace_back(
DiagLevel::Critical, argsToString(
"The original file could not be restored: ", failure.what()), context);
282 }
catch (
const std::ios_base::failure &) {
283 if (!backupPath.empty()) {
285 diag.emplace_back(
DiagLevel::Critical,
"An IO error occurred when rewriting the file to apply changed tag information.", context);
288 diag.emplace_back(
DiagLevel::Warning,
"The original file has been restored.", context);
289 }
catch (
const std::ios_base::failure &failure) {
290 diag.emplace_back(
DiagLevel::Critical, argsToString(
"The original file could not be restored: ", failure.what()), context);
293 diag.emplace_back(
DiagLevel::Critical,
"An IO error occurred when applying tag information.", context);
virtual void reset()
Discards all parsing results.
std::string containingDirectory() const
Returns the path of the directory containing the current file.
static std::string fileName(std::string_view path, bool cutExtension=false)
Returns the file name of the given file.
const std::string & path() const
Returns the path of the current file.
static std::string_view pathForOpen(std::string_view url)
Returns removes the "file:/" prefix from url to be able to pass it to functions like open(),...
std::string extension() const
Returns the extension 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...
TAG_PARSER_EXPORT void createBackupFile(const std::string &backupDir, const std::string &originalPath, std::string &backupPath, CppUtilities::NativeFileStream &originalStream, CppUtilities::NativeFileStream &backupStream)
TAG_PARSER_EXPORT void handleFailureAfterFileModifiedCanonical(MediaFileInfo &fileInfo, const std::string &originalPath, const std::string &backupPath, CppUtilities::NativeFileStream &outputStream, CppUtilities::NativeFileStream &backupStream, Diagnostics &diag, const std::string &context="making file")
Handles a failure/abort which occurred after the file has been modified.
TAG_PARSER_EXPORT void restoreOriginalFileFromBackupFile(const std::string &originalPath, const std::string &backupPath, CppUtilities::NativeFileStream &originalStream, CppUtilities::NativeFileStream &backupStream)
TAG_PARSER_EXPORT void createBackupFileCanonical(const std::string &backupDir, std::string &originalPath, std::string &backupPath, CppUtilities::NativeFileStream &originalStream, CppUtilities::NativeFileStream &backupStream)
Creates a backup file like createBackupFile() but canonicalizes originalPath before doing the backup.
TAG_PARSER_EXPORT void handleFailureAfterFileModified(MediaFileInfo &fileInfo, const std::string &backupPath, CppUtilities::NativeFileStream &outputStream, CppUtilities::NativeFileStream &backupStream, Diagnostics &diag, const std::string &context="making file")
Contains all classes and functions of the TagInfo library.