mirror of
				https://github.com/nitraiolo/CfgUSBLoader.git
				synced 2025-10-31 07:15:57 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			486 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			486 lines
		
	
	
		
			9.1 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 <malloc.h>
 | |
| #include <math.h>
 | |
| #include <ogcsys.h>
 | |
| #include <ogc/lwp_watchdog.h>
 | |
| 
 | |
| #include <dirent.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/stat.h> //for mkdir 
 | |
| #include <sys/statvfs.h>
 | |
| 
 | |
| #define GB_SIZE         1073741824.0
 | |
| 
 | |
| #include "fileOps.h"
 | |
| #include "video.h"
 | |
| #include "gettext.h"
 | |
| #include "util.h"
 | |
| #include "wpad.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 = 65536 * 8;
 | |
| static u32 blockIdx = 0;
 | |
| static u32 blockInfo[2] = {0,0};
 | |
| static u32 blockReady = 0;
 | |
| static u32 stopThread;
 | |
| static u64 folderSize = 0;
 | |
| static u64 bytesCopiedPrevFiles = 0;
 | |
| 
 | |
| void __Copy_Spinner(s64 x, u64 max)
 | |
| {
 | |
| 	static time_t start;
 | |
| 	static u32 expected;
 | |
| 	static u32 prev_d;
 | |
| 
 | |
| 	f32 percent, size;
 | |
| 	u32 d, h, m, s;
 | |
| 
 | |
| 	/* First time */
 | |
| 	if (!x) {
 | |
| 		start    = time(0);
 | |
| 		expected = 300;
 | |
| 	}
 | |
| 
 | |
| 	/* Elapsed time */
 | |
| 	d = time(0) - start;
 | |
| 
 | |
| 	if (x != max) {
 | |
| 		/* only update the display once a second results in 25% speed improvement */
 | |
| 		if (prev_d == d) return;
 | |
| 		prev_d = d;
 | |
| 		
 | |
| 		/* Expected time */
 | |
| 		if (d && x)
 | |
| 			expected = (expected * 3 + d * max / x) / 4;
 | |
| 
 | |
| 		/* Remaining time */
 | |
| 		d = (expected > d) ? (expected - d) : 1;
 | |
| 	}
 | |
| 
 | |
| 	/* Calculate time values */
 | |
| 	h =  d / 3600;
 | |
| 	m = (d / 60) % 60;
 | |
| 	s =  d % 60;
 | |
| 
 | |
| 	/* Calculate percentage/size */
 | |
| 	percent = (x * 100.0) / max;
 | |
| 	size = (max / GB_SIZE);
 | |
| 
 | |
| 	Con_ClearLine();
 | |
| 
 | |
| 	/* Show progress */
 | |
| 	if (x != max) {
 | |
| 		printf_(gt("%.2f%% of %.2fGB (%c) ETA: %d:%02d:%02d"),
 | |
| 				percent, size, "/-\\|"[(x / 10) % 4], h, m, s);
 | |
| 		printf("\r");
 | |
| 		fflush(stdout);
 | |
| 	} else {
 | |
| 		printf_(gt("%.2fGB copied in %d:%02d:%02d"), size, h, m, s);
 | |
| 		printf("  \n");
 | |
| //	printf(gt("Press any button..."));
 | |
| //	printf("\n");
 | |
| //	Wpad_WaitButtons();
 | |
| 	}
 | |
| 
 | |
| 	__console_flush(1);
 | |
| }
 | |
| 
 | |
| // return false if the file doesn't exist
 | |
