Search
lxdream.org :: lxdream/src/loader.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/loader.c
changeset 1108:305ef2082079
prev1100:50e702af9373
next1109:700c5ab26a63
author nkeynes
date Fri Jun 04 09:13:40 2010 +1000 (11 years ago)
permissions -rw-r--r--
last change Add ability to wrap a binary program up in a virtual cd image (so that we
can boot it normally)
file annotate diff log raw
nkeynes@26
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@1
     3
 *
nkeynes@26
     4
 * File loading routines, mostly for loading demos without going through the
nkeynes@1108
     5
 * whole procedure of manually making a CD image for them.
nkeynes@26
     6
 *
nkeynes@26
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@26
     8
 *
nkeynes@26
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@26
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@26
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@26
    12
 * (at your option) any later version.
nkeynes@26
    13
 *
nkeynes@26
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@26
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@26
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@26
    17
 * GNU General Public License for more details.
nkeynes@1
    18
 */
nkeynes@1
    19
nkeynes@481
    20
#include <unistd.h>
nkeynes@1
    21
#include <stdio.h>
nkeynes@736
    22
#include <string.h>
nkeynes@1
    23
#include <fcntl.h>
nkeynes@1
    24
#include <sys/stat.h>
nkeynes@1
    25
#include <errno.h>
nkeynes@1
    26
#include <stdint.h>
nkeynes@1108
    27
#include <glib/gstrfuncs.h>
nkeynes@105
    28
#include <elf.h>
nkeynes@26
    29
#include "mem.h"
nkeynes@26
    30
#include "bootstrap.h"
nkeynes@171
    31
#include "dreamcast.h"
nkeynes@450
    32
#include "config.h"
nkeynes@427
    33
#include "loader.h"
nkeynes@1108
    34
#include "drivers/cdrom/cdrom.h"
nkeynes@1108
    35
#include "drivers/cdrom/isofs.h"
nkeynes@481
    36
nkeynes@1108
    37
const char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES";
nkeynes@1108
    38
const char iso_magic[6] = "\001CD001";
nkeynes@26
    39
char *file_loader_extensions[][2] = { 
nkeynes@736
    40
        { "sbi", "Self Boot Inducer" },
nkeynes@736
    41
        { "bin", "SH4 Bin file" },
nkeynes@736
    42
        { NULL, NULL } };
nkeynes@26
    43
nkeynes@1108
    44
gboolean file_load_elf_fd( const gchar *filename, int fd );
nkeynes@1
    45
nkeynes@1108
    46
typedef enum {
nkeynes@1108
    47
    FILE_ERROR,
nkeynes@1108
    48
    FILE_BINARY,
nkeynes@1108
    49
    FILE_ELF,
nkeynes@1108
    50
    FILE_ISO,
nkeynes@1108
    51
    FILE_DISC,
nkeynes@1108
    52
    FILE_ZIP,
nkeynes@1108
    53
    FILE_SAVE_STATE,
nkeynes@1108
    54
} lxdream_file_type_t;
nkeynes@1108
    55
nkeynes@1108
    56
static lxdream_file_type_t file_magic( const gchar *filename, int fd, ERROR *err )
nkeynes@1108
    57
{
nkeynes@1108
    58
    char buf[32];
nkeynes@1108
    59
nkeynes@1108
    60
    /* begin magic */
nkeynes@1108
    61
    if( read( fd, buf, 32 ) != 32 ) {
nkeynes@1108
    62
        SET_ERROR( err, errno, "Unable to read from file '%s'", filename );
nkeynes@1108
    63
        return FILE_ERROR;
nkeynes@1108
    64
nkeynes@1108
    65
    }
nkeynes@1108
    66
nkeynes@1108
    67
    lseek( fd, 0, SEEK_SET );
nkeynes@1108
    68
    if( buf[0] == 0x7F && buf[1] == 'E' &&
nkeynes@1108
    69
            buf[2] == 'L' && buf[3] == 'F' ) {
nkeynes@1108
    70
        return FILE_ELF;
nkeynes@1108
    71
    } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) {
nkeynes@1108
    72
        return FILE_ZIP;
nkeynes@1108
    73
    } else if( memcmp( buf, DREAMCAST_SAVE_MAGIC, 16 ) == 0 ) {
nkeynes@1108
    74
        return FILE_SAVE_STATE;
nkeynes@1108
    75
    } else if( lseek( fd, 32768, SEEK_SET ) == 32768 &&
nkeynes@1108
    76
            read( fd, buf, 8 ) == 8 &&
nkeynes@1108
    77
            memcmp( buf, iso_magic, 6) == 0 ) {
nkeynes@1108
    78
        lseek( fd, 0, SEEK_SET );
nkeynes@1108
    79
        return FILE_ISO;
nkeynes@1108
    80
    }
