initial commit
This commit is contained in:
266
source/fs/dir.cpp
Normal file
266
source/fs/dir.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
#include <switch.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
#include <threads.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)
|
||||
{
|
||||
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("Opening '#%s#'...");
|
||||
|
||||
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("Copying '#%s#'...");
|
||||
|
||||
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);
|
||||
threads::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("Opening '#%s#'...");
|
||||
|
||||
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("Copying '#%s#'...");
|
||||
|
||||
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);
|
||||
threads::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);
|
||||
}
|
||||
383
source/fs/file.cpp
Normal file
383
source/fs/file.cpp
Normal file
@@ -0,0 +1,383 @@
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <switch.h>
|
||||
#include <unistd.h>
|
||||
#include <cstdarg>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <sys/stat.h>
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
#include "data.h"
|
||||
#include <threads.h>
|
||||
|
||||
static std::string wd = "sdmc:/JKSV/";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::mutex bufferLock;
|
||||
std::condition_variable cond;
|
||||
std::vector<uint8_t> sharedBuffer;
|
||||
std::string dst, dev;
|
||||
bool bufferIsFull = false;
|
||||
unsigned int filesize = 0, writeLimit = 0;
|
||||
} fileCpyThreadArgs;
|
||||
|
||||
static void writeFile_t(void *a)
|
||||
{
|
||||
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
|
||||
size_t written = 0;
|
||||
std::vector<uint8_t> localBuffer;
|
||||
std::FILE *out = std::fopen(in->dst.c_str(), "wb");
|
||||
|
||||
while(written < in->filesize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(in->bufferLock);
|
||||
in->cond.wait(buffLock, [in]{ return in->bufferIsFull;});
|
||||
localBuffer.clear();
|
||||
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferIsFull = false;
|
||||
buffLock.unlock();
|
||||
in->cond.notify_one();
|
||||
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
static void writeFileCommit_t(void *a)
|
||||
{
|
||||
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
|
||||
size_t written = 0, journalCount = 0;
|
||||
std::vector<uint8_t> localBuffer;
|
||||
FILE *out = fopen(in->dst.c_str(), "wb");
|
||||
|
||||
while(written < in->filesize)
|
||||
{`
|
||||
std::unique_lock<std::mutex> buffLock(in->bufferLock);
|
||||
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
|
||||
localBuffer.clear();
|
||||
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferIsFull = false;
|
||||
buffLock.unlock();
|
||||
in->cond.notify_one();
|
||||
|
||||
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
|
||||
|
||||
journalCount += written;
|
||||
if(journalCount >= in->writeLimit)
|
||||
{
|
||||
journalCount = 0;
|
||||
fclose(out);
|
||||
fs::commitToDevice(in->dev.c_str());
|
||||
out = fopen(in->dst.c_str(), "ab");
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
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->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;
|
||||
size_t filesize = fs::fsize(src);
|
||||
if(t)
|
||||
{
|
||||
c = (fs::copyArgs *)t->argPtr;
|
||||
c->offset = 0;
|
||||
}
|
||||
|
||||
FILE *fsrc = fopen(src.c_str(), "rb");
|
||||
if(!fsrc)
|
||||
{
|
||||
fclose(fsrc);
|
||||
return;
|
||||
}
|
||||
|
||||
fileCpyThreadArgs thrdArgs;
|
||||
thrdArgs.dst = dst;
|
||||
thrdArgs.filesize = filesize;
|
||||
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
std::vector<uint8_t> transferBuffer;
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeFile_t, &thrdArgs, NULL, 0x40000, 0x2E, 2);
|
||||
threadStart(&writeThread);
|
||||
size_t readIn = 0;
|
||||
uint64_t readCount = 0;
|
||||
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
|
||||
readCount += readIn;
|
||||
|
||||
if(c)
|
||||
c->offset = readCount;
|
||||
|
||||
if(transferBuffer.size() >= TRANSFER_BUFFER_LIMIT || readCount == filesize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
|
||||
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
|
||||
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
|
||||
transferBuffer.clear();
|
||||
thrdArgs.bufferIsFull = true;
|
||||
buffLock.unlock();
|
||||
thrdArgs.cond.notify_one();
|
||||
}
|
||||
}
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
fclose(fsrc);
|
||||
delete[] buff;
|
||||
}
|
||||
|
||||
|
||||
static void copyFileThreaded_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
|
||||
|
||||
t->status->setStatus("Copy file", in->src.c_str());
|
||||
|
||||
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);
|
||||
threads::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;
|
||||
size_t filesize = fs::fsize(src);
|
||||
if(t)
|
||||
{
|
||||
c = (fs::copyArgs *)t->argPtr;
|
||||
c->offset = 0;
|
||||
// c->prog->setMax(filesize);
|
||||
// c->prog->update(0);
|
||||
}
|
||||
|
||||
FILE *fsrc = fopen(src.c_str(), "rb");
|
||||
if(!fsrc)
|
||||
{
|
||||
fclose(fsrc);
|
||||
return;
|
||||
}
|
||||
|
||||
fileCpyThreadArgs thrdArgs;
|
||||
thrdArgs.dst = dst;
|
||||
thrdArgs.dev = dev;
|
||||
thrdArgs.filesize = filesize;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
uint64_t journalSpace = fs::getJournalSize(utinfo);
|
||||
thrdArgs.writeLimit = (journalSpace - 0x100000) < TRANSFER_BUFFER_LIMIT ? journalSpace - 0x100000 : TRANSFER_BUFFER_LIMIT;
|
||||
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeFileCommit_t, &thrdArgs, NULL, 0x040000, 0x2E, 2);
|
||||
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
size_t readIn = 0;
|
||||
uint64_t readCount = 0;
|
||||
std::vector<uint8_t> transferBuffer;
|
||||
threadStart(&writeThread);
|
||||
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
|
||||
readCount += readIn;
|
||||
if(c)
|
||||
c->offset = readCount;
|
||||
|
||||
if(transferBuffer.size() >= thrdArgs.writeLimit || readCount == filesize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
|
||||
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
|
||||
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
|
||||
transferBuffer.clear();
|
||||
thrdArgs.bufferIsFull = true;
|
||||
buffLock.unlock();
|
||||
thrdArgs.cond.notify_one();
|
||||
}
|
||||
}
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
|
||||
fclose(fsrc);
|
||||
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("Copy file", in->src.c_str());
|
||||
|
||||
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);
|
||||
threads::newThread(copyFileCommit_t, send, fs::fileDrawFunc);
|
||||
}
|
||||
|
||||
void fs::fileDrawFunc(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
if(!t->finished && t->argPtr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
remove(path.c_str());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
150
source/fs/fsfile.c
Normal file
150
source/fs/fsfile.c
Normal file
@@ -0,0 +1,150 @@
|
||||
#include <switch.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "fs/fsfile.h"
|
||||
|
||||
char *getDeviceFromPath(char *dev, size_t _max, const char *path)
|
||||
{
|
||||
memset(dev, 0, _max);
|
||||
char *c = strchr(path, ':');
|
||||
if(c - path > _max)
|
||||
return NULL;
|
||||
|
||||
//probably not good? idk
|
||||
memcpy(dev, path, c - path);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
char *getFilePath(char *pathOut, size_t _max, const char *path)
|
||||
{
|
||||
memset(pathOut, 0, _max);
|
||||
char *c = strchr(path, '/');
|
||||
size_t pLength = strlen(c);
|
||||
if(pLength > _max)
|
||||
return NULL;
|
||||
|
||||
memcpy(pathOut, c, pLength);
|
||||
|
||||
return pathOut;
|
||||
}
|
||||
|
||||
bool fsMkDir(const char *_p)
|
||||
{
|
||||
char devStr[16];
|
||||
char path[FS_MAX_PATH];
|
||||
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p))
|
||||
return false;
|
||||
|
||||
Result res = fsFsCreateDirectory(fsdevGetDeviceFileSystem(devStr), path);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
int fsremove(const char *_p)
|
||||
{
|
||||
char devStr[16];
|
||||
char path[FS_MAX_PATH];
|
||||
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p))
|
||||
return -1;
|
||||
|
||||
Result res = fsFsDeleteFile(fsdevGetDeviceFileSystem(devStr), path);
|
||||
return res;
|
||||
}
|
||||
|
||||
Result fsDelDirRec(const char *_p)
|
||||
{
|
||||
char devStr[16];
|
||||
char path[FS_MAX_PATH];
|
||||
if(!getDeviceFromPath(devStr, 16, _p) || ! getFilePath(path, FS_MAX_PATH, _p))
|
||||
return 1;
|
||||
|
||||
return fsFsDeleteDirectoryRecursively(fsdevGetDeviceFileSystem(devStr), path);
|
||||
}
|
||||
|
||||
bool fsfcreate(const char *_p, int64_t crSize)
|
||||
{
|
||||
char devStr[16];
|
||||
char filePath[FS_MAX_PATH];
|
||||
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p))
|
||||
return false;
|
||||
|
||||
FsFileSystem *s = fsdevGetDeviceFileSystem(devStr);
|
||||
if(s == NULL)
|
||||
return false;
|
||||
|
||||
Result res = fsFsCreateFile(s, filePath, crSize, 0);
|
||||
if(R_SUCCEEDED(res))
|
||||
res = fsdevCommitDevice(devStr);
|
||||
|
||||
return R_SUCCEEDED(res) ? true : false;
|
||||
}
|
||||
|
||||
FSFILE *fsfopen(const char *_p, uint32_t mode)
|
||||
{
|
||||
char devStr[16];
|
||||
char filePath[FS_MAX_PATH];
|
||||
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p))
|
||||
return NULL;
|
||||
|
||||
FsFileSystem *s = fsdevGetDeviceFileSystem(devStr);
|
||||
if(s == NULL)
|
||||
return NULL;
|
||||
|
||||
if(mode == FsOpenMode_Write)
|
||||
{
|
||||
fsFsDeleteFile(s, filePath);
|
||||
fsFsCreateFile(s, filePath, 0, 0);
|
||||
}
|
||||
|
||||
FSFILE *ret = malloc(sizeof(FSFILE));
|
||||
ret->error = fsFsOpenFile(s, filePath, mode, &ret->_f);
|
||||
if(R_FAILED(ret->error))
|
||||
{
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
fsFileGetSize(&ret->_f, &ret->fsize);
|
||||
ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode)
|
||||
{
|
||||
if(mode & FsOpenMode_Write)
|
||||
{
|
||||
fsFsDeleteFile(_s, _p);
|
||||
fsFsCreateFile(_s, _p, 0, 0);
|
||||
}
|
||||
else if(mode & FsOpenMode_Append)
|
||||
fsFsCreateFile(_s, _p, 0, 0);
|
||||
|
||||
FSFILE *ret = malloc(sizeof(FSFILE));
|
||||
ret->error = fsFsOpenFile(_s, _p, mode, &ret->_f);
|
||||
if(R_FAILED(ret->error))
|
||||
{
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
fsFileGetSize(&ret->_f, &ret->fsize);
|
||||
ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f)
|
||||
{
|
||||
size_t fullSize = sz * count;
|
||||
if(_f->offset + fullSize > _f->fsize)
|
||||
{
|
||||
s64 newSize = (_f->fsize + fullSize) - (_f->fsize - _f->offset);
|
||||
fsFileSetSize(&_f->_f, newSize);
|
||||
_f->fsize = newSize;
|
||||
}
|
||||
_f->error = fsFileWrite(&_f->_f, _f->offset, buf, fullSize, FsWriteOption_Flush);
|
||||
_f->offset += fullSize;
|
||||
|
||||
return fullSize;
|
||||
}
|
||||
251
source/fs/zip.cpp
Normal file
251
source/fs/zip.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
#include <switch.h>
|
||||
#include <time.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
#include "threads.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::mutex buffLock;
|
||||
std::condition_variable cond;
|
||||
std::vector<uint8_t> sharedBuffer;
|
||||
std::string dst, dev;
|
||||
bool bufferIsFull = false;
|
||||
unzFile unz;
|
||||
unsigned int fileSize, writeLimit = 0;
|
||||
} unzThrdArgs;
|
||||
|
||||
static void writeFileFromZip_t(void *a)
|
||||
{
|
||||
unzThrdArgs *in = (unzThrdArgs *)a;
|
||||
std::vector<uint8_t> localBuffer;
|
||||
unsigned int written = 0, journalCount = 0;
|
||||
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
uint64_t journalSpace = fs::getJournalSize(utinfo);
|
||||
|
||||
FILE *out = fopen(in->dst.c_str(), "wb");
|
||||
while(written < in->fileSize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(in->buffLock);
|
||||
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
|
||||
localBuffer.clear();
|
||||
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferIsFull = false;
|
||||
buffLock.unlock();
|
||||
in->cond.notify_one();
|
||||
|
||||
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
|
||||
journalCount += written;
|
||||
if(journalCount >= in->writeLimit)
|
||||
{
|
||||
journalCount = 0;
|
||||
fclose(out);
|
||||
fs::commitToDevice(in->dev);
|
||||
out = fopen(in->dst.c_str(), "ab");
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t)
|
||||
{
|
||||
fs::copyArgs *c = NULL;
|
||||
if(t)
|
||||
{
|
||||
t->status->setStatus("threadStatusOpeningFolder");
|
||||
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("threadStatusAddingFileToZip");
|
||||
|
||||
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[ZIP_BUFF_SIZE];
|
||||
while((readIn = fread(buff, 1, ZIP_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);
|
||||
threads::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("threadStatusDecompressingFile");
|
||||
|
||||
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));
|
||||
|
||||
unzThrdArgs unzThrd;
|
||||
unzThrd.dst = fullDst;
|
||||
unzThrd.fileSize = info.uncompressed_size;
|
||||
unzThrd.dev = dev;
|
||||
unzThrd.writeLimit = (journalSize - 0x100000) < TRANSFER_BUFFER_LIMIT ? (journalSize - 0x100000) : TRANSFER_BUFFER_LIMIT;
|
||||
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeFileFromZip_t, &unzThrd, NULL, 0x8000, 0x2B, 2);
|
||||
threadStart(&writeThread);
|
||||
|
||||
std::vector<uint8_t> transferBuffer;
|
||||
uint64_t readCount = 0;
|
||||
while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0)
|
||||
{
|
||||
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
|
||||
readCount += readIn;
|
||||
|
||||
if(c)
|
||||
c->offset += readIn;
|
||||
|
||||
if(transferBuffer.size() >= unzThrd.writeLimit || readCount == info.uncompressed_size)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(unzThrd.buffLock);
|
||||
unzThrd.cond.wait(buffLock, [&unzThrd]{ return unzThrd.bufferIsFull == false; });
|
||||
unzThrd.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
|
||||
transferBuffer.clear();
|
||||
unzThrd.bufferIsFull = true;
|
||||
unzThrd.cond.notify_one();
|
||||
}
|
||||
}
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
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);
|
||||
threads::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;
|
||||
}
|
||||
Reference in New Issue
Block a user