mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-03-21 17:24:37 -05:00
Code Revisions + Auto extend saves
This commit is contained in:
parent
94b0c800ca
commit
bf15660c2d
6
Makefile
6
Makefile
|
|
@ -32,13 +32,13 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
#---------------------------------------------------------------------------------
|
||||
TARGET := JKSV
|
||||
BUILD := build
|
||||
SOURCES := src src/ui
|
||||
SOURCES := src src/ui src/fs
|
||||
DATA := data
|
||||
INCLUDES := inc inc/ui
|
||||
INCLUDES := inc inc/ui inc/fs
|
||||
EXEFS_SRC := exefs_src
|
||||
APP_TITLE := JKSV
|
||||
APP_AUTHOR := JK
|
||||
APP_VERSION := 09.01.2021
|
||||
APP_VERSION := 10.12.2021
|
||||
ROMFS := romfs
|
||||
ICON := icon.jpg
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
186
inc/file.h
186
inc/file.h
|
|
@ -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
44
inc/fs.h
Normal 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
53
inc/fs/dir.h
Normal 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
78
inc/fs/file.h
Normal 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
46
inc/fs/fstype.h
Normal 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
18
inc/fs/zip.h
Normal 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);
|
||||
}
|
||||
21
inc/fsthrd.h
21
inc/fsthrd.h
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
10
inc/util.h
10
inc/util.h
|
|
@ -54,14 +54,8 @@ namespace util
|
|||
|
||||
std::string getStringInput(SwkbdType _type, const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]);
|
||||
|
||||
inline std::string getExtensionFromString(const std::string& get)
|
||||
{
|
||||
size_t ext = get.find_last_of('.');
|
||||
if(ext != get.npos)
|
||||
return get.substr(ext + 1, get.npos);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
std::string getExtensionFromString(const std::string& get);
|
||||
std::string getFilenameFromPath(const std::string& get);
|
||||
|
||||
std::string generateAbbrev(const uint64_t& tid);
|
||||
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ static void loadTitleDefs()
|
|||
|
||||
void cfg::loadConfig()
|
||||
{
|
||||
cfg::resetConfig();
|
||||
loadWorkDirLegacy();
|
||||
loadConfigLegacy();
|
||||
loadFavoritesLegacy();
|
||||
|
|
|
|||
10
src/data.cpp
10
src/data.cpp
|
|
@ -452,12 +452,12 @@ void data::dispStats()
|
|||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
|
||||
//Easiest/laziest way to do this
|
||||
std::string stats = ui::getUICString("infoStatus", 4) + std::to_string(users.size()) + "\n";
|
||||
std::string stats = ui::getUICString("debugStatus", 0) + std::to_string(users.size()) + "\n";
|
||||
for(data::user& u : data::users)
|
||||
stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n";
|
||||
stats += ui::getUICString("infoStatus", 5) + cu->getUsername() + "\n";
|
||||
stats += ui::getUICString("infoStatus", 6) + data::getTitleNameByTID(d->tid) + "\n";
|
||||
stats += ui::getUICString("infoStatus", 7) + data::getTitleSafeNameByTID(d->tid) + "\n";
|
||||
stats += ui::getUICString("infoStatus", 8) + std::to_string(cfg::sortType) + "\n";
|
||||
stats += ui::getUICString("debugStatus", 1) + cu->getUsername() + "\n";
|
||||
stats += ui::getUICString("debugStatus", 2) + data::getTitleNameByTID(d->tid) + "\n";
|
||||
stats += ui::getUICString("debugStatus", 3) + data::getTitleSafeNameByTID(d->tid) + "\n";
|
||||
stats += ui::getUICString("debugStatus", 4) + std::to_string(cfg::sortType) + "\n";
|
||||
gfx::drawTextf(NULL, 16, 2, 2, &green, stats.c_str());
|
||||
}
|
||||
|
|
|
|||
744
src/file.cpp
744
src/file.cpp
|
|
@ -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
565
src/fs.cpp
Normal 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
269
src/fs/dir.cpp
Normal 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
409
src/fs/file.cpp
Normal 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;
|
||||
}
|
||||
|
|
@ -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
185
src/fs/zip.cpp
Normal 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;
|
||||
}
|
||||
708
src/fsthrd.cpp
708
src/fsthrd.cpp
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -55,5 +55,4 @@ int main(int argc, const char *argv[])
|
|||
ui::exit();
|
||||
data::exit();
|
||||
gfx::exit();
|
||||
fs::exit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
182
src/ui/fm.cpp
182
src/ui/fm.cpp
|
|
@ -17,8 +17,8 @@
|
|||
typedef struct
|
||||
{
|
||||
std::string *path;
|
||||
//These can hold the same info needed for the listing menus so might as well use em
|
||||
fs::backupArgs *b;
|
||||
ui::menu *m;
|
||||
fs::dirList *d;
|
||||
} menuFuncArgs;
|
||||
|
||||
static ui::slideOutPanel *devPanel, *sdPanel;
|
||||
|
|
@ -37,13 +37,14 @@ static void refreshMenu(void *a)
|
|||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
menuFuncArgs *ma = (menuFuncArgs *)t->argPtr;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
b->d->reassign(*ma->path);
|
||||
util::copyDirListToMenu(*b->d, *b->m);
|
||||
for(int i = 1; i < b->m->getCount(); i++)
|
||||
d->reassign(*ma->path);
|
||||
util::copyDirListToMenu(*d, *m);
|
||||
for(int i = 1; i < m->getCount(); i++)
|
||||
{
|
||||
b->m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma);
|
||||
m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma);
|
||||
}
|
||||
t->finished = true;
|
||||
}
|
||||
|
|
@ -135,53 +136,53 @@ static void _sdCopyPanelDraw(void *a)
|
|||
static void _listFunctionA(void *a)
|
||||
{
|
||||
menuFuncArgs *ma = (menuFuncArgs *)a;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
bool isDir = b->d->isDir(sel - 2);
|
||||
int sel = m->getSelected();
|
||||
bool isDir = d->isDir(sel - 2);
|
||||
if(sel == 1 && (*ma->path != dev && *ma->path != "sdmc:/"))
|
||||
{
|
||||
util::removeLastFolderFromString(*ma->path);
|
||||
b->d->reassign(*ma->path);
|
||||
util::copyDirListToMenu(*b->d, *b->m);
|
||||
d->reassign(*ma->path);
|
||||
util::copyDirListToMenu(*d, *m);
|
||||
}
|
||||
else if(sel > 1 && isDir)
|
||||
{
|
||||
std::string addToPath = b->d->getItem(sel - 2);
|
||||
std::string addToPath = d->getItem(sel - 2);
|
||||
*ma->path += addToPath + "/";
|
||||
b->d->reassign(*ma->path);
|
||||
util::copyDirListToMenu(*b->d, *b->m);
|
||||
d->reassign(*ma->path);
|
||||
util::copyDirListToMenu(*d, *m);
|
||||
}
|
||||
|
||||
for(int i = 1; i < b->m->getCount(); i++)
|
||||
{
|
||||
b->m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma);
|
||||
}
|
||||
for(int i = 1; i < m->getCount(); i++)
|
||||
m->optAddButtonEvent(i, HidNpadButton_A, _listFunctionA, ma);
|
||||
}
|
||||
|
||||
static void _copyMenuCopy_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
menuFuncArgs *ma = (menuFuncArgs *)t->argPtr;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
if(ma == devArgs)
|
||||
{
|
||||
if(sel == 0)
|
||||
fs::copyDirToDir(*ma->path, *sdmcArgs->path);
|
||||
else if(sel > 1 && b->d->isDir(sel - 2))
|
||||
fs::copyDirToDirThreaded(*ma->path, *sdmcArgs->path);
|
||||
else if(sel > 1 && d->isDir(sel - 2))
|
||||
{
|
||||
std::string srcPath = *ma->path + b->d->getItem(sel - 2) + "/";
|
||||
std::string dstPath = *sdmcArgs->path + b->d->getItem(sel - 2) + "/";
|
||||
std::string srcPath = *ma->path + d->getItem(sel - 2) + "/";
|
||||
std::string dstPath = *sdmcArgs->path + d->getItem(sel - 2) + "/";
|
||||
mkdir(dstPath.substr(0, dstPath.length() - 1).c_str(), 777);
|
||||
fs::copyDirToDir(srcPath, dstPath);
|
||||
fs::copyDirToDirThreaded(srcPath, dstPath);
|
||||
}
|
||||
else if(sel > 1)
|
||||
{
|
||||
std::string srcPath = *ma->path + b->d->getItem(sel - 2);
|
||||
std::string dstPath = *sdmcArgs->path + b->d->getItem(sel - 2);
|
||||
fs::copyFile(srcPath, dstPath);
|
||||
std::string srcPath = *ma->path + d->getItem(sel - 2);
|
||||
std::string dstPath = *sdmcArgs->path + d->getItem(sel - 2);
|
||||
fs::copyFileThreaded(srcPath, dstPath);
|
||||
}
|
||||
}
|
||||
else if(ma == sdmcArgs)
|
||||
|
|
@ -190,28 +191,28 @@ static void _copyMenuCopy_t(void *a)
|
|||
if(sel == 0)
|
||||
{
|
||||
if(commit)
|
||||
fs::copyDirToDirCommit(*ma->path, *devArgs->path, dev);
|
||||
fs::copyDirToDirCommitThreaded(*ma->path, *devArgs->path, dev);
|
||||
else
|
||||
fs::copyDirToDir(*ma->path, *devArgs->path);
|
||||
fs::copyDirToDirThreaded(*ma->path, *devArgs->path);
|
||||
}
|
||||
else if(sel > 1 && b->d->isDir(sel - 2))
|
||||
else if(sel > 1 && d->isDir(sel - 2))
|
||||
{
|
||||
std::string srcPath = *ma->path + b->d->getItem(sel - 2) + "/";
|
||||
std::string dstPath = *devArgs->path + b->d->getItem(sel - 2) + "/";
|
||||
std::string srcPath = *ma->path + d->getItem(sel - 2) + "/";
|
||||
std::string dstPath = *devArgs->path + d->getItem(sel - 2) + "/";
|
||||
mkdir(dstPath.substr(0, dstPath.length() - 1).c_str(), 777);
|
||||
if(commit)
|
||||
fs::copyDirToDirCommit(srcPath, dstPath, dev);
|
||||
fs::copyDirToDirCommitThreaded(srcPath, dstPath, dev);
|
||||
else
|
||||
fs::copyDirToDir(srcPath, dstPath);
|
||||
fs::copyDirToDirThreaded(srcPath, dstPath);
|
||||
}
|
||||
else if(sel > 1)
|
||||
{
|
||||
std::string srcPath = *ma->path + b->d->getItem(sel - 2);
|
||||
std::string dstPath = *devArgs->path + b->d->getItem(sel - 2);
|
||||
std::string srcPath = *ma->path + d->getItem(sel - 2);
|
||||
std::string dstPath = *devArgs->path + d->getItem(sel - 2);
|
||||
if(commit)
|
||||
fs::copyFileCommit(srcPath, dstPath, dev);
|
||||
fs::copyFileCommitThreaded(srcPath, dstPath, dev);
|
||||
else
|
||||
fs::copyFile(srcPath, dstPath);
|
||||
fs::copyFileThreaded(srcPath, dstPath);
|
||||
}
|
||||
}
|
||||
ui::newThread(refreshMenu, devArgs, NULL);
|
||||
|
|
@ -223,9 +224,11 @@ static void _copyMenuCopy_t(void *a)
|
|||
static void _copyMenuCopy(void *a)
|
||||
{
|
||||
menuFuncArgs *ma = (menuFuncArgs *)a;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
std::string srcPath, dstPath;
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
if(sel == 0 && ma == devArgs)
|
||||
{
|
||||
srcPath = *ma->path;
|
||||
|
|
@ -233,8 +236,8 @@ static void _copyMenuCopy(void *a)
|
|||
}
|
||||
else if(sel > 1 && ma == devArgs)
|
||||
{
|
||||
srcPath = *ma->path + b->d->getItem(sel - 2);
|
||||
dstPath = *sdmcArgs->path + b->d->getItem(sel - 2);
|
||||
srcPath = *ma->path + d->getItem(sel - 2);
|
||||
dstPath = *sdmcArgs->path + d->getItem(sel - 2);
|
||||
}
|
||||
else if(sel == 0 && ma == sdmcArgs)
|
||||
{
|
||||
|
|
@ -243,13 +246,13 @@ static void _copyMenuCopy(void *a)
|
|||
}
|
||||
else if(sel > 1 && ma == sdmcArgs)
|
||||
{
|
||||
srcPath = *ma->path + b->d->getItem(b->m->getSelected() - 2);
|
||||
dstPath = *devArgs->path + b->d->getItem(b->m->getSelected() - 2);
|
||||
srcPath = *ma->path + d->getItem(m->getSelected() - 2);
|
||||
dstPath = *devArgs->path + d->getItem(m->getSelected() - 2);
|
||||
}
|
||||
|
||||
if(ma == devArgs || (ma == sdmcArgs && (type != FsSaveDataType_System || cfg::config["sysSaveWrite"])))
|
||||
{
|
||||
ui::confirmArgs *send = ui::confirmArgsCreate(false, _copyMenuCopy_t, ma, true, ui::getUICString("confirmCopy", 0), srcPath.c_str(), dstPath.c_str());
|
||||
ui::confirmArgs *send = ui::confirmArgsCreate(false, _copyMenuCopy_t, NULL, ma, ui::getUICString("confirmCopy", 0), srcPath.c_str(), dstPath.c_str());
|
||||
ui::confirm(send);
|
||||
}
|
||||
}
|
||||
|
|
@ -258,11 +261,12 @@ static void _copyMenuDelete_t(void *a)
|
|||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
menuFuncArgs *ma = (menuFuncArgs *)t->argPtr;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0));
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
if(ma == devArgs)
|
||||
{
|
||||
if(sel == 0 && *ma->path != "sdmc:/")
|
||||
|
|
@ -271,16 +275,16 @@ static void _copyMenuDelete_t(void *a)
|
|||
if(commit)
|
||||
fs::commitToDevice(dev);
|
||||
}
|
||||
else if(sel > 1 && b->d->isDir(sel - 2))
|
||||
else if(sel > 1 && d->isDir(sel - 2))
|
||||
{
|
||||
std::string delPath = *ma->path + b->d->getItem(sel - 2) + "/";
|
||||
std::string delPath = *ma->path + d->getItem(sel - 2) + "/";
|
||||
fs::delDir(delPath);
|
||||
if(commit)
|
||||
fs::commitToDevice(dev);
|
||||
}
|
||||
else if(sel > 1)
|
||||
{
|
||||
std::string delPath = *ma->path + b->d->getItem(sel - 2);
|
||||
std::string delPath = *ma->path + d->getItem(sel - 2);
|
||||
fs::delfile(delPath);
|
||||
if(commit)
|
||||
fs::commitToDevice(dev);
|
||||
|
|
@ -290,14 +294,14 @@ static void _copyMenuDelete_t(void *a)
|
|||
{
|
||||
if(sel == 0 && *ma->path != "sdmc:/")
|
||||
fs::delDir(*ma->path);
|
||||
else if(sel > 1 && b->d->isDir(sel - 2))
|
||||
else if(sel > 1 && d->isDir(sel - 2))
|
||||
{
|
||||
std::string delPath = *ma->path + b->d->getItem(sel - 2) + "/";
|
||||
std::string delPath = *ma->path + d->getItem(sel - 2) + "/";
|
||||
fs::delDir(delPath);
|
||||
}
|
||||
else if(sel > 1)
|
||||
{
|
||||
std::string delPath = *ma->path + b->d->getItem(sel - 2);
|
||||
std::string delPath = *ma->path + d->getItem(sel - 2);
|
||||
fs::delfile(delPath);
|
||||
}
|
||||
}
|
||||
|
|
@ -310,18 +314,19 @@ static void _copyMenuDelete_t(void *a)
|
|||
static void _copyMenuDelete(void *a)
|
||||
{
|
||||
menuFuncArgs *ma = (menuFuncArgs *)a;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
std::string itmPath;
|
||||
if(sel == 0)
|
||||
itmPath = *ma->path;
|
||||
else if(sel > 1)
|
||||
itmPath = *ma->path + b->d->getItem(sel - 2);
|
||||
itmPath = *ma->path + d->getItem(sel - 2);
|
||||
|
||||
if(ma == sdmcArgs || (ma == devArgs && (sel == 0 || sel > 1) && (type != FsSaveDataType_System || cfg::config["sysSaveWrite"])))
|
||||
{
|
||||
ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], _copyMenuDelete_t, a, true, ui::getUICString("confirmDelete", 0), itmPath.c_str());
|
||||
ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], _copyMenuDelete_t, NULL, a, ui::getUICString("confirmDelete", 0), itmPath.c_str());
|
||||
ui::confirm(send);
|
||||
}
|
||||
}
|
||||
|
|
@ -329,15 +334,16 @@ static void _copyMenuDelete(void *a)
|
|||
static void _copyMenuRename(void *a)
|
||||
{
|
||||
menuFuncArgs *ma = (menuFuncArgs *)a;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
if(sel > 1)
|
||||
{
|
||||
std::string getNewName = util::getStringInput(SwkbdType_QWERTY, b->d->getItem(sel - 2), ui::getUIString("swkbdRename", 0), 64, 0, NULL);
|
||||
std::string getNewName = util::getStringInput(SwkbdType_QWERTY, d->getItem(sel - 2), ui::getUIString("swkbdRename", 0), 64, 0, NULL);
|
||||
if(!getNewName.empty())
|
||||
{
|
||||
std::string prevPath = *ma->path + b->d->getItem(sel - 2);
|
||||
std::string prevPath = *ma->path + d->getItem(sel - 2);
|
||||
std::string newPath = *ma->path + getNewName;
|
||||
rename(prevPath.c_str(), newPath.c_str());
|
||||
}
|
||||
|
|
@ -365,22 +371,37 @@ static void _copyMenuMkDir(void *a)
|
|||
refreshMenu(&fake);
|
||||
}
|
||||
|
||||
static void _copyMenuGetShowDirProps_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
std::string *p = (std::string *)t->argPtr;
|
||||
unsigned dirCount = 0, fileCount = 0;
|
||||
uint64_t totalSize = 0;
|
||||
t->status->setStatus(ui::getUICString("threadStatusGetDirProps", 0));
|
||||
fs::getDirProps(*p, dirCount, fileCount, totalSize);
|
||||
ui::showMessage(ui::getUICString("fileModeFolderProperties", 0), p->c_str(), dirCount, fileCount, util::getSizeString(totalSize).c_str());
|
||||
delete p;
|
||||
t->finished = true;
|
||||
}
|
||||
|
||||
static void _copyMenuGetProps(void *a)
|
||||
{
|
||||
menuFuncArgs *ma = (menuFuncArgs *)a;
|
||||
fs::backupArgs *b = (fs::backupArgs *)ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
if(sel == 0)
|
||||
fs::getShowDirProps(*ma->path);
|
||||
else if(sel > 1 && b->d->isDir(sel - 2))
|
||||
else if(sel > 1 && d->isDir(sel - 2))
|
||||
{
|
||||
std::string folderPath = *ma->path + b->d->getItem(sel - 2) + "/";
|
||||
fs::getShowDirProps(folderPath);
|
||||
std::string *folderPath = new std::string;
|
||||
folderPath->assign(*ma->path + d->getItem(sel - 2) + "/");
|
||||
ui::newThread(_copyMenuGetShowDirProps_t, folderPath, NULL);
|
||||
}
|
||||
else if(sel > 1)
|
||||
{
|
||||
std::string filePath = *ma->path + b->d->getItem(sel - 2);
|
||||
std::string filePath = *ma->path + d->getItem(sel - 2);
|
||||
fs::getShowFileProps(filePath);
|
||||
}
|
||||
}
|
||||
|
|
@ -405,14 +426,15 @@ static void _copyMenuClose(void *a)
|
|||
static void _devMenuAddToPathFilter(void *a)
|
||||
{
|
||||
menuFuncArgs *ma = (menuFuncArgs *)a;
|
||||
fs::backupArgs *b = ma->b;
|
||||
ui::menu *m = ma->m;
|
||||
fs::dirList *d = ma->d;
|
||||
|
||||
int sel = b->m->getSelected();
|
||||
int sel = m->getSelected();
|
||||
if(sel > 1)
|
||||
{
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
std::string filterPath = *ma->path + b->d->getItem(sel - 2);
|
||||
cfg::addPathToFilter(d->tid, filterPath);
|
||||
data::userTitleInfo *tinfo = data::getCurrentUserTitleInfo();
|
||||
std::string filterPath = *ma->path + d->getItem(sel - 2);
|
||||
cfg::addPathToFilter(tinfo->tid, filterPath);
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popAddedToPathFilter", 0), filterPath.c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -421,17 +443,15 @@ void ui::fmInit()
|
|||
{
|
||||
//This needs to be done in a strange order so everything works
|
||||
devArgs = new menuFuncArgs;
|
||||
devArgs->b = new fs::backupArgs;
|
||||
devArgs->path = &devPath;
|
||||
|
||||
sdmcArgs = new menuFuncArgs;
|
||||
sdmcArgs->b = new fs::backupArgs;
|
||||
sdmcArgs->path = &sdPath;
|
||||
|
||||
devMenu = new ui::menu(10, 8, 590, 18, 5);
|
||||
devMenu->setCallback(_devMenuCallback, devArgs);
|
||||
devMenu->setActive(true);
|
||||
devArgs->b->m = devMenu;
|
||||
devArgs->m = devMenu;
|
||||
|
||||
devPanel = new ui::slideOutPanel(288, 720, 0, ui::SLD_LEFT, _devCopyPanelDraw);
|
||||
devCopyMenu = new ui::menu(10, 185, 268, 20, 5);
|
||||
|
|
@ -457,7 +477,7 @@ void ui::fmInit()
|
|||
sdMenu = new ui::menu(620, 8, 590, 18, 5);
|
||||
sdMenu->setCallback(_sdMenuCallback, sdmcArgs);
|
||||
sdMenu->setActive(false);
|
||||
sdmcArgs->b->m = sdMenu;
|
||||
sdmcArgs->m = sdMenu;
|
||||
|
||||
sdPanel = new ui::slideOutPanel(288, 720, 0, ui::SLD_RIGHT, _sdCopyPanelDraw);
|
||||
sdCopyMenu = new ui::menu(10, 210, 268, 20, 5);
|
||||
|
|
@ -475,8 +495,8 @@ void ui::fmInit()
|
|||
|
||||
devList = new fs::dirList;
|
||||
sdList = new fs::dirList;
|
||||
devArgs->b->d = devList;
|
||||
sdmcArgs->b->d = sdList;
|
||||
devArgs->d = devList;
|
||||
sdmcArgs->d = sdList;
|
||||
}
|
||||
|
||||
void ui::fmExit()
|
||||
|
|
@ -487,9 +507,7 @@ void ui::fmExit()
|
|||
delete sdCopyMenu;
|
||||
delete devList;
|
||||
delete sdList;
|
||||
delete devArgs->b;
|
||||
delete devArgs;
|
||||
delete sdmcArgs->b;
|
||||
delete sdmcArgs;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
210
src/ui/ttl.cpp
210
src/ui/ttl.cpp
|
|
@ -12,7 +12,6 @@ static ui::menu *ttlOpts, *fldMenu;
|
|||
ui::slideOutPanel *ui::ttlOptsPanel;
|
||||
static ui::slideOutPanel *infoPanel, *fldPanel;//There's no reason to have a separate folder section
|
||||
static fs::dirList *fldList;
|
||||
static fs::backupArgs *backargs;
|
||||
static std::string infoPanelString;
|
||||
static SDL_Texture *fldBuffer;//This is so folder menu doesn't draw over guide
|
||||
|
||||
|
|
@ -22,42 +21,45 @@ void ui::ttlRefresh()
|
|||
ttlViews[i]->refresh();
|
||||
}
|
||||
|
||||
static void fldFuncCancel(void *a)
|
||||
{
|
||||
std::string *del = (std::string *)a;
|
||||
delete del;
|
||||
}
|
||||
|
||||
static void fldFuncOverwrite(void *a)
|
||||
{
|
||||
fs::backupArgs *b = (fs::backupArgs *)a;
|
||||
fs::dirList *d = (fs::dirList *)b->d;
|
||||
ui::menu *m = (ui::menu *)b->m;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
int sel = fldMenu->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = fldList->getItem(sel);
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + itm);
|
||||
|
||||
int sel = m->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = d->getItem(sel);
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, a, true, ui::getUICString("confirmOverwrite", 0), itm.c_str());
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, fldFuncCancel, send, ui::getUICString("confirmOverwrite", 0), itm.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncDelete(void *a)
|
||||
{
|
||||
fs::backupArgs *b = (fs::backupArgs *)a;
|
||||
fs::dirList *d = (fs::dirList *)b->d;
|
||||
ui::menu *m = (ui::menu *)b->m;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
int sel = fldMenu->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = fldList->getItem(sel);
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + itm);
|
||||
|
||||
int sel = m->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = d->getItem(sel);
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, a, true, ui::getUICString("confirmDelete", 0), itm.c_str());
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, fldFuncCancel, send, ui::getUICString("confirmDelete", 0), itm.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncRestore(void *a)
|
||||
{
|
||||
fs::backupArgs *b = (fs::backupArgs *)a;
|
||||
fs::dirList *d = (fs::dirList *)b->d;
|
||||
ui::menu *m = (ui::menu *)b->m;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
int sel = fldMenu->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = fldList->getItem(sel);
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + itm);
|
||||
|
||||
int sel = m->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = d->getItem(sel);
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, a, true, ui::getUICString("confirmRestore", 0), itm.c_str());
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, fldFuncCancel, send, ui::getUICString("confirmRestore", 0), itm.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
|
|
@ -75,18 +77,16 @@ void ui::populateFldMenu()
|
|||
sprintf(filterPath, "sdmc:/config/JKSV/0x%016lX_filter.txt", d->tid);
|
||||
fs::loadPathFilters(d->tid);
|
||||
|
||||
*backargs = {fldMenu, fldList};
|
||||
|
||||
fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0));
|
||||
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, backargs);
|
||||
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
|
||||
|
||||
for(unsigned i = 0; i < fldList->getCount(); i++)
|
||||
{
|
||||
fldMenu->addOpt(NULL, fldList->getItem(i));
|
||||
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_A, fldFuncOverwrite, backargs);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_X, fldFuncDelete, backargs);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_Y, fldFuncRestore, backargs);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_A, fldFuncOverwrite, NULL);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_X, fldFuncDelete, NULL);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_Y, fldFuncRestore, NULL);
|
||||
}
|
||||
fldMenu->setActive(true);
|
||||
fldPanel->openPanel();
|
||||
|
|
@ -151,18 +151,33 @@ static void ttlOptsPanelDraw(void *a)
|
|||
ttlOpts->draw(panel, &ui::txtCont, true);
|
||||
}
|
||||
|
||||
static void ttlOptsShowInfoPanel(void *a)
|
||||
static void ttlOptsShowInfoPanel(void *)
|
||||
{
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
|
||||
|
||||
char tmp[256];
|
||||
sprintf(tmp, ui::getUICString("infoStatus", 4), tinfo->author.c_str());
|
||||
|
||||
size_t titleWidth = gfx::getTextWidth(tinfo->title.c_str(), 18);
|
||||
size_t pubWidth = gfx::getTextWidth(tmp, 18);
|
||||
if(titleWidth > 410 || pubWidth > 410)
|
||||
{
|
||||
size_t newWidth = titleWidth > pubWidth ? titleWidth : pubWidth;
|
||||
infoPanel->resizePanel(newWidth + 40, 720, 0);
|
||||
}
|
||||
else
|
||||
infoPanel->resizePanel(410, 720, 0);
|
||||
|
||||
ttlOpts->setActive(false);
|
||||
ui::ttlOptsPanel->closePanel();
|
||||
infoPanelString = util::getInfoString(*data::getCurrentUser(), data::getCurrentUserTitleInfo()->tid);
|
||||
infoPanel->openPanel();
|
||||
}
|
||||
|
||||
static void ttlOptsBlacklistTitle(void *a)
|
||||
{
|
||||
std::string title = data::getTitleNameByTID(data::getCurrentUserTitleInfo()->tid);
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(false, cfg::addTitleToBlacklist, NULL, true, ui::getUICString("confirmBlacklist", 0), title.c_str());
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(false, cfg::addTitleToBlacklist, NULL, NULL, ui::getUICString("confirmBlacklist", 0), title.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +228,8 @@ static void ttlOptsDeleteAllBackups(void *a)
|
|||
{
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
std::string currentTitle = data::getTitleNameByTID(d->tid);
|
||||
ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteAllBackups_t, NULL, true, ui::getUICString("confirmDeleteBackupsTitle", 0), currentTitle.c_str());
|
||||
|
||||
ui::confirmArgs *send = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteAllBackups_t, NULL, NULL, ui::getUICString("confirmDeleteBackupsTitle", 0), currentTitle.c_str());
|
||||
ui::confirm(send);
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +238,7 @@ static void ttlOptsResetSaveData_t(void *a)
|
|||
threadInfo *t = (threadInfo *)a;
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
std::string title = data::getTitleNameByTID(d->tid);
|
||||
t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0), title.c_str());
|
||||
t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0));
|
||||
|
||||
fs::mountSave(d->saveInfo);
|
||||
fs::delDir("sv:/");
|
||||
|
|
@ -238,7 +254,7 @@ static void ttlOptsResetSaveData(void *a)
|
|||
if(d->saveInfo.save_data_type != FsSaveDataType_System)
|
||||
{
|
||||
std::string title = data::getTitleNameByTID(d->tid);
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsResetSaveData_t, NULL, true, ui::getUICString("confirmResetSaveData", 0), title.c_str());
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsResetSaveData_t, NULL, NULL, ui::getUICString("confirmResetSaveData", 0), title.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
}
|
||||
|
|
@ -276,89 +292,75 @@ static void ttlOptsDeleteSaveData(void *a)
|
|||
if(d->saveInfo.save_data_type != FsSaveDataType_System)
|
||||
{
|
||||
std::string title = data::getTitleNameByTID(d->tid);
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteSaveData_t, NULL, true, ui::getUICString("confirmDeleteSaveData", 0), title.c_str());
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], ttlOptsDeleteSaveData_t, NULL, NULL, ui::getUICString("confirmDeleteSaveData", 0), title.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
}
|
||||
|
||||
static void ttlOptsExtendSaveData_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
|
||||
std::string expSizeStr = util::getStringInput(SwkbdType_NumPad, "", ui::getUICString("swkbdExpandSize", 0), 4, 0, NULL);
|
||||
if(!expSizeStr.empty())
|
||||
{
|
||||
int64_t journ = 0, expSize;
|
||||
data::titleInfo *extend = data::getTitleInfoByTID(d->tid);
|
||||
t->status->setStatus(ui::getUICString("threadStatusExtendingSaveData", 0), extend->title.c_str());
|
||||
//Get journal size
|
||||
switch(d->saveInfo.save_data_type)
|
||||
{
|
||||
case FsSaveDataType_Account:
|
||||
if(extend->nacp.user_account_save_data_journal_size_max > extend->nacp.user_account_save_data_journal_size)
|
||||
journ = extend->nacp.user_account_save_data_journal_size_max;
|
||||
else
|
||||
journ = extend->nacp.user_account_save_data_journal_size;
|
||||
break;
|
||||
|
||||
case FsSaveDataType_Bcat:
|
||||
journ = extend->nacp.bcat_delivery_cache_storage_size;
|
||||
break;
|
||||
|
||||
case FsSaveDataType_Cache:
|
||||
if(extend->nacp.cache_storage_data_and_journal_size_max > extend->nacp.cache_storage_journal_size)
|
||||
journ = extend->nacp.cache_storage_data_and_journal_size_max;
|
||||
else
|
||||
journ = extend->nacp.cache_storage_journal_size;
|
||||
break;
|
||||
|
||||
case FsSaveDataType_Device:
|
||||
if(extend->nacp.device_save_data_journal_size_max > extend->nacp.device_save_data_journal_size)
|
||||
journ = extend->nacp.device_save_data_journal_size_max;
|
||||
else
|
||||
journ = extend->nacp.device_save_data_journal_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
//will just fail
|
||||
journ = 0;
|
||||
break;
|
||||
}
|
||||
uint64_t expMB = strtoul(expSizeStr.c_str(), NULL, 10);
|
||||
expSize = expMB * 0x100000;
|
||||
FsSaveDataSpaceId space = (FsSaveDataSpaceId)d->saveInfo.save_data_space_id;
|
||||
uint64_t sid = d->saveInfo.save_data_id;
|
||||
Result res = 0;
|
||||
if(R_FAILED(res = fsExtendSaveDataFileSystem(space, sid, expSize, journ)))
|
||||
{
|
||||
int64_t totalSize = 0;
|
||||
fs::mountSave(d->saveInfo);
|
||||
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize);
|
||||
fs::unmountSave();
|
||||
|
||||
fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, expSize / 1024 / 1024, res);
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0));
|
||||
}
|
||||
else
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendSuccess", 0), extend->title.c_str());
|
||||
}
|
||||
t->finished = true;
|
||||
}
|
||||
|
||||
static void ttlOptsExtendSaveData(void *a)
|
||||
{
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
if(d->saveInfo.save_data_type != FsSaveDataType_System)
|
||||
ui::newThread(ttlOptsExtendSaveData_t, NULL, NULL);
|
||||
{
|
||||
std::string expSizeStr = util::getStringInput(SwkbdType_NumPad, "", ui::getUICString("swkbdExpandSize", 0), 4, 0, NULL);
|
||||
uint64_t extMB = strtoul(expSizeStr.c_str(), NULL, 10) * 0x100000;
|
||||
fs::extendSaveDataThreaded(d, extMB);
|
||||
}
|
||||
}
|
||||
|
||||
static void infoPanelDraw(void *a)
|
||||
{
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *t = data::getTitleInfoByTID(d->tid);
|
||||
SDL_Texture *panel = (SDL_Texture *)a;
|
||||
gfx::texDraw(panel, data::getTitleIconByTID(d->tid), 77, 32);
|
||||
gfx::drawTextfWrap(panel, 18, 32, 320, 362, &ui::txtCont, infoPanelString.c_str());
|
||||
int width = 0, rectWidth = 0, iconX = 0, drawY = 310;
|
||||
SDL_QueryTexture(panel, NULL, NULL, &width, 0);
|
||||
rectWidth = width - 20;
|
||||
|
||||
iconX = (width / 2) - 128;
|
||||
gfx::texDraw(panel, data::getTitleIconByTID(d->tid), iconX, 32);
|
||||
|
||||
gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, data::getTitleNameByTID(d->tid).c_str());
|
||||
drawY += 40;
|
||||
|
||||
gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 4), t->author.c_str());
|
||||
drawY += 40;
|
||||
|
||||
gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 0), d->tid);
|
||||
drawY += 40;
|
||||
|
||||
gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 1), d->saveInfo.save_data_id);
|
||||
drawY += 40;
|
||||
|
||||
uint32_t hours, mins;
|
||||
hours = d->playStats.playtimeMinutes / 60;
|
||||
mins = d->playStats.playtimeMinutes - (hours * 60);
|
||||
gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 2), hours, mins);
|
||||
drawY += 40;
|
||||
|
||||
gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 3), d->playStats.totalLaunches);
|
||||
drawY += 40;
|
||||
|
||||
gfx::drawRect(panel, &ui::rectLt, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 5), ui::getUICString("saveDataTypeText", d->saveInfo.save_data_type));
|
||||
drawY += 40;
|
||||
|
||||
uint8_t saveType = d->saveInfo.save_data_type;
|
||||
if(saveType == FsSaveDataType_Cache)
|
||||
{
|
||||
gfx::drawRect(panel, &ui::rectSh, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 6), d->saveInfo.save_data_index);
|
||||
drawY += 40;
|
||||
}
|
||||
|
||||
gfx::drawRect(panel, saveType == FsSaveDataType_Cache ? &ui::rectLt : &ui::rectSh, 10, drawY, rectWidth, 38);
|
||||
gfx::drawTextf(panel, 18, 20, drawY + 10, &ui::txtCont, ui::getUICString("infoStatus", 7), data::getCurrentUser()->getUsername().c_str());
|
||||
}
|
||||
|
||||
static void infoPanelCallback(void *a)
|
||||
|
|
@ -426,7 +428,6 @@ void ui::ttlInit()
|
|||
ui::registerPanel(fldPanel);
|
||||
|
||||
fldList = new fs::dirList;
|
||||
backargs = new fs::backupArgs;
|
||||
|
||||
ttlOpts->setActive(false);
|
||||
for(int i = 0; i < 8; i++)
|
||||
|
|
@ -462,7 +463,6 @@ void ui::ttlExit()
|
|||
delete fldPanel;
|
||||
delete fldMenu;
|
||||
delete fldList;
|
||||
delete backargs;
|
||||
}
|
||||
|
||||
void ui::ttlSetActive(int usr)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
18
src/util.cpp
18
src/util.cpp
|
|
@ -284,6 +284,24 @@ std::string util::getStringInput(SwkbdType _type, const std::string& def, const
|
|||
return std::string(out);
|
||||
}
|
||||
|
||||
std::string util::getExtensionFromString(const std::string& get)
|
||||
{
|
||||
size_t ext = get.find_last_of('.');
|
||||
if(ext != get.npos)
|
||||
return get.substr(ext + 1, get.npos);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string util::getFilenameFromPath(const std::string& get)
|
||||
{
|
||||
size_t nameStart = get.find_last_of('/');
|
||||
if(nameStart != get.npos)
|
||||
return get.substr(nameStart + 1, get.npos);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string util::generateAbbrev(const uint64_t& tid)
|
||||
{
|
||||
data::titleInfo *tmp = data::getTitleInfoByTID(tid);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user