nkeynes@1108
    81
    lseek( fd, 0, SEEK_SET );
nkeynes@1108
    82
    return FILE_BINARY;
nkeynes@1108
    83
}
nkeynes@427
    84
nkeynes@427
    85
nkeynes@26
    86
gboolean file_load_magic( const gchar *filename )
nkeynes@1
    87
{
nkeynes@1
    88
    char buf[32];
nkeynes@1
    89
    struct stat st;
nkeynes@446
    90
    gboolean result = TRUE;
nkeynes@736
    91
nkeynes@1
    92
    int fd = open( filename, O_RDONLY );
nkeynes@1
    93
    if( fd == -1 ) {
nkeynes@26
    94
        return FALSE;
nkeynes@1
    95
    }
nkeynes@736
    96
nkeynes@1
    97
    fstat( fd, &st );
nkeynes@736
    98
nkeynes@1
    99
    /* begin magic */
nkeynes@1
   100
    if( read( fd, buf, 32 ) != 32 ) {
nkeynes@1
   101
        ERROR( "Unable to read from file '%s'", filename );
nkeynes@1
   102
        close(fd);
nkeynes@26
   103
        return FALSE;
nkeynes@1
   104
    }
nkeynes@26
   105
    if( memcmp( buf, bootstrap_magic, 32 ) == 0 ) {
nkeynes@1
   106
        /* we have a DC bootstrap */
nkeynes@1
   107
        if( st.st_size == BOOTSTRAP_SIZE ) {
nkeynes@502
   108
            sh4ptr_t load = mem_get_region( BOOTSTRAP_LOAD_ADDR );
nkeynes@1
   109
            lseek( fd, 0, SEEK_SET );
nkeynes@1
   110
            read( fd, load, BOOTSTRAP_SIZE );
nkeynes@171
   111
            bootstrap_dump( load, TRUE );
nkeynes@736
   112
            dreamcast_program_loaded( filename, BOOTSTRAP_LOAD_ADDR + 0x300 );
nkeynes@1
   113
        } else {
nkeynes@1
   114
            /* look for a valid ISO9660 header */
nkeynes@1
   115
            lseek( fd, 32768, SEEK_SET );
nkeynes@1
   116
            read( fd, buf, 8 );
nkeynes@1
   117
            if( memcmp( buf, iso_magic, 6 ) == 0 ) {
nkeynes@1
   118
                /* Alright, got it */
nkeynes@1075
   119
                WARN( "ISO images not supported yet" );
nkeynes@1
   120
            }
nkeynes@1
   121
        }
nkeynes@26
   122
    } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) {
nkeynes@736
   123
        /* ZIP file, aka SBI file */
nkeynes@736
   124
        WARN( "SBI files not supported yet" );
nkeynes@736
   125
        result = FALSE;
nkeynes@294
   126
    } else if( memcmp( buf, DREAMCAST_SAVE_MAGIC, 16 ) == 0 ) {
nkeynes@736
   127
        /* Save state */
nkeynes@736
   128
        result = (dreamcast_load_state( filename )==0);
nkeynes@105
   129
    } else if( buf[0] == 0x7F && buf[1] == 'E' && 
nkeynes@736
   130
            buf[2] == 'L' && buf[3] == 'F' ) {
nkeynes@736
   131
        /* ELF binary */
nkeynes@736
   132
        lseek( fd, 0, SEEK_SET );
nkeynes@736
   133
        result = file_load_elf_fd( filename, fd );
nkeynes@1
   134
    } else {
nkeynes@736
   135
        result = FALSE;
nkeynes@446
   136
    }
nkeynes@1
   137
    close(fd);
nkeynes@446
   138
    return result;
nkeynes@1
   139
}
nkeynes@19
   140
nkeynes@543
   141
