"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisoburn/data_source.c" (30 Jan 2021, 8813 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "data_source.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   data source for libisoburn.
    3 
    4   Copyright 2007 - 2012 Vreixo Formoso Lopes <metalpain2002@yahoo.es>
    5                     and Thomas Schmitt <scdbackup@gmx.net>
    6   Provided under GPL version 2 or later.
    7 */
    8 
    9 #ifdef HAVE_CONFIG_H
   10 #include "../config.h"
   11 #endif
   12 
   13 #include <stdlib.h>
   14 #include <string.h>
   15 
   16 #include <stdio.h>
   17 
   18 
   19 #ifndef Xorriso_standalonE
   20 
   21 #include <libburn/libburn.h>
   22 
   23 #include <libisofs/libisofs.h>
   24 
   25 #else /* ! Xorriso_standalonE */
   26 
   27 #include "../libisofs/libisofs.h"
   28 #include "../libburn/libburn.h"
   29 
   30 #endif /* Xorriso_standalonE */
   31 
   32 
   33 #include "isoburn.h"
   34 
   35 
   36 /* Cached reading of image tree data by multiple tiles */
   37 
   38 
   39 /* Debugging only: This reports cache loads on stderr.
   40 #define Libisoburn_read_cache_reporT 1
   41 */
   42 
   43 
   44 struct isoburn_cache_tile {
   45  char *cache_data;
   46  uint32_t cache_lba;
   47  uint32_t last_error_lba;
   48  uint32_t last_aligned_error_lba;
   49  int cache_hits;
   50  int age;
   51 };
   52 
   53 struct isoburn_cached_drive {
   54  struct burn_drive *drive;
   55  struct isoburn_cache_tile **tiles;
   56  int num_tiles;
   57  int tile_blocks;
   58  int current_age;
   59 
   60  /**    
   61   Offset to be applied to all block addresses to compensate for an
   62   eventual displacement of the block addresses relative to the image
   63   start block address that was assumed when the image was created.
   64   E.g. if track number 2 gets copied into a disk file and shall then
   65   be loaded as ISO filesystem.
   66   If displacement_sign is 1 then the displacement number will be
   67   added to .read_block() addresses, if -1 it will be subtracted.
   68   Else it will be ignored.
   69  */
   70  uint32_t displacement;
   71  int      displacement_sign;
   72 
   73 };
   74 
   75 #define Libisoburn_max_agE 2000000000
   76 
   77 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag);
   78 
   79 
   80 int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
   81 {
   82  int ret, i, oldest, oldest_age;
   83  struct burn_drive *d;
   84  off_t count;
   85  uint32_t aligned_lba;
   86  char msg[80];
   87  struct isoburn_cache_tile **tiles;
   88  struct isoburn_cached_drive *icd;
   89 
   90  if(src == NULL || buffer == NULL)
   91    /* It is not required by the specs of libisofs but implicitly assumed
   92       by its current implementation that a data source read result <0 is
   93       a valid libisofs error code.
   94    */
   95    return ISO_NULL_POINTER;
   96 
   97  icd = (struct isoburn_cached_drive *) src->data;
   98  d = (struct burn_drive*) icd->drive;
   99 
  100  if(d == NULL) {
  101    /* This would happen if libisoburn saw output data in the fifo and
  102       performed early drive release and afterwards libisofs still tries
  103       to read data.
  104       That would constitute a bad conceptual problem in libisoburn.
  105    */
  106    isoburn_msgs_submit(NULL, 0x00060000,
  107      "Programming error: Drive released while libisofs still attempts to read",
  108      0, "FATAL", 0);
  109    return ISO_ASSERT_FAILURE;
  110  }
  111 
  112  tiles = icd->tiles;
  113 
  114  if(icd->displacement_sign == 1) {
  115    if(lba + icd->displacement < lba) {
  116 address_rollover:;
  117       return ISO_DISPLACE_ROLLOVER;
  118    } else
  119      lba += icd->displacement;
  120  } else if(icd->displacement_sign == -1) {
  121    if(lba < icd->displacement )
  122      goto address_rollover;
  123    else
  124      lba -= icd->displacement;
  125  }
  126 
  127  aligned_lba= lba & ~(icd->tile_blocks - 1);
  128 
  129  for (i = 0; i < icd->num_tiles; i++) {
  130    if(aligned_lba == tiles[i]->cache_lba &&
  131       tiles[i]->cache_lba != 0xffffffff) {
  132      (tiles[i]->cache_hits)++;
  133      memcpy(buffer, tiles[i]->cache_data + (lba - aligned_lba) * 2048, 2048);
  134      count= 2048;
  135      ds_inc_age(icd, i, 0);
  136      return 1;
  137    }
  138  }
  139 
  140  /* find oldest tile */
  141  oldest_age= Libisoburn_max_agE;
  142  oldest= 0;
  143  for(i = 0; i < icd->num_tiles; i++) {
  144    if(tiles[i]->cache_lba == 0xffffffff) {
  145      oldest= i;
  146  break;
  147    }
  148    if(tiles[i]->age < oldest_age) {
  149      oldest_age= tiles[i]->age;
  150      oldest= i;
  151    }
  152  }
  153 
  154  tiles[oldest]->cache_lba= 0xffffffff; /* invalidate cache */
  155  if(tiles[oldest]->last_aligned_error_lba == aligned_lba) {
  156    ret = 0;
  157  } else {
  158    ret = burn_read_data(d, (off_t) aligned_lba * (off_t) 2048,
  159                         (char *) tiles[oldest]->cache_data,
  160                         icd->tile_blocks * 2048, &count, 2);
  161  }
  162  if (ret <= 0 ) {
  163    tiles[oldest]->last_aligned_error_lba = aligned_lba;
  164 
  165    /* Read-ahead failure ? Try to read 2048 directly. */
  166    if(tiles[oldest]->last_error_lba == lba)
  167      ret = 0;
  168    else
  169      ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer,
  170                         2048, &count, 0);
  171    if (ret > 0)
  172      return 1;
  173    tiles[oldest]->last_error_lba = lba;
  174    sprintf(msg, "ds_read_block(%lu) returns %lX",
  175            (unsigned long) lba, (unsigned long) ret);
  176    isoburn_msgs_submit(NULL, 0x00060000, msg, 0, "DEBUG", 0);
  177    return ISO_DATA_SOURCE_MISHAP;
  178  }
  179 
  180 #ifdef Libisoburn_read_cache_reporT
  181  fprintf(stderr, "Tile %2.2d : After %3d hits, new load from %8x , count= %d\n",
  182          oldest, tiles[oldest]->cache_hits, aligned_lba, (int) count);
  183 #endif
  184 
  185  tiles[oldest]->cache_lba= aligned_lba;
  186  tiles[oldest]->cache_hits= 1;
  187  ds_inc_age(icd, oldest, 0);
  188 
  189  memcpy(buffer, tiles[oldest]->cache_data + (lba - aligned_lba) * 2048, 2048);
  190  count= 2048;
  191 
  192  return 1;
  193 }
  194 
  195 
  196 static int ds_open(IsoDataSource *src)
  197 {
  198  /* nothing to do, device is always grabbed */
  199  return 1;
  200 }
  201 
  202 static int ds_close(IsoDataSource *src)
  203 {
  204  /* nothing to do, device is always grabbed */
  205  return 1;
  206 }
  207 
  208 
  209 static int isoburn_cache_tile_destroy(struct isoburn_cache_tile **o,
  210                                       int flag)
  211 {
  212  if (*o == NULL)
  213    return(0);
  214  if ((*o)->cache_data != NULL)
  215    free((*o)->cache_data);
  216  free(*o);
  217  *o = NULL;
  218  return(1);
  219 }
  220 
  221 
  222 static int isoburn_cache_tile_new(struct isoburn_cache_tile **o,
  223                                   int tile_blocks, int flag)
  224 {
  225  struct isoburn_cache_tile *t;
  226 
  227  *o = t = calloc(1, sizeof(struct isoburn_cache_tile));
  228  if (t == NULL)
  229    goto fail;
  230  t->cache_data = NULL;
  231  t->cache_lba = 0xffffffff;
  232  t->cache_hits = 0;
  233  t->last_error_lba = 0xffffffff;
  234  t->last_aligned_error_lba = 0xffffffff;
  235  t->age= 0;
  236 
  237  t->cache_data = calloc(1, tile_blocks * 2048);
  238  if (t->cache_data == NULL)
  239    goto fail;
  240 
  241  return(1);
  242 fail:;
  243  isoburn_cache_tile_destroy(o, 0);
  244  return(-1);
  245 }
  246 
  247 
  248 static int isoburn_cached_drive_destroy(struct isoburn_cached_drive **o,
  249                                         int flag)
  250 {
  251  struct isoburn_cached_drive *c;
  252  int i;
  253 
  254  if (*o == NULL)
  255    return(0);
  256  c= *o;
  257  if (c->tiles != NULL) {
  258    for (i = 0; i < c->num_tiles; i++) 
  259      isoburn_cache_tile_destroy(&(c->tiles[i]), 0);
  260    free(c->tiles);
  261  }
  262  free(c);
  263  *o= NULL;
  264  return(1);
  265 }
  266 
  267 
  268 static int isoburn_cached_drive_new(struct isoburn_cached_drive **o,
  269                                     struct burn_drive *d, int cache_tiles,
  270                                     int tile_blocks, int flag)
  271 {
  272  struct isoburn_cached_drive *icd;
  273  int i, ret;
  274 
  275  *o = icd = calloc(1,sizeof(struct isoburn_cached_drive));
  276  if (*o == NULL)
  277    return(-1);
  278  icd->drive = d;
  279  icd->tiles = NULL;
  280  icd->num_tiles = cache_tiles;
  281  icd->tile_blocks = tile_blocks;
  282  icd->current_age = 0;
  283  icd->displacement = 0;
  284  icd->displacement_sign = 0;
  285 
  286  icd->tiles = calloc(1, sizeof(struct isoburn_cache_tile *) * icd->num_tiles);
  287  if (icd->tiles == NULL)
  288    goto fail;
  289  for (i = 0; i < icd->num_tiles; i++) {
  290    ret = isoburn_cache_tile_new(&(icd->tiles[i]), icd->tile_blocks, 0);
  291    if (ret <= 0)
  292      goto fail;
  293  }
  294  return(1);
  295 fail:;
  296  isoburn_cached_drive_destroy(o, 0);
  297  return(-1);
  298 }
  299 
  300 
  301 static void ds_free_data(IsoDataSource *src)
  302 {
  303  struct isoburn_cached_drive *icd;
  304 
  305  if(src->data != NULL) {
  306    icd= (struct isoburn_cached_drive *) src->data;
  307    isoburn_cached_drive_destroy(&icd, 0);
  308  }
  309  src->data= NULL;
  310 }
  311 
  312 
  313 int isoburn_data_source_shutdown(IsoDataSource *src, int flag)
  314 {
  315  struct isoburn_cached_drive *icd;
  316 
  317  if(src==NULL)
  318    return(0);
  319  icd= (struct isoburn_cached_drive *) src->data;
  320  icd->drive= NULL;
  321  return(1);
  322 }
  323 
  324 
  325 IsoDataSource *isoburn_data_source_new(struct burn_drive *d,
  326                                   uint32_t displacement, int displacement_sign,
  327                                   int cache_tiles, int tile_blocks)
  328 {
  329  IsoDataSource *src;
  330  struct isoburn_cached_drive *icd= NULL;
  331  int ret;
  332 
  333  if (d==NULL)
  334    return NULL;
  335  src = malloc(sizeof(IsoDataSource));
  336  if (src == NULL)
  337    return NULL;
  338  ret = isoburn_cached_drive_new(&icd, d, cache_tiles, tile_blocks, 0);
  339  if (ret <= 0) {
  340    free(src);
  341    return NULL;
  342  }
  343  src->version = 0;
  344  src->refcount = 1;
  345  src->read_block = ds_read_block;
  346  src->open = ds_open;
  347  src->close = ds_close;
  348  src->free_data = ds_free_data;
  349  src->data = icd;
  350  icd->displacement = displacement;
  351  icd->displacement_sign = displacement_sign;
  352  return src;
  353 }
  354 
  355 
  356 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag)
  357 {
  358  int i;
  359 
  360  (icd->current_age)++;
  361  if(icd->current_age>=Libisoburn_max_agE) { /* reset all ages (allow waste) */
  362    for(i = 0; i < icd->num_tiles; i++)
  363      (icd->tiles)[i]->age= 0;
  364    icd->current_age= 1;
  365  }
  366  (icd->tiles)[idx]->age= icd->current_age;
  367  return(1);
  368 }
  369 
  370