prepare for new backup system

This commit is contained in:
tildearrow 2023-04-06 04:22:43 -05:00
parent 72b81914b7
commit 79a317723a
4 changed files with 115 additions and 21 deletions

View file

@ -21,10 +21,12 @@
#ifdef _WIN32 #ifdef _WIN32
#include "utfutils.h" #include "utfutils.h"
#include <windows.h> #include <windows.h>
#include <shlobj.h>
#include <shlwapi.h> #include <shlwapi.h>
#else #else
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h>
#endif #endif
FILE* ps_fopen(const char* path, const char* mode) { FILE* ps_fopen(const char* path, const char* mode) {
@ -79,3 +81,22 @@ int fileExists(const char* path) {
return -1; return -1;
#endif #endif
} }
bool dirExists(const char* what) {
#ifdef _WIN32
WString ws=utf8To16(what);
return (PathIsDirectoryW(ws.c_str())!=FALSE);
#else
struct stat st;
if (stat(what,&st)<0) return false;
return (st.st_mode&S_IFDIR);
#endif
}
bool makeDir(const char* path) {
#ifdef _WIN32
return (SHCreateDirectory(NULL,utf8To16(path).c_str())!=ERROR_SUCCESS);
#else
return (mkdir(path,0755)==0);
#endif
}

View file

@ -26,5 +26,7 @@ bool moveFiles(const char* src, const char* dest);
bool deleteFile(const char* path); bool deleteFile(const char* path);
// returns 1 if file exists, 0 if it doesn't and -1 on error. // returns 1 if file exists, 0 if it doesn't and -1 on error.
int fileExists(const char* path); int fileExists(const char* path);
bool dirExists(const char* what);
bool makeDir(const char* path);
#endif #endif

View file

@ -50,13 +50,15 @@
#include <shlwapi.h> #include <shlwapi.h>
#include "../utfutils.h" #include "../utfutils.h"
#define LAYOUT_INI "\\layout.ini" #define LAYOUT_INI "\\layout.ini"
#define BACKUP_FUR "\\backup.fur" #define BACKUPS_DIR "\\backups"
#else #else
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
#include <sys/stat.h> #include <sys/stat.h>
#define LAYOUT_INI "/layout.ini" #define LAYOUT_INI "/layout.ini"
#define BACKUP_FUR "/backup.fur" #define BACKUPS_DIR "/backups"
#endif #endif
#ifdef IS_MOBILE #ifdef IS_MOBILE
@ -1454,15 +1456,8 @@ void FurnaceGUI::keyUp(SDL_Event& ev) {
// nothing for now // nothing for now
} }
bool dirExists(String what) { bool dirExists(String s) {
#ifdef _WIN32 return dirExists(s.c_str());
WString ws=utf8To16(what.c_str());
return (PathIsDirectoryW(ws.c_str())!=FALSE);
#else
struct stat st;
if (stat(what.c_str(),&st)<0) return false;
return (st.st_mode&S_IFDIR);
#endif
} }
void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
@ -2096,7 +2091,7 @@ int FurnaceGUI::load(String path) {
void FurnaceGUI::pushRecentFile(String path) { void FurnaceGUI::pushRecentFile(String path) {
if (path.empty()) return; if (path.empty()) return;
if (path==backupPath) return; if (path.find(backupPath)==0) return;
for (int i=0; i<(int)recentFile.size(); i++) { for (int i=0; i<(int)recentFile.size(); i++) {
if (recentFile[i]==path) { if (recentFile[i]==path) {
recentFile.erase(recentFile.begin()+i); recentFile.erase(recentFile.begin()+i);
@ -2110,6 +2105,35 @@ void FurnaceGUI::pushRecentFile(String path) {
} }
} }
void FurnaceGUI::delFirstBackup(String name) {
std::vector<String> listOfFiles;
#ifdef _WIN32
// TODO: Windows implementation
#else
DIR* backDir=opendir(backupPath.c_str());
if (backDir==NULL) {
logW("could not open backups dir!");
return;
}
while (true) {
struct dirent* next=readdir(backDir);
if (next==NULL) break;
if (strstr(next->d_name,name.c_str())!=next->d_name) continue;
listOfFiles.push_back(String(next->d_name));
}
closedir(backDir);
#endif
std::sort(listOfFiles.begin(),listOfFiles.end(),[](const String& a, const String& b) -> bool {
return strcmp(a.c_str(),b.c_str())<0;
});
logV("prior backups of %s:",name);
for (String& i: listOfFiles) {
logV("- %s",i);
}
}
int FurnaceGUI::loadStream(String path) { int FurnaceGUI::loadStream(String path) {
if (!path.empty()) { if (!path.empty()) {
logI("loading stream..."); logI("loading stream...");
@ -3641,7 +3665,7 @@ bool FurnaceGUI::loop() {
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("save",BIND_FOR(GUI_ACTION_SAVE))) { if (ImGui::MenuItem("save",BIND_FOR(GUI_ACTION_SAVE))) {
if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { if (curFileName=="" || (curFileName.find(backupPath)==0) || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE); openFileDialog(GUI_FILE_SAVE);
} else { } else {
if (save(curFileName,e->song.isDMF?e->song.version:0)>0) { if (save(curFileName,e->song.isDMF?e->song.version:0)>0) {
@ -4909,7 +4933,7 @@ bool FurnaceGUI::loop() {
case GUI_WARN_QUIT: case GUI_WARN_QUIT:
if (ImGui::Button("Yes")) { if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { if (curFileName=="" || curFileName.find(backupPath)==0 || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE); openFileDialog(GUI_FILE_SAVE);
postWarnAction=GUI_WARN_QUIT; postWarnAction=GUI_WARN_QUIT;
} else { } else {
@ -4933,7 +4957,7 @@ bool FurnaceGUI::loop() {
case GUI_WARN_NEW: case GUI_WARN_NEW:
if (ImGui::Button("Yes")) { if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { if (curFileName=="" || curFileName.find(backupPath)==0 || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE); openFileDialog(GUI_FILE_SAVE);
postWarnAction=GUI_WARN_NEW; postWarnAction=GUI_WARN_NEW;
} else { } else {
@ -4957,7 +4981,7 @@ bool FurnaceGUI::loop() {
case GUI_WARN_OPEN: case GUI_WARN_OPEN:
if (ImGui::Button("Yes")) { if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { if (curFileName=="" || curFileName.find(backupPath)==0 || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE); openFileDialog(GUI_FILE_SAVE);
postWarnAction=GUI_WARN_OPEN; postWarnAction=GUI_WARN_OPEN;
} else { } else {
@ -4981,7 +5005,7 @@ bool FurnaceGUI::loop() {
case GUI_WARN_OPEN_BACKUP: case GUI_WARN_OPEN_BACKUP:
if (ImGui::Button("Yes")) { if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { if (curFileName=="" || curFileName.find(backupPath)==0 || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE); openFileDialog(GUI_FILE_SAVE);
postWarnAction=GUI_WARN_OPEN_BACKUP; postWarnAction=GUI_WARN_OPEN_BACKUP;
} else { } else {
@ -5009,7 +5033,7 @@ bool FurnaceGUI::loop() {
case GUI_WARN_OPEN_DROP: case GUI_WARN_OPEN_DROP:
if (ImGui::Button("Yes")) { if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { if (curFileName=="" || curFileName.find(backupPath)==0 || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE); openFileDialog(GUI_FILE_SAVE);
postWarnAction=GUI_WARN_OPEN_DROP; postWarnAction=GUI_WARN_OPEN_DROP;
} else { } else {
@ -5421,16 +5445,59 @@ bool FurnaceGUI::loop() {
backupTimer=(backupTimer-ImGui::GetIO().DeltaTime); backupTimer=(backupTimer-ImGui::GetIO().DeltaTime);
if (backupTimer<=0) { if (backupTimer<=0) {
backupTask=std::async(std::launch::async,[this]() -> bool { backupTask=std::async(std::launch::async,[this]() -> bool {
if (backupPath==curFileName) { // TODO: remember how many backups we have made so we don't flood the directory
if (curFileName.find(backupPath)==0) {
logD("backup file open. not saving backup."); logD("backup file open. not saving backup.");
return true; return true;
} }
if (!dirExists(backupPath.c_str())) {
if (!makeDir(backupPath.c_str())) {
logW("could not create backup directory!");
return false;
}
}
logD("saving backup..."); logD("saving backup...");
SafeWriter* w=e->saveFur(true); SafeWriter* w=e->saveFur(true);
logV("writing file..."); logV("writing file...");
if (w!=NULL) { if (w!=NULL) {
FILE* outFile=ps_fopen(backupPath.c_str(),"wb"); size_t sepPos=curFileName.rfind(DIR_SEPARATOR);
String backupBaseName;
String backupFileName;
if (sepPos==String::npos) {
backupBaseName=curFileName;
} else {
backupBaseName=curFileName.substr(sepPos+1);
}
size_t dotPos=backupBaseName.rfind('.');
if (dotPos!=String::npos) {
backupBaseName=backupBaseName.substr(0,dotPos);
}
backupFileName=backupBaseName;
time_t curTime=time(NULL);
struct tm curTM;
#ifdef _WIN32
struct tm* tempTM=localtime(&curTime);
if (tempTM==NULL) {
backupFileName+="-unknownTime.fur";
} else {
curTM=*tempTM;
backupFileName+=fmt::sprintf("-%d%.2d%.2d-%.2d%.2d%.2d.fur",curTM.tm_year+1900,curTM.tm_mon+1,curTM.tm_mday,curTM.tm_hour,curTM.tm_min,curTM.tm_sec);
}
#else
if (localtime_r(&curTime,&curTM)==NULL) {
backupFileName+="-unknownTime.fur";
} else {
backupFileName+=fmt::sprintf("-%d%.2d%.2d-%.2d%.2d%.2d.fur",curTM.tm_year+1900,curTM.tm_mon+1,curTM.tm_mday,curTM.tm_hour,curTM.tm_min,curTM.tm_sec);
}
#endif
String finalPath=backupPath+String(DIR_SEPARATOR_STR)+backupFileName;
FILE* outFile=ps_fopen(finalPath.c_str(),"wb");
if (outFile!=NULL) { if (outFile!=NULL) {
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) {
logW("did not write backup entirely: %s!",strerror(errno)); logW("did not write backup entirely: %s!",strerror(errno));
@ -5441,6 +5508,9 @@ bool FurnaceGUI::loop() {
logW("could not save backup: %s!",strerror(errno)); logW("could not save backup: %s!",strerror(errno));
w->finish(); w->finish();
} }
// delete previous backup if there are too many
delFirstBackup(backupBaseName);
} }
logD("backup saved."); logD("backup saved.");
backupTimer=30.0; backupTimer=30.0;
@ -5857,7 +5927,7 @@ bool FurnaceGUI::init() {
} }
strncpy(finalLayoutPath,(e->getConfigPath()+String(LAYOUT_INI)).c_str(),4095); strncpy(finalLayoutPath,(e->getConfigPath()+String(LAYOUT_INI)).c_str(),4095);
backupPath=e->getConfigPath()+String(BACKUP_FUR); backupPath=e->getConfigPath()+String(BACKUPS_DIR);
prepareLayout(); prepareLayout();
ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_DockingEnable; ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_DockingEnable;

View file

@ -2079,6 +2079,7 @@ class FurnaceGUI {
int loadStream(String path); int loadStream(String path);
void pushRecentFile(String path); void pushRecentFile(String path);
void exportAudio(String path, DivAudioExportModes mode); void exportAudio(String path, DivAudioExportModes mode);
void delFirstBackup(String name);
bool parseSysEx(unsigned char* data, size_t len); bool parseSysEx(unsigned char* data, size_t len);