mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-16 00:15:08 +01:00
0f17471b27
*Added sources of the custom libs to the branches *Fixed crash when switching from list layout to grid/carousel layout *Removed 1:1 copy option because its meaningless and almost the same as installing all partitions *Fixed install partition selection. This option needs a reset. Go to settings and reselect your option for this. *Fixed schinese and tchinese language modes (filename bugs. has to be schinese.lang and tchinese.lang like on SVN) *Fixed bug in sound buffer circle *Fixed incorrect behaviour of x-flip when selecting system like (thx Cyan for the patch) *Accept ios revision 65535 for Waninkokos IOSes (thx to PPSainity for pointing it out) *Merged the new theming style branch into trunk. Just as a reminder: ALL old themes will not work until the themers did port it to the new style! *Removed old theme style completely Theme example: The example file of the theme is the Default.them file. It can be found in the SVN trunk. Change in loading of themes: When selecting a theme now a list of all .them files in a folder is displayed. The image folder of that theme has to be in the same folder as the .them file. The image path is defined in the head of the .them file in the line with "Image-Folder: Example\n".
421 lines
12 KiB
C
421 lines
12 KiB
C
/**
|
|
* ext2file.c - devoptab file routines for EXT2-based devices.
|
|
*
|
|
* Copyright (c) 2006 Michael "Chishm" Chisholm
|
|
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
|
* Copyright (c) 2010 Dimok
|
|
*
|
|
* This program/include file is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program/include file is distributed in the hope that it will be
|
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include "ext2_fs.h"
|
|
#include "ext2fs.h"
|
|
#include "ext2_internal.h"
|
|
#include "gekko_io.h"
|
|
#include "mem_allocate.h"
|
|
#include "partitions.h"
|
|
|
|
bool ext2Mount(const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags)
|
|
{
|
|
errcode_t retval = -1;
|
|
ext2_filsys fs = NULL;
|
|
io_channel io_chan = NULL;
|
|
gekko_fd *fd = NULL;
|
|
ext2_vd * vd = NULL;
|
|
|
|
// Sanity check
|
|
if (!name || !interface)
|
|
{
|
|
errno = EINVAL;
|
|
return false;
|
|
}
|
|
|
|
// Allocate the device driver descriptor
|
|
fd = (gekko_fd*) mem_alloc(sizeof(gekko_fd));
|
|
if (!fd)
|
|
goto cleanup;
|
|
|
|
memset(fd, 0, sizeof(gekko_fd));
|
|
|
|
// Setup the device driver descriptor
|
|
fd->interface = interface;
|
|
fd->startSector = startSector;
|
|
fd->sectorSize = 0;
|
|
fd->sectorCount = 0;
|
|
fd->cachePageCount = cachePageCount;
|
|
fd->cachePageSize = cachePageSize;
|
|
|
|
fs = mem_alloc(sizeof(struct struct_ext2_filsys));
|
|
if (!fs)
|
|
{
|
|
ext2_log_trace("no memory for fs\n");
|
|
errno = ENOMEM;
|
|
goto cleanup;
|
|
}
|
|
|
|
memset(fs, 0, sizeof(struct struct_ext2_filsys));
|
|
|
|
io_chan = mem_alloc(sizeof(struct struct_io_channel));
|
|
if (!io_chan)
|
|
{
|
|
ext2_log_trace("no memory for io_chan\n");
|
|
errno = ENOMEM;
|
|
goto cleanup;
|
|
}
|
|
|
|
memset(io_chan, 0, sizeof(struct struct_io_channel));
|
|
|
|
io_chan->magic = EXT2_ET_MAGIC_IO_CHANNEL;
|
|
io_chan->manager = gekko_io_manager;
|
|
io_chan->name = strdup(name);
|
|
if(!io_chan->name) goto cleanup;
|
|
io_chan->block_size = 1024;
|
|
io_chan->read_error = 0;
|
|
io_chan->write_error = 0;
|
|
io_chan->refcount = 1;
|
|
io_chan->private_data = fd;
|
|
io_chan->flags = flags;
|
|
|
|
retval = ext2fs_open2(io_chan->name, 0, io_chan->flags, 0, 0, &io_chan, &fs);
|
|
if(retval)
|
|
{
|
|
ext2_log_trace("error mounting %i\n", (int) retval);
|
|
goto cleanup;
|
|
}
|
|
|
|
vd = mem_alloc(sizeof(ext2_vd));
|
|
if(!vd)
|
|
{
|
|
ext2_log_trace("no memory for vd\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
// Initialise the volume descriptor
|
|
ext2InitVolume(vd);
|
|
vd->fs = fs;
|
|
vd->io = io_chan;
|
|
vd->root = EXT2_ROOT_INO;
|
|
|
|
// Add the device to the devoptab table
|
|
if (ext2AddDevice(name, vd)) {
|
|
ext2DeinitVolume(vd);
|
|
goto cleanup;
|
|
}
|
|
|
|
return true;
|
|
|
|
cleanup:
|
|
if(fd)
|
|
mem_free(fd);
|
|
if(io_chan)
|
|
mem_free(io_chan);
|
|
if(vd)
|
|
mem_free(vd);
|
|
if(fs)
|
|
{
|
|
ext2fs_close(fs);
|
|
ext2fs_free(fs);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ext2Unmount(const char *name)
|
|
{
|
|
ext2_vd *vd = NULL;
|
|
|
|
// Get the devices volume descriptor
|
|
vd = ext2GetVolume(name);
|
|
if (!vd)
|
|
return;
|
|
|
|
// Remove the device from the devoptab table
|
|
ext2RemoveDevice(name);
|
|
|
|
// Deinitialise the volume descriptor
|
|
ext2DeinitVolume(vd);
|
|
|
|
// Unmount the volume
|
|
ext2fs_close(vd->fs);
|
|
ext2fs_free(vd->fs);
|
|
|
|
//Free the io manager
|
|
mem_free(vd->io->private_data);
|
|
mem_free(vd->io);
|
|
|
|
// Free the volume descriptor
|
|
mem_free(vd);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
const char *ext2GetVolumeName (const char *name)
|
|
{
|
|
if (!name) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
// Get the devices volume descriptor
|
|
ext2_vd *vd = ext2GetVolume(name);
|
|
if (!vd) {
|
|
errno = ENODEV;
|
|
return NULL;
|
|
}
|
|
|
|
return vd->fs->super->s_volume_name;
|
|
}
|
|
|
|
bool ext2SetVolumeName (const char *name, const char *volumeName)
|
|
{
|
|
// Sanity check
|
|
if (!name || !volumeName) {
|
|
errno = EINVAL;
|
|
return false;
|
|
}
|
|
|
|
// Get the devices volume descriptor
|
|
ext2_vd *vd = ext2GetVolume(name);
|
|
if (!vd) {
|
|
errno = ENODEV;
|
|
return false;
|
|
}
|
|
|
|
// Lock
|
|
ext2Lock(vd);
|
|
int i;
|
|
for(i = 0; i < 15 && *volumeName != 0; ++i, volumeName++)
|
|
vd->fs->super->s_volume_name[i] = *volumeName;
|
|
|
|
vd->fs->super->s_volume_name[i] = '\0';
|
|
|
|
ext2fs_mark_super_dirty(vd->fs);
|
|
|
|
ext2Sync(vd, NULL);
|
|
|
|
// Unlock
|
|
ext2Unlock(vd);
|
|
|
|
return true;
|
|
}
|
|
|
|
int ext2FindPartitions (const DISC_INTERFACE *interface, sec_t **out_partitions)
|
|
{
|
|
MASTER_BOOT_RECORD mbr;
|
|
PARTITION_RECORD *partition = NULL;
|
|
int partition_count = 0, ret = -1;
|
|
sec_t part_lba = 0;
|
|
sec_t * partitions = NULL;
|
|
int i;
|
|
|
|
union {
|
|
u8 buffer[512];
|
|
MASTER_BOOT_RECORD mbr;
|
|
EXTENDED_BOOT_RECORD ebr;
|
|
} sector;
|
|
|
|
// Sanity check
|
|
if (!interface) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if(!out_partitions) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
// Start the device and check that it is inserted
|
|
if (!interface->startup()) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
if (!interface->isInserted()) {
|
|
errno = EIO;
|
|
return 0;
|
|
}
|
|
|
|
struct ext2_super_block * super = (struct ext2_super_block *) malloc(SUPERBLOCK_SIZE); //1024 bytes
|
|
if(!super)
|
|
{
|
|
ext2_log_trace("no memory for superblock");
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
partitions = (sec_t *) malloc(sizeof(sec_t));
|
|
if(!partitions)
|
|
{
|
|
ext2_log_trace("no memory for partitions");
|
|
errno = ENOMEM;
|
|
mem_free(super);
|
|
return -1;
|
|
}
|
|
// Read the first sector on the device
|
|
if (!interface->readSectors(0, 1, §or.buffer)) {
|
|
errno = EIO;
|
|
mem_free(partitions);
|
|
mem_free(super);
|
|
return -1;
|
|
}
|
|
|
|
// If this is the devices master boot record
|
|
if (sector.mbr.signature == MBR_SIGNATURE)
|
|
{
|
|
memcpy(&mbr, §or, sizeof(MASTER_BOOT_RECORD));
|
|
|
|
// Search the partition table for all EXT2/3/4 partitions (max. 4 primary partitions)
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
partition = &mbr.partitions[i];
|
|
part_lba = ext2fs_le32_to_cpu(mbr.partitions[i].lba_start);
|
|
|
|
// Figure out what type of partition this is
|
|
switch (partition->type)
|
|
{
|
|
// Ignore empty partitions
|
|
case PARTITION_TYPE_EMPTY:
|
|
continue;
|
|
|
|
// EXT2/3/4 partition
|
|
case PARTITION_TYPE_LINUX:
|
|
|
|
// Read and validate the EXT partition
|
|
if (interface->readSectors(part_lba+SUPERBLOCK_OFFSET/BYTES_PER_SECTOR, SUPERBLOCK_SIZE/BYTES_PER_SECTOR, super))
|
|
{
|
|
if (ext2fs_le16_to_cpu(super->s_magic) == EXT2_SUPER_MAGIC)
|
|
{
|
|
partition_count++;
|
|
sec_t * tmp = (sec_t *) realloc(partitions, partition_count*sizeof(sec_t));
|
|
if(!tmp) goto cleanup;
|
|
partitions = tmp;
|
|
partitions[partition_count-1] = part_lba;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
// DOS 3.3+ or Windows 95 extended partition
|
|
case PARTITION_TYPE_DOS33_EXTENDED:
|
|
case PARTITION_TYPE_WIN95_EXTENDED:
|
|
{
|
|
ext2_log_trace("Partition %i: Claims to be Extended\n", i + 1);
|
|
|
|
// Walk the extended partition chain, finding all EXT partitions within it
|
|
sec_t ebr_lba = part_lba;
|
|
sec_t next_erb_lba = 0;
|
|
do {
|
|
// Read and validate the extended boot record
|
|
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or))
|
|
{
|
|
if (sector.ebr.signature == EBR_SIGNATURE)
|
|
{
|
|
ext2_log_trace("Logical Partition @ %d: %s type 0x%x\n", ebr_lba + next_erb_lba,
|
|
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
|
sector.ebr.partition.type);
|
|
|
|
// Get the start sector of the current partition
|
|
// and the next extended boot record in the chain
|
|
part_lba = ebr_lba + next_erb_lba + ext2fs_le32_to_cpu(sector.ebr.partition.lba_start);
|
|
next_erb_lba = ext2fs_le32_to_cpu(sector.ebr.next_ebr.lba_start);
|
|
|
|
// Check if this partition has a valid EXT boot record
|
|
if (interface->readSectors(part_lba+SUPERBLOCK_OFFSET/BYTES_PER_SECTOR, SUPERBLOCK_SIZE/BYTES_PER_SECTOR, super))
|
|
{
|
|
if (ext2fs_le16_to_cpu(super->s_magic) == EXT2_SUPER_MAGIC)
|
|
{
|
|
partition_count++;
|
|
sec_t * tmp = (sec_t *) realloc(partitions, partition_count*sizeof(sec_t));
|
|
if(!tmp) goto cleanup;
|
|
partitions = tmp;
|
|
partitions[partition_count-1] = part_lba;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
next_erb_lba = 0;
|
|
}
|
|
|
|
} while (next_erb_lba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Unknown or unsupported partition type
|
|
default:
|
|
{
|
|
// Check if this partition has a valid EXT boot record anyway,
|
|
// it might be misrepresented due to a lazy partition editor
|
|
if (interface->readSectors(part_lba+SUPERBLOCK_OFFSET/BYTES_PER_SECTOR, SUPERBLOCK_SIZE/BYTES_PER_SECTOR, super))
|
|
{
|
|
if (ext2fs_le16_to_cpu(super->s_magic) == EXT2_SUPER_MAGIC)
|
|
{
|
|
partition_count++;
|
|
sec_t * tmp = (sec_t *) realloc(partitions, partition_count*sizeof(sec_t));
|
|
if(!tmp) goto cleanup;
|
|
partitions = tmp;
|
|
partitions[partition_count-1] = part_lba;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Else it is assumed this device has no master boot record
|
|
}
|
|
else
|
|
{
|
|
ext2_log_trace("No Master Boot Record was found!\n");
|
|
|
|
// As a last-ditched effort, search the first 64 sectors of the device for stray EXT partitions
|
|
for (i = 1; i < 64; i++)
|
|
{
|
|
if (interface->readSectors(i+SUPERBLOCK_OFFSET/BYTES_PER_SECTOR, SUPERBLOCK_SIZE/BYTES_PER_SECTOR, super))
|
|
{
|
|
if (ext2fs_le16_to_cpu(super->s_magic) == EXT2_SUPER_MAGIC)
|
|
{
|
|
partition_count++;
|
|
sec_t * tmp = (sec_t *) realloc(partitions, partition_count*sizeof(sec_t));
|
|
if(!tmp) goto cleanup;
|
|
partitions = tmp;
|
|
partitions[partition_count-1] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Return the found partitions (if any)
|
|
if (partition_count > 0)
|
|
{
|
|
*out_partitions = partitions;
|
|
ret = partition_count;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if(partitions && partition_count == 0)
|
|
mem_free(partitions);
|
|
if(super)
|
|
mem_free(super);
|
|
|
|
return ret;
|
|
}
|
|
|