2009-12-10 21:27:36 +01:00
|
|
|
// WBFS FAT by oggzee
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
|
|
|
|
// WBFS FAT by oggzee
|
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
#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"
|
2009-12-19 15:05:31 +01:00
|
|
|
#include "usbloader/disc.h"
|
|
|
|
#include "usbloader/sdhc.h"
|
|
|
|
#include "usbloader/usbstorage.h"
|
|
|
|
#include "usbloader/utils.h"
|
|
|
|
#include "usbloader/wbfs.h"
|
|
|
|
#include "usbloader/wdvd.h"
|
|
|
|
#include "usbloader/splits.h"
|
|
|
|
#include "usbloader/wbfs_fat.h"
|
|
|
|
#include "usbloader/partition_usbloader.h"
|
|
|
|
#include "libfat/fat.h"
|
2009-12-10 21:27:36 +01:00
|
|
|
#include "settings/cfg.h"
|
2009-11-15 20:52:58 +01:00
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
// max fat fname = 256
|
2009-12-04 16:05:20 +01:00
|
|
|
#define MAX_FAT_PATH 1024
|
2009-11-15 20:52:58 +01:00
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
char wbfs_fs_drive[16];
|
2009-11-15 20:52:58 +01:00
|
|
|
char wbfs_fat_dir[16] = "/wbfs";
|
2010-02-01 00:14:14 +01:00
|
|
|
char invalid_path[] = "/\\:|<>?*\"'";
|
2009-11-15 20:52:58 +01:00
|
|
|
|
|
|
|
int wbfs_fat_vfs_have = 0;
|
|
|
|
int wbfs_fat_vfs_lba = 0;
|
2009-12-19 15:05:31 +01:00
|
|
|
int wbfs_fat_vfs_dev = 0;
|
2009-11-15 20:52:58 +01:00
|
|
|
struct statvfs wbfs_fat_vfs;
|
|
|
|
|
|
|
|
split_info_t split;
|
|
|
|
|
|
|
|
static u32 fat_sector_size = 512;
|
|
|
|
|
2009-12-10 21:27:36 +01:00
|
|
|
static struct discHdr *fat_hdr_list = NULL;
|
|
|
|
static int fat_hdr_count = 0;
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
void WBFS_Spinner(s32 x, s32 max);
|
|
|
|
s32 __WBFS_ReadDVD(void *fp, u32 lba, u32 len, void *iobuf);
|
|
|
|
|
2009-12-10 21:27:36 +01:00
|
|
|
bool is_gameid(char *id)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i=0; i<6; i++) {
|
2009-12-20 19:28:30 +01:00
|
|
|
if (!isalnum((u32) id[i])) return false;
|
2009-12-10 21:27:36 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
|
2009-12-10 21:27:36 +01:00
|
|
|
s32 _WBFS_FAT_GetHeadersCount()
|
2009-11-15 20:52:58 +01:00
|
|
|
{
|
2009-12-10 21:27:36 +01:00
|
|
|
DIR_ITER *dir_iter;
|
2009-12-04 16:05:20 +01:00
|
|
|
char path[MAX_FAT_PATH];
|
2009-12-10 21:27:36 +01:00
|
|
|
char fname[MAX_FAT_PATH];
|
|
|
|
char fpath[MAX_FAT_PATH];
|
2009-11-15 20:52:58 +01:00
|
|
|
struct discHdr tmpHdr;
|
|
|
|
struct stat st;
|
2009-12-10 21:27:36 +01:00
|
|
|
wbfs_t *part = NULL;
|
2009-12-04 16:05:20 +01:00
|
|
|
u8 id[8];
|
2009-12-10 21:27:36 +01:00
|
|
|
int ret;
|
|
|
|
char *p;
|
|
|
|
u32 size;
|
2009-12-04 16:05:20 +01:00
|
|
|
int is_dir;
|
2010-01-10 10:16:47 +01:00
|
|
|
int len;
|
|
|
|
char dir_title[65];
|
|
|
|
char *title;
|
2009-12-10 21:27:36 +01:00
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
//dbg_time1();
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
SAFE_FREE(fat_hdr_list);
|
2009-12-10 21:27:36 +01:00
|
|
|
fat_hdr_count = 0;
|
2009-11-15 20:52:58 +01:00
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
strcpy(path, wbfs_fs_drive);
|
2009-12-10 21:27:36 +01:00
|
|
|
strcat(path, wbfs_fat_dir);
|
|
|
|
dir_iter = diropen(path);
|
|
|
|
if (!dir_iter) return 0;
|
2009-12-19 15:05:31 +01:00
|
|
|
|
2009-12-10 21:27:36 +01:00
|
|
|
while (dirnext(dir_iter, fname, &st) == 0) {
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("found: %s\n", fname); Wpad_WaitButtonsCommon();
|
2009-12-10 21:27:36 +01:00
|
|
|
if ((char)fname[0] == '.') continue;
|
2010-01-10 10:16:47 +01:00
|
|
|
len = strlen(fname);
|
|
|
|
if (len < 8) continue; // "GAMEID_x"
|
2009-12-10 21:27:36 +01:00
|
|
|
|
|
|
|
memcpy(id, fname, 6);
|
|
|
|
id[6] = 0;
|
2009-12-04 16:05:20 +01:00
|
|
|
|
|
|
|
is_dir = S_ISDIR(st.st_mode);
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("mode: %d %d %x\n", is_dir, st.st_mode, st.st_mode);
|
2009-12-04 16:05:20 +01:00
|
|
|
if (is_dir) {
|
2010-02-01 00:14:14 +01:00
|
|
|
int lay_a = 0;
|
|
|
|
int lay_b = 0;
|
2010-01-10 10:16:47 +01:00
|
|
|
if (fname[6] == '_' && is_gameid((char*)id)) {
|
|
|
|
// usb:/wbfs/GAMEID_TITLE/GAMEID.wbfs
|
2010-02-01 00:14:14 +01:00
|
|
|
lay_a = 1;
|
|
|
|
}
|
|
|
|
if (fname[len-8] == '[' && fname[len-1] == ']' && is_gameid(&fname[len-7])) {
|
|
|
|
// usb:/wbfs/TITLE[GAMEID]/GAMEID.wbfs
|
|
|
|
lay_b = 1;
|
|
|
|
}
|
|
|
|
if (!lay_a && !lay_b) continue;
|
|
|
|
if (lay_a) {
|
2010-01-10 10:16:47 +01:00
|
|
|
strncpy(dir_title, &fname[7], sizeof(dir_title));
|
|
|
|
} else {
|
2010-02-01 00:14:14 +01:00
|
|
|
try_lay_b:
|
2010-01-10 10:16:47 +01:00
|
|
|
memcpy(id, &fname[len-7], 6);
|
|
|
|
id[6] = 0;
|
|
|
|
strncpy(dir_title, fname, sizeof(dir_title));
|
|
|
|
dir_title[len-8] = 0; // cut at '['
|
|
|
|
int n = strlen(dir_title);
|
|
|
|
if (n == 0) continue;
|
|
|
|
// cut trailing _ or ' '
|
|
|
|
if (dir_title[n - 1] == ' ' || dir_title[n - 1] == '_' ) {
|
|
|
|
dir_title[n - 1] = 0;
|
|
|
|
}
|
2010-02-01 00:14:14 +01:00
|
|
|
if (strlen(dir_title) == 0) continue;
|
2010-01-10 10:16:47 +01:00
|
|
|
}
|
2009-12-10 21:27:36 +01:00
|
|
|
snprintf(fpath, sizeof(fpath), "%s/%s/%s.wbfs", path, fname, id);
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("path2: %s\n", fpath);
|
2009-12-10 21:27:36 +01:00
|
|
|
// if more than 50 games, skip second stat to improve speed
|
2010-02-01 00:14:14 +01:00
|
|
|
// but if ambiguous layout check anyway
|
|
|
|
if (fat_hdr_count < 50 || (lay_a && lay_b)) {
|
2009-12-19 15:05:31 +01:00
|
|
|
if (stat(fpath, &st) == -1) {
|
|
|
|
//printf("missing: %s\n", fpath);
|
|
|
|
// try .iso
|
|
|
|
strcpy(strrchr(fpath, '.'), ".iso"); // replace .wbfs with .iso
|
|
|
|
if (stat(fpath, &st) == -1) {
|
|
|
|
//printf("missing: %s\n", fpath);
|
2010-02-01 00:14:14 +01:00
|
|
|
if (lay_a && lay_b == 1) {
|
|
|
|
// mark lay_b so that the stat check is still done,
|
|
|
|
// but lay_b is not re-tried again
|
|
|
|
lay_b = 2;
|
|
|
|
// retry with layout b
|
|
|
|
goto try_lay_b;
|
|
|
|
}
|
2009-12-19 15:05:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2009-12-10 21:27:36 +01:00
|
|
|
} else {
|
|
|
|
st.st_size = 1024*1024;
|
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
} else {
|
|
|
|
// usb:/wbfs/GAMEID.wbfs
|
2009-12-19 15:05:31 +01:00
|
|
|
// or usb:/wbfs/GAMEID.iso
|
2009-12-10 21:27:36 +01:00
|
|
|
p = strrchr(fname, '.');
|
2009-12-04 16:05:20 +01:00
|
|
|
if (!p) continue;
|
2009-12-19 15:05:31 +01:00
|
|
|
if ( (strcasecmp(p, ".wbfs") != 0)
|
|
|
|
&& (strcasecmp(p, ".iso") != 0) ) continue;
|
|
|
|
if (p - fname != 6) continue; // GAMEID.
|
|
|
|
snprintf(fpath, sizeof(fpath), "%s/%s", path, fname);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("found: %s %d MB\n", fpath, (int)(st.st_size/1024/1024));
|
2009-11-15 20:52:58 +01:00
|
|
|
// size must be at least 1MB to be considered a valid wbfs file
|
|
|
|
if (st.st_size < 1024*1024) continue;
|
2009-12-04 16:05:20 +01:00
|
|
|
// if we have titles.txt entry use that
|
2010-01-10 10:16:47 +01:00
|
|
|
title = cfg_get_title(id);
|
2009-12-04 16:05:20 +01:00
|
|
|
// if directory, and no titles.txt get title from dir name
|
|
|
|
if (!title && is_dir) {
|
2010-01-10 10:16:47 +01:00
|
|
|
title = dir_title;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
2009-11-15 20:52:58 +01:00
|
|
|
if (title) {
|
|
|
|
memset(&tmpHdr, 0, sizeof(tmpHdr));
|
|
|
|
memcpy(tmpHdr.id, id, 6);
|
2009-12-04 16:05:20 +01:00
|
|
|
strncpy(tmpHdr.title, title, sizeof(tmpHdr.title)-1);
|
2009-11-15 20:52:58 +01:00
|
|
|
tmpHdr.magic = 0x5D1C9EA3;
|
2009-12-10 21:27:36 +01:00
|
|
|
goto add_hdr;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
2009-11-22 15:09:08 +01:00
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
// else read it from file directly
|
|
|
|
if (strcasecmp(strrchr(fpath,'.'), ".wbfs") == 0) {
|
|
|
|
// wbfs file directly
|
|
|
|
FILE *fp = fopen(fpath, "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)) {
|
|
|
|
goto add_hdr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// no title found, read it from wbfs file
|
|
|
|
// but this is a little bit slower
|
|
|
|
// open 'partition' file
|
|
|
|
part = WBFS_FAT_OpenPart(fpath);
|
|
|
|
if (!part) {
|
|
|
|
printf("bad wbfs file: %s\n", fpath);
|
|
|
|
sleep(2);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Get header */
|
|
|
|
ret = wbfs_get_disc_info(part, 0, (u8*)&tmpHdr,
|
|
|
|
sizeof(struct discHdr), &size);
|
|
|
|
WBFS_FAT_ClosePart(part);
|
|
|
|
if (ret == 0) {
|
2009-12-10 21:27:36 +01:00
|
|
|
goto add_hdr;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
2009-12-19 15:05:31 +01:00
|
|
|
} else if (strcasecmp(strrchr(fpath,'.'), ".iso") == 0) {
|
|
|
|
// iso file
|
|
|
|
FILE *fp = fopen(fpath, "rb");
|
|
|
|
if (fp != NULL) {
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
fread(&tmpHdr, sizeof(struct discHdr), 1, fp);
|
|
|
|
fclose(fp);
|
|
|
|
if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0)) {
|
|
|
|
goto add_hdr;
|
|
|
|
}
|
|
|
|
}
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
2009-12-19 15:05:31 +01:00
|
|
|
// fail:
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// succes: add tmpHdr to list:
|
2009-12-10 21:27:36 +01:00
|
|
|
add_hdr:
|
2009-12-19 15:05:31 +01:00
|
|
|
memset(&st, 0, sizeof(st));
|
|
|
|
//printf("added: %.6s %.20s\n", tmpHdr.id, tmpHdr.title); Wpad_WaitButtons();
|
2009-12-10 21:27:36 +01:00
|
|
|
fat_hdr_count++;
|
|
|
|
fat_hdr_list = realloc(fat_hdr_list, fat_hdr_count * sizeof(struct discHdr));
|
|
|
|
memcpy(&fat_hdr_list[fat_hdr_count-1], &tmpHdr, sizeof(struct discHdr));
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
2009-12-10 21:27:36 +01:00
|
|
|
dirclose(dir_iter);
|
2009-12-19 15:05:31 +01:00
|
|
|
//dbg_time2("\nFAT_GetCount"); Wpad_WaitButtonsCommon();
|
2009-11-15 20:52:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s32 WBFS_FAT_GetCount(u32 *count)
|
|
|
|
{
|
|
|
|
*count = 0;
|
2009-12-10 21:27:36 +01:00
|
|
|
_WBFS_FAT_GetHeadersCount();
|
|
|
|
if (fat_hdr_count && fat_hdr_list) {
|
|
|
|
// for compacter mem - move up as it will be freed later
|
|
|
|
int size = fat_hdr_count * sizeof(struct discHdr);
|
|
|
|
struct discHdr *buf = malloc(size);
|
|
|
|
if (buf) {
|
|
|
|
memcpy(buf, fat_hdr_list, size);
|
2009-12-19 15:05:31 +01:00
|
|
|
SAFE_FREE(fat_hdr_list);
|
2009-12-10 21:27:36 +01:00
|
|
|
fat_hdr_list = buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*count = fat_hdr_count;
|
2009-11-15 20:52:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 WBFS_FAT_GetHeaders(void *outbuf, u32 cnt, u32 len)
|
|
|
|
{
|
2009-12-10 21:27:36 +01:00
|
|
|
int i;
|
|
|
|
int slen = len;
|
|
|
|
if (slen > sizeof(struct discHdr)) {
|
|
|
|
slen = sizeof(struct discHdr);
|
|
|
|
}
|
|
|
|
for (i=0; i<cnt && i<fat_hdr_count; i++) {
|
|
|
|
memcpy(outbuf + i * len, &fat_hdr_list[i], slen);
|
|
|
|
}
|
2009-12-19 15:05:31 +01:00
|
|
|
SAFE_FREE(fat_hdr_list);
|
2009-12-10 21:27:36 +01:00
|
|
|
fat_hdr_count = 0;
|
2009-11-15 20:52:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
wbfs_disc_t* WBFS_FAT_OpenDisc(u8 *discid)
|
|
|
|
{
|
2009-12-19 15:05:31 +01:00
|
|
|
char fname[MAX_FAT_PATH];
|
|
|
|
|
|
|
|
// wbfs 'partition' file
|
|
|
|
if ( !WBFS_FAT_find_fname(discid, fname, sizeof(fname)) ) return NULL;
|
|
|
|
|
|
|
|
if (strcasecmp(strrchr(fname,'.'), ".iso") == 0) {
|
|
|
|
// .iso file
|
|
|
|
// create a fake wbfs_disc
|
|
|
|
int fd;
|
|
|
|
fd = open(fname, O_RDONLY);
|
|
|
|
if (fd == -1) return NULL;
|
|
|
|
wbfs_disc_t *iso_file = calloc(sizeof(wbfs_disc_t),1);
|
|
|
|
if (iso_file == NULL) return NULL;
|
|
|
|
// mark with a special wbfs_part
|
|
|
|
wbfs_iso_file.wbfs_sec_sz = 512;
|
|
|
|
iso_file->p = &wbfs_iso_file;
|
|
|
|
iso_file->header = (void*)fd;
|
|
|
|
return iso_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
wbfs_t *part = WBFS_FAT_OpenPart(fname);
|
2009-11-15 20:52:58 +01:00
|
|
|
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;
|
2009-12-19 15:05:31 +01:00
|
|
|
|
|
|
|
// is this really a .iso file?
|
|
|
|
if (part == &wbfs_iso_file) {
|
|
|
|
close((int)disc->header);
|
|
|
|
free(disc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
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
|
2009-12-19 15:05:31 +01:00
|
|
|
if (!wbfs_fat_vfs_have
|
|
|
|
|| wbfs_fat_vfs_lba != wbfs_part_lba
|
|
|
|
|| wbfs_fat_vfs_dev != wbfsDev )
|
|
|
|
{
|
|
|
|
ret = statvfs(wbfs_fs_drive, &wbfs_fat_vfs);
|
2009-11-15 20:52:58 +01:00
|
|
|
if (ret) return 0;
|
|
|
|
wbfs_fat_vfs_have = 1;
|
|
|
|
wbfs_fat_vfs_lba = wbfs_part_lba;
|
2009-12-19 15:05:31 +01:00
|
|
|
wbfs_fat_vfs_dev = wbfsDev;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("read %d %d\n", lba, count); //Wpad_WaitButtons();
|
2009-11-15 20:52:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nop_write_sector(void *_fp,u32 lba,u32 count,void*buf)
|
|
|
|
{
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("write %d %d\n", lba, count); //Wpad_WaitButtons();
|
2009-11-15 20:52:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
void WBFS_FAT_fname(u8 *id, char *fname, int len, char *path)
|
|
|
|
{
|
|
|
|
if (path == NULL) {
|
2009-12-19 15:05:31 +01:00
|
|
|
snprintf(fname, len, "%s%s/%.6s.wbfs", wbfs_fs_drive, wbfs_fat_dir, id);
|
2009-12-04 16:05:20 +01:00
|
|
|
} else {
|
|
|
|
snprintf(fname, len, "%s/%.6s.wbfs", path, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-01 00:14:14 +01:00
|
|
|
// format title so that it is usable in a filename
|
|
|
|
void title_filename(char *title)
|
|
|
|
{
|
|
|
|
int i, len;
|
|
|
|
// trim leading space
|
|
|
|
len = strlen(title);
|
|
|
|
while (*title == ' ') {
|
|
|
|
memmove(title, title+1, len);
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
// trim trailing space - not allowed on windows directories
|
|
|
|
while (len && title[len-1] == ' ') {
|
|
|
|
title[len-1] = 0;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
// replace silly chars with '_'
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
if(strchr(invalid_path, title[i]) || iscntrl((int) title[i])) {
|
|
|
|
title[i] = '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mk_gameid_title(struct discHdr *header, char *name, int re_space, int layout)
|
2009-12-04 16:05:20 +01:00
|
|
|
{
|
|
|
|
int i, len;
|
2010-02-01 00:14:14 +01:00
|
|
|
char title[65];
|
|
|
|
char id[8];
|
2009-12-04 16:05:20 +01:00
|
|
|
|
|
|
|
memcpy(name, header->id, 6);
|
|
|
|
name[6] = 0;
|
2010-02-01 00:14:14 +01:00
|
|
|
strncpy(title, get_title(header), sizeof(title));
|
|
|
|
title_filename(title);
|
|
|
|
|
|
|
|
if (layout == 0) {
|
|
|
|
sprintf(name, "%s_%s", id, title);
|
|
|
|
} else {
|
|
|
|
sprintf(name, "%s [%s]", title, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// replace space with '_'
|
|
|
|
if (re_space) {
|
|
|
|
len = strlen(name);
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
if(name[i]==' ') name[i] = '_';
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WBFS_FAT_get_dir(struct discHdr *header, char *path)
|
|
|
|
{
|
2009-12-19 15:05:31 +01:00
|
|
|
strcpy(path, wbfs_fs_drive);
|
2009-12-04 16:05:20 +01:00
|
|
|
strcat(path, wbfs_fat_dir);
|
|
|
|
if (Settings.FatInstallToDir) {
|
|
|
|
strcat(path, "/");
|
2010-02-01 00:14:14 +01:00
|
|
|
int layout = 0;
|
|
|
|
if (Settings.FatInstallToDir == 2) layout = 1;
|
|
|
|
mk_gameid_title(header, path + strlen(path), 0, layout);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
void mk_title_txt(struct discHdr *header, char *path)
|
|
|
|
{
|
|
|
|
char fname[MAX_FAT_PATH];
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
strcpy(fname, path);
|
|
|
|
strcat(fname, "/");
|
2010-02-01 00:14:14 +01:00
|
|
|
mk_gameid_title(header, fname+strlen(fname), 1, 0);
|
2009-12-19 15:05:31 +01:00
|
|
|
strcat(fname, ".txt");
|
|
|
|
|
|
|
|
f = fopen(fname, "wb");
|
|
|
|
if (!f) return;
|
|
|
|
fprintf(f, "%.6s = %.64s\n", header->id, get_title(header));
|
|
|
|
fclose(f);
|
|
|
|
printf("Info file: %s\n", fname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
int WBFS_FAT_find_fname(u8 *id, char *fname, int len)
|
|
|
|
{
|
|
|
|
struct stat st;
|
2009-12-19 15:05:31 +01:00
|
|
|
// look for direct .wbfs file
|
2009-12-04 16:05:20 +01:00
|
|
|
WBFS_FAT_fname(id, fname, len, NULL);
|
|
|
|
if (stat(fname, &st) == 0) return 1;
|
2009-12-19 15:05:31 +01:00
|
|
|
// look for direct .iso file
|
|
|
|
strcpy(strrchr(fname, '.'), ".iso"); // replace .wbfs with .iso
|
|
|
|
if (stat(fname, &st) == 0) return 1;
|
2009-12-04 16:05:20 +01:00
|
|
|
// direct file not found, check subdirs
|
2010-01-10 10:16:47 +01:00
|
|
|
*fname = 0;
|
2009-12-10 21:27:36 +01:00
|
|
|
DIR_ITER *dir_iter;
|
2009-12-04 16:05:20 +01:00
|
|
|
char path[MAX_FAT_PATH];
|
2009-12-10 21:27:36 +01:00
|
|
|
char name[MAX_FAT_PATH];
|
2009-12-19 15:05:31 +01:00
|
|
|
strcpy(path, wbfs_fs_drive);
|
2009-12-04 16:05:20 +01:00
|
|
|
strcat(path, wbfs_fat_dir);
|
2009-12-10 21:27:36 +01:00
|
|
|
dir_iter = diropen(path);
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("dir: %s %p\n", path, dir); Wpad_WaitButtons();
|
2009-12-10 21:27:36 +01:00
|
|
|
if (!dir_iter) {
|
2010-01-10 10:16:47 +01:00
|
|
|
return 0;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
2009-12-10 21:27:36 +01:00
|
|
|
while (dirnext(dir_iter, name, &st) == 0) {
|
2009-12-04 16:05:20 +01:00
|
|
|
if (name[0] == '.') continue;
|
2010-01-10 10:16:47 +01:00
|
|
|
int n = strlen(name);
|
|
|
|
if (n < 8) continue;
|
|
|
|
if (name[6] == '_') {
|
|
|
|
// GAMEID_TITLE
|
|
|
|
if (strncmp(name, (char*)id, 6) != 0) goto try_alter;
|
|
|
|
} else {
|
|
|
|
try_alter:
|
|
|
|
// TITLE [GAMEID]
|
|
|
|
if (name[n-8] != '[' || name[n-1] != ']') continue;
|
|
|
|
if (strncmp(&name[n-7], (char*)id, 6) != 0) continue;
|
|
|
|
}
|
2009-12-19 15:05:31 +01:00
|
|
|
// look for .wbfs file
|
|
|
|
snprintf(fname, len, "%s/%s/%.6s.wbfs", path, name, id);
|
|
|
|
if (stat(fname, &st) == 0) {
|
2010-01-10 10:16:47 +01:00
|
|
|
break;
|
2009-12-19 15:05:31 +01:00
|
|
|
}
|
|
|
|
// look for .iso file
|
|
|
|
snprintf(fname, len, "%s/%s/%.6s.iso", path, name, id);
|
2009-12-04 16:05:20 +01:00
|
|
|
if (stat(fname, &st) == 0) {
|
2010-01-10 10:16:47 +01:00
|
|
|
break;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
2010-01-10 10:16:47 +01:00
|
|
|
*fname = 0;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
2009-12-10 21:27:36 +01:00
|
|
|
dirclose(dir_iter);
|
2010-01-10 10:16:47 +01:00
|
|
|
if (*fname) {
|
|
|
|
// found
|
|
|
|
//printf("found:%s\n", fname);
|
|
|
|
return 2;
|
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
// not found
|
|
|
|
return 0;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
wbfs_t* WBFS_FAT_OpenPart(char *fname)
|
2009-11-15 20:52:58 +01:00
|
|
|
{
|
|
|
|
wbfs_t *part = NULL;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
// wbfs 'partition' file
|
|
|
|
ret = split_open(&split, fname);
|
|
|
|
if (ret) return NULL;
|
|
|
|
part = wbfs_open_partition(
|
|
|
|
split_read_sector,
|
2009-12-04 16:05:20 +01:00
|
|
|
nop_write_sector, //readonly //split_write_sector,
|
2009-11-15 20:52:58 +01:00
|
|
|
&split, fat_sector_size, split.total_sec, 0, 0);
|
|
|
|
if (!part) {
|
|
|
|
split_close(&split);
|
|
|
|
}
|
|
|
|
return part;
|
|
|
|
}
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
wbfs_t* WBFS_FAT_CreatePart(u8 *id, char *path)
|
2009-11-15 20:52:58 +01:00
|
|
|
{
|
2009-12-04 16:05:20 +01:00
|
|
|
char fname[MAX_FAT_PATH];
|
2009-11-15 20:52:58 +01:00
|
|
|
wbfs_t *part = NULL;
|
|
|
|
u64 size = (u64)143432*2*0x8000ULL;
|
|
|
|
u32 n_sector = size / 512;
|
|
|
|
int ret;
|
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
//printf("CREATE PART %s %lld %d\n", id, size, n_sector);
|
|
|
|
snprintf(fname, sizeof(fname), "%s%s", wbfs_fs_drive, wbfs_fat_dir);
|
2009-12-04 16:05:20 +01:00
|
|
|
mkdir(fname, 0777); // base usb:/wbfs
|
|
|
|
mkdir(path, 0777); // game subdir
|
|
|
|
WBFS_FAT_fname(id, fname, sizeof(fname), path);
|
2009-12-19 15:05:31 +01:00
|
|
|
printf("Writing to %s\n", fname);
|
2009-11-15 20:52:58 +01:00
|
|
|
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) {
|
2009-12-19 15:05:31 +01:00
|
|
|
printf("ERROR creating file\n");
|
|
|
|
sleep(2);
|
2009-11-15 20:52:58 +01:00
|
|
|
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)
|
|
|
|
{
|
2009-12-04 16:05:20 +01:00
|
|
|
char fname[MAX_FAT_PATH];
|
|
|
|
int loc;
|
2009-11-15 20:52:58 +01:00
|
|
|
// wbfs 'partition' file
|
2009-12-04 16:05:20 +01:00
|
|
|
loc = WBFS_FAT_find_fname(discid, fname, sizeof(fname));
|
|
|
|
if ( !loc ) return -1;
|
2009-11-15 20:52:58 +01:00
|
|
|
split_create(&split, fname, 0, 0, true);
|
|
|
|
split_close(&split);
|
2009-12-04 16:05:20 +01:00
|
|
|
if (loc == 1) return 0;
|
|
|
|
|
|
|
|
// game is in subdir
|
|
|
|
// remove optional .txt file
|
2009-12-10 21:27:36 +01:00
|
|
|
DIR_ITER *dir_iter;
|
|
|
|
struct stat st;
|
2009-12-04 16:05:20 +01:00
|
|
|
char path[MAX_FAT_PATH];
|
2009-12-10 21:27:36 +01:00
|
|
|
char name[MAX_FAT_PATH];
|
2009-12-04 16:05:20 +01:00
|
|
|
strncpy(path, fname, sizeof(path));
|
2009-12-10 21:27:36 +01:00
|
|
|
char *p = strrchr(path, '/');
|
2009-12-04 16:05:20 +01:00
|
|
|
if (p) *p = 0;
|
2009-12-10 21:27:36 +01:00
|
|
|
dir_iter = diropen(path);
|
|
|
|
if (!dir_iter) return 0;
|
|
|
|
while (dirnext(dir_iter, name, &st) == 0) {
|
2009-12-04 16:05:20 +01:00
|
|
|
if (name[0] == '.') continue;
|
|
|
|
if (name[6] != '_') continue;
|
|
|
|
if (strncmp(name, (char*)discid, 6) != 0) continue;
|
|
|
|
p = strrchr(name, '.');
|
|
|
|
if (!p) continue;
|
|
|
|
if (strcasecmp(p, ".txt") != 0) continue;
|
|
|
|
snprintf(fname, sizeof(fname), "%s/%s", path, name);
|
|
|
|
remove(fname);
|
|
|
|
break;
|
|
|
|
}
|
2009-12-10 21:27:36 +01:00
|
|
|
dirclose(dir_iter);
|
2009-12-04 16:05:20 +01:00
|
|
|
// remove game subdir
|
2010-02-01 00:14:14 +01:00
|
|
|
unlink(path);
|
2009-11-22 15:09:08 +01:00
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
s32 WBFS_FAT_AddGame(void)
|
|
|
|
{
|
|
|
|
static struct discHdr header ATTRIBUTE_ALIGN(32);
|
2009-12-04 16:05:20 +01:00
|
|
|
char path[MAX_FAT_PATH];
|
2009-11-15 20:52:58 +01:00
|
|
|
wbfs_t *part = NULL;
|
2009-12-04 16:05:20 +01:00
|
|
|
s32 ret;
|
2009-11-15 20:52:58 +01:00
|
|
|
|
|
|
|
// read ID from DVD
|
|
|
|
Disc_ReadHeader(&header);
|
2009-12-04 16:05:20 +01:00
|
|
|
// path
|
|
|
|
WBFS_FAT_get_dir(&header, path);
|
2009-11-15 20:52:58 +01:00
|
|
|
// create wbfs 'partition' file
|
2009-12-04 16:05:20 +01:00
|
|
|
part = WBFS_FAT_CreatePart(header.id, path);
|
2009-11-15 20:52:58 +01:00
|
|
|
if (!part) return -1;
|
|
|
|
/* Add game to device */
|
2009-12-19 15:05:31 +01:00
|
|
|
partition_selector_t part_sel = ALL_PARTITIONS;
|
|
|
|
int copy_1_1 = Settings.fullcopy;
|
|
|
|
switch (Settings.partitions_to_install) {
|
|
|
|
case install_game_only:
|
|
|
|
part_sel = ONLY_GAME_PARTITION;
|
|
|
|
break;
|
|
|
|
case install_all:
|
|
|
|
part_sel = ALL_PARTITIONS;
|
|
|
|
break;
|
2010-02-01 00:14:14 +01:00
|
|
|
case install_all_but_update:
|
|
|
|
part_sel = REMOVE_UPDATE_PARTITION;
|
|
|
|
break;
|
2009-12-19 15:05:31 +01:00
|
|
|
}
|
|
|
|
if (copy_1_1) {
|
2009-12-10 21:27:36 +01:00
|
|
|
part_sel = ALL_PARTITIONS;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
2009-11-15 20:52:58 +01:00
|
|
|
extern wbfs_t *hdd;
|
|
|
|
wbfs_t *old_hdd = hdd;
|
|
|
|
hdd = part; // used by spinner
|
2009-12-04 16:05:20 +01:00
|
|
|
ret = wbfs_add_disc(part, __WBFS_ReadDVD, NULL, WBFS_Spinner, part_sel, copy_1_1);
|
2009-11-15 20:52:58 +01:00
|
|
|
hdd = old_hdd;
|
|
|
|
wbfs_trim(part);
|
|
|
|
WBFS_FAT_ClosePart(part);
|
2009-12-19 15:05:31 +01:00
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
if (ret < 0) return ret;
|
2009-12-19 15:05:31 +01:00
|
|
|
mk_title_txt(&header, path);
|
2009-11-15 20:52:58 +01:00
|
|
|
|
|
|
|
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;
|
2009-12-04 16:05:20 +01:00
|
|
|
u32 wii_sec_sz;
|
2009-11-15 20:52:58 +01:00
|
|
|
|
|
|
|
// 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 */
|
2009-12-10 21:27:36 +01:00
|
|
|
partition_selector_t part_sel;
|
2009-12-19 15:05:31 +01:00
|
|
|
if (Settings.partitions_to_install) {
|
2009-12-04 16:05:20 +01:00
|
|
|
part_sel = ALL_PARTITIONS;
|
|
|
|
} else {
|
2009-12-19 15:05:31 +01:00
|
|
|
part_sel = ONLY_GAME_PARTITION;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
ret = wbfs_size_disc(part, __WBFS_ReadDVD, NULL, part_sel, &comp_sec, &last_sec);
|
2009-11-15 20:52:58 +01:00
|
|
|
wbfs_close(part);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
*comp_size = (u64)wii_sec_sz * comp_sec;
|
|
|
|
*real_size = (u64)wii_sec_sz * last_sec;
|
2009-11-15 20:52:58 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-22 15:09:08 +01:00
|
|
|
s32 WBFS_FAT_RenameGame(u8 *discid, const void *newname)
|
|
|
|
{
|
2009-12-19 15:05:31 +01:00
|
|
|
wbfs_t *part = WBFS_FAT_OpenPart((char *) discid);
|
2009-11-22 15:09:08 +01:00
|
|
|
if (!part)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
s32 ret = wbfs_ren_disc(part, discid,(u8*)newname);
|
|
|
|
|
|
|
|
WBFS_FAT_ClosePart(part);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 WBFS_FAT_ReIDGame(u8 *discid, const void *newID)
|
|
|
|
{
|
2009-12-19 15:05:31 +01:00
|
|
|
wbfs_t *part = WBFS_FAT_OpenPart((char *) discid);
|
2009-11-22 15:09:08 +01:00
|
|
|
if (!part)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
s32 ret = wbfs_rID_disc(part, discid,(u8*)newID);
|
|
|
|
|
|
|
|
WBFS_FAT_ClosePart(part);
|
|
|
|
|
|
|
|
if(ret == 0)
|
|
|
|
{
|
|
|
|
char fname[100];
|
|
|
|
char fnamenew[100];
|
|
|
|
s32 cnt = 0x31;
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
WBFS_FAT_fname(discid, fname, sizeof(fname), NULL);
|
|
|
|
WBFS_FAT_fname((u8*) newID, fnamenew, sizeof(fnamenew), NULL);
|
2009-11-22 15:09:08 +01:00
|
|
|
|
|
|
|
int stringlength = strlen(fname);
|
|
|
|
|
|
|
|
while(rename(fname, fnamenew) == 0)
|
|
|
|
{
|
|
|
|
fname[stringlength] = cnt;
|
|
|
|
fname[stringlength+1] = 0;
|
|
|
|
fnamenew[stringlength] = cnt;
|
|
|
|
fnamenew[stringlength+1] = 0;
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2010-01-04 15:11:02 +01:00
|
|
|
|
|
|
|
s32 WBFS_FAT_EstimateGameSize(void) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
partition_selector_t part_sel;
|
|
|
|
if (Settings.fullcopy) {
|
|
|
|
part_sel = ALL_PARTITIONS;
|
|
|
|
} else {
|
|
|
|
part_sel = Settings.partitions_to_install == install_game_only ? ONLY_GAME_PARTITION : ALL_PARTITIONS;
|
|
|
|
}
|
|
|
|
return wbfs_estimate_disc(part, __WBFS_ReadDVD, NULL, part_sel);
|
|
|
|
}
|