void file_load_postload( const gchar *filename, int pc )
nkeynes@110
   142
{
nkeynes@1036
   143
    gchar *bootstrap_file = lxdream_get_global_config_path_value(CONFIG_BOOTSTRAP);
nkeynes@825
   144
    if( bootstrap_file != NULL && bootstrap_file[0] != '\0' ) {
nkeynes@736
   145
        /* Load in a bootstrap before the binary, to initialize everything
nkeynes@736
   146
         * correctly
nkeynes@736
   147
         */
nkeynes@543
   148
        if( mem_load_block( bootstrap_file, BOOTSTRAP_LOAD_ADDR, BOOTSTRAP_SIZE ) == 0 ) {
nkeynes@1100
   149
            dreamcast_program_loaded( filename, BOOTSTRAP_ENTRY_ADDR );
nkeynes@1036
   150
            g_free(bootstrap_file);
nkeynes@736
   151
            return;
nkeynes@736
   152
        }
nkeynes@88
   153
    }
nkeynes@543
   154
    dreamcast_program_loaded( filename, pc );
nkeynes@1036
   155
    g_free(bootstrap_file);
nkeynes@110
   156
}    
nkeynes@110
   157
nkeynes@110
   158
nkeynes@427
   159
gboolean file_load_binary( const gchar *filename )
nkeynes@110
   160
{
nkeynes@110
   161
    /* Load the binary itself */
nkeynes@427
   162
    if(  mem_load_block( filename, BINARY_LOAD_ADDR, -1 ) == 0 ) {
nkeynes@736
   163
        file_load_postload( filename, BINARY_LOAD_ADDR );
nkeynes@736
   164
        return TRUE;
nkeynes@427
   165
    } else {
nkeynes@736
   166
        return FALSE;
nkeynes@427
   167
    }
nkeynes@19
   168
}
nkeynes@105
   169
nkeynes@1108
   170
gboolean is_sh4_elf( Elf32_Ehdr *head )
nkeynes@1108
   171
{
nkeynes@1108
   172
    return ( head->e_ident[EI_CLASS] == ELFCLASS32 &&
nkeynes@1108
   173
            head->e_ident[EI_DATA] == ELFDATA2LSB &&
nkeynes@1108
   174
            head->e_ident[EI_VERSION] == 1 &&
nkeynes@1108
   175
            head->e_type == ET_EXEC &&
nkeynes@1108
   176
            head->e_machine == EM_SH &&
nkeynes@1108
   177
            head->e_version == 1 );
nkeynes@1108
   178
}
nkeynes@1108
   179
nkeynes@1108
   180
gboolean is_arm_elf( Elf32_Ehdr *head )
nkeynes@1108
   181
{
nkeynes@1108
   182
    return ( head->e_ident[EI_CLASS] == ELFCLASS32 &&
nkeynes@1108
   183
            head->e_ident[EI_DATA] == ELFDATA2LSB &&
nkeynes@1108
   184
            head->e_ident[EI_VERSION] == 1 &&
nkeynes@1108
   185
            head->e_type == ET_EXEC &&
nkeynes@1108
   186
            head->e_machine == EM_ARM &&
nkeynes@1108
   187
            head->e_version == 1 );
nkeynes@1108
   188
}
nkeynes@1108
   189
nkeynes@543
   190
gboolean file_load_elf_fd( const gchar *filename, int fd ) 
nkeynes@105
   191
{
nkeynes@105
   192
    Elf32_Ehdr head;
nkeynes@105
   193
    Elf32_Phdr phdr;
nkeynes@105
   194
    int i;
nkeynes@105
   195
nkeynes@105
   196
    if( read( fd, &head, sizeof(head) ) != sizeof(head) )
nkeynes@736
   197
        return FALSE;
nkeynes@1108
   198
    if( !is_sh4_elf(&head) ) {
nkeynes@736
   199
        ERROR( "File is not an SH4 ELF executable file" );
nkeynes@736
   200
        return FALSE;
nkeynes@105
   201
    }
nkeynes@105
   202
nkeynes@105
   203
    /* Program headers */
nkeynes@105
   204
    for( i=0; i<head.e_phnum; i++ ) {
nkeynes@736
   205
        lseek( fd, head.e_phoff + i*head.e_phentsize, SEEK_SET );
nkeynes@736
   206
        read( fd, &phdr, sizeof(phdr) );
nkeynes@736
   207
        if( phdr.p_type == PT_LOAD ) {
nkeynes@736
   208
            lseek( fd, phdr.p_offset, SEEK_SET );
nkeynes@736
   209
            sh4ptr_t target = mem_get_region( phdr.p_vaddr );
nkeynes@736
   210
            read( fd, target, phdr.p_filesz );
nkeynes@736
   211
            if( phdr.p_memsz > phdr.p_filesz ) {
nkeynes@736
   212
                memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz );
nkeynes@736
   213
            }
nkeynes@736
   214
            INFO( "Loaded %d bytes to %08X", phdr.p_filesz, phdr.p_vaddr );
nkeynes@736
   215
        }
nkeynes@105
   216
    }
