2009-12-04 16:05:20 +01:00
|
|
|
// Modified by oggzee
|
|
|
|
|
2009-11-15 22:30:44 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ogcsys.h>
|
2009-12-04 16:05:20 +01:00
|
|
|
#include <unistd.h>
|
2009-11-15 22:30:44 +01:00
|
|
|
|
|
|
|
#include "partition_usbloader.h"
|
|
|
|
#include "sdhc.h"
|
2010-02-22 22:29:47 +01:00
|
|
|
#include "usbstorage2.h"
|
2009-11-15 22:30:44 +01:00
|
|
|
#include "utils.h"
|
|
|
|
#include "wbfs.h"
|
2009-12-04 16:05:20 +01:00
|
|
|
#include "libwbfs/libwbfs.h"
|
2009-11-15 22:30:44 +01:00
|
|
|
|
|
|
|
/* 'partition table' structure */
|
2010-09-19 01:16:05 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/* Zero bytes */
|
|
|
|
u8 padding[446];
|
2009-11-15 22:30:44 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Partition table entries */
|
|
|
|
partitionEntry entries[MAX_PARTITIONS];
|
2009-11-15 22:30:44 +01:00
|
|
|
} ATTRIBUTE_PACKED partitionTable;
|
|
|
|
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
s32 Partition_GetEntries( u32 device, partitionEntry *outbuf, u32 *outval )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
static partitionTable table ATTRIBUTE_ALIGN( 32 );
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
u32 cnt, sector_size;
|
|
|
|
s32 ret;
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Read from specified device */
|
|
|
|
switch ( device )
|
|
|
|
{
|
|
|
|
case WBFS_DEVICE_USB:
|
|
|
|
{
|
|
|
|
/* Get sector size */
|
|
|
|
ret = USBStorage2_GetCapacity( §or_size );
|
|
|
|
if ( ret == 0 )
|
|
|
|
return -1;
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Read partition table */
|
|
|
|
ret = USBStorage2_ReadSectors( 0, 1, &table );
|
|
|
|
if ( ret < 0 )
|
|
|
|
return ret;
|
2009-11-15 22:30:44 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
case WBFS_DEVICE_SDHC:
|
|
|
|
{
|
|
|
|
/* SDHC sector size */
|
|
|
|
sector_size = SDHC_SECTOR_SIZE;
|
2009-11-15 22:30:44 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Read partition table */
|
|
|
|
ret = SDHC_ReadSectors( 0, 1, &table );
|
|
|
|
if ( !ret )
|
|
|
|
return -1;
|
2009-11-15 22:30:44 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-11-15 22:30:44 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
2009-11-15 22:30:44 +01:00
|
|
|
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Swap endianess */
|
|
|
|
for ( cnt = 0; cnt < 4; cnt++ )
|
|
|
|
{
|
|
|
|
partitionEntry *entry = &table.entries[cnt];
|
2009-11-15 22:30:44 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
entry->sector = swap32( entry->sector );
|
|
|
|
entry->size = swap32( entry->size );
|
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Set partition entries */
|
|
|
|
memcpy( outbuf, table.entries, sizeof( table.entries ) );
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
/* Set sector size */
|
|
|
|
*outval = sector_size;
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
return 0;
|
2009-11-15 22:30:44 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
bool Device_ReadSectors( u32 device, u32 sector, u32 count, void *buffer )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
s32 ret;
|
|
|
|
|
|
|
|
/* Read from specified device */
|
|
|
|
switch ( device )
|
|
|
|
{
|
|
|
|
case WBFS_DEVICE_USB:
|
|
|
|
ret = USBStorage2_ReadSectors( sector, count, buffer );
|
|
|
|
if ( ret < 0 )
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case WBFS_DEVICE_SDHC:
|
|
|
|
return SDHC_ReadSectors( sector, count, buffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
bool Device_WriteSectors( u32 device, u32 sector, u32 count, void *buffer )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
s32 ret;
|
|
|
|
|
|
|
|
/* Read from specified device */
|
|
|
|
switch ( device )
|
|
|
|
{
|
|
|
|
case WBFS_DEVICE_USB:
|
|
|
|
ret = USBStorage2_WriteSectors( sector, count, buffer );
|
|
|
|
if ( ret < 0 )
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case WBFS_DEVICE_SDHC:
|
|
|
|
return SDHC_WriteSectors( sector, count, buffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
s32 Partition_GetEntriesEx( u32 device, partitionEntry *outbuf, u32 *psect_size, u8 *num )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
static partitionTable table ATTRIBUTE_ALIGN( 32 );
|
|
|
|
partitionEntry *entry;
|
|
|
|
|
|
|
|
u32 i, sector_size;
|
|
|
|
s32 ret;
|
|
|
|
int maxpart = *num;
|
|
|
|
|
|
|
|
// Get sector size
|
|
|
|
switch ( device )
|
|
|
|
{
|
|
|
|
case WBFS_DEVICE_USB:
|
|
|
|
ret = USBStorage2_GetCapacity( §or_size );
|
|
|
|
if ( ret == 0 ) return -1;
|
|
|
|
break;
|
|
|
|
case WBFS_DEVICE_SDHC:
|
|
|
|
sector_size = SDHC_SECTOR_SIZE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* Set sector size */
|
|
|
|
*psect_size = sector_size;
|
|
|
|
|
|
|
|
u32 ext = 0;
|
|
|
|
u32 next = 0;
|
|
|
|
|
|
|
|
// Read partition table
|
|
|
|
ret = Device_ReadSectors( device, 0, 1, &table );
|
|
|
|
if ( !ret ) return -1;
|
|
|
|
// Check if it's a RAW WBFS disc, without partition table
|
|
|
|
if ( get_fs_type( &table ) == FS_TYPE_WBFS )
|
|
|
|
{
|
|
|
|
memset( outbuf, 0, sizeof( table.entries ) );
|
|
|
|
wbfs_head_t *head = ( wbfs_head_t* ) & table;
|
|
|
|
outbuf->size = wbfs_ntohl( head->n_hd_sec );
|
|
|
|
*num = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Swap endianess */
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
|
|
{
|
|
|
|
entry = &table.entries[i];
|
|
|
|
entry->sector = swap32( entry->sector );
|
|
|
|
entry->size = swap32( entry->size );
|
|
|
|
if ( !ext && part_is_extended( entry->type ) )
|
|
|
|
{
|
|
|
|
ext = entry->sector;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Set partition entries */
|
|
|
|
memcpy( outbuf, table.entries, sizeof( table.entries ) );
|
|
|
|
// num primary
|
|
|
|
*num = 4;
|
|
|
|
|
|
|
|
if ( !ext ) return 0;
|
|
|
|
|
|
|
|
next = ext;
|
|
|
|
// scan extended partition for logical
|
|
|
|
for ( i = 0; i < maxpart - 4; i++ )
|
|
|
|
{
|
|
|
|
ret = Device_ReadSectors( device, next, 1, &table );
|
|
|
|
if ( !ret ) break;
|
|
|
|
if ( i == 0 )
|
|
|
|
{
|
|
|
|
// handle the invalid scenario where wbfs is on an EXTENDED
|
|
|
|
// partition instead of on the Logical inside Extended.
|
|
|
|
if ( get_fs_type( &table ) == FS_TYPE_WBFS ) break;
|
|
|
|
}
|
|
|
|
entry = &table.entries[0];
|
|
|
|
entry->sector = swap32( entry->sector );
|
|
|
|
entry->size = swap32( entry->size );
|
|
|
|
if ( entry->type && entry->size && entry->sector )
|
|
|
|
{
|
|
|
|
// rebase to abolute address
|
|
|
|
entry->sector += next;
|
|
|
|
// add logical
|
|
|
|
memcpy( &outbuf[*num], entry, sizeof( *entry ) );
|
|
|
|
( *num )++;
|
|
|
|
// get next
|
|
|
|
entry++;
|
|
|
|
if ( entry->type && entry->size && entry->sector )
|
|
|
|
{
|
|
|
|
next = ext + swap32( entry->sector );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2009-11-15 22:30:44 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
bool part_is_extended( int type )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
if ( type == 0x05 ) return true;
|
|
|
|
if ( type == 0x0f ) return true;
|
|
|
|
return false;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
bool part_is_data( int type )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
if ( type && !part_is_extended( type ) ) return true;
|
|
|
|
return false;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
bool part_valid_data( partitionEntry *entry )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
if ( entry->size && entry->type && entry->sector )
|
|
|
|
{
|
|
|
|
return part_is_data( entry->type );
|
|
|
|
}
|
|
|
|
return false;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
char* part_type_data( int type )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
switch ( type )
|
|
|
|
{
|
|
|
|
case 0x01: return "FAT12";
|
|
|
|
case 0x04: return "FAT16";
|
|
|
|
case 0x06: return "FAT16"; //+
|
|
|
|
case 0x07: return "NTFS";
|
|
|
|
case 0x0b: return "FAT32";
|
|
|
|
case 0x0c: return "FAT32";
|
|
|
|
case 0x0e: return "FAT16";
|
|
|
|
case 0x82: return "LxSWP";
|
|
|
|
case 0x83: return "LINUX";
|
|
|
|
case 0x8e: return "LxLVM";
|
|
|
|
case 0xa8: return "OSX";
|
|
|
|
case 0xab: return "OSXBT";
|
|
|
|
case 0xaf: return "OSXHF";
|
|
|
|
case 0xe8: return "LUKS";
|
|
|
|
}
|
|
|
|
return NULL;
|
2009-11-15 22:30:44 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
char *part_type_name( int type )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
static char unk[8];
|
|
|
|
if ( type == 0 ) return "UNUSED";
|
|
|
|
if ( part_is_extended( type ) ) return "EXTEND";
|
|
|
|
char *p = part_type_data( type );
|
|
|
|
if ( p ) return p;
|
|
|
|
sprintf( unk, "UNK-%02x", type );
|
|
|
|
return unk;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int get_fs_type( void *buff )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
char *buf = buff;
|
|
|
|
// WBFS
|
|
|
|
wbfs_head_t *head = ( wbfs_head_t * )buff;
|
|
|
|
if ( head->magic == wbfs_htonl( WBFS_MAGIC ) ) return FS_TYPE_WBFS;
|
|
|
|
// 55AA
|
|
|
|
if ( buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA )
|
|
|
|
{
|
|
|
|
// FAT
|
|
|
|
if ( memcmp( buf + 0x36, "FAT", 3 ) == 0 ) return FS_TYPE_FAT16;
|
|
|
|
if ( memcmp( buf + 0x52, "FAT", 3 ) == 0 ) return FS_TYPE_FAT32;
|
|
|
|
// NTFS
|
|
|
|
if ( memcmp( buf + 0x03, "NTFS", 4 ) == 0 ) return FS_TYPE_NTFS;
|
|
|
|
}
|
|
|
|
return FS_TYPE_UNK;
|
2009-11-15 22:30:44 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int get_part_fs( int fs_type )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
switch ( fs_type )
|
|
|
|
{
|
|
|
|
case FS_TYPE_FAT32: return PART_FS_FAT;
|
|
|
|
case FS_TYPE_NTFS: return PART_FS_NTFS;
|
|
|
|
case FS_TYPE_WBFS: return PART_FS_WBFS;
|
|
|
|
default: return -1;
|
|
|
|
}
|
2009-12-19 15:05:31 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
bool is_type_fat( int type )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
return ( type == FS_TYPE_FAT16 || type == FS_TYPE_FAT32 );
|
2009-11-15 22:30:44 +01:00
|
|
|
}
|
|
|
|
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
char *get_fs_name( int i )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
switch ( i )
|
|
|
|
{
|
|
|
|
case FS_TYPE_FAT16: return "FAT16";
|
|
|
|
case FS_TYPE_FAT32: return "FAT32";
|
|
|
|
case FS_TYPE_NTFS: return "NTFS";
|
|
|
|
case FS_TYPE_WBFS: return "WBFS";
|
|
|
|
}
|
|
|
|
return "";
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
s32 Partition_GetList( u32 device, PartList *plist )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
partitionEntry *entry = NULL;
|
|
|
|
PartInfo *pinfo = NULL;
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
memset( plist, 0, sizeof( PartList ) );
|
|
|
|
|
|
|
|
// Get partition entries
|
|
|
|
plist->num = MAX_PARTITIONS_EX;
|
|
|
|
ret = Partition_GetEntriesEx( device, plist->pentry, &plist->sector_size, &plist->num );
|
|
|
|
if ( ret < 0 )
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// check for RAW WBFS disc
|
|
|
|
if ( plist->num == 1 )
|
|
|
|
{
|
|
|
|
pinfo = &plist->pinfo[0];
|
|
|
|
entry = &plist->pentry[0];
|
|
|
|
plist->wbfs_n = 1;
|
|
|
|
pinfo->wbfs_i = pinfo->index = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[plist->sector_size];
|
|
|
|
|
|
|
|
// scan partitions for filesystem type
|
|
|
|
for ( i = 0; i < plist->num; i++ )
|
|
|
|
{
|
|
|
|
pinfo = &plist->pinfo[i];
|
|
|
|
entry = &plist->pentry[i];
|
|
|
|
if ( !entry->size ) continue;
|
|
|
|
if ( !entry->type ) continue;
|
|
|
|
if ( !entry->sector ) continue;
|
|
|
|
// even though wrong, it's possible WBFS is on an extended part.
|
|
|
|
//if (!part_is_data(entry->type)) continue;
|
|
|
|
if ( !Device_ReadSectors( device, entry->sector, 1, buf ) ) continue;
|
|
|
|
pinfo->fs_type = get_fs_type( buf );
|
|
|
|
if ( pinfo->fs_type == FS_TYPE_WBFS )
|
|
|
|
{
|
|
|
|
// multiple wbfs on sdhc not supported
|
|
|
|
if ( device == WBFS_DEVICE_SDHC && ( plist->wbfs_n > 1 || i > 4 ) ) continue;
|
|
|
|
plist->wbfs_n++;
|
|
|
|
pinfo->wbfs_i = pinfo->index = plist->wbfs_n;
|
|
|
|
}
|
|
|
|
else if ( is_type_fat( pinfo->fs_type ) )
|
|
|
|
{
|
|
|
|
plist->fat_n++;
|
|
|
|
pinfo->fat_i = pinfo->index = plist->fat_n;
|
|
|
|
}
|
|
|
|
else if ( pinfo->fs_type == FS_TYPE_NTFS )
|
|
|
|
{
|
|
|
|
plist->ntfs_n++;
|
|
|
|
pinfo->ntfs_i = pinfo->index = plist->ntfs_n;
|
|
|
|
}
|
|
|
|
pinfo->part_fs = get_part_fs( pinfo->fs_type );
|
|
|
|
}
|
|
|
|
return 0;
|
2009-11-15 22:30:44 +01:00
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
int Partition_FixEXT( u32 device, u8 part )
|
2010-02-09 11:59:55 +01:00
|
|
|
{
|
2010-09-19 01:16:05 +02:00
|
|
|
static partitionTable table ATTRIBUTE_ALIGN( 32 );
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ( part > 3 ) return -1;
|
|
|
|
// Read partition table
|
|
|
|
ret = Device_ReadSectors( device, 0, 1, &table );
|
|
|
|
if ( !ret ) return -1;
|
|
|
|
if ( part_is_extended( table.entries[part].type ) )
|
|
|
|
{
|
|
|
|
table.entries[part].type = 0x0b; // FAT32
|
|
|
|
ret = Device_WriteSectors( device, 0, 1, &table );
|
|
|
|
if ( !ret ) return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|