• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

libisoburn-0.5.6.pl00/libisoburn/data_source.c

Go to the documentation of this file.
00001 /*
00002   data source for libisoburn.
00003 
00004   Copyright 2007 - 2010 Vreixo Formoso Lopes <metalpain2002@yahoo.es>
00005                     and Thomas Schmitt <scdbackup@gmx.net>
00006   Provided under GPL version 2 or later.
00007 */
00008 
00009 #include <stdlib.h>
00010 #include <string.h>
00011 
00012 #include <stdio.h>
00013 
00014 
00015 #ifndef Xorriso_standalonE
00016 
00017 #include <libburn/libburn.h>
00018 
00019 #include <libisofs/libisofs.h>
00020 
00021 #else /* ! Xorriso_standalonE */
00022 
00023 #include "../libisofs/libisofs.h"
00024 #include "../libburn/libburn.h"
00025 
00026 #endif /* Xorriso_standalonE */
00027 
00028 
00029 #include "isoburn.h"
00030 
00031 
00032 /* Cached reading of image tree data */
00033 /* Multi tile:  32 * 64 kB */
00034 
00035 /* The size of a single tile.
00036    Powers of 2 only ! Less than 16 makes not much sense.
00037 */
00038 #define Libisoburn_tile_blockS 32
00039 
00040 /* The number of tiles in the cache
00041 */
00042 #define Libisoburn_cache_tileS 32
00043 
00044 
00045 /* Debugging only: This reports cache loads on stderr.
00046 #define Libisoburn_read_cache_reporT 1
00047 */
00048 
00049 
00050 struct isoburn_cache_tile {
00051  char cache_data[Libisoburn_tile_blockS * 2048];
00052  uint32_t cache_lba;
00053  uint32_t last_error_lba;
00054  uint32_t last_aligned_error_lba;
00055  int cache_hits;
00056  int age;
00057 };
00058 
00059 struct isoburn_cached_drive {
00060  struct burn_drive *drive;
00061  struct isoburn_cache_tile tiles[Libisoburn_cache_tileS];
00062  int current_age;
00063 };
00064 
00065 #define Libisoburn_max_agE 2000000000
00066 
00067 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag);
00068 
00069 
00070 int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
00071 {
00072  int ret, i, oldest, oldest_age;
00073  struct burn_drive *d;
00074  off_t count;
00075  uint32_t aligned_lba;
00076  char msg[80];
00077  struct isoburn_cache_tile *tiles;
00078  struct isoburn_cached_drive *icd;
00079 
00080  if(src == NULL || buffer == NULL)
00081    /* It is not required by the specs of libisofs but implicitely assumed
00082       by its current implementation that a data source read result <0 is
00083       a valid libisofs error code.
00084    */
00085    return ISO_NULL_POINTER;
00086 
00087  icd = (struct isoburn_cached_drive *) src->data;
00088  d = (struct burn_drive*) icd->drive;
00089 
00090  if(d == NULL) {
00091    /* This would happen if libisoburn saw output data in the fifo and
00092       performed early drive release and afterwards libisofs still tries
00093       to read data.
00094       That would constitute a bad conceptual problem in libisoburn.
00095    */
00096    isoburn_msgs_submit(NULL, 0x00060000,
00097      "Programming error: Drive released while libisofs still attempts to read",
00098      0, "FATAL", 0);
00099    return ISO_ASSERT_FAILURE;
00100  }
00101 
00102  tiles = (struct isoburn_cache_tile *) icd->tiles;
00103 
00104  aligned_lba= lba & ~(Libisoburn_tile_blockS - 1);
00105 
00106  for(i=0; i<Libisoburn_cache_tileS; i++) {
00107    if(aligned_lba == tiles[i].cache_lba && tiles[i].cache_lba != 0xffffffff) {
00108      (tiles[i].cache_hits)++;
00109      memcpy(buffer, tiles[i].cache_data + (lba - aligned_lba) * 2048, 2048);
00110      count= 2048;
00111      ds_inc_age(icd, i, 0);
00112      return 1;
00113    }
00114  }
00115 
00116  /* find oldest tile */
00117  oldest_age= Libisoburn_max_agE;
00118  oldest= 0;
00119  for(i= 0; i<Libisoburn_cache_tileS; i++) {
00120    if(tiles[i].cache_lba == 0xffffffff) {
00121      oldest= i;
00122  break;
00123    }
00124    if(tiles[i].age<oldest_age) {
00125      oldest_age= tiles[i].age;
00126      oldest= i;
00127    }
00128  }
00129 
00130  tiles[oldest].cache_lba= 0xffffffff; /* invalidate cache */
00131  if(tiles[oldest].last_aligned_error_lba == aligned_lba) {
00132    ret = 0;
00133  } else {
00134    ret = burn_read_data(d, (off_t) aligned_lba * (off_t) 2048,
00135                         (char *) tiles[oldest].cache_data,
00136                         Libisoburn_tile_blockS * 2048, &count, 2);
00137  }
00138  if (ret <= 0 ) {
00139    tiles[oldest].last_aligned_error_lba = aligned_lba;
00140 
00141    /* Read-ahead failure ? Try to read 2048 directly. */
00142    if(tiles[oldest].last_error_lba == lba)
00143      ret = 0;
00144    else
00145      ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer,
00146                         2048, &count, 0);
00147    if (ret > 0)
00148      return 1;
00149    tiles[oldest].last_error_lba = lba;
00150 
00151 #ifdef ISO_DATA_SOURCE_MISHAP
00152    ret= ISO_DATA_SOURCE_MISHAP;
00153 #else
00154    /* <<< pre libisofs-0.6.7 */
00155    /* It is not required by the specs of libisofs but implicitely assumed
00156       ...
00157       But it is not possible to ignore FAILURE.
00158       libisofs insists in original error codes, i.e. libisoburn cannot
00159       change severity FAILURE associated with ISO_FILE_READ_ERROR.
00160       So ISO_FILE_READ_ERROR is not an option and libisoburn has to
00161       misuse ISO_FILE_CANT_WRITE, which is actually for image generation
00162       and not for image reading.
00163       This is quite wrong, although the error message text is unclear
00164       enough to make it appear plausible.
00165    */
00166    ret= ISO_FILE_CANT_WRITE;
00167 #endif
00168 
00169    if(ret >= 0)
00170      ret = -1;
00171    sprintf(msg, "ds_read_block(%lu) returns %d", (unsigned long) lba, ret);
00172    isoburn_msgs_submit(NULL, 0x00060000, msg, 0, "DEBUG", 0);
00173    return ret; 
00174  }
00175 
00176 #ifdef Libisoburn_read_cache_reporT
00177  fprintf(stderr, "Tile %2.2d : After %3d hits, new load from %8x , count= %d\n",
00178          oldest, tiles[oldest].cache_hits, aligned_lba, (int) count);
00179 #endif
00180 
00181  tiles[oldest].cache_lba= aligned_lba;
00182  tiles[oldest].cache_hits= 1;
00183  ds_inc_age(icd, oldest, 0);
00184 
00185  memcpy(buffer, tiles[oldest].cache_data + (lba - aligned_lba) * 2048, 2048);
00186  count= 2048;
00187 
00188  return 1;
00189 }
00190 
00191 
00192 static int ds_open(IsoDataSource *src)
00193 {
00194  /* nothing to do, device is always grabbed */
00195  return 1;
00196 }
00197 
00198 static int ds_close(IsoDataSource *src)
00199 {
00200  /* nothing to do, device is always grabbed */
00201  return 1;
00202 }
00203 
00204 static void ds_free_data(IsoDataSource *src)
00205 {
00206  /* nothing to do */;
00207  if(src->data != NULL)
00208    free(src->data);
00209  src->data= NULL;
00210 }
00211 
00212 
00213 int isoburn_data_source_shutdown(IsoDataSource *src, int flag)
00214 {
00215  struct isoburn_cached_drive *icd;
00216 
00217  if(src==NULL)
00218    return(0);
00219  icd= (struct isoburn_cached_drive *) src->data;
00220  icd->drive= NULL;
00221  return(1);
00222 }
00223 
00224 
00225 IsoDataSource *isoburn_data_source_new(struct burn_drive *d)
00226 {
00227  IsoDataSource *ret;
00228  struct isoburn_cached_drive *icd= NULL;
00229  int i;
00230 
00231  if (d==NULL)
00232    return NULL;
00233  ret = malloc(sizeof(IsoDataSource));
00234  icd = calloc(1,sizeof(struct isoburn_cached_drive));
00235  if (ret == NULL || icd == NULL)
00236    return NULL;
00237  ret->refcount = 1;
00238  ret->read_block = ds_read_block;
00239  ret->open = ds_open;
00240  ret->close = ds_close;
00241  ret->free_data = ds_free_data;
00242  ret->data = icd;
00243  icd->drive = d;
00244  icd->current_age= 0;
00245  for(i= 0; i<Libisoburn_cache_tileS; i++) {
00246    icd->tiles[i].cache_lba = 0xffffffff;
00247    icd->tiles[i].cache_hits = 0;
00248    icd->tiles[i].last_error_lba = 0xffffffff;
00249    icd->tiles[i].last_aligned_error_lba = 0xffffffff;
00250    icd->tiles[i].age= 0;
00251  }
00252  return ret;
00253 }
00254 
00255 
00256 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag)
00257 {
00258  int i;
00259 
00260  (icd->current_age)++;
00261  if(icd->current_age>=Libisoburn_max_agE) { /* reset all ages (allow waste) */
00262    for(i= 0; i<Libisoburn_cache_tileS; i++)
00263      (icd->tiles)[i].age= 0;
00264    icd->current_age= 1;
00265  }
00266  (icd->tiles)[idx].age= icd->current_age;
00267  return(1);
00268 }
00269 
00270 

Generated on Tue Aug 17 2010 13:01:43 for libisoburn by  doxygen 1.7.1