2009-12-19 15:05:31 +01:00
|
|
|
|
|
|
|
// by oggzee
|
|
|
|
|
2009-11-15 20:52:58 +01:00
|
|
|
#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"
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
#define split_error(x) do { printf("\nsplit error: %s\n\n",x); } while(0)
|
2009-11-15 20:52:58 +01:00
|
|
|
|
2009-12-19 15:05:31 +01:00
|
|
|
// 1 cluster less than 4gb
|
2010-09-19 01:16:05 +02:00
|
|
|
u64 OPT_split_size = ( u64 )4LL * 1024 * 1024 * 1024 - 32 * 1024;
|
2009-12-19 15:05:31 +01:00
|
|
|
// 1 cluster less than 2gb
|
|
|
|
//u64 OPT_split_size = (u64)2LL * 1024 * 1024 * 1024 - 32 * 1024;
|
2009-11-15 20:52:58 +01:00
|
|
|
|
|
|
|
//split_info_t split;
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
void split_get_fname( split_info_t *s, int idx, char *fname )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
|
|
|
}
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_open_file( split_info_t *s, int idx )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// faster as it uses larger chunks than ftruncate internally
|
2010-09-19 01:16:05 +02:00
|
|
|
int write_zero( int fd, off_t size )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_fill( split_info_t *s, int idx, u64 size )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_get_file( split_info_t *s, u32 lba, u32 *sec_count, int fill )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_read_sector( void *_fp, u32 lba, u32 count, void*buf )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
void *ptr = ( ( u8 * )buf ) + ( i * 512 );
|
|
|
|
ret = read( fd, ptr, 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;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_write_sector( void *_fp, u32 lba, u32 count, void*buf )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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);
|
|
|
|
void *ptr = ( ( u8 * )buf ) + ( i * 512 );
|
|
|
|
ret = write( fd, ptr, chunk * 512 );
|
|
|
|
//printf("write ret = %d \n", ret);
|
|
|
|
if ( ret != chunk * 512 )
|
|
|
|
{
|
|
|
|
split_error( "error writing disc" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
void split_init( split_info_t *s, char *fname )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
|
|
|
}
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
void split_set_size( split_info_t *s, u64 split_size, u64 total_size )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
s->total_size = total_size;
|
|
|
|
s->split_size = split_size;
|
|
|
|
s->total_sec = total_size / 512;
|
|
|
|
s->split_sec = split_size / 512;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
void split_close( split_info_t *s )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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 ) );
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_create( split_info_t *s, char *fname,
|
|
|
|
u64 split_size, u64 total_size, bool overwrite )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int split_open( split_info_t *s, char *fname )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
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;
|
2009-11-15 20:52:58 +01:00
|
|
|
err:
|
2010-09-19 01:16:05 +02:00
|
|
|
split_close( s );
|
|
|
|
return -1;
|
2009-11-15 20:52:58 +01:00
|
|
|
}
|
|
|
|
|