4 #include <c++utilities/conversion/stringconversion.h> 5 #include <c++utilities/conversion/stringbuilder.h> 6 #include <c++utilities/io/catchiofailure.h> 8 #ifdef PLATFORM_WINDOWS 11 # include <sys/stat.h> 33 namespace BackupHelper {
45 static string backupDir;
70 if(originalStream.is_open()) {
71 originalStream.close();
74 backupStream.exceptions(ios_base::goodbit);
77 backupStream.open(backupPath, ios_base::in | ios_base::binary);
78 if(backupStream.is_open()) {
81 throwIoFailure(
"Backup/temporary file has not been created.");
84 std::remove(originalPath.c_str());
85 if(std::rename(backupPath.c_str(), originalPath.c_str())) {
89 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
90 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
91 backupStream.open(backupPath, ios_base::in | ios_base::binary);
92 originalStream.open(originalPath, ios_base::out | ios_base::binary);
93 originalStream << backupStream.rdbuf();
97 throwIoFailure((
"Unable to restore original file from backup file \"" % backupPath +
"\" after failure.").data());
105 static bool isRelative(
const std::string &path)
107 return path.empty() || (path.front() !=
'/' && (path.size() < 2 || path[1] !=
':'));
133 void createBackupFile(
const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
137 const auto backupDirRelative(isRelative(backupDir));
138 const auto originalDir(backupDirRelative ? BasicFileInfo::containingDirectory(originalPath) :
string());
141 for(
unsigned int i = 0; ; ++i) {
142 if(backupDir.empty()) {
144 backupPath = originalPath %
'.' % i +
".bak";
146 backupPath = originalPath +
".bak";
149 const auto fileName(BasicFileInfo::fileName(originalPath, i));
151 const auto ext(BasicFileInfo::extension(originalPath));
152 if(backupDirRelative) {
153 backupPath = originalDir %
'/' % backupDir %
'/' % fileName %
'.' % i + ext;
155 backupPath = backupDir %
'/' % fileName %
'.' % i + ext;
158 if(backupDirRelative) {
159 backupPath = originalDir %
'/' % backupDir %
'/' + fileName;
161 backupPath = backupDir %
'/' + fileName;
168 #ifdef PLATFORM_WINDOWS 169 if(GetFileAttributes(backupPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
171 struct stat backupStat;
172 if(stat(backupPath.c_str(), &backupStat)) {
179 if(originalStream.is_open()) {
180 originalStream.close();
184 if(std::rename(originalPath.c_str(), backupPath.c_str())) {
187 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
188 originalStream.exceptions(ios_base::failbit | ios_base::badbit);
190 if(backupStream.is_open()) {
191 backupStream.close();
193 backupStream.open(backupPath, ios_base::out | ios_base::binary);
195 originalStream.open(originalPath, ios_base::in | ios_base::binary);
197 backupStream << originalStream.rdbuf();
202 throwIoFailure(
"Unable to rename original file before rewriting it.");
209 if(originalStream.is_open()) {
210 originalStream.close();
213 if(backupStream.is_open()) {
214 backupStream.close();
217 backupStream.exceptions(ios_base::failbit | ios_base::badbit);
218 backupStream.open(backupPath, ios_base::in | ios_base::binary);
223 if(std::rename(backupPath.c_str(), originalPath.c_str())) {
224 throwIoFailure((
"Unable to restore original file from backup file \"" % backupPath +
"\" after failure.").data());
226 throwIoFailure(
"Unable to open backup file.");
260 if(!backupPath.empty()) {
262 fileInfo.
addNotification(NotificationType::Information,
"Rewriting the file to apply changed tag information has been aborted.", context);
265 fileInfo.
addNotification(NotificationType::Information,
"The original file has been restored.", context);
267 fileInfo.
addNotification(NotificationType::Critical, catchIoFailure(), context);
270 fileInfo.
addNotification(NotificationType::Information,
"Applying new tag information has been aborted.", context);
275 if(!backupPath.empty()) {
277 fileInfo.
addNotification(NotificationType::Critical,
"Rewriting the file to apply changed tag information failed.", context);
280 fileInfo.
addNotification(NotificationType::Information,
"The original file has been restored.", context);
282 fileInfo.
addNotification(NotificationType::Critical, catchIoFailure(), context);
285 fileInfo.
addNotification(NotificationType::Critical,
"Applying new tag information failed.", context);
290 const char *what = catchIoFailure();
291 if(!backupPath.empty()) {
293 fileInfo.
addNotification(NotificationType::Critical,
"An IO error occured when rewriting the file to apply changed tag information.", context);
296 fileInfo.
addNotification(NotificationType::Information,
"The original file has been restored.", context);
298 fileInfo.
addNotification(NotificationType::Critical, catchIoFailure(), context);
301 fileInfo.
addNotification(NotificationType::Critical,
"An IO error occured when applying tag information.", context);
303 throwIoFailure(what);
Contains utility classes helping to read and write streams.