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