Clean backup helper code
This commit is contained in:
parent
6a62ef7fc2
commit
25d164a5ae
|
@ -27,7 +27,7 @@ namespace Media {
|
||||||
* \brief Helps to create and restore backup files when rewriting
|
* \brief Helps to create and restore backup files when rewriting
|
||||||
* files to apply changed tag information.
|
* files to apply changed tag information.
|
||||||
*
|
*
|
||||||
* Methods in this namespace are internally used eg. in implementations of AbstractContainer::internalMake().
|
* Methods in this namespace are internally used eg. in implementations of AbstractContainer::internalMakeFile().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace BackupHelper {
|
namespace BackupHelper {
|
||||||
|
@ -37,6 +37,8 @@ namespace BackupHelper {
|
||||||
*
|
*
|
||||||
* Setting this value allows creation of backup files in a custom location
|
* Setting this value allows creation of backup files in a custom location
|
||||||
* instead of the directory of the file being modified.
|
* instead of the directory of the file being modified.
|
||||||
|
*
|
||||||
|
* \todo Add this as member variable to MediaFileInfo to avoid global.
|
||||||
*/
|
*/
|
||||||
string &backupDirectory()
|
string &backupDirectory()
|
||||||
{
|
{
|
||||||
|
@ -80,9 +82,9 @@ void restoreOriginalFileFromBackupFile(const std::string &originalPath, const st
|
||||||
}
|
}
|
||||||
// remove original file and restore backup
|
// remove original file and restore backup
|
||||||
std::remove(originalPath.c_str());
|
std::remove(originalPath.c_str());
|
||||||
if(std::rename(backupPath.c_str(), originalPath.c_str()) != 0) { // restore backup
|
if(std::rename(backupPath.c_str(), originalPath.c_str())) {
|
||||||
// unable to move the file
|
// can't rename/move the file (maybe backup dir on another partition) -> make a copy instead
|
||||||
try { // to copy
|
try {
|
||||||
// need to open all streams again
|
// need to open all streams again
|
||||||
backupStream.exceptions(ios_base::failbit | ios_base::badbit);
|
backupStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
originalStream.exceptions(ios_base::failbit | ios_base::badbit);
|
originalStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
|
@ -97,6 +99,14 @@ void restoreOriginalFileFromBackupFile(const std::string &originalPath, const st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the specified \a path is relative.
|
||||||
|
*/
|
||||||
|
static bool isRelative(const std::string &path)
|
||||||
|
{
|
||||||
|
return path.empty() || (path.front() != '/' && (path.size() < 2 || path[1] != ':'));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Creates a backup file for the specified file.
|
* \brief Creates a backup file for the specified file.
|
||||||
* \param originalPath Specifies the path of the file to be backuped.
|
* \param originalPath Specifies the path of the file to be backuped.
|
||||||
|
@ -122,11 +132,12 @@ void restoreOriginalFileFromBackupFile(const std::string &originalPath, const st
|
||||||
*/
|
*/
|
||||||
void createBackupFile(const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
|
void createBackupFile(const std::string &originalPath, std::string &backupPath, NativeFileStream &originalStream, NativeFileStream &backupStream)
|
||||||
{
|
{
|
||||||
|
// determine dirs
|
||||||
|
const auto &backupDir(backupDirectory());
|
||||||
|
const auto backupDirRelative(isRelative(backupDir));
|
||||||
|
const auto originalDir(backupDirRelative ? BasicFileInfo::containingDirectory(originalPath) : string());
|
||||||
|
|
||||||
// determine the backup path
|
// determine the backup path
|
||||||
const string &backupDir = backupDirectory();
|
|
||||||
#ifndef PLATFORM_WINDOWS
|
|
||||||
struct stat backupStat;
|
|
||||||
#endif
|
|
||||||
for(unsigned int i = 0; ; ++i) {
|
for(unsigned int i = 0; ; ++i) {
|
||||||
if(backupDir.empty()) {
|
if(backupDir.empty()) {
|
||||||
if(i) {
|
if(i) {
|
||||||
|
@ -135,63 +146,44 @@ void createBackupFile(const std::string &originalPath, std::string &backupPath,
|
||||||
backupPath = originalPath + ".bak";
|
backupPath = originalPath + ".bak";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const string fileName = BasicFileInfo::fileName(originalPath, i);
|
const auto fileName(BasicFileInfo::fileName(originalPath, i));
|
||||||
if(i) {
|
if(i) {
|
||||||
const string ext = BasicFileInfo::extension(originalPath);
|
const auto ext(BasicFileInfo::extension(originalPath));
|
||||||
if(backupDir.at(0) != '/' && (backupDir.size() < 2 || backupDir.at(1) != ':')) {
|
if(backupDirRelative) {
|
||||||
// backupDir is a relative path
|
backupPath = originalDir % '/' % backupDir % '/' % fileName % '.' % i + ext;
|
||||||
backupPath = BasicFileInfo::containingDirectory(originalPath);
|
|
||||||
backupPath += '/';
|
|
||||||
backupPath += backupDir;
|
|
||||||
backupPath += '/';
|
|
||||||
backupPath += fileName;
|
|
||||||
backupPath += '.';
|
|
||||||
backupPath += numberToString(i);
|
|
||||||
backupPath += ext;
|
|
||||||
} else {
|
} else {
|
||||||
// backupDir is an absolute path
|
backupPath = backupDir % '/' % fileName % '.' % i + ext;
|
||||||
backupPath = backupDir;
|
|
||||||
backupPath += '/';
|
|
||||||
backupPath += fileName;
|
|
||||||
backupPath += '.';
|
|
||||||
backupPath += numberToString(i);
|
|
||||||
backupPath += ext;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(backupDir.at(0) != '/' && (backupDir.size() < 2 || backupDir.at(1) != ':')) {
|
if(backupDirRelative) {
|
||||||
// backupDir is a relative path
|
backupPath = originalDir % '/' % backupDir % '/' + fileName;
|
||||||
backupPath = BasicFileInfo::containingDirectory(originalPath);
|
|
||||||
backupPath += '/';
|
|
||||||
backupPath += backupDir;
|
|
||||||
backupPath += '/';
|
|
||||||
backupPath += fileName;
|
|
||||||
} else {
|
} else {
|
||||||
// backupDir is an absolute path
|
backupPath = backupDir % '/' + fileName;
|
||||||
backupPath = backupDir;
|
|
||||||
backupPath += '/';
|
|
||||||
backupPath += fileName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// test whether the backup file already exists
|
|
||||||
|
// test whether the backup path is still unused; otherwise continue loop
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
if(GetFileAttributes(backupPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
if(GetFileAttributes(backupPath.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||||
#else
|
#else
|
||||||
|
struct stat backupStat;
|
||||||
if(stat(backupPath.c_str(), &backupStat)) {
|
if(stat(backupPath.c_str(), &backupStat)) {
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
} // else: the backup file already exists -> find another file name
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure original file is closed
|
// ensure original file is closed
|
||||||
if(originalStream.is_open()) {
|
if(originalStream.is_open()) {
|
||||||
originalStream.close();
|
originalStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// rename original file
|
// rename original file
|
||||||
if(std::rename(originalPath.c_str(), backupPath.c_str()) != 0) {
|
if(std::rename(originalPath.c_str(), backupPath.c_str())) {
|
||||||
// can't rename/move the file
|
// can't rename/move the file (maybe backup dir on another partition) -> make a copy instead
|
||||||
try { // to copy
|
try {
|
||||||
backupStream.exceptions(ios_base::failbit | ios_base::badbit);
|
backupStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
originalStream.exceptions(ios_base::failbit | ios_base::badbit);
|
originalStream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
// ensure backupStream is opened as write-only
|
// ensure backupStream is opened as write-only
|
||||||
|
@ -210,8 +202,10 @@ void createBackupFile(const std::string &originalPath, std::string &backupPath,
|
||||||
throwIoFailure("Unable to rename original file before rewriting it.");
|
throwIoFailure("Unable to rename original file before rewriting it.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manage streams
|
||||||
try {
|
try {
|
||||||
// ensure there is not file associated with the originalStream object
|
// ensure there is no file associated with the originalStream object
|
||||||
if(originalStream.is_open()) {
|
if(originalStream.is_open()) {
|
||||||
originalStream.close();
|
originalStream.close();
|
||||||
}
|
}
|
||||||
|
@ -226,7 +220,7 @@ void createBackupFile(const std::string &originalPath, std::string &backupPath,
|
||||||
catchIoFailure();
|
catchIoFailure();
|
||||||
// can't open the new file
|
// can't open the new file
|
||||||
// -> try to re-rename backup file in the error case to restore previous state
|
// -> try to re-rename backup file in the error case to restore previous state
|
||||||
if(std::rename(backupPath.c_str(), originalPath.c_str()) != 0) {
|
if(std::rename(backupPath.c_str(), originalPath.c_str())) {
|
||||||
throwIoFailure(("Unable to restore original file from backup file \"" % backupPath + "\" after failure.").data());
|
throwIoFailure(("Unable to restore original file from backup file \"" % backupPath + "\" after failure.").data());
|
||||||
} else {
|
} else {
|
||||||
throwIoFailure("Unable to open backup file.");
|
throwIoFailure("Unable to open backup file.");
|
||||||
|
|
Loading…
Reference in New Issue