nkeynes@736
   217
nkeynes@543
   218
    file_load_postload( filename, head.e_entry );
nkeynes@446
   219
    return TRUE;
nkeynes@105
   220
}
nkeynes@1108
   221
nkeynes@1108
   222
/**
nkeynes@1108
   223
 * Create a new CDROM disc containing a single 1ST_READ.BIN.
nkeynes@1108
   224
 * @param type The disc type - must be CDROM_DISC_GDROM or CDROM_DISC_XA
nkeynes@1108
   225
 * @param bin The binary data (takes ownership)
nkeynes@1108
   226
 * @param bin_size
nkeynes@1108
   227
 */
nkeynes@1108
   228
cdrom_disc_t cdrom_disc_new_wrapped_binary( cdrom_disc_type_t type, const gchar *filename, unsigned char *bin, size_t bin_size,
nkeynes@1108
   229
                                            ERROR *err )
nkeynes@1108
   230
{
nkeynes@1108
   231
    IsoImage *iso = NULL;
nkeynes@1108
   232
    unsigned char *data = bin;
nkeynes@1108
   233
    cdrom_lba_t start_lba = 45000; /* GDROM_START */
nkeynes@1108
   234
    char bootstrap[32768];
nkeynes@1108
   235
nkeynes@1108
   236
    /* 1. Load in the bootstrap */
nkeynes@1108
   237
    gchar *bootstrap_file = lxdream_get_global_config_path_value(CONFIG_BOOTSTRAP);
nkeynes@1108
   238
    if( bootstrap_file == NULL || bootstrap_file[0] == '\0' ) {
nkeynes@1108
   239
        g_free(data);
nkeynes@1108
   240
        SET_ERROR( err, ENOENT, "Unable to create CD image: bootstrap file is not configured" );
nkeynes@1108
   241
        return NULL;
nkeynes@1108
   242
    }
nkeynes@1108
   243
nkeynes@1108
   244
    FILE *f = fopen( bootstrap_file, "ro" );
nkeynes@1108
   245
    if( f == NULL ) {
nkeynes@1108
   246
        g_free(data);
nkeynes@1108
   247
        SET_ERROR( err, errno, "Unable to create CD image: bootstrap file '%s' could not be opened", bootstrap_file );
nkeynes@1108
   248
        return FALSE;
nkeynes@1108
   249
    }
nkeynes@1108
   250
    size_t len = fread( bootstrap, 1, 32768, f );
nkeynes@1108
   251
    fclose(f);
nkeynes@1108
   252
    if( len != 32768 ) {
nkeynes@1108
   253
        g_free(data);
nkeynes@1108
   254
        SET_ERROR( err, EINVAL, "Unable to create CD image: bootstrap file '%s' is invalid", bootstrap_file );
nkeynes@1108
   255
        return FALSE;
nkeynes@1108
   256
    }
nkeynes@1108
   257
nkeynes@1108
   258
    /* 2. Scramble the binary if necessary (and set type settings) */
nkeynes@1108
   259
    if( type != CDROM_DISC_GDROM ) {
nkeynes@1108
   260
        /* scramble the binary if we're going the MIL-CD route */
nkeynes@1108
   261
        unsigned char *scramblebin = g_malloc(bin_size);
nkeynes@1108
   262
        bootprogram_scramble( scramblebin, bin, bin_size );
nkeynes@1108
   263
        data = scramblebin;
nkeynes@1108
   264
        start_lba = 0x2DB6; /* CDROM_START (does it matter?) */
nkeynes@1108
   265
        g_free(bin);
nkeynes@1108
   266
    }
nkeynes@1108
   267
nkeynes@1108
   268
    /* 3. Frob the bootstrap data */
nkeynes@1108
   269
    dc_bootstrap_head_t boot_header = (dc_bootstrap_head_t)bootstrap;
nkeynes@1108
   270
    memcpy( boot_header->boot_file, "1ST_READ.BIN    ", 16 );
nkeynes@1108
   271
    char tmp[129];
nkeynes@1108
   272
    int name_len = snprintf( tmp, 129, "lxdream wrapped image: %s", filename );
nkeynes@1108
   273
    if( name_len < 128 )
nkeynes@1108
   274
        memset( tmp+name_len, ' ', 128-name_len );
nkeynes@1108
   275
    memcpy( boot_header->product_name, tmp, 128 );
nkeynes@1108
   276
//    bootstrap_update_crc(bootstrap);
nkeynes@1108
   277
nkeynes@1108
   278
nkeynes@1108
   279
    /* 4. Build the ISO image */
nkeynes@1108
   280
    int status = iso_image_new("autocd", &iso);
nkeynes@1108
   281
    if( status != 1 ) {
nkeynes@1108
   282
        g_free(data);
nkeynes@1108
   283
        return NULL;
nkeynes@1108
   284
    }
nkeynes@1108
   285
nkeynes@1108
   286
    IsoStream *stream;
nkeynes@1108
   287
    if( iso_memory_stream_new(data, bin_size, &stream) != 1 ) {
nkeynes@1108
   288
        g_free(data);
nkeynes@1108
   289
        iso_image_unref(iso);
nkeynes@1108
   290
        return NULL;
nkeynes@1108
   291
    }
nkeynes@1108
   292
    iso_tree_add_new_file(iso_image_get_root(iso), "1ST_READ.BIN", stream, NULL);
nkeynes@1108
   293
    sector_source_t track = iso_sector_source_new( iso, SECTOR_MODE2_FORM1, start_lba,
nkeynes@1108
   294
            bootstrap, err );
nkeynes@1108
   295
    if( track == NULL ) {
nkeynes@1108
   296
        iso_image_unref(iso);
nkeynes@1108
   297
        return NULL;
nkeynes@1108
   298
    }
nkeynes@1108
   299
nkeynes@1108
   300
    cdrom_disc_t disc = cdrom_disc_new_from_track( type, track, start_lba );
nkeynes@1108
   301
    iso_image_unref(iso);
nkeynes@1108
   302
    if( disc != NULL ) {
nkeynes@1108
   303
        disc->name = g_strdup(filename);
nkeynes@1108
   304
    }
nkeynes@1108
   305
    return disc;
nkeynes@1108
   306
}
nkeynes@1108
   307
