WiiFlow_Lite/source/fileOps/fileOps.c
fledge68 66c17c023c -removed sd only arg and replaced it with eisteinx2's code to detect sd only. with slight change because mountall() is called in other places.
-fixed font glyph x spacing so letters like W no longer bleed into or look like they connect to the next letter. also fixes letters like j's. thanks to usbloader gx freetypegx code.
-changed some font sizing. but had to make button fonts in bold. if not bold then sometime's the text would fade out and be hard to read. something to do with the wiiflow button images being transparent. has no effect on non transparent buttons like carbonik abz theme.
-fixed wfl so time and date in games is correct. thanks aphirst!
-now unloading theme.ini from mem after all buttons and labels are created. this is possible since coverflow.ini is now seperate from theme.ini.
- other minor code changes and rem's put in for easier code decyphering.
2018-07-09 14:53:35 +00:00

456 lines
8.7 KiB
C

/*////////////////////////////////////////////////////////////////////////////////////////
fsop contains coomprensive set of function for file and folder handling
en exposed s_fsop fsop structure can be used by callback to update operation status
////////////////////////////////////////////////////////////////////////////////////////*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <ogcsys.h>
#include <ogc/lwp_watchdog.h>
#include <malloc.h>
#include <sys/statvfs.h>
#include "fileOps/fileOps.h"
#include "gecko/gecko.hpp"
#include "loader/utils.h"
#define SET(a, b) a = b; DCFlushRange(&a, sizeof(a));
#define STACKSIZE 8192
static u8 *buff = NULL;
static FILE *fs = NULL, *ft = NULL;
static u32 block = 32768;
static u32 blockIdx = 0;
static u32 blockInfo[2] = {0,0};
static u32 blockReady = 0;
static s32 stopThread;
static u64 folderSize = 0;
u64 FolderProgressBytes;
// return false if the file doesn't exist
bool fsop_GetFileSizeBytes(const char *path, u32 *filesize) // for me stats st_size report always 0 :(
{
FILE *f;
size_t size = 0;
f = fopen(path, "rb");
if(!f)
{
if(filesize)
*filesize = size;
return false;
}
//Get file size
fseek(f, 0, SEEK_END);
size = ftell(f);
if(filesize)
*filesize = size;
fclose(f);
return true;
}
/*
Recursive fsop_GetFolderBytes
*/
u64 fsop_GetFolderBytes(const char *source)
{
DIR *pdir;
struct dirent *pent;
char newSource[1024];
u64 bytes = 0;
pdir = opendir(source);
while((pent = readdir(pdir)) != NULL)
{
// Skip it
if(pent->d_name[0] == '.')
continue;
snprintf(newSource, sizeof(newSource), "%s/%s", source, pent->d_name);
// If it is a folder... recurse...
if(fsop_FolderExist(newSource))
bytes += fsop_GetFolderBytes(newSource);
else // It is a file !
{
u32 s;
fsop_GetFileSizeBytes(newSource, &s);
bytes += s;
}
}
closedir(pdir);
return bytes;
}
u32 fsop_GetFolderKb(const char *source)
{
u32 ret = (u32)round((double)fsop_GetFolderBytes (source) / 1000.0);
return ret;
}
u32 fsop_GetFreeSpaceKb(const char *path) // Return free kb on the device passed
{
struct statvfs s;
statvfs(path, &s);
u32 ret = (u32)round(((double)s.f_bfree / 1000.0) * s.f_bsize);
return ret ;
}
static void *thread_CopyFileReader()
{
u32 rb;
stopThread = 0;
DCFlushRange(&stopThread, sizeof(stopThread));
do
{
SET(rb, fread(&buff[blockIdx*block], 1, block, fs));
SET(blockInfo[blockIdx], rb);
SET(blockReady, 1);
while(blockReady && !stopThread)
usleep(1);
}
while(stopThread == 0);
stopThread = -1;
DCFlushRange(&stopThread, sizeof(stopThread));
return 0;
}
bool fsop_CopyFile(const char *source, const char *target, progress_callback_t spinner, void *spinner_data)
{
//gprintf("Creating file: %s\n", target);
int err = 0;
u32 size;
u32 rb, wb;
fs = fopen(source, "rb");
if(!fs)
return false;
ft = fopen(target, "wb");
if(!ft)
{
fclose(fs);
return false;
}
//Get file size
fseek(fs, 0, SEEK_END);
size = ftell(fs);
if (size == 0)
{
fclose(fs);
fclose(ft);
return true;
}
// Return to beginning....
fseek(fs, 0, SEEK_SET);
u8 *threadStack = NULL;
lwp_t hthread = LWP_THREAD_NULL;
buff = malloc(block * 2);
if(buff == NULL)
return false;
blockIdx = 0;
blockReady = 0;
blockInfo[0] = 0;
blockInfo[1] = 0;
u32 bytes = 0;
threadStack = malloc(STACKSIZE);
if(threadStack == NULL)
{
free(buff);
return false;
}
LWP_CreateThread(&hthread, thread_CopyFileReader, NULL, threadStack, STACKSIZE, 30);
while(stopThread != 0)
usleep(5);
u32 bi;
do
{
while(!blockReady)
usleep(1); // Let's wait for incoming block from the thread
bi = blockIdx;
// let's th thread to read the next buff
SET(blockIdx, 1 - blockIdx);
SET(blockReady, 0);
rb = blockInfo[bi];
// write current block
wb = fwrite(&buff[bi*block], 1, rb, ft);
if(wb != rb || rb == 0)
err = 1;
bytes += rb;
if(spinner)
{
FolderProgressBytes += rb;
spinner(FolderProgressBytes, folderSize, spinner_data);
}
}
while(bytes < size && err == 0);
stopThread = 1;
DCFlushRange(&stopThread, sizeof(stopThread));
while(stopThread != -1)
usleep(5);
LWP_JoinThread(hthread, NULL);
free(threadStack);
stopThread = 1;
DCFlushRange(&stopThread, sizeof(stopThread));
fclose(fs);
fclose(ft);
free(buff);
if(err)
{
unlink(target);
return false;
}
return true;
}
/*
Recursive copyfolder
*/
static bool doCopyFolder(const char *source, const char *target, progress_callback_t spinner, void *spinner_data)
{
DIR *pdir;
struct dirent *pent;
char newSource[1024], newTarget[1024];
bool ret = true;
// If target folder doesn't exist, create it !
fsop_MakeFolder(target);
pdir = opendir(source);
while((pent = readdir(pdir)) != NULL && ret == true)
{
// Skip it
if(pent->d_name[0] == '.')
continue;
snprintf(newSource, sizeof(newSource), "%s/%s", source, pent->d_name);
snprintf(newTarget, sizeof(newTarget), "%s/%s", target, pent->d_name);
// If it is a folder... recurse...
if(fsop_FolderExist(newSource))
ret = doCopyFolder(newSource, newTarget, spinner, spinner_data);
else // It is a file !
ret = fsop_CopyFile(newSource, newTarget, spinner, spinner_data);
}
closedir(pdir);
return ret;
}
bool fsop_CopyFolder(const char *source, const char *target, progress_callback_t spinner, void *spinner_data)
{
gprintf("DML game USB->SD job started!\n");
FolderProgressBytes = 0;
folderSize = fsop_GetFolderBytes(source);
return doCopyFolder(source, target, spinner, spinner_data);
}
void fsop_deleteFolder(const char *source)
{
DIR *pdir;
struct dirent *pent;
char newSource[1024];
pdir = opendir(source);
/* first delete all subfolders and files in the folder */
while((pent = readdir(pdir)) != NULL)
{
// Skip it
if(pent->d_name[0] == '.')
continue;
snprintf(newSource, sizeof(newSource), "%s/%s", source, pent->d_name);
// If it is a folder... recurse...
if(fsop_FolderExist(newSource))
{
closedir(pdir);
fsop_deleteFolder(newSource);
pdir = opendir(source);
}
else // It is a file !
{
closedir(pdir);
fsop_deleteFile(newSource);
pdir = opendir(source);
}
}
closedir(pdir);
/* now actually delete the folder */
gprintf("Deleting directory: %s\n", source);
unlink(source);// using POSIX unlink to delete the folder
}
bool fsop_FileExist(const char *fn)
{
FILE * f;
f = fopen(fn, "rb");
if(f)
{
fclose(f);
return true;
}
return false;
}
void fsop_ReadFileLoc(const char *path, const u32 size, void *loc)
{
FILE *f = fopen(path, "rb");
fread(loc, size, 1, f);
fclose(f);
}
u8 *fsop_ReadFile(const char *path, u32 *size)
{
*(size) = 0;
u32 filesize = 0;
u8 *mem = NULL;
fsop_GetFileSizeBytes(path, &filesize);
if(filesize > 0)
{
mem = (u8*)MEM2_alloc(filesize);
if(mem != NULL)
{
//gprintf("Reading file: %s\n", path);
fsop_ReadFileLoc(path, filesize, mem);
*(size) = filesize;
}
}
return mem;
}
bool fsop_WriteFile(const char *path, const void *mem, const u32 size)
{
if(mem == NULL || size == 0)
return false;
FILE *f = fopen(path, "wb");
if(f == NULL)
return false;
//gprintf("Writing file: %s\n", path);
fwrite(mem, size, 1, f);
fclose(f);
return true;
}
void fsop_deleteFile(const char *source)
{
if(!fsop_FileExist(source))
return;
remove(source);
}
bool fsop_FolderExist(const char *path)
{
DIR *dir;
dir = opendir(path);
if(dir)
{
closedir(dir);
return true;
}
return false;
}
/*void fsop_MakeFolder(const char *path)
{
if(fsop_FolderExist(path))
return;
//gprintf("Folder path to create: %s\n", path);
mkdir(path, S_IREAD | S_IWRITE);
}*/
bool fsop_MakeFolder(const char *fullpath)
{
if(!fullpath)
return false;
bool result = false;
char dirnoslash[strlen(fullpath)+1];
strcpy(dirnoslash, fullpath);
int pos = strlen(dirnoslash)-1;
while(dirnoslash[pos] == '/')
{
dirnoslash[pos] = '\0';
pos--;
}
if(fsop_FolderExist(dirnoslash))
{
return true;
}
else
{
char parentpath[strlen(dirnoslash)+2];
strcpy(parentpath, dirnoslash);
char * ptr = strrchr(parentpath, '/');
if(!ptr)
{
//!Device root directory (must be with '/')
strcat(parentpath, "/");
struct stat filestat;
if (stat(parentpath, &filestat) == 0)
return true;
return false;
}
ptr++;
ptr[0] = '\0';
result = fsop_MakeFolder(parentpath);
}
if(!result)
return false;
if (mkdir(dirnoslash, 0777) == -1)
{
return false;
}
return true;
}