mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-12 22:45:08 +01:00
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)!!!
314 lines
7.4 KiB
C
314 lines
7.4 KiB
C
#include <ogcsys.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/fcntl.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "splits.h"
|
|
|
|
#define off64_t off_t
|
|
#define FMT_llu "%llu"
|
|
#define FMT_lld "%lld"
|
|
|
|
#define split_error(x) do { /* gprintf("\nsplit error: %s\n\n",x); */ } while(0)
|
|
|
|
// 1 sector less than 4gb
|
|
//u64 OPT_split_size = (u64)4LL * 1024 * 1024 * 1024 - 512;
|
|
// 1 sector less than 2gb
|
|
u64 OPT_split_size = (u64)2LL * 1024 * 1024 * 1024 - 512;
|
|
|
|
//split_info_t split;
|
|
|
|
void split_get_fname(split_info_t *s, int idx, char *fname)
|
|
{
|
|
strcpy(fname, s->fname);
|
|
if (idx == 0 && s->create_mode) {
|
|
strcat(fname, ".tmp");
|
|
} else if (idx > 0) {
|
|
char *c = fname + strlen(fname) - 1;
|
|
*c = '0' + idx;
|
|
}
|
|
}
|
|
|
|
int split_open_file(split_info_t *s, int idx)
|
|
{
|
|
int fd = s->fd[idx];
|
|
if (fd>=0) return fd;
|
|
char fname[1024];
|
|
split_get_fname(s, idx, fname);
|
|
//char *mode = s->create_mode ? "wb+" : "rb+";
|
|
int mode = s->create_mode ? (O_CREAT | O_RDWR) : O_RDWR ;
|
|
//printf("SPLIT OPEN %s %s %d\n", fname, mode, idx); //Wpad_WaitButtons();
|
|
//f = fopen(fname, mode);
|
|
fd = open(fname, mode);
|
|
if (fd<0) return -1;
|
|
if (idx > 0 && s->create_mode) {
|
|
printf("%s Split: %d %s \n",
|
|
s->create_mode ? "Create" : "Read",
|
|
idx, fname);
|
|
}
|
|
s->fd[idx] = fd;
|
|
return fd;
|
|
}
|
|
|
|
// faster as it uses larger chunks than ftruncate internally
|
|
int write_zero(int fd, off_t size)
|
|
{
|
|
int buf[0x4000]; //64kb
|
|
int chunk;
|
|
int ret;
|
|
memset(buf, 0, sizeof(buf));
|
|
while (size) {
|
|
chunk = size;
|
|
if (chunk > sizeof(buf)) chunk = sizeof(buf);
|
|
ret = write(fd, buf, chunk);
|
|
//printf("WZ %d %d / %lld \n", ret, chunk, size);
|
|
size -= chunk;
|
|
if (ret < 0) return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int split_fill(split_info_t *s, int idx, u64 size)
|
|
{
|
|
int fd = split_open_file(s, idx);
|
|
off64_t fsize = lseek(fd, 0, SEEK_END);
|
|
if (fsize < size) {
|
|
//printf("TRUNC %d "FMT_lld"\n", idx, size); Wpad_WaitButtons();
|
|
//ftruncate(fd, size);
|
|
write_zero(fd, size - fsize);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int split_get_file(split_info_t *s, u32 lba, u32 *sec_count, int fill)
|
|
{
|
|
int fd;
|
|
if (lba >= s->total_sec) {
|
|
fprintf(stderr, "SPLIT: invalid sector %u / %u\n", lba, (u32)s->total_sec);
|
|
return -1;
|
|
}
|
|
int idx;
|
|
idx = lba / s->split_sec;
|
|
if (idx >= s->max_split) {
|
|
fprintf(stderr, "SPLIT: invalid split %d / %d\n", idx, s->max_split - 1);
|
|
return -1;
|
|
}
|
|
fd = s->fd[idx];
|
|
if (fd<0) {
|
|
// opening new, make sure all previous are full
|
|
int i;
|
|
for (i=0; i<idx; i++) {
|
|
if (split_fill(s, i, s->split_size)) {
|
|
printf("FILL %d\n", i);
|
|
}
|
|
}
|
|
fd = split_open_file(s, idx);
|
|
}
|
|
if (fd<0) {
|
|
fprintf(stderr, "SPLIT %d: no file\n", idx);
|
|
return -1;
|
|
}
|
|
u32 sec = lba % s->split_sec; // inside file
|
|
off64_t off = (off64_t)sec * 512;
|
|
// num sectors till end of file
|
|
u32 to_end = s->split_sec - sec;
|
|
if (*sec_count > to_end) *sec_count = to_end;
|
|
if (s->create_mode) {
|
|
if (fill) {
|
|
// extend, so that read will be succesfull
|
|
split_fill(s, idx, off + 512 * (*sec_count));
|
|
} else {
|
|
// fill up so that write continues from end of file
|
|
// shouldn't be necessary, but libfat looks buggy
|
|
// and this is faster
|
|
split_fill(s, idx, off);
|
|
}
|
|
}
|
|
lseek(fd, off, SEEK_SET);
|
|
return fd;
|
|
}
|
|
|
|
int split_read_sector(void *_fp,u32 lba,u32 count,void*buf)
|
|
{
|
|
split_info_t *s = _fp;
|
|
int fd;
|
|
u64 off = lba;
|
|
off *= 512ULL;
|
|
int i;
|
|
u32 chunk;
|
|
size_t ret;
|
|
//fprintf(stderr,"READ %d %d\n", lba, count);
|
|
for (i=0; i<(int)count; i+=chunk) {
|
|
chunk = count - i;
|
|
fd = split_get_file(s, lba+i, &chunk, 1);
|
|
if (fd<0) {
|
|
fprintf(stderr,"\n\n"FMT_lld" %d %p\n",off,count,_fp);
|
|
split_error("error seeking in disc partition");
|
|
return 1;
|
|
}
|
|
//ret = fread(buf+i*512, 512ULL, chunk, f);
|
|
ret = read(fd, buf+i*512, chunk * 512);
|
|
if (ret != chunk * 512) {
|
|
fprintf(stderr, "error reading %u %u [%u] %u = %u\n",
|
|
lba, count, i, chunk, ret);
|
|
split_error("error reading disc");
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int split_write_sector(void *_fp,u32 lba,u32 count,void*buf)
|
|
{
|
|
split_info_t *s = _fp;
|
|
int fd;
|
|
u64 off = lba;
|
|
off*=512ULL;
|
|
int i;
|
|
u32 chunk;
|
|
size_t ret;
|
|
//printf("WRITE %d %d %p \n", lba, count, buf);
|
|
for (i=0; i<(int)count; i+=chunk) {
|
|
chunk = count - i;
|
|
fd = split_get_file(s, lba+i, &chunk, 0);
|
|
//if (chunk != count)
|
|
// fprintf(stderr, "WRITE CHUNK %d %d/%d\n", lba+i, chunk, count);
|
|
if (fd<0 || !chunk) {
|
|
fprintf(stderr,"\n\n"FMT_lld" %d %p\n",off,count,_fp);
|
|
split_error("error seeking in disc partition");
|
|
return 1;
|
|
}
|
|
//if (fwrite(buf+i*512, 512ULL, chunk, f) != chunk) {
|
|
//printf("write %d %p %d \n", fd, buf+i*512, chunk * 512);
|
|
ret = write(fd, buf+i*512, chunk * 512);
|
|
//printf("write ret = %d \n", ret);
|
|
if (ret != chunk * 512) {
|
|
split_error("error writing disc");
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void split_init(split_info_t *s, char *fname)
|
|
{
|
|
int i;
|
|
char *p;
|
|
//fprintf(stderr, "SPLIT_INIT %s\n", fname);
|
|
memset(s, 0, sizeof(*s));
|
|
for (i=0; i<MAX_SPLIT; i++) {
|
|
s->fd[i] = -1;
|
|
}
|
|
strcpy(s->fname, fname);
|
|
s->max_split = 1;
|
|
p = strrchr(fname, '.');
|
|
if (p && (strcasecmp(p, ".wbfs") == 0)) {
|
|
s->max_split = MAX_SPLIT;
|
|
}
|
|
}
|
|
|
|
void split_set_size(split_info_t *s, u64 split_size, u64 total_size)
|
|
{
|
|
s->total_size = total_size;
|
|
s->split_size = split_size;
|
|
s->total_sec = total_size / 512;
|
|
s->split_sec = split_size / 512;
|
|
}
|
|
|
|
void split_close(split_info_t *s)
|
|
{
|
|
int i;
|
|
char fname[1024];
|
|
char tmpname[1024];
|
|
for (i=0; i<s->max_split; i++) {
|
|
if (s->fd[i] >= 0) {
|
|
close(s->fd[i]);
|
|
}
|
|
}
|
|
if (s->create_mode) {
|
|
split_get_fname(s, -1, fname);
|
|
split_get_fname(s, 0, tmpname);
|
|
rename(tmpname, fname);
|
|
}
|
|
memset(s, 0, sizeof(*s));
|
|
}
|
|
|
|
int split_create(split_info_t *s, char *fname,
|
|
u64 split_size, u64 total_size, bool overwrite)
|
|
{
|
|
int i;
|
|
int fd;
|
|
char sname[1024];
|
|
int error = 0;
|
|
split_init(s, fname);
|
|
s->create_mode = 1;
|
|
// check if any file already exists
|
|
for (i=-1; i<s->max_split; i++) {
|
|
split_get_fname(s, i, sname);
|
|
if (overwrite) {
|
|
remove(sname);
|
|
} else {
|
|
fd = open(sname, O_RDONLY);
|
|
if (fd >= 0) {
|
|
fprintf(stderr, "Error: file already exists: %s\n", sname);
|
|
close(fd);
|
|
error = 1;
|
|
}
|
|
}
|
|
}
|
|
if (error) {
|
|
split_init(s, "");
|
|
return -1;
|
|
}
|
|
split_set_size(s, split_size, total_size);
|
|
return 0;
|
|
}
|
|
|
|
int split_open(split_info_t *s, char *fname)
|
|
{
|
|
int i;
|
|
u64 size = 0;
|
|
u64 total_size = 0;
|
|
u64 split_size = 0;
|
|
int fd;
|
|
split_init(s, fname);
|
|
for (i=0; i<s->max_split; i++) {
|
|
fd = split_open_file(s, i);
|
|
if (fd<0) {
|
|
if (i==0) goto err;
|
|
break;
|
|
}
|
|
// check previous size - all splits except last must be same size
|
|
if (i > 0 && size != split_size) {
|
|
fprintf(stderr, "split %d: invalid size "FMT_lld"", i, size);
|
|
goto err;
|
|
}
|
|
// get size
|
|
//fseeko(f, 0, SEEK_END);
|
|
//size = ftello(f);
|
|
size = lseek(fd, 0, SEEK_END);
|
|
// check sector alignment
|
|
if (size % 512) {
|
|
fprintf(stderr, "split %d: size ("FMT_lld") not sector (512) aligned!",
|
|
i, size);
|
|
}
|
|
// first sets split size
|
|
if (i==0) {
|
|
split_size = size;
|
|
}
|
|
total_size += size;
|
|
}
|
|
split_set_size(s, split_size, total_size);
|
|
return 0;
|
|
err:
|
|
split_close(s);
|
|
return -1;
|
|
}
|
|
|