diff --git a/Makefile b/Makefile index 694bb29..d996382 100644 --- a/Makefile +++ b/Makefile @@ -32,13 +32,13 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- TARGET := JKSV BUILD := build -SOURCES := src src/ui +SOURCES := src src/ui src/fs DATA := data -INCLUDES := inc inc/ui +INCLUDES := inc inc/ui inc/fs EXEFS_SRC := exefs_src APP_TITLE := JKSV APP_AUTHOR := JK -APP_VERSION := 09.01.2021 +APP_VERSION := 10.12.2021 ROMFS := romfs ICON := icon.jpg diff --git a/inc/data.h b/inc/data.h index 3f2c990..fb8ff7b 100644 --- a/inc/data.h +++ b/inc/data.h @@ -7,8 +7,8 @@ #include "gfx.h" -#define BLD_MON 9 -#define BLD_DAY 1 +#define BLD_MON 10 +#define BLD_DAY 12 #define BLD_YEAR 2021 namespace data diff --git a/inc/file.h b/inc/file.h deleted file mode 100644 index f8a5d94..0000000 --- a/inc/file.h +++ /dev/null @@ -1,186 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "fsfile.h" -#include "fsthrd.h" -#include "data.h" -#include "miscui.h" - -#define BUFF_SIZE 0xC0000 - -namespace fs -{ - void init(); - void exit(); - - //Mounts usr's save data for open. Returns false it fails - bool mountSave(const FsSaveDataInfo& _m); - inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; } - bool commitToDevice(const std::string& dev); - void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _userID); - - void copyFile(const std::string& from, const std::string& to); - void copyFileCommit(const std::string& from, const std::string& to, const std::string& dev); - - //Recursively copies 'from' to 'to' - void copyDirToDir(const std::string& from, const std::string& to); - - //Copies from to zipFile to - void copyDirToZip(const std::string& from, zipFile to); - - //Same as above, but commits data to 'dev' after every file is closed - void copyDirToDirCommit(const std::string& from, const std::string& to, const std::string& dev); - - //Copies unzfile to 'to' - void copyZipToDir(unzFile unz, const std::string& to, const std::string& dev); - - bool dirNotEmpty(const std::string& _dir); - bool zipNotEmpty(unzFile unzip); - - void mkDir(const std::string& _p); - void mkDirRec(const std::string& _p); - //deletes file - void delfile(const std::string& path); - //Recursively deletes 'path' - void delDir(const std::string& path); - - //Loads paths to filter from backup/deletion - void loadPathFilters(const uint64_t& tid); - bool pathIsFiltered(const std::string& _path); - void freePathFilters(); - - void wipeSave(); - - //Dumps all titles for current user - void dumpAllUserSaves(); - - void getShowFileProps(const std::string& _path); - void getShowDirProps(const std::string& _path); - - bool fileExists(const std::string& _path); - //Returns file size - size_t fsize(const std::string& _f); - bool isDir(const std::string& _path); - - std::string getWorkDir(); - void setWorkDir(const std::string& _w); - - class dirItem - { - public: - dirItem(const std::string& pathTo, const std::string& sItem); - std::string getItm() const { return itm; } - std::string getName() const; - std::string getExt() const; - bool isDir() const { return dir; } - - private: - std::string itm; - bool dir = false; - }; - - //Just retrieves a listing for _path and stores it in item vector - class dirList - { - public: - dirList() = default; - dirList(const std::string& _path); - void reassign(const std::string& _path); - void rescan(); - - std::string getItem(int index) const { return item[index].getItm(); } - std::string getItemExt(int index) const { return item[index].getExt(); } - bool isDir(int index) const { return item[index].isDir(); } - unsigned getCount() const { return item.size(); } - - private: - DIR *d; - struct dirent *ent; - std::string path; - std::vector item; - }; - - class dataFile - { - public: - dataFile(const std::string& _path); - ~dataFile(); - void close(){ fclose(f); } - - bool isOpen() const { return opened; } - - bool readNextLine(bool proc); - //Finds where variable name ends. When a '(' or '=' is hit. Strips spaces - void procLine(); - std::string getLine() const { return line; } - std::string getName() const { return name; } - //Reads until ';', ',', or '\n' is hit and returns as string. - std::string getNextValueStr(); - int getNextValueInt(); - - private: - FILE *f; - std::string line, name; - size_t lPos = 0; - bool opened = false; - }; - - //Structs to send data to threads - typedef struct - { - ui::menu *m; - fs::dirList *d; - } backupArgs; - - typedef struct - { - std::string to, from, dev; - zipFile z; - unzFile unz; - bool cleanup = false, trimZipPath = false; - uint8_t trimZipPlaces = 0; - uint64_t offset = 0; - ui::progBar *prog; - threadStatus *thrdStatus; - Mutex arglck = 0; - void argLock() { mutexLock(&arglck); } - void argUnlock() { mutexUnlock(&arglck); } - } copyArgs; - - typedef struct - { - FsSaveDataType type; - uint64_t tid; - AccountUid account; - uint16_t index; - } svCreateArgs; - - typedef struct - { - std::string path; - bool origin = false; - unsigned dirCount = 0; - unsigned fileCount = 0; - uint64_t totalSize = 0; - } dirCountArgs; - - copyArgs *copyArgsCreate(const std::string& from, const std::string& to, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces); - void copyArgsDestroy(copyArgs *c); - - //Take a pointer to backupArgs^ - void createNewBackup(void *a); - void overwriteBackup(void *a); - void restoreBackup(void *a); - void deleteBackup(void *a); - - void logOpen(); - void logWrite(const char *fmt, ...); - void logClose(); -} diff --git a/inc/fs.h b/inc/fs.h new file mode 100644 index 0000000..d757e98 --- /dev/null +++ b/inc/fs.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include "fs/fstype.h" +#include "fs/file.h" +#include "fs/dir.h" +#include "fs/zip.h" +#include "fs/fsfile.h" +#include "ui/miscui.h" + +#define BUFF_SIZE 0xC0000 + +namespace fs +{ + copyArgs *copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces); + void copyArgsDestroy(copyArgs *c); + + void init(); + bool mountSave(const FsSaveDataInfo& _m); + inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; } + bool commitToDevice(const std::string& dev); + std::string getWorkDir(); + void setWorkDir(const std::string& _w); + + void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t); + void createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid); + bool extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t); + void extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize); + uint64_t getJournalSize(const data::userTitleInfo *tinfo); + uint64_t getJournalSizeMax(const data::userTitleInfo *tinfo); + + //Always threaded + void wipeSave(); + + void createNewBackup(void *a); + void overwriteBackup(void *a); + void restoreBackup(void *a); + void deleteBackup(void *a); + + void logOpen(); + void logWrite(const char *fmt, ...); +} diff --git a/inc/fs/dir.h b/inc/fs/dir.h new file mode 100644 index 0000000..f817d29 --- /dev/null +++ b/inc/fs/dir.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include "type.h" + +namespace fs +{ + void mkDir(const std::string& _p); + void mkDirRec(const std::string& _p); + void delDir(const std::string& _p); + bool dirNotEmpty(const std::string& _dir); + bool isDir(const std::string& _path); + + //threadInfo is optional + void copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t); + void copyDirToDirThreaded(const std::string& src, const std::string& dst); + void copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t); + void copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev); + void getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize); + + class dirItem + { + public: + dirItem(const std::string& pathTo, const std::string& sItem); + std::string getItm() const { return itm; } + std::string getName() const; + std::string getExt() const; + bool isDir() const { return dir; } + + private: + std::string itm; + bool dir = false; + }; + + //Just retrieves a listing for _path and stores it in item vector + class dirList + { + public: + dirList() = default; + dirList(const std::string& _path); + void reassign(const std::string& _path); + void rescan(); + + std::string getItem(int index) const { return item[index].getItm(); } + std::string getItemExt(int index) const { return item[index].getExt(); } + bool isDir(int index) const { return item[index].isDir(); } + unsigned getCount() const { return item.size(); } + + private: + std::string path; + std::vector item; + }; +} diff --git a/inc/fs/file.h b/inc/fs/file.h new file mode 100644 index 0000000..26acce1 --- /dev/null +++ b/inc/fs/file.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "fs.h" +#include "data.h" +#include "ui.h" + +namespace fs +{ + //Copy args are optional and only used if passed and threaded + void copyFile(const std::string& src, const std::string& dst, threadInfo *t); + void copyFileThreaded(const std::string& src, const std::string& dst); + void copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t); + void copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev); + void fileDrawFunc(void *a); + + //deletes file + void delfile(const std::string& _p); + + //Loads paths to filter from backup/deletion + void loadPathFilters(const uint64_t& tid); + bool pathIsFiltered(const std::string& _path); + void freePathFilters(); + + void wipeSave(); + + //Dumps all titles for current user + void dumpAllUserSaves(); + + void getShowFileProps(const std::string& _path); + void getShowDirProps(const std::string& _path); + + bool fileExists(const std::string& _path); + //Returns file size + size_t fsize(const std::string& _f); + + class dataFile + { + public: + dataFile(const std::string& _path); + ~dataFile(); + void close(){ fclose(f); } + + bool isOpen() const { return opened; } + + bool readNextLine(bool proc); + //Finds where variable name ends. When a '(' or '=' is hit. Strips spaces + void procLine(); + std::string getLine() const { return line; } + std::string getName() const { return name; } + //Reads until ';', ',', or '\n' is hit and returns as string. + std::string getNextValueStr(); + int getNextValueInt(); + + private: + FILE *f; + std::string line, name; + size_t lPos = 0; + bool opened = false; + }; + + //Take a pointer to backupArgs^ + void createNewBackup(void *a); + void overwriteBackup(void *a); + void restoreBackup(void *a); + void deleteBackup(void *a); + + void logOpen(); + void logWrite(const char *fmt, ...); + void logClose(); +} diff --git a/inc/fsfile.h b/inc/fs/fsfile.h similarity index 100% rename from inc/fsfile.h rename to inc/fs/fsfile.h diff --git a/inc/fs/fstype.h b/inc/fs/fstype.h new file mode 100644 index 0000000..f2b7ffb --- /dev/null +++ b/inc/fs/fstype.h @@ -0,0 +1,46 @@ +#pragma once + +#include "data.h" +#include "ui.h" +#include "type.h" + +namespace fs +{ + typedef struct + { + std::string src, dst, dev; + zipFile z; + unzFile unz; + bool cleanup = false, trimZipPath = false; + uint8_t trimZipPlaces = 0; + uint64_t offset = 0; + ui::progBar *prog; + threadStatus *thrdStatus; + Mutex arglck = 0; + void argLock() { mutexLock(&arglck); } + void argUnlock() { mutexUnlock(&arglck); } + } copyArgs; + + typedef struct + { + FsSaveDataType type; + uint64_t tid; + AccountUid account; + uint16_t index; + } svCreateArgs; + + typedef struct + { + const data::userTitleInfo *tinfo; + uint64_t extSize; + } svExtendArgs; + + typedef struct + { + std::string path; + bool origin = false; + unsigned dirCount = 0; + unsigned fileCount = 0; + uint64_t totalSize = 0; + } dirCountArgs; +} diff --git a/inc/fs/zip.h b/inc/fs/zip.h new file mode 100644 index 0000000..4f8afb5 --- /dev/null +++ b/inc/fs/zip.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +#include "type.h" + +namespace fs +{ + //threadInfo is optional and only used when threaded versions are used + void copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t); + void copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces); + void copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t); + void copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev); + uint64_t getZipTotalSize(unzFile unz); + bool zipNotEmpty(unzFile unz); +} diff --git a/inc/fsthrd.h b/inc/fsthrd.h deleted file mode 100644 index fd13a20..0000000 --- a/inc/fsthrd.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -/*Threaded functions for copying files. - file.cpp has wrapper functions for these. - No need to call directly.*/ -namespace fs -{ - void _fileDrawFunc(void *a); - void createSaveData_t(void *a); - void copyFile_t(void *a); - void copyFileCommit_t(void *a); - void copyDirToDir_t(void *a); - void copyDirToDirCommit_t(void *a); - void copyDirToZip_t(void *a); - void copyZipToDir_t(void *a); - void wipesave_t(void *a); - void closeZip_t(void *a); - - void backupUserSaves_t(void *a); - void getShowDirProps_t(void *a); -} diff --git a/inc/ui/miscui.h b/inc/ui/miscui.h index a2ee990..dfcae36 100644 --- a/inc/ui/miscui.h +++ b/inc/ui/miscui.h @@ -28,14 +28,9 @@ namespace ui { std::string text; bool hold; - bool cleanup; - funcPtr func; + funcPtr confFunc, cancelFunc; void *args; - - //Stuff needed to keep track - bool sel = 1;//1 = YES unsigned lgFrame = 0, frameCount = 0;//To count frames cause I don't have time and am lazy - } confirmArgs; typedef struct @@ -160,7 +155,7 @@ namespace ui }; //General use - ui::confirmArgs *confirmArgsCreate(bool _hold, funcPtr _func, void *_funcArgs, bool _cleanup, const char *fmt, ...); + ui::confirmArgs *confirmArgsCreate(bool _hold, funcPtr _confFunc, funcPtr _cancelFunc, void *_funcArgs, const char *fmt, ...); void confirm(void *a); void showMessage(const char *fmt, ...); bool confirmTransfer(const std::string& f, const std::string& t); diff --git a/inc/util.h b/inc/util.h index 5b92bcb..8b4e33c 100644 --- a/inc/util.h +++ b/inc/util.h @@ -54,14 +54,8 @@ namespace util std::string getStringInput(SwkbdType _type, const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]); - inline std::string getExtensionFromString(const std::string& get) - { - size_t ext = get.find_last_of('.'); - if(ext != get.npos) - return get.substr(ext + 1, get.npos); - else - return ""; - } + std::string getExtensionFromString(const std::string& get); + std::string getFilenameFromPath(const std::string& get); std::string generateAbbrev(const uint64_t& tid); diff --git a/src/cfg.cpp b/src/cfg.cpp index aa7ae32..90675f8 100644 --- a/src/cfg.cpp +++ b/src/cfg.cpp @@ -289,6 +289,7 @@ static void loadTitleDefs() void cfg::loadConfig() { + cfg::resetConfig(); loadWorkDirLegacy(); loadConfigLegacy(); loadFavoritesLegacy(); diff --git a/src/data.cpp b/src/data.cpp index 63c22ac..0ea5277 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -452,12 +452,12 @@ void data::dispStats() data::userTitleInfo *d = data::getCurrentUserTitleInfo(); //Easiest/laziest way to do this - std::string stats = ui::getUICString("infoStatus", 4) + std::to_string(users.size()) + "\n"; + std::string stats = ui::getUICString("debugStatus", 0) + std::to_string(users.size()) + "\n"; for(data::user& u : data::users) stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n"; - stats += ui::getUICString("infoStatus", 5) + cu->getUsername() + "\n"; - stats += ui::getUICString("infoStatus", 6) + data::getTitleNameByTID(d->tid) + "\n"; - stats += ui::getUICString("infoStatus", 7) + data::getTitleSafeNameByTID(d->tid) + "\n"; - stats += ui::getUICString("infoStatus", 8) + std::to_string(cfg::sortType) + "\n"; + stats += ui::getUICString("debugStatus", 1) + cu->getUsername() + "\n"; + stats += ui::getUICString("debugStatus", 2) + data::getTitleNameByTID(d->tid) + "\n"; + stats += ui::getUICString("debugStatus", 3) + data::getTitleSafeNameByTID(d->tid) + "\n"; + stats += ui::getUICString("debugStatus", 4) + std::to_string(cfg::sortType) + "\n"; gfx::drawTextf(NULL, 16, 2, 2, &green, stats.c_str()); } diff --git a/src/file.cpp b/src/file.cpp deleted file mode 100644 index 5eaa64a..0000000 --- a/src/file.cpp +++ /dev/null @@ -1,744 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "file.h" -#include "util.h" -#include "ui.h" -#include "gfx.h" -#include "data.h" -#include "cfg.h" - -static std::string wd = "sdmc:/JKSV/"; - -static std::vector pathFilter; - -static FSFILE *debLog; - -static FsFileSystem sv; - -fs::copyArgs *fs::copyArgsCreate(const std::string& from, const std::string& to, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces) -{ - copyArgs *ret = new copyArgs; - ret->to = to; - ret->from = from; - ret->dev = dev; - ret->z = z; - ret->unz = unz; - ret->cleanup = _cleanup; - ret->prog = new ui::progBar; - ret->prog->setMax(0); - ret->prog->update(0); - ret->offset = 0; - ret->trimZipPath = _trimZipPath; - ret->trimZipPlaces = _trimPlaces; - return ret; -} - -void fs::copyArgsDestroy(copyArgs *c) -{ - delete c->prog; - delete c; - c = NULL; -} - -static struct -{ - bool operator()(const fs::dirItem& a, const fs::dirItem& b) - { - if(a.isDir() != b.isDir()) - return a.isDir(); - - for(unsigned i = 0; i < a.getItm().length(); i++) - { - char charA = tolower(a.getItm()[i]); - char charB = tolower(b.getItm()[i]); - if(charA != charB) - return charA < charB; - } - return false; - } -} sortDirList; - -void fs::mkDir(const std::string& _p) -{ - if(cfg::config["directFsCmd"]) - fsMkDir(_p.c_str()); - else - mkdir(_p.c_str(), 777); -} - -void fs::mkDirRec(const std::string& _p) -{ - //skip first slash - size_t pos = _p.find('/', 0) + 1; - while((pos = _p.find('/', pos)) != _p.npos) - { - fs::mkDir(_p.substr(0, pos).c_str()); - ++pos; - } -} - -bool fs::commitToDevice(const std::string& dev) -{ - bool ret = true; - Result res = fsdevCommitDevice(dev.c_str()); - if(R_FAILED(res)) - { - fs::logWrite("Error committing file to device -> 0x%X\n", res); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popErrorCommittingFile", 0)); - ret = false; - } - return ret; -} - -void fs::createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _userID) -{ - std::string indexStr; - uint16_t index = 0; - if(_type == FsSaveDataType_Cache && !(indexStr = util::getStringInput(SwkbdType_NumPad, "0", ui::getUIString("swkbdSaveIndex", 0), 2, 0, NULL)).empty()) - index = strtoul(indexStr.c_str(), NULL, 10); - else if(_type == FsSaveDataType_Cache && indexStr.empty()) - return; - - svCreateArgs *send = new svCreateArgs; - send->type = _type; - send->account = _userID; - send->tid = _tid; - send->index = index; - ui::newThread(fs::createSaveData_t, send, NULL); -} - -void fs::init() -{ - mkDirRec("sdmc:/config/JKSV/"); - mkDirRec(wd); - mkdir(std::string(wd + "_TRASH_").c_str(), 777); - - fs::logOpen(); -} - -void fs::exit() -{ - -} - -bool fs::mountSave(const FsSaveDataInfo& _m) -{ - Result svOpen; - FsSaveDataAttribute attr = {0}; - switch(_m.save_data_type) - { - case FsSaveDataType_System: - case FsSaveDataType_SystemBcat: - { - attr.uid = _m.uid; - attr.system_save_data_id = _m.system_save_data_id; - attr.save_data_type = _m.save_data_type; - svOpen = fsOpenSaveDataFileSystemBySystemSaveDataId(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); - } - break; - - case FsSaveDataType_Account: - { - attr.uid = _m.uid; - attr.application_id = _m.application_id; - attr.save_data_type = _m.save_data_type; - attr.save_data_rank = _m.save_data_rank; - attr.save_data_index = _m.save_data_index; - svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); - } - break; - - case FsSaveDataType_Device: - { - attr.application_id = _m.application_id; - attr.save_data_type = FsSaveDataType_Device; - svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); - } - break; - - case FsSaveDataType_Bcat: - { - attr.application_id = _m.application_id; - attr.save_data_type = FsSaveDataType_Bcat; - svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); - } - break; - - case FsSaveDataType_Cache: - { - attr.application_id = _m.application_id; - attr.save_data_type = FsSaveDataType_Cache; - attr.save_data_index = _m.save_data_index; - svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); - } - break; - - case FsSaveDataType_Temporary: - { - attr.application_id = _m.application_id; - attr.save_data_type = _m.save_data_type; - svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); - } - break; - - default: - svOpen = 1; - break; - } - - return R_SUCCEEDED(svOpen) && fsdevMountDevice("sv", sv) != -1; -} - -fs::dirItem::dirItem(const std::string& pathTo, const std::string& sItem) -{ - itm = sItem; - - std::string fullPath = pathTo + sItem; - struct stat s; - if(stat(fullPath.c_str(), &s) == 0 && S_ISDIR(s.st_mode)) - dir = true; -} - -std::string fs::dirItem::getName() const -{ - size_t extPos = itm.find_last_of('.'), slPos = itm.find_last_of('/'); - if(extPos == itm.npos) - return ""; - - return itm.substr(slPos + 1, extPos); -} - -std::string fs::dirItem::getExt() const -{ - return util::getExtensionFromString(itm); -} - -fs::dirList::dirList(const std::string& _path) -{ - path = _path; - d = opendir(path.c_str()); - - while((ent = readdir(d))) - item.emplace_back(path, ent->d_name); - - closedir(d); - - std::sort(item.begin(), item.end(), sortDirList); -} - -void fs::dirList::reassign(const std::string& _path) -{ - path = _path; - - d = opendir(path.c_str()); - - item.clear(); - - while((ent = readdir(d))) - item.emplace_back(path, ent->d_name); - - closedir(d); - - std::sort(item.begin(), item.end(), sortDirList); -} - -void fs::dirList::rescan() -{ - item.clear(); - d = opendir(path.c_str()); - - while((ent = readdir(d))) - item.emplace_back(path, ent->d_name); - - closedir(d); - - std::sort(item.begin(), item.end(), sortDirList); -} - -fs::dataFile::dataFile(const std::string& _path) -{ - f = fopen(_path.c_str(), "r"); - if(f != NULL) - opened = true; -} - -fs::dataFile::~dataFile() -{ - fclose(f); -} - -bool fs::dataFile::readNextLine(bool proc) -{ - bool ret = false; - char tmp[1024]; - while(fgets(tmp, 1024, f)) - { - if(tmp[0] != '#' && tmp[0] != '\n' && tmp[0] != '\r') - { - line = tmp; - ret = true; - break; - } - } - util::stripChar('\n', line); - util::stripChar('\r', line); - if(proc) - procLine(); - - return ret; -} - -void fs::dataFile::procLine() -{ - size_t pPos = line.find_first_of("(=,"); - if(pPos != line.npos) - { - lPos = pPos; - name.assign(line.begin(), line.begin() + lPos); - } - else - name = line; - - util::stripChar(' ', name); - ++lPos; -} - -std::string fs::dataFile::getNextValueStr() -{ - std::string ret = ""; - //Skip all spaces until we hit actual text - size_t pos1 = line.find_first_not_of(", ", lPos); - //If reading from quotes - if(line[pos1] == '"') - lPos = line.find_first_of('"', ++pos1); - else - lPos = line.find_first_of(",;\n", pos1);//Set lPos to end of string we want. This should just set lPos to the end of the line if it fails, which is ok - - ret = line.substr(pos1, lPos++ - pos1); - - util::replaceStr(ret, "\\n", "\n"); - - return ret; -} - -int fs::dataFile::getNextValueInt() -{ - int ret = 0; - std::string no = getNextValueStr(); - if(no[0] == '0' && tolower(no[1]) == 'x') - ret = strtoul(no.c_str(), NULL, 16); - else - ret = strtoul(no.c_str(), NULL, 10); - - return ret; -} - -//Wrapper functions to use functions from `fsthrd.cpp` -void fs::copyFile(const std::string& from, const std::string& to) -{ - copyArgs *send = copyArgsCreate(from, to, "", NULL, NULL, false, false, 0); - ui::newThread(copyFile_t, send, _fileDrawFunc); -} - -void fs::copyFileCommit(const std::string& from, const std::string& to, const std::string& dev) -{ - copyArgs *send = copyArgsCreate(from, to, dev, NULL, NULL, false, false, 0); - ui::newThread(copyFileCommit_t, send, _fileDrawFunc); -} - -void fs::copyDirToDir(const std::string& from, const std::string& to) -{ - fs::copyArgs *send = fs::copyArgsCreate(from, to, "", NULL, NULL, true, false, 0); - ui::newThread(fs::copyDirToDir_t, send, _fileDrawFunc); -} - -void fs::copyDirToZip(const std::string& from, zipFile to) -{ - if(cfg::config["ovrClk"]) - { - util::setCPU(util::CPU_SPEED_1785MHz); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0)); - } - copyArgs *send = copyArgsCreate(from, "", "", to, NULL, true, false, 0); - ui::newThread(copyDirToZip_t, send, _fileDrawFunc); -} - -void fs::copyZipToDir(unzFile unz, const std::string& to, const std::string& dev) -{ - if(cfg::config["ovrClk"]) - { - util::setCPU(util::CPU_SPEED_1785MHz); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0)); - } - copyArgs *send = copyArgsCreate("", to, dev, NULL, unz, true, false, 0); - ui::newThread(copyZipToDir_t, send, _fileDrawFunc); -} - -bool fs::dirNotEmpty(const std::string& _dir) -{ - fs::dirList tmp(_dir); - return tmp.getCount() > 0; -} - -bool fs::zipNotEmpty(unzFile unzip) -{ - return unzGoToFirstFile(unzip) == UNZ_OK; -} - -void fs::copyDirToDirCommit(const std::string& from, const std::string& to, const std::string& dev) -{ - fs::copyArgs *send = copyArgsCreate(from, to, dev, NULL, NULL, true, false, 0); - ui::newThread(copyDirToDirCommit_t, send, _fileDrawFunc); -} - -void fs::delfile(const std::string& path) -{ - if(cfg::config["directFsCmd"]) - fsremove(path.c_str()); - else - remove(path.c_str()); -} - -void fs::delDir(const std::string& path) -{ - dirList list(path); - for(unsigned i = 0; i < list.getCount(); i++) - { - if(pathIsFiltered(path + list.getItem(i))) - continue; - - if(list.isDir(i)) - { - std::string newPath = path + list.getItem(i) + "/"; - delDir(newPath); - - std::string delPath = path + list.getItem(i); - rmdir(delPath.c_str()); - } - else - { - std::string delPath = path + list.getItem(i); - std::remove(delPath.c_str()); - } - } - rmdir(path.c_str()); -} - -void fs::loadPathFilters(const uint64_t& tid) -{ - char path[256]; - sprintf(path, "sdmc:/config/JKSV/0x%016lX_filter.txt", tid); - if(fs::fileExists(path)) - { - fs::dataFile filter(path); - while(filter.readNextLine(false)) - pathFilter.push_back(filter.getLine()); - } -} - -bool fs::pathIsFiltered(const std::string& _path) -{ - if(pathFilter.empty()) - return false; - - for(std::string& _p : pathFilter) - { - if(_path == _p) - return true; - } - - return false; -} - -void fs::freePathFilters() -{ - pathFilter.clear(); -} - -void fs::wipeSave() -{ - ui::newThread(fs::wipesave_t, NULL, NULL); -} - -void fs::dumpAllUserSaves() -{ - //This is only really used for the progress bar - fs::copyArgs *send = fs::copyArgsCreate("", "", "", NULL, NULL, true, false, 0); - ui::newThread(fs::backupUserSaves_t, send, _fileDrawFunc); -} - -void fs::getShowFileProps(const std::string& _path) -{ - size_t size = fs::fsize(_path); - ui::showMessage(ui::getUICString("fileModeFileProperties", 0), _path.c_str(), util::getSizeString(size).c_str()); -} - -void fs::getShowDirProps(const std::string& _path) -{ - fs::dirCountArgs *send = new fs::dirCountArgs; - send->path = _path; - send->origin = true; - ui::newThread(fs::getShowDirProps_t, send, NULL); -} - -bool fs::fileExists(const std::string& path) -{ - bool ret = false; - FILE *test = fopen(path.c_str(), "rb"); - if(test != NULL) - ret = true; - fclose(test); - return ret; -} - -size_t fs::fsize(const std::string& _f) -{ - size_t ret = 0; - FILE *get = fopen(_f.c_str(), "rb"); - if(get != NULL) - { - fseek(get, 0, SEEK_END); - ret = ftell(get); - } - fclose(get); - return ret; -} - -std::string fs::getWorkDir() { return wd; } - -void fs::setWorkDir(const std::string& _w){ wd = _w; } - -bool fs::isDir(const std::string& _path) -{ - struct stat s; - return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); -} - -void fs::createNewBackup(void *a) -{ - if(!fs::dirNotEmpty("sv:/")) - { - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSaveIsEmpty", 0)); - return; - } - - uint64_t held = ui::padKeysHeld(); - - data::user *u = data::getCurrentUser(); - data::userTitleInfo *d = data::getCurrentUserTitleInfo(); - data::titleInfo *t = data::getTitleInfoByTID(d->tid); - - std::string out; - - if(held & HidNpadButton_R || cfg::config["autoName"]) - out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); - else if(held & HidNpadButton_L) - out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM); - else if(held & HidNpadButton_ZL) - out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE); - else - { - const std::string dict[] = - { - util::getDateTime(util::DATE_FMT_YMD), - util::getDateTime(util::DATE_FMT_YDM), - util::getDateTime(util::DATE_FMT_HOYSTE), - util::getDateTime(util::DATE_FMT_JHK), - util::getDateTime(util::DATE_FMT_ASC), - u->getUsernameSafe(), - t->safeTitle, - util::generateAbbrev(d->tid), - ".zip" - }; - std::string defaultText = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); - out = util::getStringInput(SwkbdType_QWERTY, defaultText, ui::getUIString("swkbdEnterName", 0), 64, 9, dict); - out = util::safeString(out); - } - - if(!out.empty()) - { - std::string ext = util::getExtensionFromString(out); - std::string path = util::generatePathByTID(d->tid) + out; - if(cfg::config["zip"] || ext == "zip") - { - if(ext != "zip")//data::zip is on but extension is not zip - path += ".zip"; - - zipFile zip = zipOpen64(path.c_str(), 0); - fs::copyDirToZip("sv:/", zip); - - } - else - { - fs::mkDir(path); - path += "/"; - fs::copyDirToDir("sv:/", path); - } - ui::populateFldMenu(); - } -} - -void fs::overwriteBackup(void *a) -{ - threadInfo *t = (threadInfo *)a; - fs::backupArgs *in = (fs::backupArgs *)t->argPtr; - ui::menu *m = in->m; - fs::dirList *d = in->d; - - data::userTitleInfo *cd = data::getCurrentUserTitleInfo(); - - unsigned ind = m->getSelected() - 1;;//Skip new - - std::string itemName = d->getItem(ind); - bool saveHasFiles = fs::dirNotEmpty("sv:/"); - if(d->isDir(ind) && saveHasFiles) - { - std::string toPath = util::generatePathByTID(cd->tid) + itemName + "/"; - //Delete and recreate - fs::delDir(toPath); - fs::mkDir(toPath); - fs::copyDirToDir("sv:/", toPath); - } - else if(!d->isDir(ind) && d->getItemExt(ind) == "zip" && saveHasFiles) - { - std::string toPath = util::generatePathByTID(cd->tid) + itemName; - fs::delfile(toPath); - zipFile zip = zipOpen64(toPath.c_str(), 0); - fs::copyDirToZip("sv:/", zip); - } - t->finished = true; -} - -void fs::restoreBackup(void *a) -{ - threadInfo *t = (threadInfo *)a; - fs::backupArgs *in = (fs::backupArgs *)t->argPtr; - ui::menu *m = in->m; - fs::dirList *d = in->d; - - data::user *u = data::getCurrentUser(); - data::userTitleInfo *cd = data::getCurrentUserTitleInfo(); - unsigned ind = m->getSelected() - 1; - - std::string itemName = d->getItem(ind); - if((cd->saveInfo.save_data_type != FsSaveDataType_System || cfg::config["sysSaveWrite"]) && m->getSelected() > 0) - { - bool saveHasFiles = fs::dirNotEmpty("sv:/"); - if(cfg::config["autoBack"] && cfg::config["zip"] && saveHasFiles) - { - std::string autoZip = util::generatePathByTID(cd->tid) + "/AUTO " + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; - zipFile zip = zipOpen64(autoZip.c_str(), 0); - fs::copyDirToZip("sv:/", zip); - } - else if(cfg::config["autoBack"] && saveHasFiles) - { - std::string autoFolder = util::generatePathByTID(cd->tid) + "/AUTO - " + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; - fs::mkDir(autoFolder.substr(0, autoFolder.length() - 1)); - fs::copyDirToDir("sv:/", autoFolder); - } - - if(d->isDir(ind)) - { - std::string fromPath = util::generatePathByTID(cd->tid) + itemName + "/"; - if(fs::dirNotEmpty(fromPath)) - { - fs::wipeSave(); - fs::copyDirToDirCommit(fromPath, "sv:/", "sv"); - } - else - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popFolderIsEmpty", 0)); - } - else if(!d->isDir(ind) && d->getItemExt(ind) == "zip") - { - std::string path = util::generatePathByTID(cd->tid) + itemName; - unzFile unz = unzOpen64(path.c_str()); - if(unz && fs::zipNotEmpty(unz)) - { - fs::wipeSave(); - fs::copyZipToDir(unz, "sv:/", "sv"); - } - else - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popZipIsEmpty", 0)); - } - else - { - //Just copy file over - std::string fromPath = util::generatePathByTID(cd->tid) + itemName; - std::string toPath = "sv:/" + itemName; - fs::copyFileCommit(fromPath, toPath, "sv"); - } - } - - if(cfg::config["autoBack"]) - ui::populateFldMenu(); - - t->finished = true; -} - -void fs::deleteBackup(void *a) -{ - threadInfo *t = (threadInfo *)a; - fs::backupArgs *in = (fs::backupArgs *)t->argPtr; - ui::menu *m = in->m; - fs::dirList *d = in->d; - - data::userTitleInfo *cd = data::getCurrentUserTitleInfo(); - unsigned ind = m->getSelected() - 1; - - std::string itemName = d->getItem(ind); - t->status->setStatus(ui::getUICString("infoStatus", 10)); - if(cfg::config["trashBin"]) - { - data::userTitleInfo *getTID = data::getCurrentUserTitleInfo(); - - std::string oldPath = util::generatePathByTID(cd->tid) + itemName; - std::string trashPath = wd + "_TRASH_/" + data::getTitleSafeNameByTID(getTID->tid); - fs::mkDir(trashPath); - trashPath += "/" + itemName; - - rename(oldPath.c_str(), trashPath.c_str()); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupMovedToTrash", 0), itemName.c_str()); - } - else if(d->isDir(ind)) - { - std::string delPath = util::generatePathByTID(cd->tid) + itemName + "/"; - fs::delDir(delPath); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), itemName.c_str()); - } - else - { - std::string delPath = util::generatePathByTID(cd->tid) + itemName; - fs::delfile(delPath); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), itemName.c_str()); - } - ui::populateFldMenu(); - t->finished = true; -} - -void fs::logOpen() -{ - std::string logPath = wd + "log.txt"; - debLog = fsfopen(logPath.c_str(), FsOpenMode_Write); - fsfclose(debLog); -} - -void fs::logWrite(const char *fmt, ...) -{ - std::string logPath = wd + "log.txt"; - debLog = fsfopen(logPath.c_str(), FsOpenMode_Append | FsOpenMode_Write); - char tmp[256]; - va_list args; - va_start(args, fmt); - vsprintf(tmp, fmt, args); - va_end(args); - fsfwrite(tmp, 1, strlen(tmp), debLog); - fsfclose(debLog); -} - diff --git a/src/fs.cpp b/src/fs.cpp new file mode 100644 index 0000000..4da11e7 --- /dev/null +++ b/src/fs.cpp @@ -0,0 +1,565 @@ +#include +#include + +#include "fs.h" +#include "cfg.h" +#include "util.h" + +static std::string wd = "sdmc:/JKSV/"; + +static FSFILE *debLog; + +static FsFileSystem sv; + +void fs::init() +{ + mkDirRec("sdmc:/config/JKSV/"); + mkDirRec(wd); + mkdir(std::string(wd + "_TRASH_").c_str(), 777); + + fs::logOpen(); +} + +bool fs::mountSave(const FsSaveDataInfo& _m) +{ + Result svOpen; + FsSaveDataAttribute attr = {0}; + switch(_m.save_data_type) + { + case FsSaveDataType_System: + case FsSaveDataType_SystemBcat: + { + attr.uid = _m.uid; + attr.system_save_data_id = _m.system_save_data_id; + attr.save_data_type = _m.save_data_type; + svOpen = fsOpenSaveDataFileSystemBySystemSaveDataId(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Account: + { + attr.uid = _m.uid; + attr.application_id = _m.application_id; + attr.save_data_type = _m.save_data_type; + attr.save_data_rank = _m.save_data_rank; + attr.save_data_index = _m.save_data_index; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Device: + { + attr.application_id = _m.application_id; + attr.save_data_type = FsSaveDataType_Device; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Bcat: + { + attr.application_id = _m.application_id; + attr.save_data_type = FsSaveDataType_Bcat; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Cache: + { + attr.application_id = _m.application_id; + attr.save_data_type = FsSaveDataType_Cache; + attr.save_data_index = _m.save_data_index; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Temporary: + { + attr.application_id = _m.application_id; + attr.save_data_type = _m.save_data_type; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr); + } + break; + + default: + svOpen = 1; + break; + } + + return R_SUCCEEDED(svOpen) && fsdevMountDevice("sv", sv) != -1; +} + +bool fs::commitToDevice(const std::string& dev) +{ + bool ret = true; + Result res = fsdevCommitDevice(dev.c_str()); + if(R_FAILED(res)) + { + fs::logWrite("Error committing file to device -> 0x%X\n", res); + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popErrorCommittingFile", 0)); + ret = false; + } + return ret; +} + +std::string fs::getWorkDir() { return wd; } + +void fs::setWorkDir(const std::string& _w) { wd = _w; } + +void fs::createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t) +{ + data::titleInfo *tinfo = data::getTitleInfoByTID(_tid); + if(t) + t->status->setStatus(ui::getUICString("threadStatusCreatingSaveData", 0), tinfo->title.c_str()); + + uint16_t cacheIndex = 0; + std::string indexStr; + if(_type == FsSaveDataType_Cache && !(indexStr = util::getStringInput(SwkbdType_NumPad, "0", ui::getUIString("swkbdSaveIndex", 0), 2, 0, NULL)).empty()) + cacheIndex = strtoul(indexStr.c_str(), NULL, 10); + else if(_type == FsSaveDataType_Cache && indexStr.empty()) + { + if(t) + t->finished = true; + return; + } + + FsSaveDataAttribute attr; + memset(&attr, 0, sizeof(FsSaveDataAttribute)); + attr.application_id = _tid; + attr.uid = _uid; + attr.system_save_data_id = 0; + attr.save_data_type = _type; + attr.save_data_rank = 0; + attr.save_data_index = cacheIndex; + + FsSaveDataCreationInfo crt; + memset(&crt, 0, sizeof(FsSaveDataCreationInfo)); + int64_t saveSize = 0, journalSize = 0; + switch(_type) + { + case FsSaveDataType_Account: + saveSize = tinfo->nacp.user_account_save_data_size; + journalSize = tinfo->nacp.user_account_save_data_journal_size; + break; + + case FsSaveDataType_Device: + saveSize = tinfo->nacp.device_save_data_size; + journalSize = tinfo->nacp.device_save_data_journal_size; + break; + + case FsSaveDataType_Bcat: + saveSize = tinfo->nacp.bcat_delivery_cache_storage_size; + journalSize = tinfo->nacp.bcat_delivery_cache_storage_size; + break; + + case FsSaveDataType_Cache: + saveSize = 32 * 1024 * 1024; + if(tinfo->nacp.cache_storage_journal_size > tinfo->nacp.cache_storage_data_and_journal_size_max) + journalSize = tinfo->nacp.cache_storage_journal_size; + else + journalSize = tinfo->nacp.cache_storage_data_and_journal_size_max; + break; + + default: + if(t) + t->finished = true; + return; + break; + } + crt.save_data_size = saveSize; + crt.journal_size = journalSize; + crt.available_size = 0x4000; + crt.owner_id = _type == FsSaveDataType_Bcat ? 0x010000000000000C : tinfo->nacp.save_data_owner_id; + crt.flags = 0; + crt.save_data_space_id = FsSaveDataSpaceId_User; + + FsSaveDataMetaInfo meta; + memset(&meta, 0, sizeof(FsSaveDataMetaInfo)); + if(_type != FsSaveDataType_Bcat) + { + meta.size = 0x40060; + meta.type = FsSaveDataMetaType_Thumbnail; + } + + Result res = 0; + if(R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &crt, &meta))) + { + util::createTitleDirectoryByTID(_tid); + data::loadUsersTitles(false); + ui::ttlRefresh(); + } + else + { + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataCreationFailed", 0)); + fs::logWrite("SaveCreate Failed -> %X\n", res); + } +} + +static void createSaveData_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::svCreateArgs *crt = (fs::svCreateArgs *)t->argPtr; + fs::createSaveData(crt->type, crt->tid, crt->account, t); + delete crt; + t->finished = true; +} + +void fs::createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid) +{ + fs::svCreateArgs *send = new fs::svCreateArgs; + send->type = _type; + send->tid = _tid; + send->account = _uid; + ui::newThread(createSaveData_t, send, NULL); +} + +bool fs::extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t) +{ + if(t) + t->status->setStatus(ui::getUICString("threadStatusExtendingSaveData", 0), data::getTitleNameByTID(tinfo->tid).c_str()); + + uint64_t journal = fs::getJournalSizeMax(tinfo); + uint64_t saveID = tinfo->saveInfo.save_data_id; + FsSaveDataSpaceId space = (FsSaveDataSpaceId)tinfo->saveInfo.save_data_space_id; + Result res = 0; + if(R_FAILED((res = fsExtendSaveDataFileSystem(space, saveID, extSize, journal)))) + { + int64_t totalSize = 0; + fs::mountSave(tinfo->saveInfo); + fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize); + fs::unmountSave(); + + fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, extSize / 1024 / 1024, res); + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0)); + return false; + } + return true; +} + +static void extendSaveData_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::svExtendArgs *e = (fs::svExtendArgs *)t->argPtr; + fs::extendSaveData(e->tinfo, e->extSize, t); + delete e; + t->finished = true; +} + +void fs::extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize) +{ + fs::svExtendArgs *send = new fs::svExtendArgs; + send->tinfo = tinfo; + send->extSize = extSize; + ui::newThread(extendSaveData_t, send, NULL); +} + +uint64_t fs::getJournalSize(const data::userTitleInfo *tinfo) +{ + uint64_t ret = 0; + data::titleInfo *t = data::getTitleInfoByTID(tinfo->tid); + switch(tinfo->saveInfo.save_data_type) + { + case FsSaveDataType_Account: + ret = t->nacp.user_account_save_data_journal_size; + break; + + case FsSaveDataType_Device: + ret = t->nacp.device_save_data_journal_size; + break; + + case FsSaveDataType_Bcat: + ret = t->nacp.bcat_delivery_cache_storage_size; + break; + + case FsSaveDataType_Cache: + if(t->nacp.cache_storage_journal_size > 0) + ret = t->nacp.cache_storage_journal_size; + else + ret = t->nacp.cache_storage_data_and_journal_size_max; + break; + + default: + ret = BUFF_SIZE; + break; + } + return ret; +} + +uint64_t fs::getJournalSizeMax(const data::userTitleInfo *tinfo) +{ + uint64_t ret = 0; + data::titleInfo *extend = data::getTitleInfoByTID(tinfo->tid); + switch(tinfo->saveInfo.save_data_type) + { + case FsSaveDataType_Account: + if(extend->nacp.user_account_save_data_journal_size_max > extend->nacp.user_account_save_data_journal_size) + ret = extend->nacp.user_account_save_data_journal_size_max; + else + ret = extend->nacp.user_account_save_data_journal_size; + break; + + case FsSaveDataType_Bcat: + ret = extend->nacp.bcat_delivery_cache_storage_size; + break; + + case FsSaveDataType_Cache: + if(extend->nacp.cache_storage_data_and_journal_size_max > extend->nacp.cache_storage_journal_size) + ret = extend->nacp.cache_storage_data_and_journal_size_max; + else + ret = extend->nacp.cache_storage_journal_size; + break; + + case FsSaveDataType_Device: + if(extend->nacp.device_save_data_journal_size_max > extend->nacp.device_save_data_journal_size) + ret = extend->nacp.device_save_data_journal_size_max; + else + ret = extend->nacp.device_save_data_journal_size; + break; + + default: + //will just fail + ret = 0; + break; + } + return ret; +} + +static void wipeSave_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0)); + fs::delDir("sv:/"); + fs::commitToDevice("sv"); + t->finished = true; +} + +void fs::wipeSave() +{ + ui::newThread(wipeSave_t, NULL, NULL); +} + +void fs::createNewBackup(void *a) +{ + if(!fs::dirNotEmpty("sv:/")) + { + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSaveIsEmpty", 0)); + return; + } + + uint64_t held = ui::padKeysHeld(); + + data::user *u = data::getCurrentUser(); + data::userTitleInfo *d = data::getCurrentUserTitleInfo(); + data::titleInfo *t = data::getTitleInfoByTID(d->tid); + + std::string out; + + if(held & HidNpadButton_R || cfg::config["autoName"]) + out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); + else if(held & HidNpadButton_L) + out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM); + else if(held & HidNpadButton_ZL) + out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE); + else + { + const std::string dict[] = + { + util::getDateTime(util::DATE_FMT_YMD), + util::getDateTime(util::DATE_FMT_YDM), + util::getDateTime(util::DATE_FMT_HOYSTE), + util::getDateTime(util::DATE_FMT_JHK), + util::getDateTime(util::DATE_FMT_ASC), + u->getUsernameSafe(), + t->safeTitle, + util::generateAbbrev(d->tid), + ".zip" + }; + std::string defaultText = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); + out = util::getStringInput(SwkbdType_QWERTY, defaultText, ui::getUIString("swkbdEnterName", 0), 64, 9, dict); + out = util::safeString(out); + } + + if(!out.empty()) + { + std::string ext = util::getExtensionFromString(out); + std::string path = util::generatePathByTID(d->tid) + out; + if(cfg::config["zip"] || ext == "zip") + { + if(ext != "zip")//data::zip is on but extension is not zip + path += ".zip"; + + zipFile zip = zipOpen64(path.c_str(), 0); + fs::copyDirToZipThreaded("sv:/", zip, false, 0); + + } + else + { + fs::mkDir(path); + path += "/"; + fs::copyDirToDirThreaded("sv:/", path); + } + ui::populateFldMenu(); + } +} + +void fs::overwriteBackup(void *a) +{ + threadInfo *t = (threadInfo *)a; + std::string *dst = (std::string *)t->argPtr; + bool saveHasFiles = fs::dirNotEmpty("sv:/"); + if(fs::isDir(*dst) && saveHasFiles) + { + fs::delDir(*dst); + fs::mkDir(*dst); + dst->append("/"); + fs::copyDirToDirThreaded("sv:/", *dst); + } + else if(!fs::isDir(*dst) && util::getExtensionFromString(*dst) == "zip" && saveHasFiles) + { + fs::delfile(*dst); + zipFile zip = zipOpen64(dst->c_str(), 0); + fs::copyDirToZipThreaded("sv:/", zip, false, 0); + } + delete dst; + t->finished = true; +} + +void fs::restoreBackup(void *a) +{ + threadInfo *t = (threadInfo *)a; + std::string *restore = (std::string *)t->argPtr; + data::user *u = data::getCurrentUser(); + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + if((utinfo->saveInfo.save_data_type != FsSaveDataType_System || cfg::config["sysSaveWrite"])) + { + bool saveHasFiles = fs::dirNotEmpty("sv:/"); + if(cfg::config["autoBack"] && cfg::config["zip"] && saveHasFiles) + { + std::string autoZip = util::generatePathByTID(utinfo->tid) + "/AUTO " + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; + zipFile zip = zipOpen64(autoZip.c_str(), 0); + fs::copyDirToZipThreaded("sv:/", zip, false, 0); + } + else if(cfg::config["autoBack"] && saveHasFiles) + { + std::string autoFolder = util::generatePathByTID(utinfo->tid) + "/AUTO - " + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; + fs::mkDir(autoFolder.substr(0, autoFolder.length() - 1)); + fs::copyDirToDirThreaded("sv:/", autoFolder); + } + + if(fs::isDir(*restore)) + { + restore->append("/"); + if(fs::dirNotEmpty(*restore)) + { + t->status->setStatus(ui::getUICString("threadStatusCalculatingSaveSize", 0)); + unsigned dirCount = 0, fileCount = 0; + uint64_t saveSize = 0; + int64_t availSize = 0; + fs::getDirProps(*restore, dirCount, fileCount, saveSize); + fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize); + if((int)saveSize > availSize) + { + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + fs::unmountSave(); + fs::extendSaveData(utinfo, saveSize + 0x500000, t); + fs::mountSave(utinfo->saveInfo); + } + + fs::wipeSave(); + fs::copyDirToDirCommitThreaded(*restore, "sv:/", "sv"); + } + else + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popFolderIsEmpty", 0)); + } + else if(!fs::isDir(*restore) && util::getExtensionFromString(*restore) == "zip") + { + unzFile unz = unzOpen64(restore->c_str()); + if(unz && fs::zipNotEmpty(unz)) + { + t->status->setStatus(ui::getUICString("threadStatusCalculatingSaveSize", 0)); + uint64_t saveSize = fs::getZipTotalSize(unz); + int64_t availSize = 0; + fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize); + if((int)saveSize > availSize) + { + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + fs::unmountSave(); + fs::extendSaveData(utinfo, saveSize + 0x500000, t); + fs::mountSave(utinfo->saveInfo); + } + + fs::wipeSave(); + fs::copyZipToDirThreaded(unz, "sv:/", "sv"); + } + else + { + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popZipIsEmpty", 0)); + unzClose(unz); + } + } + else + { + std::string dstPath = "sv:/" + util::getFilenameFromPath(*restore); + fs::copyFileCommitThreaded(*restore, dstPath, "sv"); + } + } + if(cfg::config["autoBack"]) + ui::populateFldMenu(); + + delete restore; + t->finished = true; +} + +void fs::deleteBackup(void *a) +{ + threadInfo *t = (threadInfo *)a; + std::string *deletePath = (std::string *)t->argPtr; + std::string backupName = util::getFilenameFromPath(*deletePath); + + t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0)); + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + if(cfg::config["trashBin"]) + { + std::string oldPath = *deletePath; + std::string trashPath = wd + "_TRASH_/" + data::getTitleSafeNameByTID(utinfo->tid); + fs::mkDir(trashPath); + trashPath += "/" + backupName; + + rename(oldPath.c_str(), trashPath.c_str()); + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupMovedToTrash", 0), backupName.c_str()); + } + else if(fs::isDir(*deletePath)) + { + *deletePath += "/"; + fs::delDir(*deletePath); + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str()); + } + else + { + fs::delfile(*deletePath); + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str()); + } + ui::populateFldMenu(); + delete deletePath; + t->finished = true; +} + +void fs::logOpen() +{ + std::string logPath = wd + "log.txt"; + debLog = fsfopen(logPath.c_str(), FsOpenMode_Write); + fsfclose(debLog); +} + +void fs::logWrite(const char *fmt, ...) +{ + std::string logPath = wd + "log.txt"; + debLog = fsfopen(logPath.c_str(), FsOpenMode_Append | FsOpenMode_Write); + char tmp[256]; + va_list args; + va_start(args, fmt); + vsprintf(tmp, fmt, args); + va_end(args); + fsfwrite(tmp, 1, strlen(tmp), debLog); + fsfclose(debLog); +} + diff --git a/src/fs/dir.cpp b/src/fs/dir.cpp new file mode 100644 index 0000000..783b975 --- /dev/null +++ b/src/fs/dir.cpp @@ -0,0 +1,269 @@ +#include +#include + +#include "fs.h" +#include "cfg.h" +#include "util.h" + +static struct +{ + bool operator()(const fs::dirItem& a, const fs::dirItem& b) + { + if(a.isDir() != b.isDir()) + return a.isDir(); + + for(unsigned i = 0; i < a.getItm().length(); i++) + { + char charA = tolower(a.getItm()[i]); + char charB = tolower(b.getItm()[i]); + if(charA != charB) + return charA < charB; + } + return false; + } +} sortDirList; + +void fs::mkDir(const std::string& _p) +{ + if(cfg::config["directFsCmd"]) + fsMkDir(_p.c_str()); + else + mkdir(_p.c_str(), 777); +} + +void fs::mkDirRec(const std::string& _p) +{ + //skip first slash + size_t pos = _p.find('/', 0) + 1; + while((pos = _p.find('/', pos)) != _p.npos) + { + fs::mkDir(_p.substr(0, pos).c_str()); + ++pos; + } +} + +void fs::delDir(const std::string& path) +{ + dirList list(path); + for(unsigned i = 0; i < list.getCount(); i++) + { + if(pathIsFiltered(path + list.getItem(i))) + continue; + + if(list.isDir(i)) + { + std::string newPath = path + list.getItem(i) + "/"; + delDir(newPath); + + std::string delPath = path + list.getItem(i); + rmdir(delPath.c_str()); + } + else + { + std::string delPath = path + list.getItem(i); + std::remove(delPath.c_str()); + } + } + rmdir(path.c_str()); +} + +bool fs::dirNotEmpty(const std::string& _dir) +{ + fs::dirList tmp(_dir); + return tmp.getCount() > 0; +} + +bool fs::isDir(const std::string& _path) +{ + struct stat s; + return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); +} + +void fs::copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t) +{ + if(t) + t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), src.c_str()); + + fs::dirList *list = new fs::dirList(src); + for(unsigned i = 0; i < list->getCount(); i++) + { + if(pathIsFiltered(src + list->getItem(i))) + continue; + + if(list->isDir(i)) + { + std::string newSrc = src + list->getItem(i) + "/"; + std::string newDst = dst + list->getItem(i) + "/"; + fs::mkDir(newDst.substr(0, newDst.length() - 1)); + fs::copyDirToDir(newSrc, newDst, t); + } + else + { + std::string fullSrc = src + list->getItem(i); + std::string fullDst = dst + list->getItem(i); + + if(t) + t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), fullSrc.c_str()); + + fs::copyFile(fullSrc, fullDst, t); + } + } + delete list; +} + +static void copyDirToDir_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + fs::copyDirToDir(in->src, in->dst, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + t->finished = true; +} + +void fs::copyDirToDirThreaded(const std::string& src, const std::string& dst) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0); + ui::newThread(copyDirToDir_t, send, fs::fileDrawFunc); +} + +void fs::copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t) +{ + if(t) + t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), src.c_str()); + + fs::dirList *list = new fs::dirList(src); + for(unsigned i = 0; i < list->getCount(); i++) + { + if(pathIsFiltered(src + list->getItem(i))) + continue; + + if(list->isDir(i)) + { + std::string newSrc = src + list->getItem(i) + "/"; + std::string newDst = dst + list->getItem(i) + "/"; + fs::mkDir(newDst.substr(0, newDst.length() - 1)); + fs::copyDirToDirCommit(newSrc, newDst, dev, t); + } + else + { + std::string fullSrc = src + list->getItem(i); + std::string fullDst = dst + list->getItem(i); + + if(t) + t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), fullSrc.c_str()); + + fs::copyFileCommit(fullSrc, fullDst, dev, t); + } + } + delete list; +} + +static void copyDirToDirCommit_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + fs::copyDirToDirCommit(in->src, in->dst, in->dev, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + t->finished = true; +} + +void fs::copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0); + ui::newThread(copyDirToDirCommit_t, send, fs::fileDrawFunc); +} + +void fs::getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize) +{ + fs::dirList *d = new fs::dirList(path); + for(unsigned i = 0; i < d->getCount(); i++) + { + if(d->isDir(i)) + { + ++dirCount; + std::string newPath = path + d->getItem(i) + "/"; + fs::getDirProps(newPath, dirCount, fileCount, totalSize); + } + else + { + ++fileCount; + std::string filePath = path + d->getItem(i); + totalSize += fs::fsize(filePath); + } + } + delete d; +} + +fs::dirItem::dirItem(const std::string& pathTo, const std::string& sItem) +{ + itm = sItem; + + std::string fullPath = pathTo + sItem; + struct stat s; + if(stat(fullPath.c_str(), &s) == 0 && S_ISDIR(s.st_mode)) + dir = true; +} + +std::string fs::dirItem::getName() const +{ + size_t extPos = itm.find_last_of('.'), slPos = itm.find_last_of('/'); + if(extPos == itm.npos) + return ""; + + return itm.substr(slPos + 1, extPos); +} + +std::string fs::dirItem::getExt() const +{ + return util::getExtensionFromString(itm); +} + +fs::dirList::dirList(const std::string& _path) +{ + DIR *d; + struct dirent *ent; + path = _path; + d = opendir(path.c_str()); + + while((ent = readdir(d))) + item.emplace_back(path, ent->d_name); + + closedir(d); + + std::sort(item.begin(), item.end(), sortDirList); +} + +void fs::dirList::reassign(const std::string& _path) +{ + DIR *d; + struct dirent *ent; + path = _path; + + d = opendir(path.c_str()); + + item.clear(); + + while((ent = readdir(d))) + item.emplace_back(path, ent->d_name); + + closedir(d); + + std::sort(item.begin(), item.end(), sortDirList); +} + +void fs::dirList::rescan() +{ + item.clear(); + DIR *d; + struct dirent *ent; + d = opendir(path.c_str()); + + while((ent = readdir(d))) + item.emplace_back(path, ent->d_name); + + closedir(d); + + std::sort(item.begin(), item.end(), sortDirList); +} diff --git a/src/fs/file.cpp b/src/fs/file.cpp new file mode 100644 index 0000000..50887c6 --- /dev/null +++ b/src/fs/file.cpp @@ -0,0 +1,409 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fs.h" +#include "util.h" +#include "ui.h" +#include "gfx.h" +#include "data.h" +#include "cfg.h" + +static std::string wd = "sdmc:/JKSV/"; + +static std::vector pathFilter; + +fs::copyArgs *fs::copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces) +{ + copyArgs *ret = new copyArgs; + ret->src = src; + ret->dst = dst; + ret->dev = dev; + ret->z = z; + ret->unz = unz; + ret->cleanup = _cleanup; + ret->prog = new ui::progBar; + ret->prog->setMax(0); + ret->prog->update(0); + ret->offset = 0; + ret->trimZipPath = _trimZipPath; + ret->trimZipPlaces = _trimPlaces; + return ret; +} + +void fs::copyArgsDestroy(copyArgs *c) +{ + delete c->prog; + delete c; + c = NULL; +} + +fs::dataFile::dataFile(const std::string& _path) +{ + f = fopen(_path.c_str(), "r"); + if(f != NULL) + opened = true; +} + +fs::dataFile::~dataFile() +{ + fclose(f); +} + +bool fs::dataFile::readNextLine(bool proc) +{ + bool ret = false; + char tmp[1024]; + while(fgets(tmp, 1024, f)) + { + if(tmp[0] != '#' && tmp[0] != '\n' && tmp[0] != '\r') + { + line = tmp; + ret = true; + break; + } + } + util::stripChar('\n', line); + util::stripChar('\r', line); + if(proc) + procLine(); + + return ret; +} + +void fs::dataFile::procLine() +{ + size_t pPos = line.find_first_of("(=,"); + if(pPos != line.npos) + { + lPos = pPos; + name.assign(line.begin(), line.begin() + lPos); + } + else + name = line; + + util::stripChar(' ', name); + ++lPos; +} + +std::string fs::dataFile::getNextValueStr() +{ + std::string ret = ""; + //Skip all spaces until we hit actual text + size_t pos1 = line.find_first_not_of(", ", lPos); + //If reading from quotes + if(line[pos1] == '"') + lPos = line.find_first_of('"', ++pos1); + else + lPos = line.find_first_of(",;\n", pos1);//Set lPos to end of string we want. This should just set lPos to the end of the line if it fails, which is ok + + ret = line.substr(pos1, lPos++ - pos1); + + util::replaceStr(ret, "\\n", "\n"); + + return ret; +} + +int fs::dataFile::getNextValueInt() +{ + int ret = 0; + std::string no = getNextValueStr(); + if(no[0] == '0' && tolower(no[1]) == 'x') + ret = strtoul(no.c_str(), NULL, 16); + else + ret = strtoul(no.c_str(), NULL, 10); + + return ret; +} + +void fs::copyFile(const std::string& src, const std::string& dst, threadInfo *t) +{ + fs::copyArgs *c = NULL; + if(t) + { + c = (fs::copyArgs *)t->argPtr; + c->offset = 0; + c->prog->setMax(fs::fsize(src)); + c->prog->update(0); + } + + if(cfg::config["directFsCmd"]) + { + FSFILE *fsrc = fsfopen(src.c_str(), FsOpenMode_Read); + FSFILE *fdst = fsfopen(dst.c_str(), FsOpenMode_Write); + + if(!fsrc || !fdst) + { + fsfclose(fsrc); + fsfclose(fdst); + return; + } + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + size_t readIn = 0; + while((readIn = fsfread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + fsfwrite(buff, 1, readIn, fdst); + if(c) + c->offset += readIn; + } + fsfclose(fsrc); + fsfclose(fdst); + delete[] buff; + } + else + { + FILE *fsrc = fopen(src.c_str(), "rb"); + FILE *fdst = fopen(dst.c_str(), "wb"); + + if(!fsrc || !fdst) + { + fclose(fsrc); + fclose(fdst); + return; + } + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + size_t readIn = 0; + while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + fwrite(buff, 1, readIn, fdst); + if(c) + c->offset += readIn; + } + fclose(fsrc); + fclose(fdst); + delete[] buff; + } +} + +static void copyFileThreaded_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + + t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), in->src); + + fs::copyFile(in->src, in->dst, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + t->finished = true; +} + +void fs::copyFileThreaded(const std::string& src, const std::string& dst) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0); + ui::newThread(copyFileThreaded_t, send, fs::fileDrawFunc); +} + +void fs::copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t) +{ + fs::copyArgs *c = NULL; + if(t) + { + c = (fs::copyArgs *)t->argPtr; + c->offset = 0; + c->prog->setMax(fs::fsize(src)); + c->prog->update(0); + } + + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + uint64_t journ = fs::getJournalSize(utinfo); + if(cfg::config["directFsCmd"]) + { + FSFILE *fsrc = fsfopen(src.c_str(), FsOpenMode_Read); + FSFILE *fdst = fsfopen(dst.c_str(), FsOpenMode_Write); + + if(!fsrc || !fdst) + { + fsfclose(fsrc); + fsfclose(fdst); + return; + } + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + size_t readIn = 0, writeCount = 0; + while((readIn = fsfread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + fsfwrite(buff, 1, readIn, fdst); + writeCount += readIn; + if(c) + c->offset += readIn; + + if(writeCount >= (journ - 0x100000)) + { + writeCount = 0; + fsfclose(fdst); + if(!fs::commitToDevice(dev.c_str())) + break; + + fdst = fsfopen(dst.c_str(), FsOpenMode_Write | FsOpenMode_Append); + } + } + fsfclose(fsrc); + fsfclose(fdst); + fs::commitToDevice(dev); + delete[] buff; + } + else + { + FILE *fsrc = fopen(src.c_str(), "rb"); + FILE *fdst = fopen(dst.c_str(), "wb"); + + if(!fsrc || !fdst) + { + fclose(fsrc); + fclose(fdst); + return; + } + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + size_t readIn = 0, writeCount = 0; + while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + fwrite(buff, 1, readIn, fdst); + writeCount += readIn; + if(c) + c->offset += readIn; + + if(writeCount >= (journ - 0x100000)) + { + writeCount = 0; + fclose(fdst); + if(!fs::commitToDevice(dev)) + break; + + fdst = fopen(dst.c_str(), "ab"); + } + } + fclose(fsrc); + fclose(fdst); + fs::commitToDevice(dev); + delete[] buff; + } +} + +static void copyFileCommit_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + + t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), in->src); + in->prog->setMax(fs::fsize(in->src)); + in->prog->update(0); + + fs::copyFileCommit(in->src, in->dst, in->dev, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + + t->finished = true; +} + +void fs::copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0); + ui::newThread(copyFileCommit_t, send, fs::fileDrawFunc); +} + +void fs::fileDrawFunc(void *a) +{ + threadInfo *t = (threadInfo *)a; + if(!t->finished) + { + copyArgs *c = (copyArgs *)t->argPtr; + std::string tmp; + t->status->getStatus(tmp); + c->argLock(); + c->prog->update(c->offset); + c->prog->draw(tmp); + c->argUnlock(); + } +} + +void fs::delfile(const std::string& path) +{ + if(cfg::config["directFsCmd"]) + fsremove(path.c_str()); + else + remove(path.c_str()); +} + +void fs::loadPathFilters(const uint64_t& tid) +{ + char path[256]; + sprintf(path, "sdmc:/config/JKSV/0x%016lX_filter.txt", tid); + if(fs::fileExists(path)) + { + fs::dataFile filter(path); + while(filter.readNextLine(false)) + pathFilter.push_back(filter.getLine()); + } +} + +bool fs::pathIsFiltered(const std::string& _path) +{ + if(pathFilter.empty()) + return false; + + for(std::string& _p : pathFilter) + { + if(_path == _p) + return true; + } + + return false; +} + +void fs::freePathFilters() +{ + pathFilter.clear(); +} + +void fs::dumpAllUserSaves() +{ + //This is only really used for the progress bar + /*fs::copyArgs *send = fs::copyArgsCreate("", "", "", NULL, NULL, true, false, 0); + ui::newThread(fs::backupUserSaves_t, send, _fileDrawFunc);*/ +} + +void fs::getShowFileProps(const std::string& _path) +{ + size_t size = fs::fsize(_path); + ui::showMessage(ui::getUICString("fileModeFileProperties", 0), _path.c_str(), util::getSizeString(size).c_str()); +} + +void fs::getShowDirProps(const std::string& _path) +{ + fs::dirCountArgs *send = new fs::dirCountArgs; + send->path = _path; + send->origin = true; +// ui::newThread(fs::getShowDirProps_t, send, NULL); +} + +bool fs::fileExists(const std::string& path) +{ + bool ret = false; + FILE *test = fopen(path.c_str(), "rb"); + if(test != NULL) + ret = true; + fclose(test); + return ret; +} + +size_t fs::fsize(const std::string& _f) +{ + size_t ret = 0; + FILE *get = fopen(_f.c_str(), "rb"); + if(get != NULL) + { + fseek(get, 0, SEEK_END); + ret = ftell(get); + } + fclose(get); + return ret; +} diff --git a/src/fsfile.c b/src/fs/fsfile.c similarity index 99% rename from src/fsfile.c rename to src/fs/fsfile.c index 3c350ac..d0b7d52 100644 --- a/src/fsfile.c +++ b/src/fs/fsfile.c @@ -3,7 +3,7 @@ #include #include -#include "fsfile.h" +#include "fs/fsfile.h" char *getDeviceFromPath(char *dev, size_t _max, const char *path) { diff --git a/src/fs/zip.cpp b/src/fs/zip.cpp new file mode 100644 index 0000000..2aa9c06 --- /dev/null +++ b/src/fs/zip.cpp @@ -0,0 +1,185 @@ +#include +#include + +#include "fs.h" +#include "util.h" + +void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t) +{ + fs::copyArgs *c = NULL; + if(t) + { + t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), src.c_str()); + c = (fs::copyArgs *)t->argPtr; + } + + fs::dirList *list = new fs::dirList(src); + for(unsigned i = 0; i < list->getCount(); i++) + { + std::string itm = list->getItem(i); + if(fs::pathIsFiltered(src + itm)) + continue; + + if(list->isDir(i)) + { + std::string newSrc = src + itm + "/"; + fs::copyDirToZip(newSrc, dst, trimPath, trimPlaces, t); + } + else + { + time_t raw; + time(&raw); + tm *locTime = localtime(&raw); + zip_fileinfo inf = { (unsigned)locTime->tm_sec, (unsigned)locTime->tm_min, (unsigned)locTime->tm_hour, + (unsigned)locTime->tm_mday, (unsigned)locTime->tm_mon, (unsigned)(1900 + locTime->tm_year), 0, 0, 0 }; + + std::string filename = src + itm; + size_t zipNameStart = 0; + if(trimPath) + util::trimPath(filename, trimPlaces); + else + zipNameStart = filename.find_first_of('/') + 1; + + if(t) + t->status->setStatus(ui::getUICString("threadStatusAddingFileToZip", 0), itm.c_str()); + + int zipOpenFile = zipOpenNewFileInZip64(dst, filename.substr(zipNameStart, filename.npos).c_str(), &inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0); + if(zipOpenFile == ZIP_OK) + { + std::string fullSrc = src + itm; + if(c) + { + c->offset = 0; + c->prog->setMax(fs::fsize(fullSrc)); + c->prog->update(0); + } + + FILE *fsrc = fopen(fullSrc.c_str(), "rb"); + size_t readIn = 0; + uint8_t *buff = new uint8_t[BUFF_SIZE]; + while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + zipWriteInFileInZip(dst, buff, readIn); + if(c) + c->offset += readIn; + } + delete[] buff; + fclose(fsrc); + } + } + } +} + +void copyDirToZip_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *c = (fs::copyArgs *)t->argPtr; + fs::copyDirToZip(c->src, c->z, c->trimZipPath, c->trimZipPlaces, t); + if(c->cleanup) + { + zipClose(c->z, NULL); + delete c; + } + t->finished = true; +} + +void fs::copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, "", "", dst, NULL, true, false, 0); + ui::newThread(copyDirToZip_t, send, fs::fileDrawFunc); +} + +void fs::copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t) +{ + fs::copyArgs *c = NULL; + if(t) + c = (fs::copyArgs *)t->argPtr; + + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + uint64_t journalSize = getJournalSize(utinfo), writeCount = 0; + char filename[FS_MAX_PATH]; + uint8_t *buff = new uint8_t[BUFF_SIZE]; + int readIn = 0; + unz_file_info64 info; + do + { + unzGetCurrentFileInfo64(src, &info, filename, FS_MAX_PATH, NULL, 0, NULL, 0); + if(unzOpenCurrentFile(src) == UNZ_OK) + { + if(t) + t->status->setStatus(ui::getUICString("threadStatusDecompressingFile", 0), filename); + + if(c) + { + c->prog->setMax(info.uncompressed_size); + c->prog->update(0); + c->offset = 0; + } + + std::string fullDst = dst + filename; + fs::mkDirRec(fullDst.substr(0, fullDst.find_last_of('/') + 1)); + + FILE *fdst = fopen(fullDst.c_str(), "wb"); + while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0) + { + c->offset += readIn; + writeCount += readIn; + fwrite(buff, 1, readIn, fdst); + if(writeCount >= journalSize - 0x100000) + { + writeCount = 0; + fclose(fdst); + if(!fs::commitToDevice(dev)) + break; + + fdst = fopen(fullDst.c_str(), "ab"); + } + } + fclose(fdst); + fs::commitToDevice(dev); + } + } + while(unzGoToNextFile(src) != UNZ_END_OF_LIST_OF_FILE); + delete[] buff; +} + +static void copyZipToDir_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *c = (fs::copyArgs *)t->argPtr; + fs::copyZipToDir(c->unz, c->dst, c->dev, t); + if(c->cleanup) + { + unzClose(c->unz); + delete c; + } + t->finished = true; +} + +void fs::copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev) +{ + fs::copyArgs *send = fs::copyArgsCreate("", dst, dev, NULL, src, true, false, 0); + ui::newThread(copyZipToDir_t, send, fs::fileDrawFunc); +} + +uint64_t fs::getZipTotalSize(unzFile unz) +{ + uint64_t ret = 0; + if(unzGoToFirstFile(unz) == UNZ_OK) + { + unz_file_info64 finfo; + char filename[FS_MAX_PATH]; + do + { + unzGetCurrentFileInfo64(unz, &finfo, filename, FS_MAX_PATH, NULL, 0, NULL, 0); + ret += finfo.uncompressed_size; + } while(unzGoToNextFile(unz) != UNZ_END_OF_LIST_OF_FILE); + unzGoToFirstFile(unz); + } + return ret; +} + +bool fs::zipNotEmpty(unzFile unz) +{ + return unzGoToFirstFile(unz) == UNZ_OK; +} diff --git a/src/fsthrd.cpp b/src/fsthrd.cpp deleted file mode 100644 index 2079c29..0000000 --- a/src/fsthrd.cpp +++ /dev/null @@ -1,708 +0,0 @@ -#include - -#include "file.h" -#include "util.h" -#include "cfg.h" - -static uint64_t getJournalSize(const data::titleInfo *t) -{ - uint64_t journalSize = 0; - data::userTitleInfo *d = data::getCurrentUserTitleInfo(); - switch(d->saveInfo.save_data_type) - { - case FsSaveDataType_Account: - journalSize = t->nacp.user_account_save_data_journal_size; - break; - - case FsSaveDataType_Device: - journalSize = t->nacp.device_save_data_journal_size; - break; - - case FsSaveDataType_Bcat: - journalSize = t->nacp.bcat_delivery_cache_storage_size; - break; - - case FsSaveDataType_Cache: - if(t->nacp.cache_storage_journal_size > 0) - journalSize = t->nacp.cache_storage_journal_size; - else - journalSize = t->nacp.cache_storage_data_and_journal_size_max; - break; - - default: - journalSize = BUFF_SIZE; - break; - } - return journalSize; -} - -void fs::_fileDrawFunc(void *a) -{ - threadInfo *t = (threadInfo *)a; - if(!t->finished) - { - copyArgs *c = (copyArgs *)t->argPtr; - std::string tmp; - t->status->getStatus(tmp); - c->argLock(); - c->prog->draw(tmp); - c->argUnlock(); - } -} - -void fs::createSaveData_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - fs::svCreateArgs *s = (fs::svCreateArgs *)t->argPtr; - - data::titleInfo *create = data::getTitleInfoByTID(s->tid); - t->status->setStatus(ui::getUICString("threadStatusCreatingSaveData", 0), create->title.c_str()); - - FsSaveDataAttribute attr; - memset(&attr, 0, sizeof(FsSaveDataAttribute)); - attr.application_id = s->tid; - attr.uid = s->account; - attr.system_save_data_id = 0; - attr.save_data_type = s->type; - attr.save_data_rank = 0; - attr.save_data_index = s->index; - - FsSaveDataCreationInfo svCreate; - memset(&svCreate, 0, sizeof(FsSaveDataCreationInfo)); - int64_t saveSize = 0, journalSize = 0; - switch(s->type) - { - case FsSaveDataType_Account: - saveSize = create->nacp.user_account_save_data_size; - journalSize = create->nacp.user_account_save_data_journal_size; - break; - - case FsSaveDataType_Device: - saveSize = create->nacp.device_save_data_size; - journalSize = create->nacp.device_save_data_journal_size; - break; - - case FsSaveDataType_Bcat: - saveSize = create->nacp.bcat_delivery_cache_storage_size; - journalSize = create->nacp.bcat_delivery_cache_storage_size; - break; - - case FsSaveDataType_Cache: - saveSize = 32 * 1024 * 1024;//Todo: Add target folder/zip selection for size - if(create->nacp.cache_storage_journal_size > create->nacp.cache_storage_data_and_journal_size_max) - journalSize = create->nacp.cache_storage_journal_size; - else - journalSize = create->nacp.cache_storage_data_and_journal_size_max; - break; - - default: - delete s; - t->finished = true; - return; - break; - } - svCreate.save_data_size = saveSize; - svCreate.journal_size = journalSize; - svCreate.available_size = 0x4000; - svCreate.owner_id = s->type == FsSaveDataType_Bcat ? 0x010000000000000C : create->nacp.save_data_owner_id; - svCreate.flags = 0; - svCreate.save_data_space_id = FsSaveDataSpaceId_User; - - FsSaveDataMetaInfo meta; - memset(&meta, 0, sizeof(FsSaveDataMetaInfo)); - if(s->type != FsSaveDataType_Bcat) - { - meta.size = 0x40060; - meta.type = FsSaveDataMetaType_Thumbnail; - } - - Result res = 0; - if(R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &svCreate, &meta))) - { - util::createTitleDirectoryByTID(s->tid); - data::loadUsersTitles(false); - ui::ttlRefresh(); - } - else - { - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataCreationFailed", 0)); - fs::logWrite("SaveCreate Failed -> %X\n", res); - } - delete s; - t->finished = true; -} - -void fs::copyFile_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - copyArgs *args = (copyArgs *)t->argPtr; - t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), args->from.c_str()); - - args->prog->setMax(fs::fsize(args->from)); - args->prog->update(0); - - uint8_t *buff = new uint8_t[BUFF_SIZE]; - if(cfg::config["directFsCmd"]) - { - FSFILE *in = fsfopen(args->from.c_str(), FsOpenMode_Read); - FSFILE *out = fsfopen(args->to.c_str(), FsOpenMode_Write); - - if(!in || !out) - { - fsfclose(in); - fsfclose(out); - t->finished = true; - return; - } - size_t readIn = 0; - while((readIn = fsfread(buff, 1, BUFF_SIZE, in)) > 0) - { - fsfwrite(buff, 1, readIn, out); - args->argLock(); - args->offset = in->offset; - args->prog->update(args->offset); - args->argUnlock(); - } - fsfclose(in); - fsfclose(out); - } - else - { - FILE *in = fopen(args->from.c_str(), "rb"); - FILE *out = fopen(args->to.c_str(), "wb"); - if(!in || !out) - { - fclose(in); - fclose(out); - t->finished = true; - return; - } - - size_t readIn = 0; - while((readIn = fread(buff, 1, BUFF_SIZE, in)) > 0) - { - fwrite(buff, 1, readIn, out); - args->argLock(); - args->offset = ftell(in); - args->prog->update(args->offset); - args->argUnlock(); - } - fclose(in); - fclose(out); - } - delete[] buff; - if(args->cleanup) - copyArgsDestroy(args); - t->finished = true; -} - -void fs::copyFileCommit_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - copyArgs *args = (copyArgs *)t->argPtr; - data::userTitleInfo *d = data::getCurrentUserTitleInfo(); - data::titleInfo *info = data::getTitleInfoByTID(d->tid); - t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), args->from.c_str()); - - args->prog->setMax(fs::fsize(args->from)); - args->prog->update(0); - - uint64_t journalSize = getJournalSize(info), writeCount = 0; - uint8_t *buff = new uint8_t[BUFF_SIZE]; - - if(cfg::config["directFsCmd"]) - { - FSFILE *in = fsfopen(args->from.c_str(), FsOpenMode_Read); - FSFILE *out = fsfopen(args->to.c_str(), FsOpenMode_Write); - - if(!in || !out) - { - fsfclose(in); - fsfclose(out); - t->finished = true; - return; - } - - size_t readIn = 0; - while((readIn = fsfread(buff, 1, BUFF_SIZE, in)) > 0) - { - fsfwrite(buff, 1, readIn, out); - writeCount += readIn; - if(writeCount >= (journalSize - 0x100000)) - { - writeCount = 0; - fsfclose(out); - if(!commitToDevice(args->dev)) - break; - - out = fsfopen(args->to.c_str(), FsOpenMode_Write | FsOpenMode_Append); - } - args->argLock(); - args->offset = out->offset; - args->prog->update(args->offset); - args->argUnlock(); - } - fsfclose(in); - fsfclose(out); - } - else - { - FILE *in = fopen(args->from.c_str(), "rb"); - FILE *out = fopen(args->to.c_str(), "wb"); - - if(!in || !out) - { - fclose(in); - fclose(out); - t->finished = true; - return; - } - - size_t readIn = 0; - while((readIn = fread(buff, 1, BUFF_SIZE, in)) > 0) - { - fwrite(buff, 1, readIn, out); - writeCount += readIn; - if(writeCount >= (journalSize - 0x100000)) - { - writeCount = 0; - fclose(out); - if(!commitToDevice(args->dev)) - break; - - out = fopen(args->to.c_str(), "ab"); - } - args->argLock(); - args->offset = ftell(out); - args->prog->update(args->offset); - args->argUnlock(); - } - fclose(in); - fclose(out); - } - delete[] buff; - - commitToDevice(args->dev.c_str()); - - if(args->cleanup) - copyArgsDestroy(args); - t->finished = true; -} - -void fs::copyDirToDir_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - copyArgs *args = (copyArgs *)t->argPtr; - - fs::dirList *list = new fs::dirList(args->from); - for(int i = 0; i < (int)list->getCount(); i++) - { - if(pathIsFiltered(args->from + list->getItem(i))) - continue; - - if(list->isDir(i)) - { - std::string newSrc = args->from + list->getItem(i) + "/"; - std::string newDst = args->to + list->getItem(i) + "/"; - fs::mkDir(newDst.substr(0, newDst.length() - 1)); - - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - tmpArgs->from = newSrc; - tmpArgs->to = newDst; - tmpArgs->prog = args->prog; - tmpArgs->cleanup = false; - fs::copyDirToDir_t(fakeThread); - delete fakeThread; - delete tmpArgs; - } - else - { - std::string fullSrc = args->from + list->getItem(i); - std::string fullDst = args->to + list->getItem(i); - - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - tmpArgs->from = fullSrc; - tmpArgs->to = fullDst; - tmpArgs->prog = args->prog; - tmpArgs->cleanup = false; - fs::copyFile_t(fakeThread); - delete fakeThread; - delete tmpArgs; - } - } - - delete list; - - if(args->cleanup) - copyArgsDestroy(args); - - t->finished = true; -} - -void fs::copyDirToDirCommit_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - copyArgs *args = (copyArgs *)t->argPtr; - - fs::dirList *list = new fs::dirList(args->from); - for(int i = 0; i < (int)list->getCount(); i++) - { - if(pathIsFiltered(args->from + list->getItem(i))) - continue; - - if(list->isDir(i)) - { - std::string newSrc = args->from + list->getItem(i) + "/"; - std::string newDst = args->to + list->getItem(i) + "/"; - fs::mkDir(newDst.substr(0, newDst.length() - 1)); - - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - tmpArgs->from = newSrc; - tmpArgs->to = newDst; - tmpArgs->dev = args->dev; - tmpArgs->prog = args->prog; - tmpArgs->cleanup = false; - fs::copyDirToDirCommit_t(fakeThread); - delete fakeThread; - delete tmpArgs; - } - else - { - std::string fullSrc = args->from + list->getItem(i); - std::string fullDst = args->to + list->getItem(i); - - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - tmpArgs->from = fullSrc; - tmpArgs->to = fullDst; - tmpArgs->dev = args->dev; - tmpArgs->prog = args->prog; - tmpArgs->cleanup = false; - fs::copyFileCommit_t(fakeThread); - delete fakeThread; - delete tmpArgs; - } - } - - delete list; - - if(args->cleanup) - copyArgsDestroy(args); - - t->finished = true; -} - -void fs::copyDirToZip_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - copyArgs *args = (copyArgs *)t->argPtr; - bool trimPath = args->trimZipPath; - uint8_t trimPlaces = args->trimZipPlaces; - - t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), args->from.c_str()); - fs::dirList *list = new fs::dirList(args->from); - - unsigned listTotal = list->getCount(); - for(unsigned i = 0; i < listTotal; i++) - { - std::string itm = list->getItem(i); - if(fs::pathIsFiltered(args->from + itm)) - continue; - - if(list->isDir(i)) - { - std::string newFrom = args->from + itm + "/"; - //Fake thread and new args to point to src thread stuff - //This wouldn't work spawning a new thread. - threadInfo *tmpThread = new threadInfo; - tmpThread->status = t->status; - fs::copyArgs *tmpArgs = new fs::copyArgs; - tmpArgs->from = newFrom; - tmpArgs->prog = args->prog; - tmpArgs->z = args->z; - tmpArgs->cleanup = false; - tmpArgs->trimZipPath = args->trimZipPath; - tmpArgs->trimZipPlaces = args->trimZipPlaces; - tmpThread->argPtr = tmpArgs; - copyDirToZip_t(tmpThread); - delete tmpThread; - delete tmpArgs; - } - else - { - time_t raw; - time(&raw); - tm *locTime = localtime(&raw); - - zip_fileinfo inf = { (unsigned)locTime->tm_sec, (unsigned)locTime->tm_min, (unsigned)locTime->tm_hour, - (unsigned)locTime->tm_mday, (unsigned)locTime->tm_mon, (unsigned)(1900 + locTime->tm_year), 0, 0, 0 }; - - std::string filename = args->from + itm; - size_t zipFileNameStart = 0; - if(trimPath) - util::trimPath(filename, trimPlaces); - else - zipFileNameStart = filename.find_first_of('/') + 1; - t->status->setStatus(ui::getUICString("threadStatusAddingFileToZip", 0), itm.c_str()); - int zOpenFile = zipOpenNewFileInZip64(args->z, filename.substr(zipFileNameStart, filename.length()).c_str(), &inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0); - if(zOpenFile == ZIP_OK) - { - std::string fullFrom = args->from + itm; - args->prog->setMax(fs::fsize(fullFrom)); - args->prog->update(0); - args->offset = 0; - FILE *cpy = fopen(fullFrom.c_str(), "rb"); - size_t readIn = 0; - uint8_t *buff = new uint8_t[BUFF_SIZE]; - while((readIn = fread(buff, 1, BUFF_SIZE, cpy)) > 0) - { - zipWriteInFileInZip(args->z, buff, readIn); - args->offset += readIn; - args->prog->update(args->offset); - } - delete[] buff; - fclose(cpy); - zipCloseFileInZip(args->z); - } - } - } - delete list; - if(args->cleanup) - { - if(cfg::config["ovrClk"]) - util::setCPU(util::CPU_SPEED_1224MHz); - ui::newThread(closeZip_t, args->z, NULL); - delete args->prog; - delete args; - } - t->finished = true; -} - -void fs::copyZipToDir_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - copyArgs *args = (copyArgs *)t->argPtr; - - data::userTitleInfo *d = data::getCurrentUserTitleInfo(); - data::titleInfo *tinfo = data::getTitleInfoByTID(d->tid); - uint64_t journalSize = getJournalSize(tinfo), writeCount = 0; - char filename[FS_MAX_PATH]; - uint8_t *buff = new uint8_t[BUFF_SIZE]; - int readIn = 0; - unz_file_info64 info; - do - { - unzGetCurrentFileInfo64(args->unz, &info, filename, FS_MAX_PATH, NULL, 0, NULL, 0); - if(unzOpenCurrentFile(args->unz) == UNZ_OK) - { - t->status->setStatus(ui::getUICString("threadStatusDecompressingFile", 0), filename); - std::string path = args->to + filename; - mkDirRec(path.substr(0, path.find_last_of('/') + 1)); - - args->prog->setMax(info.uncompressed_size); - args->prog->update(0); - args->offset = 0; - size_t done = 0; - if(cfg::config["directFsCmd"]) - { - FSFILE *out = fsfopen(path.c_str(), FsOpenMode_Write); - while((readIn = unzReadCurrentFile(args->unz, buff, BUFF_SIZE)) > 0) - { - done += readIn; - writeCount += readIn; - args->offset += readIn; - args->prog->update(args->offset); - fsfwrite(buff, 1, readIn, out); - if(writeCount >= (journalSize - 0x100000)) - { - writeCount = 0; - fsfclose(out); - if(!commitToDevice(args->dev.c_str())) - break; - - out = fsfopen(path.c_str(), FsOpenMode_Write | FsOpenMode_Append); - } - } - fsfclose(out); - } - else - { - FILE *out = fopen(path.c_str(), "wb"); - - while((readIn = unzReadCurrentFile(args->unz, buff, BUFF_SIZE)) > 0) - { - done += readIn; - writeCount += readIn; - args->offset += readIn; - args->prog->update(args->offset); - fwrite(buff, 1, readIn, out); - if(writeCount >= (journalSize - 0x100000)) - { - writeCount = 0; - fclose(out); - if(!commitToDevice(args->dev.c_str())) - break; - - out = fopen(path.c_str(), "ab"); - } - } - fclose(out); - } - unzCloseCurrentFile(args->unz); - commitToDevice(args->dev.c_str()); - } - } - while(unzGoToNextFile(args->unz) != UNZ_END_OF_LIST_OF_FILE); - - if(args->cleanup) - { - unzClose(args->unz); - copyArgsDestroy(args); - if(cfg::config["ovrClk"]) - util::setCPU(util::CPU_SPEED_1224MHz); - } - delete[] buff; - t->finished = true; -} - -void fs::wipesave_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0)); - fs::delDir("sv:/"); - fs::commitToDevice("sv"); - t->finished = true; -} - -void fs::closeZip_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - zipFile z = t->argPtr; - zipClose(z, NULL); - t->finished = true; -} - -void fs::backupUserSaves_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - fs::copyArgs *c = (fs::copyArgs *)t->argPtr; - data::user *u = data::getCurrentUser(); - - if(cfg::config["ovrClk"] && cfg::config["zip"]) - { - util::setCPU(util::CPU_SPEED_1785MHz); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0)); - } - - for(unsigned i = 0; i < u->titleInfo.size(); i++) - { - std::string title = data::getTitleNameByTID(u->titleInfo[i].tid); - t->status->setStatus(std::string("#" + title + "#").c_str()); - if((ui::padKeysDown() & HidNpadButton_B) || (ui::padKeysHeld() & HidNpadButton_B)) - { - delete c; - t->finished = true; - return; - } - - bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo); - util::createTitleDirectoryByTID(u->titleInfo[i].tid); - if(saveMounted && cfg::config["zip"] && fs::dirNotEmpty("sv:/")) - { - fs::loadPathFilters(u->titleInfo[i].tid); - std::string outPath = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + ".zip"; - zipFile zip = zipOpen64(outPath.c_str(), 0); - - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - tmpArgs->from = "sv:/"; - tmpArgs->z = zip; - tmpArgs->cleanup = false; - tmpArgs->prog = c->prog; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - copyDirToZip_t(fakeThread); - zipClose(zip, NULL); - fs::freePathFilters(); - delete fakeThread; - delete tmpArgs; - } - else if(saveMounted && fs::dirNotEmpty("sv:/")) - { - fs::loadPathFilters(u->titleInfo[i].tid); - std::string outPath = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD) + "/"; - fs::mkDir(outPath.substr(0, outPath.length() - 1)); - - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - tmpArgs->from = "sv:/"; - tmpArgs->to = outPath; - tmpArgs->cleanup = false; - tmpArgs->prog = c->prog; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - copyDirToDir_t(fakeThread); - fs::freePathFilters(); - delete fakeThread; - delete tmpArgs; - } - fs::unmountSave(); - } - delete c; - if(cfg::config["ovrClk"] && cfg::config["zip"]) - util::setCPU(util::CPU_SPEED_1224MHz); - - t->finished = true; -} - -void fs::getShowDirProps_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - fs::dirCountArgs *d = (fs::dirCountArgs *)t->argPtr; - - t->status->setStatus(ui::getUICString("threadStatusGetDirProps", 0)); - - fs::dirList *dir = new fs::dirList(d->path); - for(unsigned i = 0; i < dir->getCount(); i++) - { - if(dir->isDir(i)) - { - d->dirCount++; - threadInfo *fakeThread = new threadInfo; - dirCountArgs *tmpArgs = new dirCountArgs; - tmpArgs->path = d->path + dir->getItem(i) + "/"; - tmpArgs->origin = false; - fakeThread->status = t->status; - fakeThread->argPtr = tmpArgs; - getShowDirProps_t(fakeThread); - d->dirCount += tmpArgs->dirCount; - d->fileCount += tmpArgs->fileCount; - d->totalSize += tmpArgs->totalSize; - delete fakeThread; - delete tmpArgs; - } - else - { - std::string filePath = d->path + dir->getItem(i); - d->fileCount++; - d->totalSize += fs::fsize(filePath); - } - } - if(d->origin) - { - ui::showMessage(ui::getUICString("fileModeFolderProperties", 0), d->path.c_str(), d->dirCount, d->fileCount, util::getSizeString(d->totalSize).c_str()); - delete d; - } - t->finished = true; -} diff --git a/src/main.cpp b/src/main.cpp index 52e0664..d90c780 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,5 +55,4 @@ int main(int argc, const char *argv[]) ui::exit(); data::exit(); gfx::exit(); - fs::exit(); } diff --git a/src/ui/ext.cpp b/src/ui/ext.cpp index 20af02f..b899e76 100644 --- a/src/ui/ext.cpp +++ b/src/ui/ext.cpp @@ -148,7 +148,6 @@ static void extMenuPackJKSVZip_t(void *a) fs::dirList *jksv = new fs::dirList(fs::getWorkDir()); uint8_t pathTrimPlaces = util::getTotalPlacesInPath(fs::getWorkDir()); - fs::logWrite("pathTrimPlaces = %u\n", pathTrimPlaces); size_t dirCount = jksv->getCount(); if(dirCount > 0) { @@ -159,18 +158,7 @@ static void extMenuPackJKSVZip_t(void *a) if(jksv->isDir(i) && jksv->getItem(i) != "_TRASH_") { std::string srcPath = fs::getWorkDir() + jksv->getItem(i) + "/"; - threadInfo *fakeThread = new threadInfo; - fs::copyArgs *tmpArgs = new fs::copyArgs; - tmpArgs->from = srcPath; - tmpArgs->z = zip; - tmpArgs->prog = c->prog; - tmpArgs->trimZipPath = true; - tmpArgs->trimZipPlaces = pathTrimPlaces; - fakeThread->argPtr = tmpArgs; - fakeThread->status = t->status; - fs::copyDirToZip_t(fakeThread); - delete tmpArgs; - delete fakeThread; + fs::copyDirToZip(srcPath, zip, true, pathTrimPlaces, t); } } zipClose(zip, NULL); @@ -187,7 +175,7 @@ static void extMenuPackJKSV(void *a) { //Only for progress bar fs::copyArgs *send = fs::copyArgsCreate("", "", "", NULL, NULL, true, false, 0); - ui::newThread(extMenuPackJKSVZip_t, send, fs::_fileDrawFunc); + ui::newThread(extMenuPackJKSVZip_t, send, fs::fileDrawFunc); } static void extMenuOutputEnUs(void *a) diff --git a/src/ui/fm.cpp b/src/ui/fm.cpp index 225ae29..e0a4d4b 100644 --- a/src/ui/fm.cpp +++ b/src/ui/fm.cpp @@ -17,8 +17,8 @@ typedef struct { std::string *path; - //These can hold the same info needed for the listing menus so might as well use em - fs::backupArgs *b; + ui::menu *m; + fs::dirList *d; } menuFuncArgs; static ui::slideOutPanel *devPanel, *sdPanel; @@ -37,13 +37,14 @@ static void refreshMenu(void *a) { threadInfo *t = (threadInfo *)a; menuFuncArgs *ma = (menuFuncArgs *)t->argPtr; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - b->d->reassign(*ma->path); - util::copyDirListToMenu(*b->d, *b->m); - for(int i = 1; i < b->m->getCount(); i++) + d->reassign(*ma->path); + util::copyDirListToMenu(*d, *m); + for(int i = 1; i < m->getCount(); i++) { - b->m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma); + m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma); } t->finished = true; } @@ -135,53 +136,53 @@ static void _sdCopyPanelDraw(void *a) static void _listFunctionA(void *a) { menuFuncArgs *ma = (menuFuncArgs *)a; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - int sel = b->m->getSelected(); - bool isDir = b->d->isDir(sel - 2); + int sel = m->getSelected(); + bool isDir = d->isDir(sel - 2); if(sel == 1 && (*ma->path != dev && *ma->path != "sdmc:/")) { util::removeLastFolderFromString(*ma->path); - b->d->reassign(*ma->path); - util::copyDirListToMenu(*b->d, *b->m); + d->reassign(*ma->path); + util::copyDirListToMenu(*d, *m); } else if(sel > 1 && isDir) { - std::string addToPath = b->d->getItem(sel - 2); + std::string addToPath = d->getItem(sel - 2); *ma->path += addToPath + "/"; - b->d->reassign(*ma->path); - util::copyDirListToMenu(*b->d, *b->m); + d->reassign(*ma->path); + util::copyDirListToMenu(*d, *m); } - for(int i = 1; i < b->m->getCount(); i++) - { - b->m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma); - } + for(int i = 1; i < m->getCount(); i++) + m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma); } static void _copyMenuCopy_t(void *a) { threadInfo *t = (threadInfo *)a; menuFuncArgs *ma = (menuFuncArgs *)t->argPtr; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - int sel = b->m->getSelected(); + int sel = m->getSelected(); if(ma == devArgs) { if(sel == 0) - fs::copyDirToDir(*ma->path, *sdmcArgs->path); - else if(sel > 1 && b->d->isDir(sel - 2)) + fs::copyDirToDirThreaded(*ma->path, *sdmcArgs->path); + else if(sel > 1 && d->isDir(sel - 2)) { - std::string srcPath = *ma->path + b->d->getItem(sel - 2) + "/"; - std::string dstPath = *sdmcArgs->path + b->d->getItem(sel - 2) + "/"; + std::string srcPath = *ma->path + d->getItem(sel - 2) + "/"; + std::string dstPath = *sdmcArgs->path + d->getItem(sel - 2) + "/"; mkdir(dstPath.substr(0, dstPath.length() - 1).c_str(), 777); - fs::copyDirToDir(srcPath, dstPath); + fs::copyDirToDirThreaded(srcPath, dstPath); } else if(sel > 1) { - std::string srcPath = *ma->path + b->d->getItem(sel - 2); - std::string dstPath = *sdmcArgs->path + b->d->getItem(sel - 2); - fs::copyFile(srcPath, dstPath); + std::string srcPath = *ma->path + d->getItem(sel - 2); + std::string dstPath = *sdmcArgs->path + d->getItem(sel - 2); + fs::copyFileThreaded(srcPath, dstPath); } } else if(ma == sdmcArgs) @@ -190,28 +191,28 @@ static void _copyMenuCopy_t(void *a) if(sel == 0) { if(commit) - fs::copyDirToDirCommit(*ma->path, *devArgs->path, dev); + fs::copyDirToDirCommitThreaded(*ma->path, *devArgs->path, dev); else - fs::copyDirToDir(*ma->path, *devArgs->path); + fs::copyDirToDirThreaded(*ma->path, *devArgs->path); } - else if(sel > 1 && b->d->isDir(sel - 2)) + else if(sel > 1 && d->isDir(sel - 2)) { - std::string srcPath = *ma->path + b->d->getItem(sel - 2) + "/"; - std::string dstPath = *devArgs->path + b->d->getItem(sel - 2) + "/"; + std::string srcPath = *ma->path + d->getItem(sel - 2) + "/"; + std::string dstPath = *devArgs->path + d->getItem(sel - 2) + "/"; mkdir(dstPath.substr(0, dstPath.length() - 1).c_str(), 777); if(commit) - fs::copyDirToDirCommit(srcPath, dstPath, dev); + fs::copyDirToDirCommitThreaded(srcPath, dstPath, dev); else - fs::copyDirToDir(srcPath, dstPath); + fs::copyDirToDirThreaded(srcPath, dstPath); } else if(sel > 1) { - std::string srcPath = *ma->path + b->d->getItem(sel - 2); - std::string dstPath = *devArgs->path + b->d->getItem(sel - 2); + std::string srcPath = *ma->path + d->getItem(sel - 2); + std::string dstPath = *devArgs->path + d->getItem(sel - 2); if(commit) - fs::copyFileCommit(srcPath, dstPath, dev); + fs::copyFileCommitThreaded(srcPath, dstPath, dev); else - fs::copyFile(srcPath, dstPath); + fs::copyFileThreaded(srcPath, dstPath); } } ui::newThread(refreshMenu, devArgs, NULL); @@ -223,9 +224,11 @@ static void _copyMenuCopy_t(void *a) static void _copyMenuCopy(void *a) { menuFuncArgs *ma = (menuFuncArgs *)a; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; + std::string srcPath, dstPath; - int sel = b->m->getSelected(); + int sel = m->getSelected(); if(sel == 0 && ma == devArgs) { srcPath = *ma->path; @@ -233,8 +236,8 @@ static void _copyMenuCopy(void *a) } else if(sel > 1 && ma == devArgs) { - srcPath = *ma->path + b->d->getItem(sel - 2); - dstPath = *sdmcArgs->path + b->d->getItem(sel - 2); + srcPath = *ma->path + d->getItem(sel - 2); + dstPath = *sdmcArgs->path + d->getItem(sel - 2); } else if(sel == 0 && ma == sdmcArgs) { @@ -243,13 +246,13 @@ static void _copyMenuCopy(void *a) } else if(sel > 1 && ma == sdmcArgs) { - srcPath = *ma->path + b->d->getItem(b->m->getSelected() - 2); - dstPath = *devArgs->path + b->d->getItem(b->m->getSelected() - 2); + srcPath = *ma->path + d->getItem(m->getSelected() - 2); + dstPath = *devArgs->path + d->getItem(m->getSelected() - 2); } if(ma == devArgs || (ma == sdmcArgs && (type != FsSaveDataType_System || cfg::config["sysSaveWrite"]))) { - ui::confirmArgs *send = ui::confirmArgsCreate(false, _copyMenuCopy_t, ma, true, ui::getUICString("confirmCopy", 0), srcPath.c_str(), dstPath.c_str()); + ui::confirmArgs *send = ui::confirmArgsCreate(false, _copyMenuCopy_t, NULL, ma, ui::getUICString("confirmCopy", 0), srcPath.c_str(), dstPath.c_str()); ui::confirm(send); } } @@ -258,11 +261,12 @@ static void _copyMenuDelete_t(void *a) { threadInfo *t = (threadInfo *)a; menuFuncArgs *ma = (menuFuncArgs *)t->argPtr; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0)); - int sel = b->m->getSelected(); + int sel = m->getSelected(); if(ma == devArgs) { if(sel == 0 && *ma->path != "sdmc:/") @@ -271,16 +275,16 @@ static void _copyMenuDelete_t(void *a) if(commit) fs::commitToDevice(dev); } - else if(sel > 1 && b->d->isDir(sel - 2)) + else if(sel > 1 && d->isDir(sel - 2)) { - std::string delPath = *ma->path + b->d->getItem(sel - 2) + "/"; + std::string delPath = *ma->path + d->getItem(sel - 2) + "/"; fs::delDir(delPath); if(commit) fs::commitToDevice(dev); } else if(sel > 1) { - std::string delPath = *ma->path + b->d->getItem(sel - 2); + std::string delPath = *ma->path + d->getItem(sel - 2); fs::delfile(delPath); if(commit) fs::commitToDevice(dev); @@ -290,14 +294,14 @@ static void _copyMenuDelete_t(void *a) { if(sel == 0 && *ma->path != "sdmc:/") fs::delDir(*ma->path); - else if(sel > 1 && b->d->isDir(sel - 2)) + else if(sel > 1 && d->isDir(sel - 2)) { - std::string delPath = *ma->path + b->d->getItem(sel - 2) + "/"; + std::string delPath = *ma->path + d->getItem(sel - 2) + "/"; fs::delDir(delPath); } else if(sel > 1) { - std::string delPath = *ma->path + b->d->getItem(sel - 2); + std::string delPath = *ma->path + d->getItem(sel - 2); fs::delfile(delPath); } } @@ -310,18 +314,19 @@ static void _copyMenuDelete_t(void *a) static void _copyMenuDelete(void *a) { menuFuncArgs *ma = (menuFuncArgs *)a; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - int sel = b->m->getSelected(); + int sel = m->getSelected(); std::string itmPath; if(sel == 0) itmPath = *ma->path; else if(sel > 1) - itmPath = *ma->path + b->d->getItem(sel - 2); + itmPath = *ma->path + d->getItem(sel - 2); if(ma == sdmcArgs || (ma == devArgs && (sel == 0 || sel > 1) && (type != FsSaveDataType_System || cfg::config["sysSaveWrite"]))) { - ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], _copyMenuDelete_t, a, true, ui::getUICString("confirmDelete", 0), itmPath.c_str()); + ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], _copyMenuDelete_t, NULL, a, ui::getUICString("confirmDelete", 0), itmPath.c_str()); ui::confirm(send); } } @@ -329,15 +334,16 @@ static void _copyMenuDelete(void *a) static void _copyMenuRename(void *a) { menuFuncArgs *ma = (menuFuncArgs *)a; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - int sel = b->m->getSelected(); + int sel = m->getSelected(); if(sel > 1) { - std::string getNewName = util::getStringInput(SwkbdType_QWERTY, b->d->getItem(sel - 2), ui::getUIString("swkbdRename", 0), 64, 0, NULL); + std::string getNewName = util::getStringInput(SwkbdType_QWERTY, d->getItem(sel - 2), ui::getUIString("swkbdRename", 0), 64, 0, NULL); if(!getNewName.empty()) { - std::string prevPath = *ma->path + b->d->getItem(sel - 2); + std::string prevPath = *ma->path + d->getItem(sel - 2); std::string newPath = *ma->path + getNewName; rename(prevPath.c_str(), newPath.c_str()); } @@ -365,22 +371,37 @@ static void _copyMenuMkDir(void *a) refreshMenu(&fake); } +static void _copyMenuGetShowDirProps_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + std::string *p = (std::string *)t->argPtr; + unsigned dirCount = 0, fileCount = 0; + uint64_t totalSize = 0; + t->status->setStatus(ui::getUICString("threadStatusGetDirProps", 0)); + fs::getDirProps(*p, dirCount, fileCount, totalSize); + ui::showMessage(ui::getUICString("fileModeFolderProperties", 0), p->c_str(), dirCount, fileCount, util::getSizeString(totalSize).c_str()); + delete p; + t->finished = true; +} + static void _copyMenuGetProps(void *a) { menuFuncArgs *ma = (menuFuncArgs *)a; - fs::backupArgs *b = (fs::backupArgs *)ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - int sel = b->m->getSelected(); + int sel = m->getSelected(); if(sel == 0) fs::getShowDirProps(*ma->path); - else if(sel > 1 && b->d->isDir(sel - 2)) + else if(sel > 1 && d->isDir(sel - 2)) { - std::string folderPath = *ma->path + b->d->getItem(sel - 2) + "/"; - fs::getShowDirProps(folderPath); + std::string *folderPath = new std::string; + folderPath->assign(*ma->path + d->getItem(sel - 2) + "/"); + ui::newThread(_copyMenuGetShowDirProps_t, folderPath, NULL); } else if(sel > 1) { - std::string filePath = *ma->path + b->d->getItem(sel - 2); + std::string filePath = *ma->path + d->getItem(sel - 2); fs::getShowFileProps(filePath); } } @@ -405,14 +426,15 @@ static void _copyMenuClose(void *a) static void _devMenuAddToPathFilter(void *a) { menuFuncArgs *ma = (menuFuncArgs *)a; - fs::backupArgs *b = ma->b; + ui::menu *m = ma->m; + fs::dirList *d = ma->d; - int sel = b->m->getSelected(); + int sel = m->getSelected(); if(sel > 1) { - data::userTitleInfo *d = data::getCurrentUserTitleInfo(); - std::string filterPath = *ma->path + b->d->getItem(sel - 2); - cfg::addPathToFilter(d->tid, filterPath); + data::userTitleInfo *tinfo = data::getCurrentUserTitleInfo(); + std::string filterPath = *ma->path + d->getItem(sel - 2); + cfg::addPathToFilter(tinfo->tid, filterPath); ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popAddedToPathFilter", 0), filterPath.c_str()); } } @@ -421,17 +443,15 @@ void ui::fmInit() { //This needs to be done in a strange order so everything works devArgs = new menuFuncArgs; - devArgs->b = new fs::backupArgs; devArgs->path = &devPath; sdmcArgs = new menuFuncArgs; - sdmcArgs->b = new fs::backupArgs; sdmcArgs->path = &sdPath; devMenu = new ui::menu(10, 8, 590, 18, 5); devMenu->setCallback(_devMenuCallback, devArgs); devMenu->setActive(true); - devArgs->b->m = devMenu; + devArgs->m = devMenu; devPanel = new ui::slideOutPanel(288, 720, 0, ui::SLD_LEFT, _devCopyPanelDraw); devCopyMenu = new ui::menu(10, 185, 268, 20, 5); @@ -457,7 +477,7 @@ void ui::fmInit() sdMenu = new ui::menu(620, 8, 590, 18, 5); sdMenu->setCallback(_sdMenuCallback, sdmcArgs); sdMenu->setActive(false); - sdmcArgs->b->m = sdMenu; + sdmcArgs->m = sdMenu; sdPanel = new ui::slideOutPanel(288, 720, 0, ui::SLD_RIGHT, _sdCopyPanelDraw); sdCopyMenu = new ui::menu(10, 210, 268, 20, 5); @@ -475,8 +495,8 @@ void ui::fmInit() devList = new fs::dirList; sdList = new fs::dirList; - devArgs->b->d = devList; - sdmcArgs->b->d = sdList; + devArgs->d = devList; + sdmcArgs->d = sdList; } void ui::fmExit() @@ -487,9 +507,7 @@ void ui::fmExit() delete sdCopyMenu; delete devList; delete sdList; - delete devArgs->b; delete devArgs; - delete sdmcArgs->b; delete sdmcArgs; } diff --git a/src/ui/miscui.cpp b/src/ui/miscui.cpp index 305ff83..11e4d32 100644 --- a/src/ui/miscui.cpp +++ b/src/ui/miscui.cpp @@ -135,15 +135,15 @@ void ui::menu::update() bool change = false; if( (down & HidNpadButton_AnyUp) || ((held & HidNpadButton_AnyUp) && fc == 10) ) { - if(selected > 0) - --selected; + if(--selected < 0) + selected = mSize; change = true; } else if( (down & HidNpadButton_AnyDown) || ((held & HidNpadButton_AnyDown) && fc == 10)) { - if(selected < mSize) - ++selected; + if(++selected > mSize) + selected = 0; change = true; } @@ -379,7 +379,7 @@ void ui::popMessageMngr::draw() } } -ui::confirmArgs *ui::confirmArgsCreate(bool _hold, funcPtr _func, void *_funcArgs, bool _cleanup, const char *fmt, ...) +ui::confirmArgs *ui::confirmArgsCreate(bool _hold, funcPtr _confFunc, funcPtr _cancelFunc, void *_funcArgs, const char *fmt, ...) { char tmp[1024]; va_list args; @@ -389,9 +389,9 @@ ui::confirmArgs *ui::confirmArgsCreate(bool _hold, funcPtr _func, void *_funcArg ui::confirmArgs *ret = new confirmArgs; ret->hold = _hold; - ret->func = _func; + ret->confFunc = _confFunc; + ret->cancelFunc = _cancelFunc; ret->args = _funcArgs; - ret->cleanup = _cleanup; ret->text = tmp; return ret; @@ -410,7 +410,7 @@ void confirm_t(void *a) if((down & HidNpadButton_A) && !c->hold) { - ui::newThread(c->func, c->args, NULL); + ui::newThread(c->confFunc, c->args, NULL); break; } else if((held & HidNpadButton_A) && c->hold) @@ -420,18 +420,20 @@ void confirm_t(void *a) if(c->frameCount >= 120) { - ui::newThread(c->func, c->args, NULL); + ui::newThread(c->confFunc, c->args, NULL); break; } } else if(down & HidNpadButton_B) + { + if(c->cancelFunc) + (*c->cancelFunc)(c->args); break; + } svcSleepThread(10000000);//Close enough } - if(c->cleanup) - delete c; - + delete c; t->finished = true; } diff --git a/src/ui/sett.cpp b/src/ui/sett.cpp index 9981153..229126a 100644 --- a/src/ui/sett.cpp +++ b/src/ui/sett.cpp @@ -68,7 +68,7 @@ static void settMenuDeleteAllBackups_t(void *a) static void settMenuDeleteAllBackups(void *a) { - ui::confirmArgs *send = ui::confirmArgsCreate(true, settMenuDeleteAllBackups_t, NULL, true, ui::getUICString("confirmDeleteBackupsAll", 0)); + ui::confirmArgs *send = ui::confirmArgsCreate(true, settMenuDeleteAllBackups_t, NULL, NULL, ui::getUICString("confirmDeleteBackupsAll", 0)); ui::confirm(send); } @@ -123,7 +123,7 @@ static void toggleOpt(void *a) case 0: fs::delDir(fs::getWorkDir() + "_TRASH_/"); mkdir(std::string(fs::getWorkDir() + "_TRASH_").c_str(), 777); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("infoStatus", 11)); + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popTrashEmptied", 0)); break; case 1: diff --git a/src/ui/thrdProc.cpp b/src/ui/thrdProc.cpp index 7f4f2d4..b882cec 100644 --- a/src/ui/thrdProc.cpp +++ b/src/ui/thrdProc.cpp @@ -43,7 +43,7 @@ void ui::threadProcMngr::update() { Result res = 0; threadInfo *t = threads[0]; - if(!t->running && R_SUCCEEDED((res = threadCreate(&t->thrd, t->thrdFunc, t, NULL, 0x20000, 0x2B, 1)))) + if(!t->running && R_SUCCEEDED((res = threadCreate(&t->thrd, t->thrdFunc, t, NULL, 0x80000, 0x2B, 1)))) { threadStart(&t->thrd); t->running = true; diff --git a/src/ui/ttl.cpp b/src/ui/ttl.cpp index 4c651a4..b9ea34c 100644 --- a/src/ui/ttl.cpp +++ b/src/ui/ttl.cpp @@ -12,7 +12,6 @@ static ui::menu *ttlOpts, *fldMenu; ui::slideOutPanel *ui::ttlOptsPanel; static ui::slideOutPanel *infoPanel, *fldPanel;//There's no reason to have a separate folder section static fs::dirList *fldList; -static fs::backupArgs *backargs; static std::string infoPanelString; static SDL_Texture *fldBuffer;//This is so folder menu doesn't draw over guide @@ -22,42 +21,45 @@ void ui::ttlRefresh() ttlViews[i]->refresh(); } +static void fldFuncCancel(void *a) +{ + std::string *del = (std::string *)a; + delete del; +} + static void fldFuncOverwrite(void *a) { - fs::backupArgs *b = (fs::backupArgs *)a; - fs::dirList *d = (fs::dirList *)b->d; - ui::menu *m = (ui::menu *)b->m; + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + int sel = fldMenu->getSelected() - 1;//Skip 'New' + std::string itm = fldList->getItem(sel); + std::string *send = new std::string; + send->assign(util::generatePathByTID(utinfo->tid) + itm); - int sel = m->getSelected() - 1;//Skip 'New' - std::string itm = d->getItem(sel); - - ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, a, true, ui::getUICString("confirmOverwrite", 0), itm.c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, fldFuncCancel, send, ui::getUICString("confirmOverwrite", 0), itm.c_str()); ui::confirm(conf); } static void fldFuncDelete(void *a) { - fs::backupArgs *b = (fs::backupArgs *)a; - fs::dirList *d = (fs::dirList *)b->d; - ui::menu *m = (ui::menu *)b->m; + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + int sel = fldMenu->getSelected() - 1;//Skip 'New' + std::string itm = fldList->getItem(sel); + std::string *send = new std::string; + send->assign(util::generatePathByTID(utinfo->tid) + itm); - int sel = m->getSelected() - 1;//Skip 'New' - std::string itm = d->getItem(sel); - - ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, a, true, ui::getUICString("confirmDelete", 0), itm.c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, fldFuncCancel, send, ui::getUICString("confirmDelete", 0), itm.c_str()); ui::confirm(conf); } static void fldFuncRestore(void *a) { - fs::backupArgs *b = (fs::backupArgs *)a; - fs::dirList *d = (fs::dirList *)b->d; - ui::menu *m = (ui::menu *)b->m; + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + int sel = fldMenu->getSelected() - 1;//Skip 'New' + std::string itm = fldList->getItem(sel); + std::string *send = new std::string; + send->assign(util::generatePathByTID(utinfo->tid) + itm); - int sel = m->getSelected() - 1;//Skip 'New' - std::string itm = d->getItem(sel); - - ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, a, true, ui::getUICString("confirmRestore", 0), itm.c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, fldFuncCancel, send, ui::getUICString("confirmRestore", 0), itm.c_str()); ui::confirm(conf); } @@ -75,18 +77,16 @@ void ui::populateFldMenu() sprintf(filterPath, "sdmc:/config/JKSV/0x%016lX_filter.txt", d->tid); fs::loadPathFilters(d->tid); - *backargs = {fldMenu, fldList}; - fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0)); - fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, backargs); + fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL); for(unsigned i = 0; i < fldList->getCount(); i++) { fldMenu->addOpt(NULL, fldList->getItem(i)); - fldMenu->optAddButtonEvent(i + 1, HidNpadButton_A, fldFuncOverwrite, backargs); - fldMenu->optAddButtonEvent(i + 1, HidNpadButton_X, fldFuncDelete, backargs); - fldMenu->optAddButtonEvent(i + 1, HidNpadButton_Y, fldFuncRestore, backargs); + fldMenu->optAddButtonEvent(i + 1, HidNpadButton_A, fldFuncOverwrite, NULL); + fldMenu->optAddButtonEvent(i + 1, HidNpadButton_X, fldFuncDelete, NULL); + fldMenu->optAddButtonEvent(i + 1, HidNpadButton_Y, fldFuncRestore, NULL); } fldMenu->setActive(true); fldPanel->openPanel(); @@ -151,18 +151,33 @@ static void ttlOptsPanelDraw(void *a) ttlOpts->draw(panel, &ui::txtCont, true); } -static void ttlOptsShowInfoPanel(void *a) +static void ttlOptsShowInfoPanel(void *) { + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid); + + char tmp[256]; + sprintf(tmp, ui::getUICString("infoStatus", 4), tinfo->author.c_str()); + + size_t titleWidth = gfx::getTextWidth(tinfo->title.c_str(), 18); + size_t pubWidth = gfx::getTextWidth(tmp, 18); + if(titleWidth > 410 || pubWidth > 410) + { + size_t newWidth = titleWidth > pubWidth ? titleWidth : pubWidth; + infoPanel->resizePanel(newWidth + 40, 720, 0); + } + else + infoPanel->resizePanel(410, 720, 0); + ttlOpts->setActive(false); ui::ttlOptsPanel->closePanel(); - infoPanelString = util::getInfoString(*data::getCurrentUser(), data::getCurrentUserTitleInfo()->tid); infoPanel->openPanel(); } static void ttlOptsBlacklistTitle(void *a) { std::string title = data::getTitleNameByTID(data::getCurrentUserTitleInfo()->tid); - ui::confirmArgs *conf = ui::confirmArgsCreate(false, cfg::addTitleToBlacklist, NULL, true, ui::getUICString("confirmBlacklist", 0), title.c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(false, cfg::addTitleToBlacklist, NULL, NULL, ui::getUICString("confirmBlacklist", 0), title.c_str()); ui::confirm(conf); } @@ -213,7 +228,8 @@ static void ttlOptsDeleteAllBackups(void *a) { data::userTitleInfo *d = data::getCurrentUserTitleInfo(); std::string currentTitle = data::getTitleNameByTID(d->tid); - ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteAllBackups_t, NULL, true, ui::getUICString("confirmDeleteBackupsTitle", 0), currentTitle.c_str()); + + ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteAllBackups_t, NULL, NULL, ui::getUICString("confirmDeleteBackupsTitle", 0), currentTitle.c_str()); ui::confirm(send); } @@ -222,7 +238,7 @@ static void ttlOptsResetSaveData_t(void *a) threadInfo *t = (threadInfo *)a; data::userTitleInfo *d = data::getCurrentUserTitleInfo(); std::string title = data::getTitleNameByTID(d->tid); - t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0), title.c_str()); + t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0)); fs::mountSave(d->saveInfo); fs::delDir("sv:/"); @@ -238,7 +254,7 @@ static void ttlOptsResetSaveData(void *a) if(d->saveInfo.save_data_type != FsSaveDataType_System) { std::string title = data::getTitleNameByTID(d->tid); - ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsResetSaveData_t, NULL, true, ui::getUICString("confirmResetSaveData", 0), title.c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsResetSaveData_t, NULL, NULL, ui::getUICString("confirmResetSaveData", 0), title.c_str()); ui::confirm(conf); } } @@ -276,89 +292,75 @@ static void ttlOptsDeleteSaveData(void *a) if(d->saveInfo.save_data_type != FsSaveDataType_System) { std::string title = data::getTitleNameByTID(d->tid); - ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteSaveData_t, NULL, true, ui::getUICString("confirmDeleteSaveData", 0), title.c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteSaveData_t, NULL, NULL, ui::getUICString("confirmDeleteSaveData", 0), title.c_str()); ui::confirm(conf); } } -static void ttlOptsExtendSaveData_t(void *a) -{ - threadInfo *t = (threadInfo *)a; - data::userTitleInfo *d = data::getCurrentUserTitleInfo(); - - std::string expSizeStr = util::getStringInput(SwkbdType_NumPad, "", ui::getUICString("swkbdExpandSize", 0), 4, 0, NULL); - if(!expSizeStr.empty()) - { - int64_t journ = 0, expSize; - data::titleInfo *extend = data::getTitleInfoByTID(d->tid); - t->status->setStatus(ui::getUICString("threadStatusExtendingSaveData", 0), extend->title.c_str()); - //Get journal size - switch(d->saveInfo.save_data_type) - { - case FsSaveDataType_Account: - if(extend->nacp.user_account_save_data_journal_size_max > extend->nacp.user_account_save_data_journal_size) - journ = extend->nacp.user_account_save_data_journal_size_max; - else - journ = extend->nacp.user_account_save_data_journal_size; - break; - - case FsSaveDataType_Bcat: - journ = extend->nacp.bcat_delivery_cache_storage_size; - break; - - case FsSaveDataType_Cache: - if(extend->nacp.cache_storage_data_and_journal_size_max > extend->nacp.cache_storage_journal_size) - journ = extend->nacp.cache_storage_data_and_journal_size_max; - else - journ = extend->nacp.cache_storage_journal_size; - break; - - case FsSaveDataType_Device: - if(extend->nacp.device_save_data_journal_size_max > extend->nacp.device_save_data_journal_size) - journ = extend->nacp.device_save_data_journal_size_max; - else - journ = extend->nacp.device_save_data_journal_size; - break; - - default: - //will just fail - journ = 0; - break; - } - uint64_t expMB = strtoul(expSizeStr.c_str(), NULL, 10); - expSize = expMB * 0x100000; - FsSaveDataSpaceId space = (FsSaveDataSpaceId)d->saveInfo.save_data_space_id; - uint64_t sid = d->saveInfo.save_data_id; - Result res = 0; - if(R_FAILED(res = fsExtendSaveDataFileSystem(space, sid, expSize, journ))) - { - int64_t totalSize = 0; - fs::mountSave(d->saveInfo); - fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize); - fs::unmountSave(); - - fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, expSize / 1024 / 1024, res); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0)); - } - else - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendSuccess", 0), extend->title.c_str()); - } - t->finished = true; -} - static void ttlOptsExtendSaveData(void *a) { data::userTitleInfo *d = data::getCurrentUserTitleInfo(); if(d->saveInfo.save_data_type != FsSaveDataType_System) - ui::newThread(ttlOptsExtendSaveData_t, NULL, NULL); + { + std::string expSizeStr = util::getStringInput(SwkbdType_NumPad, "", ui::getUICString("swkbdExpandSize", 0), 4, 0, NULL); + uint64_t extMB = strtoul(expSizeStr.c_str(), NULL, 10) * 0x100000; + fs::extendSaveDataThreaded(d, extMB); + } } static void infoPanelDraw(void *a) { data::userTitleInfo *d = data::getCurrentUserTitleInfo(); + data::titleInfo *t = data::getTitleInfoByTID(d->tid); SDL_Texture *panel = (SDL_Texture *)a; - gfx::texDraw(panel, data::getTitleIconByTID(d->tid), 77, 32); - gfx::drawTextfWrap(panel, 18, 32, 320, 362, &ui::txtCont, infoPanelString.c_str()); + int width = 0, rectWidth = 0, iconX = 0, drawY = 310; + SDL_QueryTexture(panel, NULL, NULL, &width, 0); + rectWidth = width - 20; + + iconX = (width / 2) - 128; + gfx::texDraw(panel, data::getTitleIconByTID(d->tid), iconX, 32); + + gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, data::getTitleNameByTID(d->tid).c_str()); + drawY += 40; + + gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 4), t->author.c_str()); + drawY += 40; + + gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 0), d->tid); + drawY += 40; + + gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 1), d->saveInfo.save_data_id); + drawY += 40; + + uint32_t hours, mins; + hours = d->playStats.playtimeMinutes / 60; + mins = d->playStats.playtimeMinutes - (hours * 60); + gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 2), hours, mins); + drawY += 40; + + gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 3), d->playStats.totalLaunches); + drawY += 40; + + gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 5), ui::getUICString("saveDataTypeText", d->saveInfo.save_data_type)); + drawY += 40; + + uint8_t saveType = d->saveInfo.save_data_type; + if(saveType == FsSaveDataType_Cache) + { + gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 6), d->saveInfo.save_data_index); + drawY += 40; + } + + gfx::drawRect(panel, saveType == FsSaveDataType_Cache ? &ui::rectLt : &ui::rectSh, 10, drawY, rectWidth, 38); + gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 7), data::getCurrentUser()->getUsername().c_str()); } static void infoPanelCallback(void *a) @@ -426,7 +428,6 @@ void ui::ttlInit() ui::registerPanel(fldPanel); fldList = new fs::dirList; - backargs = new fs::backupArgs; ttlOpts->setActive(false); for(int i = 0; i < 8; i++) @@ -462,7 +463,6 @@ void ui::ttlExit() delete fldPanel; delete fldMenu; delete fldList; - delete backargs; } void ui::ttlSetActive(int usr) diff --git a/src/ui/uistr.cpp b/src/ui/uistr.cpp index e9a2dc0..22b1c7c 100644 --- a/src/ui/uistr.cpp +++ b/src/ui/uistr.cpp @@ -150,6 +150,13 @@ void ui::initStrings() addUIString("saveTypeMainMenu", 3, "System"); addUIString("saveTypeMainMenu", 4, "System BCAT"); addUIString("saveTypeMainMenu", 5, "SysTemp Storagetem"); + addUIString("saveDataTypeText", 0, "System"); + addUIString("saveDataTypeText", 1, "Account"); + addUIString("saveDataTypeText", 2, "BCAT"); + addUIString("saveDataTypeText", 3, "Device"); + addUIString("saveDataTypeText", 4, "Temporary"); + addUIString("saveDataTypeText", 5, "Cache"); + addUIString("saveDataTypeText", 6, "System BCAT"); //Internet Related addUIString("onlineErrorConnecting", 0, "Error Connecting!"); @@ -247,7 +254,6 @@ void ui::initStrings() addUIString("threadStatusOpeningFolder", 0, "Opening '#%s#'..."); addUIString("threadStatusAddingFileToZip", 0, "Adding '#%s#' to ZIP..."); addUIString("threadStatusDecompressingFile", 0, "Decompressing '#%s#'..."); - addUIString("threadStatusResettingSaveData", 0, "Resetting Save Data for #%s#..."); addUIString("threadStatusDeletingSaveData", 0, "Deleting Save Data for #%s#..."); addUIString("threadStatusExtendingSaveData", 0, "Extending Save Data for #%s#..."); addUIString("threadStatusCreatingSaveData", 0, "Creating Save Data for #%s#..."); @@ -257,6 +263,8 @@ void ui::initStrings() addUIString("threadStatusDownloadingUpdate", 0, "Downloading update..."); addUIString("threadStatusGetDirProps", 0, "Getting Folder Properties..."); addUIString("threadStatusPackingJKSV", 0, "Writing JKSV folder contents to ZIP..."); + addUIString("threadStatusSavingTranslations", 0, "Saving the file master..."); + addUIString("threadStatusCalculatingSaveSize", 0, "Calculating save data size..."); //Random leftover pop-ups addUIString("popCPUBoostEnabled", 0, "CPU Boost Enabled for ZIP."); @@ -268,6 +276,7 @@ void ui::initStrings() addUIString("popAddedToPathFilter", 0, "'#%s#' added to path filters."); addUIString("popChangeOutputFolder", 0, "#%s# changed to #%s#"); addUIString("popChangeOutputError", 0, "#%s# contains illegal or non-ASCII characters."); + addUIString("popTrashEmptied", 0, "Trash emptied"); //Keyboard hints addUIString("swkbdEnterName", 0, "Enter a new name"); @@ -281,18 +290,20 @@ void ui::initStrings() addUIString("swkbdExpandSize", 0, "Enter New Size in MB"); //Status informations - addUIString("infoStatus", 0, "TID: "); - addUIString("infoStatus", 1, "SID: "); - addUIString("infoStatus", 2, "Play Time: "); - addUIString("infoStatus", 3, "Total Launches: "); - addUIString("infoStatus", 4, "User Count: "); - addUIString("infoStatus", 5, "Current User: "); - addUIString("infoStatus", 6, "Current Title: "); - addUIString("infoStatus", 7, "Safe Title: "); - addUIString("infoStatus", 8, "Sort Type: "); - addUIString("infoStatus", 9, "Saving the file master..."); - addUIString("infoStatus", 10, "Deleting..."); - addUIString("infoStatus", 11, "Trash emptied."); + addUIString("infoStatus", 0, "TID: %016lX"); + addUIString("infoStatus", 1, "SID: %016lX"); + addUIString("infoStatus", 2, "Play Time: %02d:%02d"); + addUIString("infoStatus", 3, "Total Launches: %u"); + addUIString("infoStatus", 4, "Publisher: %s"); + addUIString("infoStatus", 5, "Save Type: %s"); + addUIString("infoStatus", 6, "Cache Index: %u"); + addUIString("infoStatus", 7, "User: %s"); + + addUIString("debugStatus", 0, "User Count: "); + addUIString("debugStatus", 1, "Current User: "); + addUIString("debugStatus", 2, "Current Title: "); + addUIString("debugStatus", 3, "Safe Title: "); + addUIString("debugStatus", 4, "Sort Type: "); } void ui::loadTrans() diff --git a/src/ui/usr.cpp b/src/ui/usr.cpp index 40cb295..eed17c7 100644 --- a/src/ui/usr.cpp +++ b/src/ui/usr.cpp @@ -182,7 +182,7 @@ static void usrOptDeleteAllUserSaves_t(void *a) static void usrOptDeleteAllUserSaves(void *a) { data::user *u = data::getCurrentUser(); - ui::confirmArgs *conf = ui::confirmArgsCreate(true, usrOptDeleteAllUserSaves_t, NULL, true, ui::getUICString("saveDataDeleteAllUser", 0), u->getUsername().c_str()); + ui::confirmArgs *conf = ui::confirmArgsCreate(true, usrOptDeleteAllUserSaves_t, NULL, NULL, ui::getUICString("saveDataDeleteAllUser", 0), u->getUsername().c_str()); ui::confirm(conf); } @@ -237,22 +237,22 @@ static void createSaveData(void *a) case 2: tid = bcatSids[bcatSaveMenu->getSelected()]; - fs::createSaveData(FsSaveDataType_Bcat, tid, util::u128ToAccountUID(0)); + fs::createSaveDataThreaded(FsSaveDataType_Bcat, tid, util::u128ToAccountUID(0)); break; case 3: tid = devSids[deviceSaveMenu->getSelected()]; - fs::createSaveData(FsSaveDataType_Device, tid, util::u128ToAccountUID(0)); + fs::createSaveDataThreaded(FsSaveDataType_Device, tid, util::u128ToAccountUID(0)); break; case 5: tid = cacheSids[cacheSaveMenu->getSelected()]; - fs::createSaveData(FsSaveDataType_Cache, tid, util::u128ToAccountUID(0)); + fs::createSaveDataThreaded(FsSaveDataType_Cache, tid, util::u128ToAccountUID(0)); break; default: tid = accSids[saveCreateMenu->getSelected()]; - fs::createSaveData(FsSaveDataType_Account, tid, u->getUID()); + fs::createSaveDataThreaded(FsSaveDataType_Account, tid, u->getUID()); break; } } @@ -268,17 +268,17 @@ static void usrOptCreateAllSaves_t(void *a) { AccountUid uid = u->getUID(); for(unsigned i = 0; i < accSids.size(); i++) - fs::createSaveData(FsSaveDataType_Account, accSids[i], uid); + fs::createSaveDataThreaded(FsSaveDataType_Account, accSids[i], uid); } else if(sel == devPos) { for(unsigned i = 0; i < devSids.size(); i++) - fs::createSaveData(FsSaveDataType_Device, devSids[i], util::u128ToAccountUID(0)); + fs::createSaveDataThreaded(FsSaveDataType_Device, devSids[i], util::u128ToAccountUID(0)); } else if(sel == bcatPos) { for(unsigned i = 0; i < bcatSids.size(); i++) - fs::createSaveData(FsSaveDataType_Bcat, bcatSids[i], util::u128ToAccountUID(0)); + fs::createSaveDataThreaded(FsSaveDataType_Bcat, bcatSids[i], util::u128ToAccountUID(0)); } t->finished = true; } @@ -286,8 +286,8 @@ static void usrOptCreateAllSaves_t(void *a) static void usrOptCreateAllSaves(void *a) { data::user *u = data::getCurrentUser(); - ui::confirmArgs *send = ui::confirmArgsCreate(true, usrOptCreateAllSaves_t, NULL, true, ui::getUICString("confirmCreateAllSaveData", 0), u->getUsername().c_str()); - ui::confirm(send); + ui::confirmArgs *conf = ui::confirmArgsCreate(true, usrOptCreateAllSaves_t, NULL, NULL, ui::getUICString("confirmCreateAllSaveData", 0), u->getUsername().c_str()); + ui::confirm(conf); } //Sets up save create menus diff --git a/src/util.cpp b/src/util.cpp index 85b4b61..0e2bdfd 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -284,6 +284,24 @@ std::string util::getStringInput(SwkbdType _type, const std::string& def, const return std::string(out); } +std::string util::getExtensionFromString(const std::string& get) +{ + size_t ext = get.find_last_of('.'); + if(ext != get.npos) + return get.substr(ext + 1, get.npos); + else + return ""; +} + +std::string util::getFilenameFromPath(const std::string& get) +{ + size_t nameStart = get.find_last_of('/'); + if(nameStart != get.npos) + return get.substr(nameStart + 1, get.npos); + else + return ""; +} + std::string util::generateAbbrev(const uint64_t& tid) { data::titleInfo *tmp = data::getTitleInfoByTID(tid);