TDT/arm9/src/storage.c
2019-06-20 14:24:53 -05:00

530 lines
9.3 KiB
C

#include "storage.h"
#include "main.h"
#include "message.h"
#include <dirent.h>
#define TITLE_LIMIT 39
//printing
void printBytes(unsigned long long bytes)
{
if (bytes < 1024)
iprintf("%dB", (unsigned int)bytes);
else if (bytes < 1024 * 1024)
printf("%.2fKB", (float)bytes / 1024.f);
else if (bytes < 1024 * 1024 * 1024)
printf("%.2fMB", (float)bytes / 1024.f / 1024.f);
else
printf("%.2fGB", (float)bytes / 1024.f / 1024.f / 1024.f);
}
//progress bar
static int lastBars = 0;
void printProgressBar(float percent)
{
if (percent < 0.f) percent = 0.f;
if (percent > 1.f) percent = 1.f;
int bars = (int)(30.f * percent);
//skip redundant prints
if (bars != lastBars)
{
consoleSelect(&topScreen);
iprintf("\x1B[42m"); //green
//Print frame
if (lastBars <= 0)
{
iprintf("\x1b[23;0H[");
iprintf("\x1b[23;31H]");
}
//Print bars
if (bars > 0)
{
for (int i = 0; i < bars; i++)
iprintf("\x1b[23;%dH|", 1 + i);
}
lastBars = bars;
iprintf("\x1B[47m"); //white
}
}
void clearProgressBar()
{
lastBars = 0;
consoleSelect(&topScreen);
iprintf("\x1b[23;0H ");
}
//files
bool fileExists(char const* path)
{
if (!path) return false;
FILE* f = fopen(path, "rb");
if (!f)
return false;
fclose(f);
return true;
}
int copyFile(char const* src, char const* dst)
{
if (!src) return 1;
unsigned long long size = getFileSizePath(src);
return copyFilePart(src, 0, size, dst);
}
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst)
{
if (!src) return 1;
if (!dst) return 2;
FILE* fin = fopen(src, "rb");
if (!fin)
{
fclose(fin);
return 3;
}
else
{
FILE* fout = fopen(dst, "wb");
if (!fout)
{
fclose(fin);
fclose(fout);
return 4;
}
else
{
fseek(fin, offset, SEEK_SET);
consoleSelect(&topScreen);
int bytesRead;
unsigned int totalBytesRead = 0;
#define BUFF_SIZE 128 //Arbitrary. A value too large freezes the ds.
char* buffer = (char*)malloc(BUFF_SIZE);
while (1)
{
unsigned int toRead = BUFF_SIZE;
if (size - totalBytesRead < BUFF_SIZE)
toRead = size - totalBytesRead;
bytesRead = fread(buffer, 1, toRead, fin);
fwrite(buffer, bytesRead, 1, fout);
totalBytesRead += bytesRead;
printProgressBar( ((float)totalBytesRead / (float)size) );
if (bytesRead != BUFF_SIZE)
break;
}
clearProgressBar();
consoleSelect(&bottomScreen);
free(buffer);
}
fclose(fout);
}
fclose(fin);
return 0;
}
unsigned long long getFileSize(FILE* f)
{
if (!f) return 0;
fseek(f, 0, SEEK_END);
unsigned long long size = ftell(f);
fseek(f, 0, SEEK_SET);
return size;
}
unsigned long long getFileSizePath(char const* path)
{
if (!path) return 0;
FILE* f = fopen(path, "rb");
unsigned long long size = getFileSize(f);
fclose(f);
return size;
}
bool padFile(char const* path, int size)
{
if (!path) return false;
FILE* f = fopen(path, "ab");
if (!f)
{
return false;
}
else
{
char zero = 0;
fwrite(&zero, size, 1, f);
}
fclose(f);
return true;
}
//directories
bool dirExists(char const* path)
{
if (!path) return false;
DIR* dir = opendir(path);
if (!dir)
return false;
closedir(dir);
return true;
}
bool copyDir(char const* src, char const* dst)
{
if (!src || !dst) return false;
// iprintf("copyDir\n%s\n%s\n\n", src, dst);
bool result = true;
DIR* dir = opendir(src);
struct dirent* ent;
if (!dir)
{
return false;
}
else
{
while ( (ent = readdir(dir)) )
{
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
continue;
if (ent->d_type == DT_DIR)
{
char* dsrc = (char*)malloc(strlen(src) + strlen(ent->d_name) + 1);
sprintf(dsrc, "%s/%s", src, ent->d_name);
char* ddst = (char*)malloc(strlen(dst) + strlen(ent->d_name) + 1);
sprintf(ddst, "%s/%s", dst, ent->d_name);
mkdir(ddst, 0777);
if (!copyDir(dsrc, ddst))
result = false;
free(ddst);
free(dsrc);
}
else
{
char* fsrc = (char*)malloc(strlen(src) + strlen(ent->d_name) + 1);
sprintf(fsrc, "%s/%s", src, ent->d_name);
char* fdst = (char*)malloc(strlen(dst) + strlen(ent->d_name) + 1);
sprintf(fdst, "%s/%s", dst, ent->d_name);
// iprintf("%s\n%s\n\n", fsrc, fdst);
iprintf("%s...", fdst);
int ret = copyFile(fsrc, fdst);
if(ret != 0)
{
iprintf("\x1B[31m"); //red
iprintf("Fail\n");
iprintf("\x1B[33m"); //yellow
switch (ret)
{
case 1:
iprintf("Empty input path.\n");
break;
case 2:
iprintf("Empty output path.\n");
break;
case 3:
iprintf("Error opening input file.\n");
break;
case 4:
iprintf("Error opening output file.\n");
break;
}
iprintf("\x1B[47m"); //white
result = false;
}
else
{
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
free(fdst);
free(fsrc);
}
}
}
closedir(dir);
return result;
}
bool deleteDir(char const* path)
{
if (!path) return false;
if (strcmp("/", path) == 0)
{
//oh fuck no
return false;
}
bool result = true;
DIR* dir = opendir(path);
struct dirent* ent;
if (!dir)
{
result = false;
}
else
{
while ( (ent = readdir(dir)) )
{
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
continue;
if (ent->d_type == DT_DIR)
{
//Delete directory
char subpath[512];
sprintf(subpath, "%s/%s", path, ent->d_name);
if (!deleteDir(subpath))
result = false;
}
else
{
//Delete file
char fpath[512];
sprintf(fpath, "%s/%s", path, ent->d_name);
iprintf("%s...", fpath);
if (remove(fpath) != 0)
{
iprintf("\x1B[31m");
iprintf("Fail\n");
iprintf("\x1B[47m");
result = false;
}
else
{
iprintf("\x1B[42m");
iprintf("Done\n");
iprintf("\x1B[47m");
}
}
}
}
closedir(dir);
iprintf("%s...", path);
if (remove(path) != 0)
{
iprintf("\x1B[31m");
iprintf("Fail\n");
iprintf("\x1B[47m");
result = false;
}
else
{
iprintf("\x1B[42m");
iprintf("Done\n");
iprintf("\x1B[47m");
}
return result;
}
unsigned long long getDirSize(const char* path)
{
if (!path) return 0;
unsigned long long size = 0;
DIR* dir = opendir(path);
struct dirent* ent;
if (dir)
{
while ((ent = readdir(dir)))
{
if(strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
continue;
if (ent->d_type == DT_DIR)
{
char fullpath[512];
sprintf(fullpath, "%s/%s", path, ent->d_name);
size += getDirSize(fullpath);
}
else
{
char fullpath[260];
sprintf(fullpath, "%s/%s", path, ent->d_name);
size += getFileSizePath(fullpath);
}
}
}
closedir(dir);
return size;
}
//home menu
int getMenuSlots()
{
//Assume the home menu has a hard limit on slots
//Find a better way to do this
return TITLE_LIMIT;
}
int getMenuSlotsFree()
{
//Get number of open menu slots by subtracting the number of directories in the title folders
//Find a better way to do this
const int NUM_OF_DIRS = 3;
const char* dirs[] = {
"00030004",
"00030005",
"00030015"
};
int freeSlots = getMenuSlots();
DIR* dir;
struct dirent* ent;
for (int i = 0; i < NUM_OF_DIRS; i++)
{
char path[256];
sprintf(path, "/title/%s", dirs[i]);
dir = opendir(path);
if (dir)
{
while ( (ent = readdir(dir)) != NULL )
{
if(strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
continue;
if (ent->d_type == DT_DIR)
freeSlots -= 1;
}
}
closedir(dir);
}
return freeSlots;
}
//SD card
bool sdIsInserted()
{
//Find a better way to do this.
return true;
}
unsigned long long getSDCardSize()
{
if (sdIsInserted())
{
struct statvfs st;
if (statvfs("/", &st) == 0)
return st.f_bsize * st.f_blocks;
}
return 0;
}
unsigned long long getSDCardFree()
{
if (sdIsInserted())
{
struct statvfs st;
if (statvfs("/", &st) == 0)
return st.f_bsize * st.f_bavail;
}
return 0;
}
//internal storage
unsigned long long getDsiSize()
{
//The DSi has 256MB of internal storage. Some is unavailable and used by other things.
//Find a better way to do this
return 240 * 1024 * 1024;
}
unsigned long long getDsiFree()
{
//Get free space by subtracting file sizes in emulated nand folders
//Find a better way to do this
long long size = getDsiSize();
size -= getDirSize("/sys");
size -= getDirSize("/title/0003000f");
size -= getDirSize("/title/00030004");
size -= getDirSize("/title/00030005");
size -= getDirSize("/title/00030017");
size -= getDirSize("/ticket");
size -= getDirSize("/shared1");
size -= getDirSize("/shared2");
size -= getDirSize("/import");
size -= getDirSize("/tmp");
size -= getDirSize("/progress");
size -= getDirSize("/photo");
size -= getDirSize("/private");
if (size < 0)
return 0;
return (unsigned long long)size;
}