nkeynes@1107 | 1 | /**
|
nkeynes@1107 | 2 | * $Id$
|
nkeynes@1107 | 3 | *
|
nkeynes@1107 | 4 | * libisofs adapter
|
nkeynes@1107 | 5 | *
|
nkeynes@1107 | 6 | * Copyright (c) 2010 Nathan Keynes.
|
nkeynes@1107 | 7 | *
|
nkeynes@1107 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@1107 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@1107 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@1107 | 11 | * (at your option) any later version.
|
nkeynes@1107 | 12 | *
|
nkeynes@1107 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@1107 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@1107 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@1107 | 16 | * GNU General Public License for more details.
|
nkeynes@1107 | 17 | */
|
nkeynes@1107 | 18 |
|
nkeynes@1107 | 19 | #include <assert.h>
|
nkeynes@1108 | 20 | #include <stdio.h>
|
nkeynes@1108 | 21 | #include <unistd.h>
|
nkeynes@1296 | 22 | #include <glib.h>
|
nkeynes@1107 | 23 |
|
nkeynes@1107 | 24 | #define LIBISOFS_WITHOUT_LIBBURN 1
|
nkeynes@1107 | 25 |
|
nkeynes@1107 | 26 | #include "drivers/cdrom/cdrom.h"
|
nkeynes@1107 | 27 | #include "drivers/cdrom/isofs.h"
|
nkeynes@1107 | 28 |
|
nkeynes@1107 | 29 | static int isofs_dummy_fn(IsoDataSource *src)
|
nkeynes@1107 | 30 | {
|
nkeynes@1107 | 31 | return 1;
|
nkeynes@1107 | 32 | }
|
nkeynes@1107 | 33 |
|
nkeynes@1107 | 34 | static int isofs_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
|
nkeynes@1107 | 35 | {
|
nkeynes@1107 | 36 | sector_source_t source = (sector_source_t)src->data;
|
nkeynes@1107 | 37 | cdrom_error_t err = sector_source_read_sectors(source, lba, 1,
|
nkeynes@1107 | 38 | CDROM_READ_MODE2_FORM1|CDROM_READ_DATA, buffer, NULL );
|
nkeynes@1107 | 39 | if( err != CDROM_ERROR_OK ) {
|
nkeynes@1107 | 40 | return ISO_DATA_SOURCE_FAILURE;
|
nkeynes@1107 | 41 | }
|
nkeynes@1107 | 42 | return 1;
|
nkeynes@1107 | 43 | }
|
nkeynes@1107 | 44 |
|
nkeynes@1107 | 45 | static void isofs_release(IsoDataSource *src)
|
nkeynes@1107 | 46 | {
|
nkeynes@1107 | 47 | sector_source_unref((sector_source_t)src->data);
|
nkeynes@1107 | 48 | }
|
nkeynes@1107 | 49 |
|
nkeynes@1107 | 50 | static IsoDataSource *iso_data_source_new( sector_source_t source )
|
nkeynes@1107 | 51 | {
|
nkeynes@1107 | 52 | IsoDataSource *src = g_malloc0(sizeof(IsoDataSource));
|
nkeynes@1107 | 53 | src->refcount = 1;
|
nkeynes@1107 | 54 | src->open = isofs_dummy_fn;
|
nkeynes@1107 | 55 | src->close = isofs_dummy_fn;
|
nkeynes@1107 | 56 | src->read_block = isofs_read_block;
|
nkeynes@1107 | 57 | src->free_data = isofs_release;
|
nkeynes@1107 | 58 | src->data = source;
|
nkeynes@1107 | 59 | sector_source_ref(source);
|
nkeynes@1107 | 60 | return src;
|
nkeynes@1107 | 61 | }
|
nkeynes@1107 | 62 |
|
nkeynes@1109 | 63 | static void iso_error_convert( int status, ERROR *err )
|
nkeynes@1109 | 64 | {
|
nkeynes@1109 | 65 | switch( status ) {
|
nkeynes@1109 | 66 | case ISO_SUCCESS:
|
nkeynes@1109 | 67 | err->code = LX_ERR_NONE;
|
nkeynes@1109 | 68 | break;
|
nkeynes@1109 | 69 | case ISO_OUT_OF_MEM:
|
nkeynes@1109 | 70 | SET_ERROR( err, LX_ERR_NOMEM, "Unable to allocate memory for ISO filesystem" );
|
nkeynes@1109 | 71 | break;
|
nkeynes@1109 | 72 | case ISO_FILE_READ_ERROR:
|
nkeynes@1109 | 73 | SET_ERROR( err, LX_ERR_FILE_IOERROR, "Read error" );
|
nkeynes@1109 | 74 | break;
|
nkeynes@1109 | 75 | default:
|
nkeynes@1109 | 76 | SET_ERROR( err, LX_ERR_UNHANDLED, "Unknown error in ISO filesystem" );
|
nkeynes@1109 | 77 | break;
|
nkeynes@1109 | 78 | }
|
nkeynes@1109 | 79 | }
|
nkeynes@1109 | 80 |
|
nkeynes@1107 | 81 | /**
|
nkeynes@1107 | 82 | * Construct an isofs image from an existing sector source.
|
nkeynes@1107 | 83 | */
|
nkeynes@1107 | 84 | IsoImage *iso_image_new_from_source( sector_source_t source, cdrom_lba_t start, ERROR *err )
|
nkeynes@1107 | 85 | {
|
nkeynes@1107 | 86 | IsoImage *iso = NULL;
|
nkeynes@1107 | 87 | IsoReadOpts *opts;
|
nkeynes@1107 | 88 | IsoDataSource *src;
|
nkeynes@1107 | 89 |
|
nkeynes@1107 | 90 | int status = iso_image_new(NULL, &iso);
|
nkeynes@1107 | 91 | if( status != 1 )
|
nkeynes@1107 | 92 | return NULL;
|
nkeynes@1107 | 93 |
|
nkeynes@1107 | 94 | status = iso_read_opts_new(&opts,0);
|
nkeynes@1107 | 95 | if( status != 1 ) {
|
nkeynes@1107 | 96 | iso_image_unref( iso );
|
nkeynes@1107 | 97 | return NULL;
|
nkeynes@1107 | 98 | }
|
nkeynes@1107 | 99 |
|
nkeynes@1107 | 100 | iso_read_opts_set_start_block(opts, start);
|
nkeynes@1107 | 101 | src = iso_data_source_new(source);
|
nkeynes@1107 | 102 | status = iso_image_import(iso, src, opts, NULL);
|
nkeynes@1107 | 103 | iso_data_source_unref(src);
|
nkeynes@1107 | 104 | iso_read_opts_free(opts);
|
nkeynes@1107 | 105 | if( status != 1 ) {
|
nkeynes@1107 | 106 | iso_image_unref(iso);
|
nkeynes@1107 | 107 | return NULL;
|
nkeynes@1107 | 108 | }
|
nkeynes@1107 | 109 | return iso;
|
nkeynes@1107 | 110 | }
|
nkeynes@1107 | 111 |
|
nkeynes@1107 | 112 | IsoImage *iso_image_new_from_disc( cdrom_disc_t disc, cdrom_lba_t start_sector, ERROR *err )
|
nkeynes@1107 | 113 | {
|
nkeynes@1107 | 114 | return iso_image_new_from_source( &disc->source, start_sector, err );
|
nkeynes@1107 | 115 | }
|
nkeynes@1107 | 116 |
|
nkeynes@1107 | 117 | IsoImage *iso_image_new_from_track( cdrom_disc_t disc, cdrom_track_t track, ERROR *err )
|
nkeynes@1107 | 118 | {
|
nkeynes@1107 | 119 | return iso_image_new_from_source( &disc->source, track->lba, err );
|
nkeynes@1107 | 120 | }
|
nkeynes@1107 | 121 |
|
nkeynes@1107 | 122 |
|
nkeynes@1107 | 123 | IsoImageFilesystem *iso_filesystem_new_from_source( sector_source_t source, cdrom_lba_t start, ERROR *err )
|
nkeynes@1107 | 124 | {
|
nkeynes@1107 | 125 | IsoImageFilesystem *iso = NULL;
|
nkeynes@1107 | 126 | IsoReadOpts *opts;
|
nkeynes@1107 | 127 | IsoDataSource *src;
|
nkeynes@1107 | 128 |
|
nkeynes@1107 | 129 | int status = iso_read_opts_new(&opts,0);
|
nkeynes@1107 | 130 | if( status != 1 ) {
|
nkeynes@1109 | 131 | iso_error_convert(status, err);
|
nkeynes@1107 | 132 | return NULL;
|
nkeynes@1107 | 133 | }
|
nkeynes@1107 | 134 |
|
nkeynes@1107 | 135 | iso_read_opts_set_start_block(opts, start);
|
nkeynes@1107 | 136 | src = iso_data_source_new(source);
|
nkeynes@1107 | 137 | status = iso_image_filesystem_new(src, opts, 0x1FFFFF, &iso);
|
nkeynes@1107 | 138 | iso_data_source_unref(src);
|
nkeynes@1107 | 139 | iso_read_opts_free(opts);
|
nkeynes@1107 | 140 | if( status != 1 ) {
|
nkeynes@1109 | 141 | iso_error_convert(status, err);
|
nkeynes@1107 | 142 | return NULL;
|
nkeynes@1107 | 143 | }
|
nkeynes@1107 | 144 | return iso;
|
nkeynes@1107 | 145 |
|
nkeynes@1107 | 146 | }
|
nkeynes@1107 | 147 |
|
nkeynes@1107 | 148 | IsoImageFilesystem *iso_filesystem_new_from_disc( cdrom_disc_t disc, cdrom_lba_t start_sector, ERROR *err )
|
nkeynes@1107 | 149 | {
|
nkeynes@1107 | 150 | return iso_filesystem_new_from_source( &disc->source, start_sector, err );
|
nkeynes@1107 | 151 | }
|
nkeynes@1107 | 152 |
|
nkeynes@1107 | 153 | IsoImageFilesystem *iso_filesystem_new_from_track( cdrom_disc_t disc, cdrom_track_t track, ERROR *err )
|
nkeynes@1107 | 154 | {
|
nkeynes@1107 | 155 | return iso_filesystem_new_from_source( &disc->source, track->lba, err );
|
nkeynes@1107 | 156 | }
|
nkeynes@1107 | 157 |
|
nkeynes@1107 | 158 |
|
nkeynes@1107 | 159 | /**
|
nkeynes@1107 | 160 | * Construct a sector source from a given IsoImage.
|
nkeynes@1107 | 161 | */
|
nkeynes@1107 | 162 | sector_source_t iso_sector_source_new( IsoImage *image, sector_mode_t mode, cdrom_lba_t start_sector,
|
nkeynes@1107 | 163 | const char *bootstrap, ERROR *err )
|
nkeynes@1107 | 164 | {
|
nkeynes@1107 | 165 | assert( mode == SECTOR_MODE1 || mode == SECTOR_MODE2_FORM1 );
|
nkeynes@1107 | 166 |
|
nkeynes@1107 | 167 | IsoWriteOpts *opts;
|
nkeynes@1107 | 168 | struct burn_source *burn;
|
nkeynes@1107 | 169 |
|
nkeynes@1107 | 170 | int status = iso_write_opts_new(&opts, 0);
|
nkeynes@1109 | 171 | if( status != 1 ) {
|
nkeynes@1109 | 172 | iso_error_convert(status, err);
|
nkeynes@1107 | 173 | return NULL;
|
nkeynes@1109 | 174 | }
|
nkeynes@1107 | 175 | iso_write_opts_set_appendable(opts,0);
|
nkeynes@1107 | 176 | iso_write_opts_set_ms_block(opts, start_sector);
|
nkeynes@1107 | 177 |
|
nkeynes@1107 | 178 | status = iso_image_create_burn_source(image, opts, &burn);
|
nkeynes@1107 | 179 | iso_write_opts_free(opts);
|
nkeynes@1107 | 180 | if( status != 1 ) {
|
nkeynes@1109 | 181 | iso_error_convert(status, err);
|
nkeynes@1107 | 182 | return NULL;
|
nkeynes@1107 | 183 | }
|
nkeynes@1107 | 184 |
|
nkeynes@1107 | 185 | off_t size = burn->get_size(burn);
|
nkeynes@1107 | 186 | sector_source_t source = tmpfile_sector_source_new(mode);
|
nkeynes@1107 | 187 | if( source == NULL ) {
|
nkeynes@1107 | 188 | burn->free_data(burn);
|
nkeynes@1107 | 189 | free(burn);
|
nkeynes@1107 | 190 | return NULL;
|
nkeynes@1107 | 191 | }
|
nkeynes@1107 | 192 |
|
nkeynes@1298 | 193 | unsigned char buf[2048];
|
nkeynes@1107 | 194 | cdrom_count_t expect = size/2048;
|
nkeynes@1108 | 195 | int fd = file_sector_source_get_fd(source);
|
nkeynes@1108 | 196 | source->size = expect;
|
nkeynes@1108 | 197 | lseek( fd, 0, SEEK_SET );
|
nkeynes@1114 | 198 | write( fd, bootstrap, 32768 );
|
nkeynes@1107 | 199 | for( cdrom_count_t count = 0; count < expect; count++ ) {
|
nkeynes@1108 | 200 | if( burn->read == NULL ) {
|
nkeynes@1108 | 201 | status = burn->read_xt(burn, buf, 2048);
|
nkeynes@1108 | 202 | } else {
|
nkeynes@1108 | 203 | status = burn->read(burn, buf, 2048);
|
nkeynes@1108 | 204 | }
|
nkeynes@1107 | 205 | if( status == 0 ) {
|
nkeynes@1107 | 206 | /* EOF */
|
nkeynes@1107 | 207 | break;
|
nkeynes@1107 | 208 | } else if( status != 2048 ) {
|
nkeynes@1107 | 209 | /* Error */
|
nkeynes@1107 | 210 | sector_source_unref(source);
|
nkeynes@1107 | 211 | source = NULL;
|
nkeynes@1107 | 212 | break;
|
nkeynes@1107 | 213 | }
|
nkeynes@1114 | 214 | /* Discard first 16 sectors, replaced with the bootstrap */
|
nkeynes@1114 | 215 | if( count >= (32768/2048) )
|
nkeynes@1114 | 216 | write( fd, buf, 2048 );
|
nkeynes@1107 | 217 | }
|
nkeynes@1107 | 218 | burn->free_data(burn);
|
nkeynes@1107 | 219 | free(burn);
|
nkeynes@1107 | 220 | return source;
|
nkeynes@1107 | 221 | }
|
nkeynes@1107 | 222 |
|