nkeynes@1108
   308
cdrom_disc_t cdrom_wrap_elf_fd( cdrom_disc_type_t type, const gchar *filename, int fd, ERROR *err )
nkeynes@1108
   309
{
nkeynes@1108
   310
    Elf32_Ehdr head;
nkeynes@1108
   311
    int i;
nkeynes@1108
   312
nkeynes@1108
   313
    /* Check the file header is actually an SH4 binary */
nkeynes@1108
   314
    if( read( fd, &head, sizeof(head) ) != sizeof(head) )
nkeynes@1108
   315
        return FALSE;
nkeynes@1108
   316
    if( !is_sh4_elf(&head) ) {
nkeynes@1108
   317
        SET_ERROR( err, EINVAL, "File is not an SH4 ELF executable file" );
nkeynes@1108
   318
        return FALSE;
nkeynes@1108
   319
    }
nkeynes@1108
   320
    if( head.e_entry != BINARY_LOAD_ADDR ) {
nkeynes@1108
   321
        SET_ERROR( err, EINVAL, "SH4 Binary has incorrect entry point (should be %08X but is %08X)", BINARY_LOAD_ADDR, head.e_entry );
nkeynes@1108
   322
        return FALSE;
nkeynes@1108
   323
    }
nkeynes@1108
   324
nkeynes@1108
   325
    /* Load the program headers */
nkeynes@1108
   326
    Elf32_Phdr phdr[head.e_phnum];
nkeynes@1108
   327
    lseek( fd, head.e_phoff, SEEK_SET );
nkeynes@1108
   328
    if( read( fd, phdr, sizeof(phdr) ) != sizeof(phdr) ) {
nkeynes@1108
   329
        SET_ERROR( err, EINVAL, "File is not a valid executable file" );
nkeynes@1108
   330
        return FALSE;
nkeynes@1108
   331
    }
nkeynes@1108
   332
nkeynes@1108
   333
    sh4addr_t start = (sh4addr_t)-1, end=0;
nkeynes@1108
   334
    /* Scan program headers for memory range in use */
nkeynes@1108
   335
    for( i=0; i<head.e_phnum; i++ ) {
nkeynes@1108
   336
        if( phdr[i].p_type == PT_LOAD ) {
nkeynes@1108
   337
            if( phdr[i].p_vaddr < start )
nkeynes@1108
   338
                start = phdr[i].p_vaddr;
nkeynes@1108
   339
            if( phdr[i].p_vaddr + phdr[i].p_memsz > end )
nkeynes@1108
   340
                end = phdr[i].p_vaddr + phdr[i].p_memsz;
nkeynes@1108
   341
        }
nkeynes@1108
   342
    }
nkeynes@1108
   343
nkeynes@1108
   344
    if( start != BINARY_LOAD_ADDR ) {
nkeynes@1108
   345
        SET_ERROR( err, EINVAL, "SH4 Binary has incorrect load address (should be %08X but is %08X)", BINARY_LOAD_ADDR, start );
nkeynes@1108
   346
        return FALSE;
nkeynes@1108
   347
    }
nkeynes@1108
   348
    if( end >= 0x8D000000 ) {
nkeynes@1108
   349
        SET_ERROR( err, EINVAL, "SH4 binary is too large to fit in memory (end address is %08X)", end );
nkeynes@1108
   350
        return FALSE;
nkeynes@1108
   351
    }
nkeynes@1108
   352
nkeynes@1108
   353
    /* Load the program into memory */
nkeynes@1108
   354
    char *program = g_malloc0( end-start );
nkeynes@1108
   355
    for( i=0; i<head.e_phnum; i++ ) {
nkeynes@1108
   356
        if( phdr[i].p_type == PT_LOAD ) {
nkeynes@1108
   357
            lseek( fd, phdr[i].p_offset, SEEK_SET );
nkeynes@1108
   358
            uint32_t size = MIN( phdr[i].p_filesz, phdr[i].p_memsz);
nkeynes@1108
   359
            read( fd, program + phdr[i].p_vaddr, size );
nkeynes@1108
   360
        }
nkeynes@1108
   361
    }
nkeynes@1108
   362
nkeynes@1108
   363
    /* And finally pass it over to the disc wrapper */
nkeynes@1108
   364
    return cdrom_disc_new_wrapped_binary(type, filename, program, end-start, err );
nkeynes@1108
   365
}
nkeynes@1108
   366
