Code Revisions + Auto extend saves

This commit is contained in:
J-D-K 2021-10-12 21:36:33 -04:00
parent 94b0c800ca
commit bf15660c2d
31 changed files with 1959 additions and 1925 deletions

View File

@ -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

View File

@ -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

View File

@ -1,186 +0,0 @@
#pragma once
#include <string>
#include <cstdio>
#include <vector>
#include <switch.h>
#include <dirent.h>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#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<dirItem> 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();
}

44
inc/fs.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <minizip/zip.h>
#include <minizip/unzip.h>
#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, ...);
}

53
inc/fs/dir.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <string>
#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<dirItem> item;
};
}

78
inc/fs/file.h Normal file
View File

@ -0,0 +1,78 @@
#pragma once
#include <string>
#include <cstdio>
#include <vector>
#include <switch.h>
#include <dirent.h>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#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();
}

46
inc/fs/fstype.h Normal file
View File

@ -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;
}

18
inc/fs/zip.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <string>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -289,6 +289,7 @@ static void loadTitleDefs()
void cfg::loadConfig()
{
cfg::resetConfig();
loadWorkDirLegacy();
loadConfigLegacy();
loadFavoritesLegacy();

View File

@ -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());
}

View File

@ -1,744 +0,0 @@
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <switch.h>
#include <unistd.h>
#include <cstdarg>
#include <sys/stat.h>
#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<std::string> 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);
}

565
src/fs.cpp Normal file
View File

@ -0,0 +1,565 @@
#include <switch.h>
#include <string>
#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);
}

269
src/fs/dir.cpp Normal file
View File

@ -0,0 +1,269 @@
#include <switch.h>
#include <algorithm>
#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);
}

409
src/fs/file.cpp Normal file
View File

@ -0,0 +1,409 @@
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <switch.h>
#include <unistd.h>
#include <cstdarg>
#include <sys/stat.h>
#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<std::string> 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;
}

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#include <malloc.h>
#include "fsfile.h"
#include "fs/fsfile.h"
char *getDeviceFromPath(char *dev, size_t _max, const char *path)
{

185
src/fs/zip.cpp Normal file
View File

@ -0,0 +1,185 @@
#include <switch.h>
#include <time.h>
#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;
}

View File

@ -1,708 +0,0 @@
#include <switch.h>
#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;
}

View File

@ -55,5 +55,4 @@ int main(int argc, const char *argv[])
ui::exit();
data::exit();
gfx::exit();
fs::exit();
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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:

View File

@ -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;

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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);