a09abe355f
* Fixed issue 1058 * Menus splitted to several smaller files, to reduce compile time This version has FAT support. You can change the used partition in the game load options. Default WBFS will be used, if found. Otherwise the first FAT partition with games will be used. FAT will only work when using Hermes cios (222/223)!!!
339 lines
7.1 KiB
C
339 lines
7.1 KiB
C
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <malloc.h>
|
|
#include <ogcsys.h>
|
|
#include <dirent.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <sys/statvfs.h>
|
|
#include <ctype.h>
|
|
|
|
#include "libwbfs/libwbfs.h"
|
|
#include "sdhc.h"
|
|
#include "usbstorage.h"
|
|
#include "utils.h"
|
|
#include "video.h"
|
|
#include "wbfs.h"
|
|
#include "wdvd.h"
|
|
#include "splits.h"
|
|
#include "fat.h"
|
|
#include "partition.h"
|
|
#include "wpad.h"
|
|
#include "wbfs_fat.h"
|
|
#include "disc.h"
|
|
#include "settings/cfg.h"
|
|
|
|
// WBFS FAT by oggzee
|
|
|
|
#define D_S(A) A, sizeof(A)
|
|
|
|
char wbfs_fat_drive[16];
|
|
char wbfs_fat_dir[16] = "/wbfs";
|
|
|
|
int wbfs_fat_vfs_have = 0;
|
|
int wbfs_fat_vfs_lba = 0;
|
|
struct statvfs wbfs_fat_vfs;
|
|
|
|
split_info_t split;
|
|
|
|
static u32 fat_sector_size = 512;
|
|
|
|
void WBFS_Spinner(s32 x, s32 max);
|
|
s32 __WBFS_ReadDVD(void *fp, u32 lba, u32 len, void *iobuf);
|
|
|
|
s32 _WBFS_FAT_GetHeadersCount(void *outbuf, u32 *count, u32 len)
|
|
{
|
|
DIR *dir;
|
|
struct dirent *dent;
|
|
char *p;
|
|
int ret, cnt = 0;
|
|
char path[100];
|
|
wbfs_t *part = NULL;
|
|
u32 size;
|
|
u8 *ptr;
|
|
struct discHdr tmpHdr;
|
|
int hdrsize;
|
|
struct stat st;
|
|
//dbg_time1();
|
|
|
|
strcpy(path, wbfs_fat_drive);
|
|
strcat(path, wbfs_fat_dir);
|
|
dir = opendir(path);
|
|
if (!dir) {
|
|
*count = 0;
|
|
return 0;
|
|
}
|
|
while ((dent = readdir(dir)) != NULL) {
|
|
if (outbuf && cnt >= *count) break;
|
|
if ((char)dent->d_name[0] == '.') continue;
|
|
p = strrchr(dent->d_name, '.');
|
|
if (!p) continue;
|
|
if (strcasecmp(p, ".wbfs") != 0) continue;
|
|
if (strlen(dent->d_name) != 11) continue; // GAMEID.wbfs
|
|
u8 id[8];
|
|
memcpy(id, dent->d_name, 6);
|
|
id[6] = 0;
|
|
|
|
strcpy(path, wbfs_fat_drive);
|
|
strcat(path, wbfs_fat_dir);
|
|
strcat(path, "/");
|
|
strcat(path, dent->d_name);
|
|
stat(path, &st);
|
|
// size must be at least 1MB to be considered a valid wbfs file
|
|
if (st.st_size < 1024*1024) continue;
|
|
if (!outbuf) {
|
|
// just counting
|
|
cnt++;
|
|
continue;
|
|
}
|
|
ptr = ((u8 *)outbuf) + (cnt * len);
|
|
hdrsize = len;
|
|
|
|
char *title = cfg_get_title(id);
|
|
if (title) {
|
|
memset(&tmpHdr, 0, sizeof(tmpHdr));
|
|
memcpy(tmpHdr.id, id, 6);
|
|
strncpy(tmpHdr.title, title, sizeof(tmpHdr.title));
|
|
tmpHdr.magic = 0x5D1C9EA3;
|
|
memcpy(ptr, &tmpHdr, hdrsize);
|
|
cnt++;
|
|
continue;
|
|
}
|
|
|
|
// no title found, read it from wbfs file directly
|
|
FILE *fp = fopen(path, "rb");
|
|
if (fp != NULL) {
|
|
fseek(fp, 512, SEEK_SET);
|
|
fread(&tmpHdr, sizeof(struct discHdr), 1, fp);
|
|
fclose(fp);
|
|
|
|
if (tmpHdr.magic == 0x5D1C9EA3 && (memcmp(tmpHdr.id, id, 6) == 0)) {
|
|
memcpy(ptr, &tmpHdr, hdrsize);
|
|
cnt++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// no title found, read it from wbfs file
|
|
// but this is a little bit slower
|
|
// open 'partition' file
|
|
part = WBFS_FAT_OpenPart(id);
|
|
if (!part) {
|
|
continue;
|
|
}
|
|
|
|
/* Get header */
|
|
ret = wbfs_get_disc_info(part, 0, ptr, hdrsize, &size);
|
|
if (ret == 0) cnt++;
|
|
WBFS_FAT_ClosePart(part);
|
|
}
|
|
*count = cnt;
|
|
closedir(dir);
|
|
//dbg_time2("\nFAT HDRS");
|
|
//Wpad_WaitButtons();
|
|
return 0;
|
|
}
|
|
|
|
|
|
s32 WBFS_FAT_GetCount(u32 *count)
|
|
{
|
|
*count = 0;
|
|
_WBFS_FAT_GetHeadersCount(NULL, count, 0);
|
|
return 0;
|
|
}
|
|
|
|
s32 WBFS_FAT_GetHeaders(void *outbuf, u32 cnt, u32 len)
|
|
{
|
|
_WBFS_FAT_GetHeadersCount(outbuf, &cnt, len);
|
|
return 0;
|
|
}
|
|
|
|
wbfs_disc_t* WBFS_FAT_OpenDisc(u8 *discid)
|
|
{
|
|
wbfs_t *part = WBFS_FAT_OpenPart(discid);
|
|
if (!part) return NULL;
|
|
return wbfs_open_disc(part, discid);
|
|
}
|
|
|
|
void WBFS_FAT_CloseDisc(wbfs_disc_t* disc)
|
|
{
|
|
if (!disc) return;
|
|
wbfs_t *part = disc->p;
|
|
wbfs_close_disc(disc);
|
|
WBFS_FAT_ClosePart(part);
|
|
return;
|
|
}
|
|
|
|
s32 WBFS_FAT_DiskSpace(f32 *used, f32 *free)
|
|
{
|
|
f32 size;
|
|
int ret;
|
|
|
|
*used = 0;
|
|
*free = 0;
|
|
// statvfs is slow, so cache values
|
|
if (!wbfs_fat_vfs_have || wbfs_fat_vfs_lba != wbfs_part_lba) {
|
|
ret = statvfs(wbfs_fat_drive, &wbfs_fat_vfs);
|
|
|
|
if (ret) return 0;
|
|
wbfs_fat_vfs_have = 1;
|
|
wbfs_fat_vfs_lba = wbfs_part_lba;
|
|
}
|
|
|
|
/* FS size in GB */
|
|
size = (f32)wbfs_fat_vfs.f_frsize * (f32)wbfs_fat_vfs.f_blocks / GB_SIZE;
|
|
*free = (f32)wbfs_fat_vfs.f_frsize * (f32)wbfs_fat_vfs.f_bfree / GB_SIZE;
|
|
*used = size - *free;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nop_read_sector(void *_fp,u32 lba,u32 count,void*buf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int nop_write_sector(void *_fp,u32 lba,u32 count,void*buf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void WBFS_FAT_fname(u8 *id, char *fname, int len)
|
|
{
|
|
snprintf(fname, len, "%s%s/%.6s.wbfs", wbfs_fat_drive, wbfs_fat_dir, id);
|
|
}
|
|
|
|
wbfs_t* WBFS_FAT_OpenPart(u8 *id)
|
|
{
|
|
char fname[100];
|
|
wbfs_t *part = NULL;
|
|
int ret;
|
|
|
|
// wbfs 'partition' file
|
|
WBFS_FAT_fname(id, fname, sizeof(fname));
|
|
ret = split_open(&split, fname);
|
|
if (ret) return NULL;
|
|
part = wbfs_open_partition(
|
|
split_read_sector,
|
|
nop_write_sector, //readonly //split_write_sector,
|
|
&split, fat_sector_size, split.total_sec, 0, 0);
|
|
if (!part) {
|
|
split_close(&split);
|
|
}
|
|
return part;
|
|
}
|
|
|
|
wbfs_t* WBFS_FAT_CreatePart(u8 *id)
|
|
{
|
|
char fname[100];
|
|
wbfs_t *part = NULL;
|
|
u64 size = (u64)143432*2*0x8000ULL;
|
|
u32 n_sector = size / 512;
|
|
int ret;
|
|
|
|
snprintf(D_S(fname), "%s%s", wbfs_fat_drive, wbfs_fat_dir);
|
|
mkdir(fname, 0777);
|
|
WBFS_FAT_fname(id, fname, sizeof(fname));
|
|
ret = split_create(&split, fname, OPT_split_size, size, true);
|
|
if (ret) return NULL;
|
|
|
|
// force create first file
|
|
u32 scnt = 0;
|
|
int fd = split_get_file(&split, 0, &scnt, 0);
|
|
if (fd<0) {
|
|
split_close(&split);
|
|
return NULL;
|
|
}
|
|
|
|
part = wbfs_open_partition(
|
|
split_read_sector,
|
|
split_write_sector,
|
|
&split, fat_sector_size, n_sector, 0, 1);
|
|
if (!part) {
|
|
split_close(&split);
|
|
}
|
|
return part;
|
|
}
|
|
|
|
void WBFS_FAT_ClosePart(wbfs_t* part)
|
|
{
|
|
if (!part) return;
|
|
split_info_t *s = (split_info_t*)part->callback_data;
|
|
wbfs_close(part);
|
|
if (s) split_close(s);
|
|
}
|
|
|
|
s32 WBFS_FAT_RemoveGame(u8 *discid)
|
|
{
|
|
char fname[100];
|
|
// wbfs 'partition' file
|
|
WBFS_FAT_fname(discid, fname, sizeof(fname));
|
|
split_create(&split, fname, 0, 0, true);
|
|
split_close(&split);
|
|
|
|
// Reset FAT stats
|
|
wbfs_fat_vfs_have = 0;
|
|
return 0;
|
|
}
|
|
|
|
s32 WBFS_FAT_AddGame(void)
|
|
{
|
|
static struct discHdr header ATTRIBUTE_ALIGN(32);
|
|
s32 ret;
|
|
wbfs_t *part = NULL;
|
|
|
|
//write_test(); return -1;
|
|
|
|
// read ID from DVD
|
|
Disc_ReadHeader(&header);
|
|
// create wbfs 'partition' file
|
|
part = WBFS_FAT_CreatePart(header.id);
|
|
if (!part) return -1;
|
|
/* Add game to device */
|
|
extern wbfs_t *hdd;
|
|
wbfs_t *old_hdd = hdd;
|
|
hdd = part; // used by spinner
|
|
ret = wbfs_add_disc(part, __WBFS_ReadDVD, NULL, WBFS_Spinner, ONLY_GAME_PARTITION, 0);
|
|
hdd = old_hdd;
|
|
wbfs_trim(part);
|
|
WBFS_FAT_ClosePart(part);
|
|
|
|
// Reset FAT stats
|
|
wbfs_fat_vfs_have = 0;
|
|
if (ret < 0) return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 WBFS_FAT_DVD_Size(u64 *comp_size, u64 *real_size)
|
|
{
|
|
s32 ret;
|
|
u32 comp_sec = 0, last_sec = 0;
|
|
|
|
wbfs_t *part = NULL;
|
|
u64 size = (u64)143432*2*0x8000ULL;
|
|
u32 n_sector = size / fat_sector_size;
|
|
u32 wii_sec_sz;
|
|
|
|
// init a temporary dummy part
|
|
// as a placeholder for wbfs_size_disc
|
|
part = wbfs_open_partition(
|
|
nop_read_sector, nop_write_sector,
|
|
NULL, fat_sector_size, n_sector, 0, 1);
|
|
if (!part) return -1;
|
|
wii_sec_sz = part->wii_sec_sz;
|
|
|
|
/* Add game to device */
|
|
ret = wbfs_size_disc(part, __WBFS_ReadDVD, NULL, ONLY_GAME_PARTITION, &comp_sec, &last_sec);
|
|
wbfs_close(part);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (comp_size != NULL) *comp_size = (u64)wii_sec_sz * comp_sec;
|
|
if (real_size != NULL) *real_size = (u64)wii_sec_sz * last_sec;
|
|
|
|
return 0;
|
|
}
|
|
|