nkeynes@1108
   367
cdrom_disc_t cdrom_wrap_magic( cdrom_disc_type_t type, const gchar *filename, ERROR *err )
nkeynes@1108
   368
{
nkeynes@1108
   369
    cdrom_disc_t disc;
nkeynes@1108
   370
    char *data;
nkeynes@1108
   371
    int len;
nkeynes@1108
   372
    struct stat st;
nkeynes@1108
   373
    int fd = open( filename, O_RDONLY );
nkeynes@1108
   374
    if( fd == -1 ) {
nkeynes@1108
   375
        SET_ERROR( err, errno, "Unable to open file '%s'", filename );
nkeynes@1108
   376
        return NULL;
nkeynes@1108
   377
    }
nkeynes@1108
   378
nkeynes@1108
   379
nkeynes@1108
   380
    lxdream_file_type_t filetype = file_magic( filename, fd, err );
nkeynes@1108
   381
    switch( filetype ) {
nkeynes@1108
   382
    case FILE_BINARY:
nkeynes@1108
   383
        fstat( fd, &st );
nkeynes@1108
   384
        data = g_malloc(st.st_size);
nkeynes@1108
   385
        len = read( fd, data, st.st_size );
nkeynes@1108
   386
        close(fd);
nkeynes@1108
   387
        if( len != st.st_size ) {
nkeynes@1108
   388
            SET_ERROR( err, errno, "Error reading binary file '%s'", filename );
nkeynes@1108
   389
            return NULL;
nkeynes@1108
   390
        }
nkeynes@1108
   391
        return cdrom_disc_new_wrapped_binary( type, filename, data, st.st_size, err );
nkeynes@1108
   392
    case FILE_ELF:
nkeynes@1108
   393
        disc = cdrom_wrap_elf_fd(type, filename, fd, err);
nkeynes@1108
   394
        close(fd);
nkeynes@1108
   395
        return disc;
nkeynes@1108
   396
    default:
nkeynes@1108
   397
        close(fd);
nkeynes@1108
   398
        SET_ERROR( err, EINVAL, "File '%s' cannot be wrapped (not a binary)", filename );
nkeynes@1108
   399
        return NULL;
nkeynes@1108
   400
    }
nkeynes@1108
   401
nkeynes@1108
   402
}
.