| bool fsop_GetFileSizeBytes (char *path, size_t *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 (char *source)
 | |
| {
 | |
| 	DIR *pdir;
 | |
| 	struct dirent *pent;
 | |
| 	char newSource[300];
 | |
| 	u64 bytes = 0;
 | |
| 	
 | |
| 	pdir=opendir(source);
 | |
| 	
 | |
| 	while ((pent=readdir(pdir)) != NULL) 
 | |
| 	{
 | |
| 		// Skip it
 | |
| 		if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0)
 | |
| 			continue;
 | |
| 			
 | |
| 		sprintf (newSource, "%s/%s", source, pent->d_name);
 | |
| 		
 | |
| 		// If it is a folder... recurse...
 | |
| 		if (fsop_DirExist (newSource))
 | |
| 		{
 | |
| 			bytes += fsop_GetFolderBytes (newSource);
 | |
| 		}
 | |
| 		else	// It is a file !
 | |
| 		{
 | |
| 			size_t s;
 | |
| 			fsop_GetFileSizeBytes (newSource, &s);
 | |
| 			bytes += s;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	closedir(pdir);
 | |
| 	
 | |
| 	//Debug ("fsop_GetFolderBytes (%s) = %llu", source, bytes);
 | |
| 	
 | |
| 	return bytes;
 | |
| 	}
 | |
| 
 | |
| u32 fsop_GetFolderKb (char *source)
 | |
| {
 | |
| 	u32 ret = (u32) round ((double)fsop_GetFolderBytes (source) / 1000.0);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| u32 fsop_GetFreeSpaceKb (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 ;
 | |
| }
 | |
| 
 | |
| bool fsop_FileExist (char *fn)
 | |
| {
 | |
| 	FILE * f;
 | |
| 	f = fopen(fn, "rb");
 | |
| 	if (!f) return false;
 | |
| 	fclose(f);
 | |
| 	return true;
 | |
| }
 | |
| 	
 | |
| bool fsop_DirExist (char *path)
 | |
| {
 | |
| 	DIR *dir;
 | |
| 	
 | |
| 	dir=opendir(path);
 | |
| 	if (dir)
 | |
| 	{
 | |
| 		closedir(dir);
 | |
| 		return true;
 | |
| 	}
 | |
| 	
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| static void *thread_CopyFileReader (void *arg)
 | |
| {
 | |
| 	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 doCopyFile (char *source, char *target)
 | |
| {
 | |
| 	int err = 0;
 | |
| 
 | |
| 	u32 size;
 | |
| 	u32 bytes, rb,wb;
 | |
| 	
 | |
| 	if (strstr (source, "usb:") && strstr (target, "usb:"))
 | |
| 	{
 | |
| 		block = 1024*1024;
 | |
| 	}
 | |
| 	else block = 65536 * 8;
 | |
| 	
 | |
| 	fs = fopen(source, "rb");
 | |
| 	if (!fs)
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	ft = fopen(target, "wt");
 | |
| 	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 = memalign (32, block*2);
 | |
| 	if (buff == NULL) 
 | |
| 	{
 | |
| 		fclose (fs);
 | |
| 		fclose (ft);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	blockIdx = 0;
 | |
| 	blockReady = 0;
 | |
| 	blockInfo[0] = 0;
 | |
| 	blockInfo[1] = 0;
 | |
| 
 | |
| 	threadStack = memalign(32,STACKSIZE);
 | |
| 	LWP_CreateThread (&hthread, thread_CopyFileReader, NULL, threadStack, STACKSIZE, 30);
 | |
| 
 | |
| 	while (stopThread != 0)
 | |
| 		usleep (5);
 | |
| 
 | |
| 	bytes = 0;
 | |
| 	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 (rb != wb) err = 1;
 | |
| 		if (rb == 0) err = 1;
 | |
| 		bytes += rb;
 | |
| 
 | |
| 		__Copy_Spinner(bytes + bytesCopiedPrevFiles, folderSize);
 | |
| 	}
 | |
| 	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);
 | |
| 	
 | |
| 	bytesCopiedPrevFiles += bytes; 		//keep total bytes when copying dir
 | |
| 
 | |
| 	if (err) 
 | |
| 	{
 | |
| 		unlink (target);
 | |
| 		return false;
 | |
| 	}
 | |
| 	
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool fsop_CopyFile (char *source, char *target)
 | |
| {
 | |
| 	size_t s;
 | |
| 	fsop_GetFileSizeBytes (source, &s);
 | |
| 	folderSize = s;
 | |
| 	__Copy_Spinner(0, folderSize);				// init spinner
 | |
| 	bytesCopiedPrevFiles = 0;
 | |
| 
 | |
| 	return doCopyFile (source, target);
 | |
| }
 | |
| 
 | |
| /*
 | |
| Semplified folder make
 | |
| */
 | |
| bool fsop_MakeFolder (char *path)
 | |
| {
 | |
| 	if (mkdir(path, S_IREAD | S_IWRITE) == 0) return true;
 | |
| 	
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| /*
 | |
| Recursive copyfolder
 | |
| */
 | |
| static bool doCopyFolder (char *source, char *target)
 | |
| {
 | |
| 	DIR *pdir;
 | |
| 	struct dirent *pent;
 | |
| 	char newSource[300], newTarget[300];
 | |
| 	bool ret = true;
 | |
| 	
 | |
| 	// If target folder doesn't exist, create it !
 | |
| 	if (!fsop_DirExist (target))
 | |
| 	{
 | |
| 		fsop_MakeFolder (target);
 | |
| 	}
 | |
| 
 | |
| 	pdir=opendir(source);
 | |
| 	
 | |
| 	while ((pent=readdir(pdir)) != NULL && ret == true) 
 | |
| 	{
 | |
| 		// Skip it
 | |
| 		if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0)
 | |
| 			continue;
 | |
| 			
 | |
| 		sprintf (newSource, "%s/%s", source, pent->d_name);
 | |
| 		sprintf (newTarget, "%s/%s", target, pent->d_name);
 | |
| 		
 | |
| 		// If it is a folder... recurse...
 | |
| 		if (fsop_DirExist (newSource))
 | |
| 		{
 | |
| 			ret = doCopyFolder (newSource, newTarget);
 | |
| 		}
 | |
| 		else	// It is a file !
 | |
| 		{
 | |
| 			ret = doCopyFile (newSource, newTarget);
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	closedir(pdir);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 	
 | |
| bool fsop_CopyFolder (char *source, char *target)
 | |
| {
 | |
| 	folderSize = fsop_GetFolderBytes(source);
 | |
| 	__Copy_Spinner(0, folderSize);				// init spinner
 | |
| 	bytesCopiedPrevFiles = 0;
 | |
| 
 | |
| 	return doCopyFolder (source, target);
 | |
| }
 | |
| 
 | |
| // Pass  <mount>://<folder1>/<folder2>.../<folderN> or <mount>:/<folder1>/<folder2>.../<folderN>
 | |
| bool fsop_CreateFolderTree (char *path)
 | |
| {
 | |
| 	int i;
 | |
| 	int start, len;
 | |
| 	char buff[300];
 | |
| 	char b[8];
 | |
| 	char *p;
 | |
| 	
 | |
| 	start = 0;
 | |
| 	
 | |
| 	strcpy (b, "://");
 | |
| 	p = strstr (path, b);
 | |
| 	if (p == NULL)
 | |
| 	{
 | |
| 		strcpy (b, ":/");
 | |
| 		p = strstr (path, b);
 | |
| 		if (p == NULL)
 | |
| 			return false; // path must contain
 | |
| 	}
 | |
| 	
 | |
| 	start = (p - path) + strlen(b);
 | |
| 	
 | |
| 	len = strlen(path);
 | |
| 
 | |
| 	for (i = start; i <= len; i++)
 | |
| 	{
 | |
| 		if (path[i] == '/' || i == len)
 | |
| 		{
 | |
| 			strcpy (buff, path);
 | |
| 			buff[i] = 0;
 | |
| 			
 | |
| 			if (!fsop_DirExist(buff))
 | |
| 				fsop_MakeFolder(buff);
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	// Check if the tree has been created
 | |
| 	return fsop_DirExist (path);
 | |
| }
 | |
| 
 | |
| void fsop_deleteFolder(char *source)
 | |
| {
 | |
| 	DIR *pdir;
 | |
| 	struct dirent *pent;
 | |
| 	char newSource[300];
 | |
| 
 | |
| 	pdir = opendir(source);
 | |
| 
 | |
| 	while ((pent=readdir(pdir)) != NULL) 
 | |
| 	{
 | |
| 		// Skip it
 | |
| 		if (strcmp (pent->d_name, ".") == 0 || strcmp (pent->d_name, "..") == 0)
 | |
| 			continue;
 | |
| 
 | |
| 		sprintf (newSource, "%s/%s", source, pent->d_name);
 | |
| 
 | |
| 		// If it is a folder... recurse...
 | |
| 		if (fsop_DirExist(newSource))
 | |
| 		{
 | |
| 			fsop_deleteFolder(newSource);
 | |
| 		}
 | |
| 		else	// It is a file !
 | |
| 		{
 | |
| 			dbg_printf("Deleting file: %s\n",newSource);
 | |
| 			remove(newSource);
 | |
| 		}
 | |
| 	}
 | |
| 	closedir(pdir);
 | |
| 	dbg_printf("Deleting directory: %s\n",source);
 | |
| 	unlink(source);
 | |
| }
 | 
