usbloadergx/source/usbloader/wbfs/wbfs_fat.cpp

916 lines
24 KiB
C++
Raw Normal View History

// WBFS FAT by oggzee
#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 "settings/CSettings.h"
#include "usbloader/disc.h"
#include "fatmounter.h"
#include "wbfs_fat.h"
#include "prompts/ProgressWindow.h"
#include "wbfs_rw.h"
#include "gecko.h"
#define MAX_FAT_PATH 1024
#define TITLE_LEN 64
using namespace std;
char Wbfs_Fat::wbfs_fs_drive[16];
char Wbfs_Fat::wbfs_fat_dir[16] = "/wbfs";
char Wbfs_Fat::invalid_path[] = "/\\:|<>?*\"'";
struct discHdr *Wbfs_Fat::fat_hdr_list = NULL;
u32 Wbfs_Fat::fat_hdr_count = 0;
extern "C"
{
2010-09-24 02:48:03 +02:00
int _FAT_get_fragments(const char *path, _frag_append_t append_fragment, void *callback_data);
extern FragList *frag_list;
}
u32 Wbfs_Fat::fat_sector_size = 512;
2010-09-24 02:48:03 +02:00
Wbfs_Fat::Wbfs_Fat(u32 device, u32 lba, u32 size) :
Wbfs(device, lba, size)
{
}
s32 Wbfs_Fat::Open()
{
2010-09-24 02:48:03 +02:00
if (device == WBFS_DEVICE_USB && lba == fat_usb_sec)
{
2010-09-24 02:48:03 +02:00
strcpy(wbfs_fs_drive, "USB:");
}
2010-09-24 02:48:03 +02:00
else if (device == WBFS_DEVICE_SDHC && lba == fat_sd_sec)
{
2010-09-24 02:48:03 +02:00
strcpy(wbfs_fs_drive, "SD:");
}
else
{
2010-09-24 02:48:03 +02:00
if (WBFSDevice_Init(lba)) return -1;
strcpy(wbfs_fs_drive, "WBFS:");
}
return 0;
}
2010-09-24 02:48:03 +02:00
wbfs_disc_t* Wbfs_Fat::OpenDisc(u8 *discid)
{
char fname[MAX_FAT_PATH];
// wbfs 'partition' file
2010-09-24 02:48:03 +02:00
if (!FindFilename(discid, fname, sizeof(fname))) return NULL;
2010-09-24 02:48:03 +02:00
if (strcasecmp(strrchr(fname, '.'), ".iso") == 0)
{
// .iso file
// create a fake wbfs_disc
int fd;
2010-09-24 02:48:03 +02:00
fd = open(fname, O_RDONLY);
if (fd == -1) return NULL;
wbfs_disc_t *iso_file = (wbfs_disc_t *) 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;
2010-09-24 02:48:03 +02:00
iso_file->header = (wbfs_disc_info_t*) fd;
return iso_file;
}
2010-09-24 02:48:03 +02:00
wbfs_t *part = OpenPart(fname);
if (!part) return NULL;
return wbfs_open_disc(part, discid);
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::CloseDisc(wbfs_disc_t* disc)
{
2010-09-24 02:48:03 +02:00
if (!disc) return;
wbfs_t *part = disc->p;
// is this really a .iso file?
2010-09-24 02:48:03 +02:00
if (part == &wbfs_iso_file)
{
2010-09-24 02:48:03 +02:00
close((int) disc->header);
free(disc);
return;
}
2010-09-24 02:48:03 +02:00
wbfs_close_disc(disc);
ClosePart(part);
return;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::GetCount(u32 *count)
{
*count = 0;
GetHeadersCount();
2010-09-24 02:48:03 +02:00
if (fat_hdr_count && fat_hdr_list)
{
// for compacter mem - move up as it will be freed later
2010-09-24 02:48:03 +02:00
int size = fat_hdr_count * sizeof(struct discHdr);
struct discHdr *buf = (struct discHdr *) malloc(size);
if (buf)
{
2010-09-24 02:48:03 +02:00
memcpy(buf, fat_hdr_list, size);
SAFE_FREE( fat_hdr_list );
fat_hdr_list = buf;
}
}
*count = fat_hdr_count;
return 0;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::GetHeaders(struct discHdr *outbuf, u32 cnt, u32 len)
{
u32 i;
2010-09-24 02:48:03 +02:00
if (len > sizeof(struct discHdr))
{
2010-09-24 02:48:03 +02:00
len = sizeof(struct discHdr);
}
#ifdef DEBUG_WBFS
gprintf( "\n\tGetHeaders" );
#endif
2010-09-24 02:48:03 +02:00
for (i = 0; i < cnt && i < fat_hdr_count; i++)
{
2010-09-24 02:48:03 +02:00
memcpy(&outbuf[i], &fat_hdr_list[i], len);
}
SAFE_FREE( fat_hdr_list );
fat_hdr_count = 0;
#ifdef DEBUG_WBFS
gprintf( "...ok" );
#endif
return 0;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::AddGame(void)
{
static struct discHdr header ATTRIBUTE_ALIGN( 32 );
char path[MAX_FAT_PATH];
wbfs_t *part = NULL;
s32 ret;
// read ID from DVD
2010-09-24 02:48:03 +02:00
Disc_ReadHeader(&header);
// path
2010-09-24 02:48:03 +02:00
GetDir(&header, path);
// create wbfs 'partition' file
2010-09-24 02:48:03 +02:00
part = CreatePart(header.id, path);
if (!part) return -1;
/* Add game to device */
partition_selector_t part_sel = ALL_PARTITIONS;
int copy_1_1 = Settings.fullcopy;
2010-09-24 02:48:03 +02:00
switch (Settings.partitions_to_install)
{
case install_game_only:
part_sel = ONLY_GAME_PARTITION;
break;
case install_all:
part_sel = ALL_PARTITIONS;
break;
case install_all_but_update:
part_sel = REMOVE_UPDATE_PARTITION;
break;
}
2010-09-24 02:48:03 +02:00
if (copy_1_1)
{
part_sel = ALL_PARTITIONS;
}
wbfs_t *old_hdd = hdd;
hdd = part; // used by spinner
2010-09-24 02:48:03 +02:00
ret = wbfs_add_disc(part, __ReadDVD, NULL, ProgressCallback, part_sel, copy_1_1);
hdd = old_hdd;
2010-09-24 02:48:03 +02:00
wbfs_trim(part);
ClosePart(part);
2010-09-24 02:48:03 +02:00
if (ret < 0) return ret;
mk_title_txt(&header, path);
return 0;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::RemoveGame(u8 *discid)
{
char fname[MAX_FAT_PATH];
int loc;
// wbfs 'partition' file
2010-09-24 02:48:03 +02:00
loc = FindFilename(discid, fname, sizeof(fname));
if (!loc) return -1;
split_create(&split, fname, 0, 0, true);
split_close(&split);
if (loc == 1) return 0;
// game is in subdir
// remove optional .txt file
DIR_ITER *dir_iter;
struct stat st;
char path[MAX_FAT_PATH];
char name[MAX_FAT_PATH];
2010-09-24 02:48:03 +02:00
strncpy(path, fname, sizeof(path));
char *p = strrchr(path, '/');
if (p) *p = 0;
dir_iter = diropen(path);
if (!dir_iter) return 0;
while (dirnext(dir_iter, name, &st) == 0)
{
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;
}
2010-09-24 02:48:03 +02:00
dirclose(dir_iter);
// remove game subdir
2010-09-24 02:48:03 +02:00
unlink(path);
return 0;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::DiskSpace(f32 *used, f32 *free)
{
f32 size;
int ret;
struct statvfs wbfs_fat_vfs;
*used = 0;
*free = 0;
2010-09-24 02:48:03 +02:00
ret = statvfs(wbfs_fs_drive, &wbfs_fat_vfs);
if (ret) return -1;
/* FS size in GB */
2010-09-24 02:48:03 +02:00
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;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::RenameGame(u8 *discid, const void *newname)
{
2010-09-24 02:48:03 +02:00
wbfs_t *part = OpenPart((char *) discid);
if (!part) return -1;
2010-09-24 02:48:03 +02:00
s32 ret = wbfs_ren_disc(part, discid, (u8*) newname);
2010-09-24 02:48:03 +02:00
ClosePart(part);
return ret;
}
2010-09-24 02:48:03 +02:00
s32 Wbfs_Fat::ReIDGame(u8 *discid, const void *newID)
{
2010-09-24 02:48:03 +02:00
wbfs_t *part = OpenPart((char *) discid);
if (!part) return -1;
2010-09-24 02:48:03 +02:00
s32 ret = wbfs_rID_disc(part, discid, (u8*) newID);
2010-09-24 02:48:03 +02:00
ClosePart(part);
2010-09-24 02:48:03 +02:00
if (ret == 0)
{
char fname[100];
char fnamenew[100];
s32 cnt = 0x31;
2010-09-24 02:48:03 +02:00
Filename(discid, fname, sizeof(fname), NULL);
Filename((u8*) newID, fnamenew, sizeof(fnamenew), NULL);
2010-09-24 02:48:03 +02:00
int stringlength = strlen(fname);
2010-09-24 02:48:03 +02:00
while (rename(fname, fnamenew) == 0)
{
fname[stringlength] = cnt;
2010-09-24 02:48:03 +02:00
fname[stringlength + 1] = 0;
fnamenew[stringlength] = cnt;
2010-09-24 02:48:03 +02:00
fnamenew[stringlength + 1] = 0;
cnt++;
}
}
return ret;
}
f32 Wbfs_Fat::EstimateGameSize()
{
wbfs_t *part = NULL;
2010-09-24 02:48:03 +02:00
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
2010-09-24 02:48:03 +02:00
part = wbfs_open_partition(nop_rw_sector, nop_rw_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;
2010-09-24 02:48:03 +02:00
if (Settings.fullcopy)
{
part_sel = ALL_PARTITIONS;
}
else
{
part_sel = Settings.partitions_to_install == install_game_only ? ONLY_GAME_PARTITION : ALL_PARTITIONS;
}
2010-09-24 02:48:03 +02:00
return wbfs_estimate_disc(part, __ReadDVD, NULL, part_sel);
}
// TITLE [GAMEID]
2010-09-24 02:48:03 +02:00
bool Wbfs_Fat::CheckLayoutB(char *fname, int len, u8* id, char *fname_title)
{
2010-09-24 02:48:03 +02:00
if (len <= 8) return false;
if (fname[len - 8] != '[' || fname[len - 1] != ']') return false;
if (!is_gameid(&fname[len - 7])) return false;
strncpy(fname_title, fname, TITLE_LEN);
// cut at '['
2010-09-24 02:48:03 +02:00
fname_title[len - 8] = 0;
int n = strlen(fname_title);
if (n == 0) return false;
// cut trailing _ or ' '
2010-09-24 02:48:03 +02:00
if (fname_title[n - 1] == ' ' || fname_title[n - 1] == '_')
{
fname_title[n - 1] = 0;
}
2010-09-24 02:48:03 +02:00
if (strlen(fname_title) == 0) return false;
if (id)
{
2010-09-24 02:48:03 +02:00
memcpy(id, &fname[len - 7], 6);
id[6] = 0;
}
return true;
}
s32 Wbfs_Fat::GetHeadersCount()
{
char path[MAX_FAT_PATH];
char fname[MAX_FAT_PATH];
char fpath[MAX_FAT_PATH];
struct discHdr tmpHdr;
struct stat st;
wbfs_t *part = NULL;
u8 id[8];
int ret;
char *p;
u32 size;
int is_dir;
int len;
char dir_title[65];
char fname_title[TITLE_LEN];
char *title;
DIR_ITER *dir_iter;
//dbg_time1();
SAFE_FREE( fat_hdr_list );
fat_hdr_count = 0;
2010-09-24 02:48:03 +02:00
strcpy(path, wbfs_fs_drive);
strcat(path, wbfs_fat_dir);
2010-09-24 02:48:03 +02:00
dir_iter = diropen(path);
if (!dir_iter) return 0;
2010-09-24 02:48:03 +02:00
dir_iter = diropen(path);
if (!dir_iter) return 0;
2010-09-24 02:48:03 +02:00
while (dirnext(dir_iter, fname, &st) == 0)
{
//printf("found: %s\n", fname); Wpad_WaitButtonsCommon();
2010-09-24 02:48:03 +02:00
if ((char) fname[0] == '.') continue;
len = strlen(fname);
if (len < 8) continue; // "GAMEID_x"
2010-09-24 02:48:03 +02:00
memcpy(id, fname, 6);
id[6] = 0;
*fname_title = 0;
is_dir = S_ISDIR( st.st_mode );
//printf("mode: %d %d %x\n", is_dir, st.st_mode, st.st_mode);
2010-09-24 02:48:03 +02:00
if (is_dir)
{
int lay_a = 0;
int lay_b = 0;
2010-09-24 02:48:03 +02:00
if (fname[6] == '_' && is_gameid((char*) id))
{
// usb:/wbfs/GAMEID_TITLE/GAMEID.wbfs
lay_a = 1;
}
2010-09-24 02:48:03 +02:00
if (CheckLayoutB(fname, len, NULL, fname_title))
{
// usb:/wbfs/TITLE[GAMEID]/GAMEID.wbfs
lay_b = 1;
}
2010-09-24 02:48:03 +02:00
if (!lay_a && !lay_b) continue;
if (lay_a)
{
2010-09-24 02:48:03 +02:00
strncpy(dir_title, &fname[7], sizeof(dir_title));
}
else
{
2010-09-24 02:48:03 +02:00
try_lay_b: if (!CheckLayoutB(fname, len, id, fname_title)) continue;
}
2010-09-24 02:48:03 +02:00
snprintf(fpath, sizeof(fpath), "%s/%s/%s.wbfs", path, fname, id);
//printf("path2: %s\n", fpath);
// if more than 50 games, skip second stat to improve speed
// but if ambiguous layout check anyway
2010-09-24 02:48:03 +02:00
if (fat_hdr_count < 50 || (lay_a && lay_b))
{
2010-09-24 02:48:03 +02:00
if (stat(fpath, &st) == -1)
{
//printf("missing: %s\n", fpath);
// try .iso
2010-09-24 02:48:03 +02:00
strcpy(strrchr(fpath, '.'), ".iso"); // replace .wbfs with .iso
if (stat(fpath, &st) == -1)
{
//printf("missing: %s\n", fpath);
// try .ciso
2010-09-24 02:48:03 +02:00
strcpy(strrchr(fpath, '.'), ".ciso"); // replace .iso with .ciso
if (stat(fpath, &st) == -1)
{
2010-09-24 02:48:03 +02: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;
}
continue;
}
}
}
}
else
{
st.st_size = 1024 * 1024;
}
}
else
{
// usb:/wbfs/GAMEID.wbfs
// or usb:/wbfs/GAMEID.iso
// or usb:/wbfs/GAMEID.ciso
2010-09-24 02:48:03 +02:00
p = strrchr(fname, '.');
if (!p) continue;
if ((strcasecmp(p, ".wbfs") != 0) && (strcasecmp(p, ".iso") != 0) && (strcasecmp(p, ".ciso") != 0)) continue;
int n = p - fname; // length withouth .wbfs
2010-09-24 02:48:03 +02:00
if (n != 6)
{
// TITLE [GAMEID].wbfs
2010-09-24 02:48:03 +02:00
if (!CheckLayoutB(fname, n, id, fname_title)) continue;
}
2010-09-24 02:48:03 +02:00
snprintf(fpath, sizeof(fpath), "%s/%s", path, fname);
}
//printf("found: %s %d MB\n", fpath, (int)(st.st_size/1024/1024));
// size must be at least 1MB to be considered a valid wbfs file
2010-09-24 02:48:03 +02:00
if (st.st_size < 1024 * 1024) continue;
// if we have titles.txt entry use that
2010-09-24 02:48:03 +02:00
title = cfg_get_title(id);
// if no titles.txt get title from dir or file name
2010-09-24 02:48:03 +02:00
if (!title && *fname_title)
{
title = fname_title;
}
2010-09-24 02:48:03 +02:00
if (title)
{
2010-09-24 02:48:03 +02:00
memset(&tmpHdr, 0, sizeof(tmpHdr));
memcpy(tmpHdr.id, id, 6);
strncpy(tmpHdr.title, title, sizeof(tmpHdr.title) - 1);
tmpHdr.magic = 0x5D1C9EA3;
goto add_hdr;
}
// else read it from file directly
2010-09-24 02:48:03 +02:00
if (strcasecmp(strrchr(fpath, '.'), ".wbfs") == 0)
{
// wbfs file directly
2010-09-24 02:48:03 +02:00
FILE *fp = fopen(fpath, "rb");
if (fp != NULL)
{
2010-09-24 02:48:03 +02:00
fseek(fp, 512, SEEK_SET);
fread(&tmpHdr, sizeof(struct discHdr), 1, fp);
fclose(fp);
tmpHdr.is_ciso = 0;
2010-09-24 02:48:03 +02:00
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
2010-09-24 02:48:03 +02:00
part = OpenPart(fpath);
if (!part)
{
continue;
}
// Get header
2010-09-24 02:48:03 +02:00
ret = wbfs_get_disc_info(part, 0, (u8*) &tmpHdr, sizeof(struct discHdr), &size);
ClosePart(part);
if (ret == 0)
{
goto add_hdr;
}
}
2010-09-24 02:48:03 +02:00
else if (strcasecmp(strrchr(fpath, '.'), ".iso") == 0)
{
// iso file
2010-09-24 02:48:03 +02:00
FILE *fp = fopen(fpath, "rb");
if (fp != NULL)
{
2010-09-24 02:48:03 +02:00
fseek(fp, 0, SEEK_SET);
fread(&tmpHdr, sizeof(struct discHdr), 1, fp);
fclose(fp);
tmpHdr.is_ciso = 0;
2010-09-24 02:48:03 +02:00
if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0))
{
goto add_hdr;
}
}
}
2010-09-24 02:48:03 +02:00
else if (strcasecmp(strrchr(fpath, '.'), ".ciso") == 0)
{
// ciso file
2010-09-24 02:48:03 +02:00
FILE *fp = fopen(fpath, "rb");
if (fp != NULL)
{
2010-09-24 02:48:03 +02:00
fseek(fp, 0x8000, SEEK_SET);
fread(&tmpHdr, sizeof(struct discHdr), 1, fp);
fclose(fp);
tmpHdr.is_ciso = 1;
2010-09-24 02:48:03 +02:00
if ((tmpHdr.magic == 0x5D1C9EA3) && (memcmp(tmpHdr.id, id, 6) == 0))
{
goto add_hdr;
}
}
}
// fail:
continue;
// succes: add tmpHdr to list:
2010-09-24 02:48:03 +02:00
add_hdr: memset(&st, 0, sizeof(st));
//printf("added: %.6s %.20s\n", tmpHdr.id, tmpHdr.title); Wpad_WaitButtons();
fat_hdr_count++;
2010-09-24 02:48:03 +02:00
fat_hdr_list = (struct discHdr *) realloc(fat_hdr_list, fat_hdr_count * sizeof(struct discHdr));
memcpy(&fat_hdr_list[fat_hdr_count - 1], &tmpHdr, sizeof(struct discHdr));
}
2010-09-24 02:48:03 +02:00
dirclose(dir_iter);
//dbg_time2("\nFAT_GetCount"); Wpad_WaitButtonsCommon();
return 0;
}
2010-09-24 02:48:03 +02:00
int Wbfs_Fat::FindFilename(u8 *id, char *fname, int len)
{
struct stat st;
// look for direct .wbfs file
2010-09-24 02:48:03 +02:00
Filename(id, fname, len, NULL);
if (stat(fname, &st) == 0) return 1;
// look for direct .iso file
2010-09-24 02:48:03 +02:00
strcpy(strrchr(fname, '.'), ".iso"); // replace .wbfs with .iso
if (stat(fname, &st) == 0) return 1;
// look for direct .ciso file
2010-09-24 02:48:03 +02:00
strcpy(strrchr(fname, '.'), ".ciso"); // replace .iso with .ciso
if (stat(fname, &st) == 0) return 1;
// direct file not found, check subdirs
*fname = 0;
DIR_ITER *dir_iter;
char path[MAX_FAT_PATH];
char name[MAX_FAT_PATH];
2010-09-24 02:48:03 +02:00
strcpy(path, wbfs_fs_drive);
strcat(path, wbfs_fat_dir);
dir_iter = diropen(path);
//printf("dir: %s %p\n", path, dir); Wpad_WaitButtons();
2010-09-24 02:48:03 +02:00
if (!dir_iter)
{
return 0;
}
2010-09-24 02:48:03 +02:00
while (dirnext(dir_iter, name, &st) == 0)
{
//dbg_printf("name:%s\n", name);
2010-09-24 02:48:03 +02:00
if (name[0] == '.') continue;
int n = strlen(name);
if (n < 8) continue;
if (S_ISDIR( st.st_mode ))
{
2010-09-24 02:48:03 +02:00
if (name[6] == '_')
{
// GAMEID_TITLE
2010-09-24 02:48:03 +02:00
if (strncmp(name, (char*) id, 6) != 0) goto try_alter;
}
else
{
2010-09-24 02:48:03 +02:00
try_alter:
// TITLE [GAMEID]
2010-09-24 02:48:03 +02:00
if (name[n - 8] != '[' || name[n - 1] != ']') continue;
if (strncmp(&name[n - 7], (char*) id, 6) != 0) continue;
}
// look for .wbfs file
2010-09-24 02:48:03 +02:00
snprintf(fname, len, "%s/%s/%.6s.wbfs", path, name, id);
if (stat(fname, &st) == 0) break;
// look for .iso file
2010-09-24 02:48:03 +02:00
snprintf(fname, len, "%s/%s/%.6s.iso", path, name, id);
if (stat(fname, &st) == 0) break;
// look for .ciso file
2010-09-24 02:48:03 +02:00
snprintf(fname, len, "%s/%s/%.6s.ciso", path, name, id);
}
else
{
// TITLE [GAMEID].wbfs
char fn_title[TITLE_LEN];
u8 fn_id[8];
2010-09-24 02:48:03 +02:00
char *p = strrchr(name, '.');
if (!p) continue;
if ((strcasecmp(p, ".wbfs") != 0) && (strcasecmp(p, ".iso") != 0) && (strcasecmp(p, ".ciso") != 0)) continue;
int n = p - name; // length withouth .wbfs
2010-09-24 02:48:03 +02:00
if (!CheckLayoutB(name, n, fn_id, fn_title)) continue;
if (strncmp((char*) fn_id, (char*) id, 6) != 0) continue;
snprintf(fname, len, "%s/%s", path, name);
}
2010-09-24 02:48:03 +02:00
if (stat(fname, &st) == 0) break;
*fname = 0;
}
2010-09-24 02:48:03 +02:00
dirclose(dir_iter);
if (*fname)
{
// found
//printf("found:%s\n", fname);
return 2;
}
// not found
return 0;
}
2010-09-24 02:48:03 +02:00
wbfs_t* Wbfs_Fat::OpenPart(char *fname)
{
wbfs_t *part = NULL;
int ret;
// wbfs 'partition' file
2010-09-24 02:48:03 +02:00
ret = split_open(&split, fname);
if (ret) return NULL;
part = wbfs_open_partition(split_read_sector, nop_rw_sector, //readonly //split_write_sector,
&split, fat_sector_size, split.total_sec, 0, 0);
if (!part)
{
2010-09-24 02:48:03 +02:00
split_close(&split);
}
return part;
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::ClosePart(wbfs_t* part)
{
2010-09-24 02:48:03 +02:00
if (!part) return;
split_info_t *s = (split_info_t*) part->callback_data;
wbfs_close(part);
if (s) split_close(s);
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::Filename(u8 *id, char *fname, int len, char *path)
{
2010-09-24 02:48:03 +02:00
if (path == NULL)
{
2010-09-24 02:48:03 +02:00
snprintf(fname, len, "%s%s/%.6s.wbfs", wbfs_fs_drive, wbfs_fat_dir, id);
}
else
{
2010-09-24 02:48:03 +02:00
snprintf(fname, len, "%s/%.6s.wbfs", path, id);
}
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::GetDir(struct discHdr *header, char *path)
{
2010-09-24 02:48:03 +02:00
strcpy(path, wbfs_fs_drive);
strcat(path, wbfs_fat_dir);
if (Settings.FatInstallToDir)
{
2010-09-24 02:48:03 +02:00
strcat(path, "/");
int layout = 0;
2010-09-24 02:48:03 +02:00
if (Settings.FatInstallToDir == 2) layout = 1;
mk_gameid_title(header, path + strlen(path), 0, layout);
}
}
2010-09-24 02:48:03 +02:00
wbfs_t* Wbfs_Fat::CreatePart(u8 *id, char *path)
{
char fname[MAX_FAT_PATH];
wbfs_t *part = NULL;
2010-09-24 02:48:03 +02:00
u64 size = (u64) 143432 * 2 * 0x8000ULL;
u32 n_sector = size / 512;
int ret;
//printf("CREATE PART %s %lld %d\n", id, size, n_sector);
2010-09-24 02:48:03 +02:00
snprintf(fname, sizeof(fname), "%s%s", wbfs_fs_drive, wbfs_fat_dir);
mkdir(fname, 0777); // base usb:/wbfs
mkdir(path, 0777); // game subdir
Filename(id, fname, sizeof(fname), path);
printf("Writing to %s\n", fname);
ret = split_create(&split, fname, OPT_split_size, size, true);
if (ret) return NULL;
// force create first file
u32 scnt = 0;
2010-09-24 02:48:03 +02:00
int fd = split_get_file(&split, 0, &scnt, 0);
if (fd < 0)
{
2010-09-24 02:48:03 +02:00
printf("ERROR creating file\n");
sleep(2);
split_close(&split);
return NULL;
}
2010-09-24 02:48:03 +02:00
part = wbfs_open_partition(split_read_sector, split_write_sector, &split, fat_sector_size, n_sector, 0, 1);
if (!part)
{
2010-09-24 02:48:03 +02:00
split_close(&split);
}
return part;
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::mk_title_txt(struct discHdr *header, char *path)
{
char fname[MAX_FAT_PATH];
FILE *f;
2010-09-24 02:48:03 +02:00
strcpy(fname, path);
strcat(fname, "/");
mk_gameid_title(header, fname + strlen(fname), 1, 0);
strcat(fname, ".txt");
2010-09-24 02:48:03 +02:00
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);
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::mk_gameid_title(struct discHdr *header, char *name, int re_space, int layout)
{
int i, len;
char title[65];
char id[8];
2010-09-24 02:48:03 +02:00
memcpy(name, header->id, 6);
name[6] = 0;
2010-09-24 02:48:03 +02:00
strncpy(title, get_title(header), sizeof(title));
title_filename(title);
2010-09-24 02:48:03 +02:00
if (layout == 0)
{
2010-09-24 02:48:03 +02:00
sprintf(name, "%s_%s", id, title);
}
else
{
2010-09-24 02:48:03 +02:00
sprintf(name, "%s [%s]", title, id);
}
// replace space with '_'
2010-09-24 02:48:03 +02:00
if (re_space)
{
2010-09-24 02:48:03 +02:00
len = strlen(name);
for (i = 0; i < len; i++)
{
2010-09-24 02:48:03 +02:00
if (name[i] == ' ') name[i] = '_';
}
}
}
2010-09-24 02:48:03 +02:00
void Wbfs_Fat::title_filename(char *title)
{
int i, len;
// trim leading space
2010-09-24 02:48:03 +02:00
len = strlen(title);
while (*title == ' ')
{
2010-09-24 02:48:03 +02:00
memmove(title, title + 1, len);
len--;
}
// trim trailing space - not allowed on windows directories
2010-09-24 02:48:03 +02:00
while (len && title[len - 1] == ' ')
{
2010-09-24 02:48:03 +02:00
title[len - 1] = 0;
len--;
}
// replace silly chars with '_'
2010-09-24 02:48:03 +02:00
for (i = 0; i < len; i++)
{
2010-09-24 02:48:03 +02:00
if (strchr(invalid_path, title[i]) || iscntrl((int) title[i]))
{
title[i] = '_';
}
}
}
2010-09-24 02:48:03 +02:00
bool Wbfs_Fat::is_gameid(char *id)
{
int i;
2010-09-24 02:48:03 +02:00
for (i = 0; i < 6; i++)
{
2010-09-24 02:48:03 +02:00
if (!isalnum((u32) id[i])) return false;
}
return true;
}
2010-09-24 02:48:03 +02:00
int Wbfs_Fat::GetFragList(u8 *id)
{
char fname[1024];
char fname1[1024];
struct stat st;
FragList *fs = NULL;
FragList *fa = NULL;
FragList *fw = NULL;
int ret;
int i;
int is_wbfs = 0;
int ret_val = -1;
2010-09-24 02:48:03 +02:00
ret = FindFilename(id, fname, sizeof(fname));
if (!ret) return -1;
2010-09-24 02:48:03 +02:00
if (strcasecmp(strrchr(fname, '.'), ".wbfs") == 0)
{
is_wbfs = 1;
}
2010-09-24 02:48:03 +02:00
fs = (FragList *) malloc(sizeof(FragList));
fa = (FragList *) malloc(sizeof(FragList));
fw = (FragList *) malloc(sizeof(FragList));
2010-09-24 02:48:03 +02:00
frag_init(fa, MAX_FRAG);
2010-09-24 02:48:03 +02:00
for (i = 0; i < 10; i++)
{
2010-09-24 02:48:03 +02:00
frag_init(fs, MAX_FRAG);
if (i > 0)
{
2010-09-24 02:48:03 +02:00
fname[strlen(fname) - 1] = '0' + i;
if (stat(fname, &st) == -1) break;
}
2010-09-24 02:48:03 +02:00
strcpy(fname1, fname);
if ((ret = GetFragList((char *) &fname, &_frag_append, fs)))
{
ret_val = ret;
goto out;
}
2010-09-24 02:48:03 +02:00
frag_concat(fa, fs);
}
2010-09-24 02:48:03 +02:00
frag_list = (FragList *) malloc(sizeof(FragList));
frag_init(frag_list, MAX_FRAG);
if (is_wbfs)
{
// if wbfs file format, remap.
//printf("=====\n");
2010-09-24 02:48:03 +02:00
wbfs_disc_t *d = OpenDisc(id);
if (!d) goto out;
frag_init(fw, MAX_FRAG);
ret = wbfs_get_fragments(d, &_frag_append, fw);
if (ret) goto out;
CloseDisc(d);
// DEBUG:
//frag_list->num = MAX_FRAG-10; // stress test
2010-09-24 02:48:03 +02:00
ret = frag_remap(frag_list, fw, fa);
if (ret) goto out;
}
else
{
// .iso does not need remap just copy
//printf("fa:\n");
2010-09-24 02:48:03 +02:00
memcpy(frag_list, fa, sizeof(FragList));
}
ret_val = 0;
2010-09-24 02:48:03 +02:00
out: if (ret_val)
{
// error
SAFE_FREE( frag_list );
}
SAFE_FREE( fs );
SAFE_FREE( fa );
SAFE_FREE( fw );
return ret_val;
}
2010-09-24 02:48:03 +02:00
int Wbfs_Fat::GetFragList(char *filename, _frag_append_t append_fragment, FragList *fs)
{
2010-09-24 02:48:03 +02:00
return _FAT_get_fragments(filename, append_fragment, fs);
}
2010-09-24 02:48:03 +02:00
bool Wbfs_Fat::ShowFreeSpace(void)
{
return false;
}