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 1178:e55ec927d55d
prev1121:c2d827cbdf37
next1296:30ecee61f811
author Nathan Keynes <nkeynes@lxdream.org>
date Sat Sep 17 22:39:36 2011 +1000 (12 years ago)
permissions -rw-r--r--
last change Fix structure packing on v55 nero images (64-bit)
Add basic support for track mode 16 (CDDA + subchannel data, 2448 bytes)
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 "lxpaths.h"
    29 #include "drivers/cdrom/sector.h"
    30 #include "drivers/cdrom/cdrom.h"
    31 #include "drivers/cdrom/ecc.h"
    33 #define CHECK_READ(dev,lba,count) \
    34     if( !IS_SECTOR_SOURCE(dev) ) { \
    35         return CDROM_ERROR_NODISC; \
    36     } else if( (dev)->size != 0 && ((lba) >= (dev)->size || (lba+block_count) > (dev)->size) ) { \
    37         return CDROM_ERROR_BADREAD; \
    38     }
    40 /* Default read mode for each sector mode */
    41 const uint32_t cdrom_sector_read_mode[] = { 0,
    42         CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
    43         CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
    44         CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
    45         CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
    46         CDROM_READ_RAW, CDROM_READ_RAW,
    47         CDROM_READ_CDDA|CDROM_READ_DATA};
    49 /* Block size for each sector mode */
    50 const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352, 2448 };
    52 const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
    53         "Mode 2 semiraw", "XA Raw", "Non-XA Raw", "CDDA+Subchan" };
    56 /********************* Public functions *************************/
    57 cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
    58 {
    59     CHECK_READ(device,lba,block_count);
    60     return device->read_blocks(device, lba, block_count, buf);
    61 }
    63 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,
    64                                           unsigned char *buf, size_t *length )
    65 {
    66     CHECK_READ(device,lba,block_count);
    67     return device->read_sectors(device, lba, block_count, mode, buf, length);
    68 }
    70 void sector_source_ref( sector_source_t device )
    71 {
    72     assert( IS_SECTOR_SOURCE(device) );
    73     device->ref_count++;
    74 }
    76 void sector_source_unref( sector_source_t device )
    77 {
    78     if( device == NULL )
    79         return;
    80     assert( IS_SECTOR_SOURCE(device) );
    81     if( device->ref_count > 0 )
    82         device->ref_count--;
    83     if( device->ref_count == 0 )
    84         device->destroy(device);
    85 }
    87 void sector_source_release( sector_source_t device )
    88 {
    89     assert( IS_SECTOR_SOURCE(device) );
    90     if( device->ref_count == 0 )
    91         device->destroy(device);
    92 }
    94 /************************** Sector mangling ***************************/
    95 /*
    96  * Private functions used to pack/unpack sectors, determine mode, and
    97  * evaluate sector reads.
    98  */
   100 /** Basic data sector header structure */
   101 struct cdrom_sector_header {
   102     uint8_t sync[12];
   103     uint8_t msf[3];
   104     uint8_t mode;
   105     uint8_t subhead[8]; // Mode-2 XA sectors only
   106 };
   108 static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
   110 /* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
   111 static const uint8_t legal_nonxa_fields[] =
   112 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
   113   TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
   114   TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
   115   FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
   117 /* Field combinations that are legal for mode 2 form 1 or form 2 reads */
   118 static const uint8_t legal_xa_fields[] =
   119 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
   120   TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
   121   TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
   122   FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
   124 /**
   125  * Position per sector mode of each of the fields
   126  *   sync, header, subheader, data, ecc.
   127  *
   128  */
   129 static const uint32_t sector_field_positions[][6] = {
   130         { 0, 0, 0, 0, 0, 0 },    /* Unknown */
   131         { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
   132         { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
   133         { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
   134         { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
   135         { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
   139 /**
   140  * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
   141  * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
   142  * will return BADREADMODE, as it's impossible to tell.
   143  *
   144  * @param track_mode one of the CDROM_MODE* constants
   145  * @param read_mode the full read mode
   146  */
   147 static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
   148 {
   149     int read_sector_type = CDROM_READ_TYPE(read_mode);
   150     int read_sector_fields = CDROM_READ_FIELDS(read_mode);
   152     /* Check the sector type is consistent */
   153     switch( read_sector_type ) {
   154     case CDROM_READ_ANY: break;
   155     case CDROM_READ_CDDA:
   156         if( sector_mode != SECTOR_CDDA && sector_mode != SECTOR_CDDA_SUBCHANNEL )
   157             return CDROM_ERROR_BADREADMODE;
   158         break;
   159     case CDROM_READ_MODE1:
   160     case CDROM_READ_MODE2_FORM1:
   161         if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
   162             return CDROM_ERROR_BADREADMODE;
   163         break;
   164     case CDROM_READ_MODE2_FORM2:
   165         if( sector_mode != SECTOR_MODE2_FORM2 )
   166             return CDROM_ERROR_BADREADMODE;
   167         break;
   168     case CDROM_READ_MODE2:
   169         if( sector_mode != SECTOR_MODE2_FORMLESS )
   170             return CDROM_ERROR_BADREADMODE;
   171         break;
   172     default: /* Illegal read mode */
   173         return CDROM_ERROR_BADFIELD;
   174     }
   176     /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
   177     switch( sector_mode ) {
   178     case SECTOR_CDDA:
   179     case SECTOR_CDDA_SUBCHANNEL:
   180         return CDROM_ERROR_OK; /* Everything is OK */
   181     case SECTOR_MODE2_FORM1:
   182     case SECTOR_MODE2_FORM2:
   183         if( !legal_xa_fields[read_sector_fields>>11] )
   184             return CDROM_ERROR_BADFIELD;
   185         else
   186             return CDROM_ERROR_OK;
   187     case SECTOR_MODE1:
   188     case SECTOR_MODE2_FORMLESS:
   189         if( !legal_nonxa_fields[read_sector_fields>>11] )
   190             return CDROM_ERROR_BADFIELD;
   191         else
   192             return CDROM_ERROR_OK;
   193     default:
   194         return CDROM_ERROR_BADFIELD;
   195     }
   196 }
   198 static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
   199 {
   200     struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
   202     switch( raw_mode ) {
   203     case SECTOR_SEMIRAW_MODE2: /* XA sectors */
   204     case SECTOR_RAW_XA:
   205         switch( header->mode ) {
   206         case 1: return SECTOR_MODE1;
   207         case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
   208         default: return SECTOR_UNKNOWN;
   209         }
   210     case SECTOR_RAW_NONXA:
   211         switch( header->mode ) {
   212         case 1: return SECTOR_MODE1;
   213         case 2: return SECTOR_MODE2_FORMLESS;
   214         default: return SECTOR_UNKNOWN;
   215         }
   216     default:
   217         return raw_mode;
   218     }
   219 }
   221 /**
   222  * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
   223  * necessary.
   224  */
   225 static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
   226 {
   227     cdrom_error_t err;
   229     switch( device->mode ) {
   230     case SECTOR_RAW_XA:
   231     case SECTOR_RAW_NONXA:
   232         return device->read_blocks(device, lba, 1, buf);
   233     case SECTOR_SEMIRAW_MODE2:
   234         memcpy( buf, cdrom_sync_data, 12 );
   235         cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
   236         return device->read_blocks(device, lba, 1, &buf[16]);
   237     case SECTOR_MODE1:
   238     case SECTOR_MODE2_FORMLESS:
   239         err = device->read_blocks(device, lba, 1, &buf[16]);
   240         if( err == CDROM_ERROR_OK ) {
   241             do_encode_L2( buf, device->mode, lba );
   242         }
   243         return err;
   244     case SECTOR_MODE2_FORM1:
   245         *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
   246         err = device->read_blocks(device, lba, 1, &buf[24]);
   247         if( err == CDROM_ERROR_OK ) {
   248             do_encode_L2( buf, device->mode, lba );
   249         }
   250         return err;
   251     case SECTOR_MODE2_FORM2:
   252         *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
   253         err = device->read_blocks(device, lba, 1, &buf[24]);
   254         if( err == CDROM_ERROR_OK ) {
   255             do_encode_L2( buf, device->mode, lba );
   256         }
   257         return err;
   258     default:
   259         abort();
   260     }
   261 }
   263 static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
   264 {
   265     int start=-1,end=0;
   266     int i;
   268     for( i=0; i<5; i++ ) {
   269         if( fields & (0x8000>>i) ) {
   270             if( start == -1 )
   271                 start = sector_field_positions[mode][i];
   272             else if( end != sector_field_positions[mode][i] )
   273                 return CDROM_ERROR_BADFIELD;
   274             end = sector_field_positions[mode][i+1];
   275         }
   276     }
   277     if( start == -1 ) {
   278         *length = 0;
   279     } else {
   280         memcpy( buf, &raw_sector[start], end-start );
   281         *length = end-start;
   282     }
   283     return CDROM_ERROR_OK;
   284 }
   286 cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
   287 {
   288     sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
   289     if( sector_mode == SECTOR_UNKNOWN )
   290         return CDROM_ERROR_BADREAD;
   291     cdrom_error_t status = is_legal_read( sector_mode, mode );
   292     if( status != CDROM_ERROR_OK )
   293         return status;
   294     return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
   295 }
   297 /**
   298  * This is horribly complicated by the need to handle mapping between all possible
   299  * sector modes + read modes, but fortunately most sources can just supply
   300  * a single block type and not care about the details here.
   301  */
   302 cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
   303         cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
   304         unsigned char *buf, size_t *length )
   305 {
   306     unsigned char tmp[2448];
   307     int read_sector_type = CDROM_READ_TYPE(mode);
   308     int read_sector_fields = CDROM_READ_FIELDS(mode);
   309     int i;
   310     size_t len = 0;
   311     cdrom_error_t err;
   313     CHECK_READ(device, lba, count);
   315     switch(device->mode) {
   316     case SECTOR_CDDA:
   317         if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
   318             return CDROM_ERROR_BADREADMODE;
   319         if( read_sector_fields != 0 ) {
   320             len = block_count * CDROM_MAX_SECTOR_SIZE;
   321             device->read_blocks( device, lba, block_count, buf );
   322         }
   323         break;
   324     case SECTOR_CDDA_SUBCHANNEL:
   325         if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
   326             return CDROM_ERROR_BADREADMODE;
   327         if( read_sector_fields != 0 ) {
   328             len = block_count * 2352;
   329             for( i=0; i<block_count; i++ ) {
   330                 device->read_blocks( device, lba+i, 1, tmp );
   331                 memcpy( &buf[2352*i], tmp, 2352 );
   332             }
   333         }
   334         break;
   335     case SECTOR_RAW_XA:
   336     case SECTOR_RAW_NONXA:
   337     case SECTOR_SEMIRAW_MODE2:
   338         /* We (may) have to break the raw sector up into requested fields.
   339          * Process sectors one at a time
   340          */
   341         for( i=0; i<block_count; i++ ) {
   342             size_t tmplen;
   343             err = read_raw_sector( device, lba+i, tmp );
   344             if( err != CDROM_ERROR_OK )
   345                 return err;
   346             err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
   347             if( err != CDROM_ERROR_OK )
   348                 return err;
   349             len += tmplen;
   350         }
   351         break;
   352     default: /* Data-only blocks */
   353         err = is_legal_read( device->mode, mode );
   354         if( err != CDROM_ERROR_OK )
   355             return err;
   356         if( read_sector_fields == 0 ) { /* Read nothing */
   357             if( length != NULL )
   358                 *length = 0;
   359             return CDROM_ERROR_OK;
   360         } else if( read_sector_fields == CDROM_READ_DATA ) {
   361             /* Data-only */
   362             if( length != NULL )
   363                 *length = block_count * CDROM_SECTOR_SIZE(device->mode);
   364             return device->read_blocks( device, lba, block_count, buf );
   365         } else if( read_sector_fields == CDROM_READ_RAW ) {
   366             for( i=0; i<block_count; i++ ) {
   367                 err = read_raw_sector( device, lba+i, &buf[2352*i] );
   368                 if( err != CDROM_ERROR_OK )
   369                     return err;
   370             }
   371             len = block_count * CDROM_MAX_SECTOR_SIZE;
   372         } else {
   373             for( i=0; i<block_count; i++ ) {
   374                 size_t tmplen;
   375                 err = read_raw_sector( device, lba+i, tmp );
   376                 if( err != CDROM_ERROR_OK )
   377                     return err;
   378                 err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
   379                 if( err != CDROM_ERROR_OK )
   380                     return err;
   381                 len += tmplen;
   382             }
   383         }
   384     }
   385     if( length != NULL )
   386         *length = len;
   387     return CDROM_ERROR_OK;
   389 }
   391 /************************ Base implementation *************************/
   393 /**
   394  * Default destroy implementation - clears the tag and frees memory.
   395  */
   396 void default_sector_source_destroy( sector_source_t device )
   397 {
   398     assert( device != NULL && device->ref_count == 0 );
   399     device->tag = 0;
   400     g_free( device );
   401 }
   403 sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
   404                         sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
   405 {
   406     device->tag = SECTOR_SOURCE_TAG;
   407     device->ref_count = 0;
   408     device->type = type;
   409     device->mode = mode;
   410     device->size = size;
   411     device->read_blocks = readfn;
   412     device->read_sectors = default_sector_source_read_sectors;
   413     if( destroyfn == NULL )
   414         device->destroy = default_sector_source_destroy;
   415     else
   416         device->destroy = destroyfn;
   417     return device;
   418 }
   420 /************************ Null device implementation *************************/
   421 cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
   422 {
   423     memset( buf, 0,  block_count*CDROM_SECTOR_SIZE(device->mode) );
   424     return CDROM_ERROR_OK;
   425 }
   427 sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
   428 {
   429     return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
   430             null_sector_source_read, default_sector_source_destroy );
   431 }
   433 /************************ File device implementation *************************/
   434 typedef struct file_sector_source {
   435     struct sector_source dev;
   436     FILE *file;
   437     uint32_t offset; /* offset in file where source begins */
   438     sector_source_t ref; /* Parent source reference */
   439     gboolean closeOnDestroy;
   440 } *file_sector_source_t;
   442 void file_sector_source_destroy( sector_source_t dev )
   443 {
   444     assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
   445     file_sector_source_t fdev = (file_sector_source_t)dev;
   447     if( fdev->closeOnDestroy && fdev->file != NULL ) {
   448         fclose( fdev->file );
   449     }
   450     sector_source_unref( fdev->ref );
   451     fdev->file = NULL;
   452     default_sector_source_destroy(dev);
   453 }
   455 cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
   456 {
   457     assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
   458     file_sector_source_t fdev = (file_sector_source_t)dev;
   460     uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
   461     uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
   462     fseek( fdev->file, off, SEEK_SET );
   464     size_t len = fread( buf, 1, size, fdev->file );
   465     if( len == -1 ) {
   466         return CDROM_ERROR_READERROR;
   467     } else if( len < size ) {
   468         /* zero-fill */
   469         memset( buf + len, 0, size-len );
   470     }
   471     return CDROM_ERROR_OK;
   472 }
   474 sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
   475                                         cdrom_count_t sector_count, gboolean closeOnDestroy )
   476 {
   477     if( sector_count == FILE_SECTOR_FULL_FILE ) {
   478         unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
   479         if( sector_size == 0 )
   480             sector_size = 2048;
   481         struct stat st;
   483         if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
   484             /* can't stat file? */
   485             return NULL;
   486         }
   488         sector_count = (st.st_size + sector_size-1) / sector_size;
   489     }
   491     file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
   492     dev->file = f;
   493     dev->offset = offset;
   494     dev->closeOnDestroy = closeOnDestroy;
   495     dev->ref = NULL;
   496     return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode,  sector_count, file_sector_source_read, file_sector_source_destroy );
   497 }
   499 sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
   500 {
   501     return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
   502 }
   504 sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
   505                                                  cdrom_count_t sector_count )
   506 {
   507     int fd = open( filename, O_RDONLY|O_NONBLOCK );
   508     if( fd == -1 ) {
   509         return NULL;
   510     }
   511     FILE *f = fdopen( fd , "ro" );
   512     if( f == NULL ) {
   513         close(fd);
   514         return NULL;
   515     } else {
   516         return file_sector_source_new( f, mode, offset, sector_count, TRUE );
   517     }
   518 }
   520 sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
   521                                                cdrom_count_t sector_count )
   522 {
   523     assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
   524     file_sector_source_t fref = (file_sector_source_t)ref;
   526     sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
   527     ((file_sector_source_t)source)->ref = ref;
   528     sector_source_ref(ref);
   529     return source;
   530 }
   532 FILE *file_sector_source_get_file( sector_source_t ref )
   533 {
   534     assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
   535     file_sector_source_t fref = (file_sector_source_t)ref;
   536     return fref->file;
   537 }
   539 int file_sector_source_get_fd( sector_source_t ref )
   540 {
   541     return fileno(file_sector_source_get_file(ref));
   542 }
   544 void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
   545 {
   546     assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
   547     file_sector_source_t fref = (file_sector_source_t)ref;
   548     fref->closeOnDestroy = closeOnDestroy;
   549 }
   551 /********************** Temporary file implementation ************************/
   552 /**
   553  * The tmpfile source behaves exactly like a regular file source, except that
   554  * it creates a new temporary file, which is deleted on destruction or program
   555  * exit. The file is initially empty, so the user will need to get the fd and
   556  * write something to it before use.
   557  */
   559 typedef struct tmpfile_sector_source {
   560     struct file_sector_source file;
   561     const char *filename;
   562 } *tmpfile_sector_source_t;
   564 static GList *tmpfile_open_list = NULL;
   565 static gboolean tmpfile_atexit_installed = 0; /* TRUE to indicate atexit hook is registered */
   567 static void tmpfile_sector_close( sector_source_t dev )
   568 {
   569     assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
   570     tmpfile_sector_source_t fdev = (tmpfile_sector_source_t)dev;
   572     if( fdev->file.file != NULL ) {
   573         fclose( fdev->file.file );
   574         fdev->file.file = NULL;
   575     }
   576     if( fdev->filename != NULL ) {
   577         unlink(fdev->filename);
   578         g_free((char *)fdev->filename);
   579         fdev->filename = NULL;
   580     }
   581 }
   584 /**
   585  * atexit hook to close any open tmpfiles - make sure they're deleted.
   586  */
   587 static void tmpfile_atexit_hook(void)
   588 {
   589     GList *ptr;
   590     for( ptr = tmpfile_open_list; ptr != NULL; ptr = ptr->next ) {
   591         sector_source_t source = (sector_source_t)ptr->data;
   592         tmpfile_sector_close(source);
   593     }
   594 }
   597 static void tmpfile_sector_source_destroy( sector_source_t dev )
   598 {
   599     tmpfile_sector_close(dev);
   600     tmpfile_open_list = g_list_remove(tmpfile_open_list, dev);
   601     default_sector_source_destroy(dev);
   602 }
   604 sector_source_t tmpfile_sector_source_new( sector_mode_t mode )
   605 {
   606     if( !tmpfile_atexit_installed ) {
   607         atexit(tmpfile_atexit_hook);
   608     }
   610     gchar *tmpdir = getenv("TMPDIR");
   611     if( tmpdir == NULL ) {
   612         tmpdir = "/tmp";
   613     }
   614     gchar *tempfile = get_filename_at(tmpdir, "cd.XXXXXXX");
   615     int fd = mkstemp( tempfile );
   616     if( fd == -1 ) {
   617         g_free(tempfile);
   618         return FALSE;
   619     }
   621     FILE *f = fdopen( fd, "w+" );
   622     if( f == NULL ) {
   623         close(fd);
   624         unlink(tempfile);
   625         g_free(tempfile);
   626         return NULL;
   627     }
   629     tmpfile_sector_source_t dev = g_malloc0(sizeof(struct tmpfile_sector_source));
   630     dev->file.file = f;
   631     dev->filename = tempfile;
   632     sector_source_t source = sector_source_init( &dev->file.dev, FILE_SECTOR_SOURCE, mode, 0, file_sector_source_read, tmpfile_sector_source_destroy );
   633     tmpfile_open_list = g_list_append(tmpfile_open_list, source);
   634     return source;
   635 }
   637 /************************ Memory device implementation *************************/
   638 typedef struct mem_sector_source {
   639     struct sector_source dev;
   640     unsigned char *buffer;
   641     gboolean freeOnDestroy;
   642 } *mem_sector_source_t;
   644 static void mem_sector_source_destroy( sector_source_t dev )
   645 {
   646     assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
   647     mem_sector_source_t mdev = (mem_sector_source_t)dev;
   649     if( mdev->freeOnDestroy ) {
   650         free(mdev->buffer);
   651     }
   652     mdev->buffer = NULL;
   653     default_sector_source_destroy(dev);
   654 }
   656 static cdrom_error_t mem_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
   657 {
   658     assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
   659     mem_sector_source_t mdev = (mem_sector_source_t)dev;
   661     if( (lba + block_count) >= dev->size )
   662         return CDROM_ERROR_BADREAD;
   663     uint32_t off = lba * CDROM_SECTOR_SIZE(dev->mode);
   664     uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
   666     memcpy( buf, mdev->buffer + off, size );
   667     return CDROM_ERROR_OK;
   668 }
   670 sector_source_t mem_sector_source_new_buffer( unsigned char *buffer, sector_mode_t mode,
   671                                        cdrom_count_t sector_count, gboolean freeOnDestroy )
   672 {
   673     assert( mode != SECTOR_UNKNOWN );
   674     assert( buffer != NULL );
   675     mem_sector_source_t dev = g_malloc(sizeof(struct mem_sector_source));
   676     dev->buffer = buffer;
   677     dev->freeOnDestroy = freeOnDestroy;
   678     return sector_source_init( &dev->dev, MEM_SECTOR_SOURCE, mode, sector_count, mem_sector_source_read, mem_sector_source_destroy );
   679 }
   681 sector_source_t mem_sector_source_new( sector_mode_t mode, cdrom_count_t sector_count )
   682 {
   683     return mem_sector_source_new_buffer( g_malloc( sector_count * CDROM_SECTOR_SIZE(mode) ), mode,
   684                                          sector_count, TRUE );
   685 }
   687 unsigned char *mem_sector_source_get_buffer( sector_source_t dev )
   688 {
   689     assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
   690     mem_sector_source_t mdev = (mem_sector_source_t)dev;
   691     return mdev->buffer;
   692 }
   695 /************************ Track device implementation *************************/
   696 typedef struct track_sector_source {
   697     struct sector_source dev;
   698     cdrom_disc_t disc;
   699     uint32_t start_lba;
   700 } *track_sector_source_t;
   702 cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
   703                                                unsigned char *out )
   704 {
   705     size_t length;
   706     assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
   707     assert( dev->mode != SECTOR_UNKNOWN );
   708     track_sector_source_t tdev = (track_sector_source_t)dev;
   709     return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
   710 }
   712 cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
   713                                                 cdrom_read_mode_t mode, unsigned char *out, size_t *length )
   714 {
   715     assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
   716     track_sector_source_t tdev = (track_sector_source_t)dev;
   718     return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
   719 }
   721 void track_sector_source_destroy( sector_source_t dev )
   722 {
   723     assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
   724     track_sector_source_t tdev = (track_sector_source_t)dev;
   725     sector_source_unref( &tdev->disc->source );
   726     default_sector_source_destroy(dev);
   727 }
   729 sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
   730 {
   731     if( disc == NULL ) {
   732         return NULL;
   733     }
   734     track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
   735     dev->disc = disc;
   736     dev->start_lba = lba;
   737     sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
   738                         track_sector_source_read_blocks, track_sector_source_destroy );
   739     dev->dev.read_sectors = track_sector_source_read_sectors;
   740     sector_source_ref( &disc->source );
   741     return &dev->dev;
   742 }
.