Search
lxdream.org :: lxdream/src/drivers/cdrom/sector.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/sector.c
changeset 1099:566cdeb157ec
prev1097:d4807997e450
next1107:7b279d10f46f
author nkeynes
date Wed Feb 10 18:16:19 2010 +1000 (10 years ago)
permissions -rw-r--r--
last change First draft of basic ISO9660 filesystem reader
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * low-level 'block device' for input to gdrom discs.
     5  *
     6  * Copyright (c) 2009 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include <sys/stat.h>
    20 #include <glib/gmem.h>
    21 #include <assert.h>
    22 #include <stdlib.h>
    23 #include <stdio.h>
    24 #include <string.h>
    25 #include <unistd.h>
    26 #include <fcntl.h>
    28 #include "drivers/cdrom/sector.h"
    29 #include "drivers/cdrom/cdrom.h"
    30 #include "drivers/cdrom/ecc.h"
    32 #define CHECK_READ(dev,lba,count) \
    33     if( !IS_SECTOR_SOURCE(dev) ) { \
    34         return CDROM_ERROR_NODISC; \
    35     } else if( (dev)->size != 0 && ((lba) >= (dev)->size || (lba+block_count) > (dev)->size) ) { \
    36         return CDROM_ERROR_BADREAD; \
    37     }
    39 /* Default read mode for each sector mode */
    40 const uint32_t cdrom_sector_read_mode[] = { 0,
    41         CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
    42         CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
    43         CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
    44         CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
    45         CDROM_READ_RAW, CDROM_READ_RAW };
    47 /* Block size for each sector mode */
    48 const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352 };
    50 const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
    51         "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
    54 /********************* Public functions *************************/
    55 cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
    56 {
    57     CHECK_READ(device,lba,block_count);
    58     return device->read_blocks(device, lba, block_count, buf);
    59 }
    61 cdrom_error_t sector_source_read_sectors( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
    62                                           unsigned char *buf, size_t *length )
    63 {
    64     CHECK_READ(device,lba,block_count);
    65     return device->read_sectors(device, lba, block_count, mode, buf, length);
    66 }
    68 void sector_source_ref( sector_source_t device )
    69 {
    70     assert( IS_SECTOR_SOURCE(device) );
    71     device->ref_count++;
    72 }
    74 void sector_source_unref( sector_source_t device )
    75 {
    76     if( device == NULL )
    77         return;
    78     assert( IS_SECTOR_SOURCE(device) );
    79     if( device->ref_count > 0 )
    80         device->ref_count--;
    81     if( device->ref_count == 0 )
    82         device->destroy(device);
    83 }
    85 void sector_source_release( sector_source_t device )
    86 {
    87     assert( IS_SECTOR_SOURCE(device) );
    88     if( device->ref_count == 0 )
    89         device->destroy(device);
    90 }
    92 /************************** Sector mangling ***************************/
    93 /*
    94  * Private functions used to pack/unpack sectors, determine mode, and
    95  * evaluate sector reads.
    96  */
    98 /** Basic data sector header structure */
    99 struct cdrom_sector_header {
   100     uint8_t sync[12];
   101     uint8_t msf[3];
   102     uint8_t mode;
   103     uint8_t subhead[8]; // Mode-2 XA sectors only
   104 };
   106 static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
   108 /* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
   109 static const uint8_t legal_nonxa_fields[] =
   110 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
   111   TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
   112   TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
   113   FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
   115 /* Field combinations that are legal for mode 2 form 1 or form 2 reads */
   116 static const uint8_t legal_xa_fields[] =
   117 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
   118   TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
   119   TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
   120   FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
   122 /**
   123  * Position per sector mode of each of the fields
   124  *   sync, header, subheader, data, ecc.
   125  *
   126  */
   127 static const uint32_t sector_field_positions[][6] = {
   128         { 0, 0, 0, 0, 0, 0 },    /* Unknown */
   129         { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
   130         { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
   131         { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
   132         { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
   133         { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
   137 /**
   138  * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
   139  * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
   140  * will return BADREADMODE, as it's impossible to tell.
   141  *
   142  * @param track_mode one of the CDROM_MODE* constants
   143  * @param read_mode the full read mode
   144  */
   145 static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
   146 {
   147     int read_sector_type = CDROM_READ_TYPE(read_mode);
   148     int read_sector_fields = CDROM_READ_FIELDS(read_mode);
   150     /* Check the sector type is consistent */
   151     switch( read_sector_type ) {
   152     case CDROM_READ_ANY: break;
   153     case CDROM_READ_CDDA:
   154         if( sector_mode != SECTOR_CDDA )
   155             return CDROM_ERROR_BADREADMODE;
   156         break;
   157     case CDROM_READ_MODE1:
   158     case CDROM_READ_MODE2_FORM1:
   159         if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
   160             return CDROM_ERROR_BADREADMODE;
   161         break;
   162     case CDROM_READ_MODE2_FORM2:
   163         if( sector_mode != SECTOR_MODE2_FORM2 )
   164             return CDROM_ERROR_BADREADMODE;
   165         break;
   166     case CDROM_READ_MODE2:
   167         if( sector_mode != SECTOR_MODE2_FORMLESS )
   168             return CDROM_ERROR_BADREADMODE;
   169         break;
   170     default: /* Illegal read mode */
   171         return CDROM_ERROR_BADFIELD;
   172     }
   174     /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
   175     switch( sector_mode ) {
   176     case SECTOR_CDDA:
   177         return CDROM_ERROR_OK; /* Everything is OK */
   178     case SECTOR_MODE2_FORM1:
   179     case SECTOR_MODE2_FORM2:
   180         if( !legal_xa_fields[read_sector_fields>>11] )
   181             return CDROM_ERROR_BADFIELD;
   182         else
   183             return CDROM_ERROR_OK;
   184     case SECTOR_MODE1:
   185     case SECTOR_MODE2_FORMLESS:
   186         if( !legal_nonxa_fields[read_sector_fields>>11] )
   187             return CDROM_ERROR_BADFIELD;
   188         else
   189             return CDROM_ERROR_OK;
   190     default:
   191         return CDROM_ERROR_BADFIELD;
   192     }
   193 }
   195 static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
   196 {
   197     struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
   199     switch( raw_mode ) {
   200     case SECTOR_SEMIRAW_MODE2: /* XA sectors */
   201     case SECTOR_RAW_XA:
   202         switch( header->mode ) {
   203         case 1: return SECTOR_MODE1;
   204         case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
   205         default: return SECTOR_UNKNOWN;
   206         }
   207     case SECTOR_RAW_NONXA:
   208         switch( header->mode ) {
   209         case 1: return SECTOR_MODE1;
   210         case 2: return SECTOR_MODE2_FORMLESS;
   211         default: return SECTOR_UNKNOWN;
   212         }
   213     default:
   214         return raw_mode;
   215     }
   216 }
   218 /**
   219  * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
   220  * necessary.
   221  */
   222 static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
   223 {
   224     cdrom_error_t err;
   226     switch( device->mode ) {
   227     case SECTOR_RAW_XA:
   228     case SECTOR_RAW_NONXA:
   229         return device->read_blocks(device, lba, 1, buf);
   230     case SECTOR_SEMIRAW_MODE2:
   231         memcpy( buf, cdrom_sync_data, 12 );
   232         cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
   233         return device->read_blocks(device, lba, 1, &buf[16]);
   234     case SECTOR_MODE1:
   235     case SECTOR_MODE2_FORMLESS:
   236         err = device->read_blocks(device, lba, 1, &buf[16]);
   237         if( err == CDROM_ERROR_OK ) {
   238             do_encode_L2( buf, device->mode, lba );
   239         }
   240         return err;
   241     case SECTOR_MODE2_FORM1:
   242         *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
   243         err = device->read_blocks(device, lba, 1, &buf[24]);
   244         if( err == CDROM_ERROR_OK ) {
   245             do_encode_L2( buf, device->mode, lba );
   246         }
   247         return err;
   248     case SECTOR_MODE2_FORM2:
   249         *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
   250         err = device->read_blocks(device, lba, 1, &buf[24]);
   251         if( err == CDROM_ERROR_OK ) {
   252             do_encode_L2( buf, device->mode, lba );
   253         }
   254         return err;
   255     default:
   256         abort();
   257     }
   258 }
   260 static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
   261 {
   262     int start=-1,end=0;
   263     int i;
   265     for( i=0; i<5; i++ ) {
   266         if( fields & (0x8000>>i) ) {
   267             if( start == -1 )
   268                 start = sector_field_positions[mode][i];
   269             else if( end != sector_field_positions[mode][i] )
   270                 return CDROM_ERROR_BADFIELD;
   271             end = sector_field_positions[mode][i+1];
   272         }
   273     }
   274     if( start == -1 ) {
   275         *length = 0;
   276     } else {
   277         memcpy( buf, &raw_sector[start], end-start );
   278         *length = end-start;
   279     }
   280     return CDROM_ERROR_OK;
   281 }
   283 cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
   284 {
   285     sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
   286     if( sector_mode == SECTOR_UNKNOWN )
   287         return CDROM_ERROR_BADREAD;
   288     cdrom_error_t status = is_legal_read( sector_mode, mode );
   289     if( status != CDROM_ERROR_OK )
   290         return status;
   291     return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
   292 }
   294 /**
   295  * This is horribly complicated by the need to handle mapping between all possible
   296  * sector modes + read modes, but fortunately most sources can just supply
   297  * a single block type and not care about the details here.
   298  */
   299 cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
   300         cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
   301         unsigned char *buf, size_t *length )
   302 {
   303     unsigned char tmp[CDROM_MAX_SECTOR_SIZE];
   304     int read_sector_type = CDROM_READ_TYPE(mode);
   305     int read_sector_fields = CDROM_READ_FIELDS(mode);
   306     int i;
   307     size_t len = 0;
   308     cdrom_error_t err;
   310     CHECK_READ(device, lba, count);
   312     switch(device->mode) {
   313     case SECTOR_CDDA:
   314         if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
   315             return CDROM_ERROR_BADREADMODE;
   316         if( read_sector_fields != 0 ) {
   317             len = block_count * CDROM_MAX_SECTOR_SIZE;
   318             device->read_blocks( device, lba, block_count, buf );
   319         }
   320         break;
   321     case SECTOR_RAW_XA:
   322     case SECTOR_RAW_NONXA:
   323     case SECTOR_SEMIRAW_MODE2:
   324         /* We (may) have to break the raw sector up into requested fields.
   325          * Process sectors one at a time
   326          */
   327         for( i=0; i<block_count; i++ ) {
   328             size_t tmplen;
   329             err = read_raw_sector( device, lba+i, tmp );
   330             if( err != CDROM_ERROR_OK )
   331                 return err;
   332             err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
   333             if( err != CDROM_ERROR_OK )
   334                 return err;
   335             len += tmplen;
   336         }
   337         break;
   338     default: /* Data-only blocks */
   339         err = is_legal_read( device->mode, mode );
   340         if( err != CDROM_ERROR_OK )
   341             return err;
   342         if( read_sector_fields == 0 ) { /* Read nothing */
   343             if( length != NULL )
   344                 *length = 0;
   345             return CDROM_ERROR_OK;
   346         } else if( read_sector_fields == CDROM_READ_DATA ) {
   347             /* Data-only */
   348             if( length != NULL )
   349                 *length = block_count * CDROM_SECTOR_SIZE(device->mode);
   350             return device->read_blocks( device, lba, block_count, buf );
   351         } else if( read_sector_fields == CDROM_READ_RAW ) {
   352             for( i=0; i<block_count; i++ ) {
   353                 err = read_raw_sector( device, lba+i, &buf[2352*i] );
   354                 if( err != CDROM_ERROR_OK )
   355                     return err;
   356             }
   357             len = block_count * CDROM_MAX_SECTOR_SIZE;
   358         } else {
   359             for( i=0; i<block_count; i++ ) {
   360                 size_t tmplen;
   361                 err = read_raw_sector( device, lba+i, tmp );
   362                 if( err != CDROM_ERROR_OK )
   363                     return err;
   364                 err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
   365                 if( err != CDROM_ERROR_OK )
   366                     return err;
   367                 len += tmplen;
   368             }
   369         }
   370     }
   371     if( length != NULL )
   372         *length = len;
   373     return CDROM_ERROR_OK;
   375 }
   377 /************************ Base implementation *************************/
   379 /**
   380  * Default destroy implementation - clears the tag and frees memory.
   381  */
   382 void default_sector_source_destroy( sector_source_t device )
   383 {
   384     assert( device != NULL && device->ref_count == 0 );
   385     device->tag = 0;
   386     g_free( device );
   387 }
   389 sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
   390                         sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
   391 {
   392     device->tag = SECTOR_SOURCE_TAG;
   393     device->ref_count = 0;
   394     device->type = type;
   395     device->mode = mode;
   396     device->size = size;
   397     device->read_blocks = readfn;
   398     device->read_sectors = default_sector_source_read_sectors;
   399     if( destroyfn == NULL )
   400         device->destroy = default_sector_source_destroy;
   401     else
   402         device->destroy = destroyfn;
   403     return device;
   404 }
   406 /************************ Null device implementation *************************/
   407 cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
   408 {
   409     memset( buf, 0,  block_count*CDROM_SECTOR_SIZE(device->mode) );
   410     return CDROM_ERROR_OK;
   411 }
   413 sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
   414 {
   415     return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
   416             null_sector_source_read, default_sector_source_destroy );
   417 }
   419 /************************ File device implementation *************************/
   420 typedef struct file_sector_source {
   421     struct sector_source dev;
   422     FILE *file;
   423     uint32_t offset; /* offset in file where source begins */
   424     sector_source_t ref; /* Parent source reference */
   425     gboolean closeOnDestroy;
   426 } *file_sector_source_t;
   428 void file_sector_source_destroy( sector_source_t dev )
   429 {
   430     assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
   431     file_sector_source_t fdev = (file_sector_source_t)dev;
   433     if( fdev->closeOnDestroy && fdev->file != NULL ) {
   434         fclose( fdev->file );
   435     }
   436     sector_source_unref( fdev->ref );
   437     fdev->file = NULL;
   438     default_sector_source_destroy(dev);
   439 }
   441 cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
   442 {
   443     assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
   444     file_sector_source_t fdev = (file_sector_source_t)dev;
   446     uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
   447     uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
   448     fseek( fdev->file, off, SEEK_SET );
   450     size_t len = fread( buf, 1, size, fdev->file );
   451     if( len == -1 ) {
   452         return CDROM_ERROR_READERROR;
   453     } else if( len < size ) {
   454         /* zero-fill */
   455         memset( buf + len, 0, size-len );
   456     }
   457     return CDROM_ERROR_OK;
   458 }
   460 sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
   461                                         cdrom_count_t sector_count, gboolean closeOnDestroy )
   462 {
   463     if( sector_count == FILE_SECTOR_FULL_FILE ) {
   464         unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
   465         if( sector_size == 0 )
   466             sector_size = 2048;
   467         struct stat st;
   469         if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
   470             /* can't stat file? */
   471             return NULL;
   472         }
   474         sector_count = (st.st_size + sector_size-1) / sector_size;
   475     }
   477     file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
   478     dev->file = f;
   479     dev->offset = offset;
   480     dev->closeOnDestroy = closeOnDestroy;
   481     dev->ref = NULL;
   482     return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode,  sector_count, file_sector_source_read, file_sector_source_destroy );
   483 }
   485 sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
   486 {
   487     return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
   488 }
   490 sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
   491                                                  cdrom_count_t sector_count )
   492 {
   493     int fd = open( filename, O_RDONLY|O_NONBLOCK );
   494     if( fd == -1 ) {
   495         return NULL;
   496     }
   497     FILE *f = fdopen( fd , "ro" );
   498     if( f == NULL ) {
   499         close(fd);
   500         return NULL;
   501     } else {
   502         return file_sector_source_new( f, mode, offset, sector_count, TRUE );
   503     }
   504 }
   506 sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
   507                                                cdrom_count_t sector_count )
   508 {
   509     assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
   510     file_sector_source_t fref = (file_sector_source_t)ref;
   512     sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
   513     ((file_sector_source_t)source)->ref = ref;
   514     sector_source_ref(ref);
   515     return source;
   516 }
   518 FILE *file_sector_source_get_file( sector_source_t ref )
   519 {
   520     assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
   521     file_sector_source_t fref = (file_sector_source_t)ref;
   522     return fref->file;
   523 }
   525 int file_sector_source_get_fd( sector_source_t ref )
   526 {
   527     return fileno(file_sector_source_get_file(ref));
   528 }
   530 void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
   531 {
   532     assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
   533     file_sector_source_t fref = (file_sector_source_t)ref;
   534     fref->closeOnDestroy = closeOnDestroy;
   535 }
   537 /************************ Track device implementation *************************/
   538 typedef struct track_sector_source {
   539     struct sector_source dev;
   540     cdrom_disc_t disc;
   541     uint32_t start_lba;
   542 } *track_sector_source_t;
   544 cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
   545                                                unsigned char *out )
   546 {
   547     size_t length;
   548     assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
   549     assert( dev->mode != SECTOR_UNKNOWN );
   550     track_sector_source_t tdev = (track_sector_source_t)dev;
   551     return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
   552 }
   554 cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
   555                                                 cdrom_read_mode_t mode, unsigned char *out, size_t *length )
   556 {
   557     assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
   558     track_sector_source_t tdev = (track_sector_source_t)dev;
   560     return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
   561 }
   563 void track_sector_source_destroy( sector_source_t dev )
   564 {
   565     assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
   566     track_sector_source_t tdev = (track_sector_source_t)dev;
   567     sector_source_unref( &tdev->disc->source );
   568     default_sector_source_destroy(dev);
   569 }
   571 sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
   572 {
   573     if( disc == NULL ) {
   574         return NULL;
   575     }
   576     track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
   577     dev->disc = disc;
   578     dev->start_lba = lba;
   579     sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
   580                         track_sector_source_read_blocks, track_sector_source_destroy );
   581     dev->dev.read_sectors = track_sector_source_read_sectors;
   582     sector_source_ref( &disc->source );
   583     return &dev->dev;
   584 }
.