usbloadergx/source/libwbfs/libwbfs.c

805 lines
25 KiB
C
Raw Normal View History

// Copyright 2009 Kwiirk
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
2009-12-19 16:47:12 +01:00
// Modified by oggzee
#include "libwbfs.h"
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define ERROR(x) do {wbfs_error(x);goto error;}while(0)
#define ALIGN_LBA(x) (((x)+p->hd_sec_sz-1)&(~(p->hd_sec_sz-1)))
wbfs_t wbfs_iso_file;
static int force_mode=0;
2009-12-19 16:47:12 +01:00
void wbfs_set_force_mode(int force) {
force_mode = force;
}
2009-12-19 16:47:12 +01:00
static u8 size_to_shift(u32 size) {
u8 ret = 0;
while (size) {
ret++;
size>>=1;
}
return ret-1;
}
#define read_le32_unaligned(x) ((x)[0]|((x)[1]<<8)|((x)[2]<<16)|((x)[3]<<24))
wbfs_t*wbfs_open_hd(rw_sector_callback_t read_hdsector,
rw_sector_callback_t write_hdsector,
void *callback_data,
int hd_sector_size, int num_hd_sector __attribute((unused)), int reset) {
int i=num_hd_sector,ret;
u8 *ptr,*tmp_buffer = wbfs_ioalloc(hd_sector_size);
u8 part_table[16*4];
ret = read_hdsector(callback_data,0,1,tmp_buffer);
if (ret)
return 0;
//find wbfs partition
wbfs_memcpy(part_table,tmp_buffer+0x1be,16*4);
ptr = part_table;
for (i=0;i<4;i++,ptr+=16) {
u32 part_lba = read_le32_unaligned(ptr+0x8);
wbfs_head_t *head = (wbfs_head_t *)tmp_buffer;
ret = read_hdsector(callback_data,part_lba,1,tmp_buffer);
// verify there is the magic.
if (head->magic == wbfs_htonl(WBFS_MAGIC)) {
wbfs_t*p = wbfs_open_partition(read_hdsector,write_hdsector,
callback_data,hd_sector_size,0,part_lba,reset);
wbfs_iofree(tmp_buffer);
return p;
}
}
wbfs_iofree(tmp_buffer);
if (reset) { // XXX make a empty hd partition..
}
return 0;
}
wbfs_t*wbfs_open_partition(rw_sector_callback_t read_hdsector,
rw_sector_callback_t write_hdsector,
void *callback_data,
int hd_sector_size, int num_hd_sector, u32 part_lba, int reset) {
wbfs_t *p = wbfs_malloc(sizeof(wbfs_t));
wbfs_head_t *head = wbfs_ioalloc(hd_sector_size?hd_sector_size:512);
//constants, but put here for consistancy
p->wii_sec_sz = 0x8000;
p->wii_sec_sz_s = size_to_shift(0x8000);
p->n_wii_sec = (num_hd_sector/0x8000)*hd_sector_size;
p->n_wii_sec_per_disc = 143432*2;//support for double layers discs..
p->head = head;
p->part_lba = part_lba;
// init the partition
if (reset) {
u8 sz_s;
wbfs_memset(head,0,hd_sector_size);
head->magic = wbfs_htonl(WBFS_MAGIC);
head->hd_sec_sz_s = size_to_shift(hd_sector_size);
head->n_hd_sec = wbfs_htonl(num_hd_sector);
// choose minimum wblk_sz that fits this partition size
for (sz_s=6;sz_s<11;sz_s++) {
// ensure that wbfs_sec_sz is big enough to address every blocks using 16 bits
if (p->n_wii_sec <((1U<<16)*(1<<sz_s)))
break;
}
head->wbfs_sec_sz_s = sz_s+p->wii_sec_sz_s;
} else
read_hdsector(callback_data,p->part_lba,1,head);
if (head->magic != wbfs_htonl(WBFS_MAGIC))
ERROR("bad magic");
if (!force_mode && hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size))
ERROR("hd sector size doesn't match");
if (!force_mode && num_hd_sector && head->n_hd_sec != wbfs_htonl(num_hd_sector))
ERROR("hd num sector doesn't match");
p->hd_sec_sz = 1<<head->hd_sec_sz_s;
p->hd_sec_sz_s = head->hd_sec_sz_s;
p->n_hd_sec = wbfs_ntohl(head->n_hd_sec);
p->n_wii_sec = (p->n_hd_sec/p->wii_sec_sz)*(p->hd_sec_sz);
p->wbfs_sec_sz_s = head->wbfs_sec_sz_s;
p->wbfs_sec_sz = 1<<p->wbfs_sec_sz_s;
p->n_wbfs_sec = p->n_wii_sec >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
p->n_wbfs_sec_per_disc = p->n_wii_sec_per_disc >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
p->disc_info_sz = ALIGN_LBA(sizeof(wbfs_disc_info_t) + p->n_wbfs_sec_per_disc*2);
//printf("hd_sector_size %X wii_sector size %X wbfs sector_size %X\n",p->hd_sec_sz,p->wii_sec_sz,p->wbfs_sec_sz);
p->read_hdsector = read_hdsector;
p->write_hdsector = write_hdsector;
p->callback_data = callback_data;
p->freeblks_lba = (p->wbfs_sec_sz - p->n_wbfs_sec/8)>>p->hd_sec_sz_s;
if (!reset)
p->freeblks = 0; // will alloc and read only if needed
else {
// init with all free blocks
p->freeblks = wbfs_ioalloc(ALIGN_LBA(p->n_wbfs_sec/8));
wbfs_memset(p->freeblks,0xff,p->n_wbfs_sec/8);
}
p->max_disc = (p->freeblks_lba-1)/(p->disc_info_sz>>p->hd_sec_sz_s);
if (p->max_disc > p->hd_sec_sz - sizeof(wbfs_head_t))
p->max_disc = p->hd_sec_sz - sizeof(wbfs_head_t);
p->tmp_buffer = wbfs_ioalloc(p->hd_sec_sz);
p->n_disc_open = 0;
return p;
error:
wbfs_free(p);
wbfs_iofree(head);
return 0;
}
void wbfs_sync(wbfs_t*p) {
// copy back descriptors
if (p->write_hdsector) {
p->write_hdsector(p->callback_data,p->part_lba+0,1, p->head);
if (p->freeblks)
p->write_hdsector(p->callback_data,p->part_lba+p->freeblks_lba,ALIGN_LBA(p->n_wbfs_sec/8)>>p->hd_sec_sz_s, p->freeblks);
}
}
2009-12-19 16:47:12 +01:00
void wbfs_close(wbfs_t*p) {
wbfs_sync(p);
if (p->n_disc_open)
ERROR("trying to close wbfs while discs still open");
wbfs_iofree(p->head);
wbfs_iofree(p->tmp_buffer);
if (p->freeblks)
wbfs_iofree(p->freeblks);
wbfs_free(p);
error:
return;
}
wbfs_disc_t *wbfs_open_disc(wbfs_t* p, u8 *discid) {
u32 i;
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
wbfs_disc_t *d = 0;
for (i=0;i<p->max_disc;i++) {
if (p->head->disc_table[i]) {
p->read_hdsector(p->callback_data,
p->part_lba+1+i*disc_info_sz_lba,1,p->tmp_buffer);
if (wbfs_memcmp(discid,p->tmp_buffer,6)==0) {
d = wbfs_malloc(sizeof(*d));
if (!d)
ERROR("allocating memory");
d->p = p;
d->i = i;
d->header = wbfs_ioalloc(p->disc_info_sz);
if (!d->header)
ERROR("allocating memory");
p->read_hdsector(p->callback_data,
p->part_lba+1+i*disc_info_sz_lba,
disc_info_sz_lba,d->header);
p->n_disc_open ++;
// for(i=0;i<p->n_wbfs_sec_per_disc;i++)
// printf("%d,",wbfs_ntohs(d->header->wlba_table[i]));
return d;
}
}
}
return 0;
error:
if (d)
wbfs_iofree(d);
return 0;
}
void wbfs_close_disc(wbfs_disc_t*d) {
d->p->n_disc_open --;
wbfs_iofree(d->header);
wbfs_free(d);
}
// offset is pointing 32bit words to address the whole dvd, although len is in bytes
int wbfs_disc_read(wbfs_disc_t*d,u32 offset, u32 len, u8 *data) {
if (d->p == &wbfs_iso_file) {
return wbfs_iso_file_read(d, offset, data, len);
}
wbfs_t *p = d->p;
u16 wlba = offset>>(p->wbfs_sec_sz_s-2);
u32 iwlba_shift = p->wbfs_sec_sz_s - p->hd_sec_sz_s;
u32 lba_mask = (p->wbfs_sec_sz-1)>>(p->hd_sec_sz_s);
u32 lba = (offset>>(p->hd_sec_sz_s-2))&lba_mask;
u32 off = offset&((p->hd_sec_sz>>2)-1);
u16 iwlba = wbfs_ntohs(d->header->wlba_table[wlba]);
u32 len_copied;
int err = 0;
u8 *ptr = data;
if (unlikely(iwlba==0))
return 1;
if (unlikely(off)) {
off*=4;
err = p->read_hdsector(p->callback_data,
p->part_lba + (iwlba<<iwlba_shift) + lba, 1, p->tmp_buffer);
if (err)
return err;
len_copied = p->hd_sec_sz - off;
if (likely(len < len_copied))
len_copied = len;
wbfs_memcpy(ptr, p->tmp_buffer + off, len_copied);
len -= len_copied;
ptr += len_copied;
lba++;
if (unlikely(lba>lba_mask && len)) {
lba=0;
iwlba = wbfs_ntohs(d->header->wlba_table[++wlba]);
if (unlikely(iwlba==0))
return 1;
}
}
while (likely(len>=p->hd_sec_sz)) {
u32 nlb = len>>(p->hd_sec_sz_s);
if (unlikely(lba + nlb > p->wbfs_sec_sz)) // dont cross wbfs sectors..
nlb = p->wbfs_sec_sz-lba;
err = p->read_hdsector(p->callback_data,
p->part_lba + (iwlba<<iwlba_shift) + lba, nlb, ptr);
if (err)
return err;
len -= nlb<<p->hd_sec_sz_s;
ptr += nlb<<p->hd_sec_sz_s;
lba += nlb;
if (unlikely(lba>lba_mask && len)) {
lba = 0;
iwlba =wbfs_ntohs(d->header->wlba_table[++wlba]);
if (unlikely(iwlba==0))
return 1;
}
}
if (unlikely(len)) {
err = p->read_hdsector(p->callback_data,
p->part_lba + (iwlba<<iwlba_shift) + lba, 1, p->tmp_buffer);
if (err)
return err;
wbfs_memcpy(ptr, p->tmp_buffer, len);
}
return 0;
}
// disc listing
u32 wbfs_count_discs(wbfs_t*p) {
u32 i,count=0;
for (i=0;i<p->max_disc;i++)
if (p->head->disc_table[i])
count++;
return count;
}
2009-12-19 16:47:12 +01:00
u32 wbfs_sector_used(wbfs_t *p,wbfs_disc_info_t *di) {
u32 tot_blk=0,j;
for (j=0;j<p->n_wbfs_sec_per_disc;j++)
if (wbfs_ntohs(di->wlba_table[j]))
tot_blk++;
return tot_blk;
2009-12-19 16:47:12 +01:00
}
u32 wbfs_sector_used2(wbfs_t *p, wbfs_disc_info_t *di, u32 *last_blk) {
u32 tot_blk=0,j;
for (j=0;j<p->n_wbfs_sec_per_disc;j++)
if (wbfs_ntohs(di->wlba_table[j])) {
if (last_blk) *last_blk = j;
tot_blk++;
}
return tot_blk;
}
2009-12-19 16:47:12 +01:00
u32 wbfs_get_disc_info(wbfs_t*p, u32 index,u8 *header,int header_size,u32 *size) { //size in 32 bit
u32 i,count=0;
if (!p) return 1;
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
for (i=0;i<p->max_disc;i++)
if (p->head->disc_table[i]) {
if (count++==index) {
p->read_hdsector(p->callback_data,
p->part_lba+1+i*disc_info_sz_lba,1,p->tmp_buffer);
if (header_size > (int)p->hd_sec_sz)
header_size = p->hd_sec_sz;
u32 magic = wbfs_ntohl(*(u32*)(p->tmp_buffer+24));
if (magic!=0x5D1C9EA3) {
p->head->disc_table[i]=0;
return 1;
}
memcpy(header,p->tmp_buffer,header_size);
if (size) {
u8 *header = wbfs_ioalloc(p->disc_info_sz);
p->read_hdsector(p->callback_data,
p->part_lba+1+i*disc_info_sz_lba,disc_info_sz_lba,header);
u32 sec_used = wbfs_sector_used(p,(wbfs_disc_info_t *)header);
wbfs_iofree(header);
*size = sec_used<<(p->wbfs_sec_sz_s-2);
}
return 0;
}
}
return 1;
}
static void load_freeblocks(wbfs_t*p) {
if (p->freeblks)
return;
// XXX should handle malloc error..
p->freeblks = wbfs_ioalloc(ALIGN_LBA(p->n_wbfs_sec/8));
p->read_hdsector(p->callback_data,p->part_lba+p->freeblks_lba,ALIGN_LBA(p->n_wbfs_sec/8)>>p->hd_sec_sz_s, p->freeblks);
}
u32 wbfs_count_usedblocks(wbfs_t*p) {
u32 i,j,count=0;
load_freeblocks(p);
for (i=0;i<p->n_wbfs_sec/(8*4);i++) {
u32 v = wbfs_ntohl(p->freeblks[i]);
if (v == ~0U)
count+=32;
else if (v!=0)
for (j=0;j<32;j++)
if (v & (1<<j))
count++;
}
return count;
}
// write access
2009-12-19 16:47:12 +01:00
//static
int block_used(u8 *used,u32 i,u32 wblk_sz) {
u32 k;
i*=wblk_sz;
for (k=0;k<wblk_sz;k++)
if (i+k<143432*2 && used[i+k])
return 1;
return 0;
}
static u32 alloc_block(wbfs_t*p) {
u32 i,j;
for (i=0;i<p->n_wbfs_sec/(8*4);i++) {
u32 v = wbfs_ntohl(p->freeblks[i]);
if (v != 0) {
for (j=0;j<32;j++)
if (v & (1<<j)) {
p->freeblks[i] = wbfs_htonl(v & ~(1<<j));
return (i*32)+j+1;
}
}
}
return ~0;
}
static void free_block(wbfs_t *p,int bl) {
int i = (bl-1)/(32);
int j = (bl-1)&31;
u32 v = wbfs_ntohl(p->freeblks[i]);
p->freeblks[i] = wbfs_htonl(v | 1<<j);
}
2009-12-19 16:47:12 +01:00
u32 wbfs_add_disc(wbfs_t*p, read_wiidisc_callback_t read_src_wii_disc,
void *callback_data,progress_callback_t spinner,partition_selector_t sel,int copy_1_1) {
int i,discn;
u32 tot,cur;
u32 wii_sec_per_wbfs_sect = 1<<(p->wbfs_sec_sz_s-p->wii_sec_sz_s);
wiidisc_t *d = 0;
u8 *used = 0;
wbfs_disc_info_t *info = 0;
u8* copy_buffer = 0;
int retval = -1;
int num_wbfs_sect_to_copy;
u32 last_used;
used = wbfs_malloc(p->n_wii_sec_per_disc);
if (!used)
ERROR("unable to alloc memory");
// copy_1_1 needs disk usage for layers detection
//if(!copy_1_1)
{
d = wd_open_disc(read_src_wii_disc,callback_data);
if (!d)
ERROR("unable to open wii disc");
wd_build_disc_usage(d,sel,used);
wd_close_disc(d);
d = 0;
}
for (i=0;i<p->max_disc;i++)// find a free slot.
if (p->head->disc_table[i]==0)
break;
if (i==p->max_disc)
ERROR("no space left on device (table full)");
p->head->disc_table[i] = 1;
discn = i;
load_freeblocks(p);
// build disc info
info = wbfs_ioalloc(p->disc_info_sz);
read_src_wii_disc(callback_data,0,0x100,info->disc_header_copy);
copy_buffer = wbfs_ioalloc(p->wii_sec_sz);
if (!copy_buffer)
ERROR("alloc memory");
tot=0;
cur=0;
num_wbfs_sect_to_copy = p->n_wbfs_sec_per_disc;
// count total number of sectors to write
last_used = 0;
for (i=0; i<num_wbfs_sect_to_copy; i++) {
if (block_used(used,i,wii_sec_per_wbfs_sect)) {
tot += wii_sec_per_wbfs_sect;
last_used = i;
}
}
if (copy_1_1) {
// detect single or dual layer
if ( (last_used + 1) > (p->n_wbfs_sec_per_disc / 2) ) {
// dual layer
num_wbfs_sect_to_copy = p->n_wbfs_sec_per_disc;
} else {
// single layer
num_wbfs_sect_to_copy = p->n_wbfs_sec_per_disc / 2;
}
tot = num_wbfs_sect_to_copy * wii_sec_per_wbfs_sect;
}
/*
// num of hd sectors to copy could be specified directly
if (copy_1_1 > 1) {
u32 hd_sec_per_wii_sec = p->wii_sec_sz / p->hd_sec_sz;
num_wbfs_sect_to_copy = copy_1_1 / hd_sec_per_wii_sec / wii_sec_per_wbfs_sect;
tot = num_wbfs_sect_to_copy * wii_sec_per_wbfs_sect;
}*/
int ret = 0;
if (spinner) spinner(0,tot);
for (i=0; i<num_wbfs_sect_to_copy; i++) {
u16 bl = 0;
if (copy_1_1 || block_used(used,i,wii_sec_per_wbfs_sect)) {
u16 j;
bl = alloc_block(p);
if (bl==0xffff)
ERROR("no space left on device (disc full)");
for (j=0; j<wii_sec_per_wbfs_sect;j++) {
u32 offset = (i*(p->wbfs_sec_sz>>2)) + (j*(p->wii_sec_sz>>2));
ret = read_src_wii_disc(callback_data,offset,p->wii_sec_sz,copy_buffer);
if (ret) {
if (copy_1_1 && i > p->n_wbfs_sec_per_disc / 2) {
// end of dual layer data
if (j > 0) {
info->wlba_table[i] = wbfs_htons(bl);
}
spinner(tot,tot);
break;
}
//ERROR("read error");
printf("\rWARNING: read (%u) error (%d)\n", offset, ret);
}
//fix the partition table
if (offset == (0x40000>>2))
wd_fix_partition_table(d, sel, copy_buffer);
p->write_hdsector(p->callback_data,
p->part_lba+bl*(p->wbfs_sec_sz/p->hd_sec_sz) + j*(p->wii_sec_sz/p->hd_sec_sz),
p->wii_sec_sz/p->hd_sec_sz, copy_buffer);
cur++;
if (spinner)
spinner(cur,tot);
}
}
if (ret) break;
info->wlba_table[i] = wbfs_htons(bl);
}
// write disc info
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
p->write_hdsector(p->callback_data,p->part_lba+1+discn*disc_info_sz_lba,disc_info_sz_lba,info);
wbfs_sync(p);
retval = 0;
error:
if (d)
wd_close_disc(d);
if (used)
wbfs_free(used);
if (info)
wbfs_iofree(info);
if (copy_buffer)
wbfs_iofree(copy_buffer);
// init with all free blocks
return retval;
}
u32 wbfs_rm_disc(wbfs_t*p, u8* discid) {
wbfs_disc_t *d = wbfs_open_disc(p,discid);
int i;
int discn = 0;
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
if (!d)
return 1;
load_freeblocks(p);
discn = d->i;
for ( i=0; i< p->n_wbfs_sec_per_disc; i++) {
u32 iwlba = wbfs_ntohs(d->header->wlba_table[i]);
if (iwlba)
free_block(p,iwlba);
}
memset(d->header,0,p->disc_info_sz);
p->write_hdsector(p->callback_data,p->part_lba+1+discn*disc_info_sz_lba,disc_info_sz_lba,d->header);
p->head->disc_table[discn] = 0;
wbfs_close_disc(d);
wbfs_sync(p);
return 0;
}
u32 wbfs_ren_disc(wbfs_t*p, u8* discid, u8* newname) {
wbfs_disc_t *d = wbfs_open_disc(p,discid);
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
if (!d)
return 1;
memset(d->header->disc_header_copy+0x20, 0, 0x40);
strncpy((char *) d->header->disc_header_copy+0x20, (char *) newname, 0x39);
p->write_hdsector(p->callback_data,p->part_lba+1+d->i*disc_info_sz_lba,disc_info_sz_lba,d->header);
wbfs_close_disc(d);
return 0;
}
u32 wbfs_rID_disc(wbfs_t*p, u8* discid, u8* newID) {
wbfs_disc_t *d = wbfs_open_disc(p,discid);
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
if (!d)
return 1;
memset(d->header->disc_header_copy, 0, 0x10);
strncpy((char *) d->header->disc_header_copy, (char *) newID, 0x9);
p->write_hdsector(p->callback_data,p->part_lba+1+d->i*disc_info_sz_lba,disc_info_sz_lba,d->header);
wbfs_close_disc(d);
return 0;
}
// trim the file-system to its minimum size
u32 wbfs_trim(wbfs_t*p) {
u32 maxbl;
load_freeblocks(p);
maxbl = alloc_block(p);
p->n_hd_sec = maxbl<<(p->wbfs_sec_sz_s-p->hd_sec_sz_s);
p->head->n_hd_sec = wbfs_htonl(p->n_hd_sec);
// make all block full
memset(p->freeblks,0,p->n_wbfs_sec/8);
wbfs_sync(p);
// os layer will truncate the file.
return maxbl;
2009-12-19 16:47:12 +01:00
}
// data extraction
u32 wbfs_extract_disc(wbfs_disc_t*d, rw_sector_callback_t write_dst_wii_sector,void *callback_data,progress_callback_t spinner) {
wbfs_t *p = d->p;
u8* copy_buffer = 0;
int i;
int src_wbs_nlb=p->wbfs_sec_sz/p->hd_sec_sz;
int dst_wbs_nlb=p->wbfs_sec_sz/p->wii_sec_sz;
copy_buffer = wbfs_ioalloc(p->wbfs_sec_sz);
if (!copy_buffer)
ERROR("alloc memory");
for ( i=0; i< p->n_wbfs_sec_per_disc; i++) {
u32 iwlba = wbfs_ntohs(d->header->wlba_table[i]);
if (iwlba) {
if (spinner)
spinner(i,p->n_wbfs_sec_per_disc);
p->read_hdsector(p->callback_data, p->part_lba + iwlba*src_wbs_nlb, src_wbs_nlb, copy_buffer);
write_dst_wii_sector(callback_data, i*dst_wbs_nlb, dst_wbs_nlb, copy_buffer);
}
}
wbfs_iofree(copy_buffer);
return 0;
error:
return 1;
}
float wbfs_estimate_disc
(
wbfs_t *p, read_wiidisc_callback_t read_src_wii_disc,
void *callback_data,
partition_selector_t sel) {
u8 *b;
int i;
u32 tot;
u32 wii_sec_per_wbfs_sect = 1 << (p->wbfs_sec_sz_s-p->wii_sec_sz_s);
wiidisc_t *d = 0;
u8 *used = 0;
wbfs_disc_info_t *info = 0;
tot = 0;
used = wbfs_malloc(p->n_wii_sec_per_disc);
if (!used) {
ERROR("unable to alloc memory");
}
d = wd_open_disc(read_src_wii_disc, callback_data);
if (!d) {
ERROR("unable to open wii disc");
}
wd_build_disc_usage(d,sel,used);
wd_close_disc(d);
d = 0;
info = wbfs_ioalloc(p->disc_info_sz);
b = (u8 *)info;
read_src_wii_disc(callback_data, 0, 0x100, info->disc_header_copy);
//fprintf(stderr, "estimating %c%c%c%c%c%c %s...\n",b[0], b[1], b[2], b[3], b[4], b[5], b + 0x20);
for (i = 0; i < p->n_wbfs_sec_per_disc; i++) {
if (block_used(used, i, wii_sec_per_wbfs_sect)) {
tot++;
}
}
//memcpy(header, b,0x100);
error:
if (d)
wd_close_disc(d);
if (used)
wbfs_free(used);
if (info)
wbfs_iofree(info);
return tot * (((p->wbfs_sec_sz*1.0) / p->hd_sec_sz) * 512);
}
u32 wbfs_size_disc(wbfs_t*p,read_wiidisc_callback_t read_src_wii_disc,
void *callback_data,partition_selector_t sel,
u32 *comp_size, u32 *real_size) {
int i;
u32 tot = 0, last = 0;
u32 wii_sec_per_wbfs_sect = 1<<(p->wbfs_sec_sz_s-p->wii_sec_sz_s);
wiidisc_t *d = 0;
u8 *used = 0;
used = wbfs_malloc(p->n_wii_sec_per_disc);
if (!used)
ERROR("unable to alloc memory");
d = wd_open_disc(read_src_wii_disc,callback_data);
if (!d)
ERROR("unable to open wii disc");
wd_build_disc_usage(d,sel,used);
wd_close_disc(d);
d = 0;
// count total number to write for spinner
for (i=0; i<p->n_wbfs_sec_per_disc;i++) {
if (block_used(used,i,wii_sec_per_wbfs_sect)) {
tot += wii_sec_per_wbfs_sect;
last = i * wii_sec_per_wbfs_sect;
}
}
error:
if (d)
wd_close_disc(d);
if (used)
wbfs_free(used);
*comp_size = tot;
*real_size = last;
return 0;
}
2009-12-19 16:47:12 +01:00
// offset is pointing 32bit words to address the whole dvd, although len is in bytes
//int wbfs_disc_read(wbfs_disc_t*d,u32 offset, u8 *data, u32 len)
// offset points 32bit words, count counts bytes
//int (*read_wiidisc_callback_t)(void*fp,u32 offset,u32 count,void*iobuf);
// connect wiidisc to wbfs_disc
int read_wiidisc_wbfsdisc(void*fp,u32 offset,u32 count,void*iobuf) {
return wbfs_disc_read((wbfs_disc_t*)fp, offset, count, iobuf);
2009-12-19 16:47:12 +01:00
}
int wbfs_extract_file(wbfs_disc_t*d, char *path, void **data) {
wiidisc_t *wd = 0;
int ret = 0;
wd = wd_open_disc(read_wiidisc_wbfsdisc, d);
if (!wd) {
ERROR("opening wbfs disc");
return -1;
}
wd->extracted_size = 0;
*data = wd_extract_file(wd, ONLY_GAME_PARTITION, path);
ret = wd->extracted_size;
if (!*data) {
//ERROR("file not found");
ret = -1;
}
wd_close_disc(wd);
2009-12-19 16:47:12 +01:00
error:
return ret;
}
int wbfs_get_fragments(wbfs_disc_t *d, _frag_append_t append_fragment, void *callback_data) {
if (!d) return -1;
wbfs_t *p = d->p;
int src_wbs_nlb = p->wbfs_sec_sz / p->hd_sec_sz;
int i, ret, last = 0;
for ( i=0; i< p->n_wbfs_sec_per_disc; i++) {
u32 iwlba = wbfs_ntohs(d->header->wlba_table[i]);
if (iwlba) {
ret = append_fragment(callback_data,
i * src_wbs_nlb, // offset
p->part_lba + iwlba * src_wbs_nlb, // sector
src_wbs_nlb); // count
if (ret) return ret; // error
last = i;
}
}
if (last < p->n_wbfs_sec_per_disc / 2) {
last = p->n_wbfs_sec_per_disc / 2;
}
u32 size = last * src_wbs_nlb;
append_fragment(callback_data, size, 0, 0); // set size
return 0;
}
// wrapper for reading .iso files using wbfs apis
#include <unistd.h>
#include <sys/stat.h>
// offset is pointing 32bit words to address the whole dvd, although len is in bytes
int wbfs_iso_file_read(wbfs_disc_t*d,u32 offset, u8 *data, u32 len) {
if (!d || d->p != &wbfs_iso_file) return -1;
int fd = (int)d->header;
off_t off = ((u64)offset) << 2;
off_t ret_off;
int ret;
ret_off = lseek(fd, off, SEEK_SET);
if (ret_off != off) return -1;
ret = read(fd, data, len);
if (ret != len) return -2;
return 0;
}
u32 wbfs_disc_sector_used(wbfs_disc_t *d, u32 *num_blk) {
if (d->p == &wbfs_iso_file) {
int fd = (int)d->header;
struct stat st;
if (fstat(fd, &st) == -1) return 0;
if (num_blk) {
*num_blk = (st.st_size >> 9); // in 512 units
}
return st.st_blocks; // in 512 units (can be sparse)
}
u32 last_blk = 0;
u32 ret;
ret = wbfs_sector_used2(d->p, d->header, &last_blk);
if (num_blk) {
*num_blk = last_blk + 1;
}
return ret;
}
2009-12-19 16:47:12 +01:00