/* data source for libisoburn. Copyright 2007 Vreixo Formoso Lopes */ #include #include #include #ifndef Xorriso_standalonE #include #include #else /* ! Xorriso_standalonE */ #include "../libisofs/libisofs.h" #include "../libburn/libburn.h" #endif /* Xorriso_standalonE */ #include "isoburn.h" /* Powers of 2 only ! Less than 16 makes not much sense. */ #define Libisoburn_tile_blockS 32 /* Undef to get to older single tile version */ #define Libisoburn_cache_tileS 32 /* Debugging only: This reports cache loads on stderr. #define Libisoburn_read_cache_reporT 1 */ /* Cached reading of image tree data */ #ifdef Libisoburn_cache_tileS /* Multi tile: 32 * 64 kB */ struct isoburn_cache_tile { char cache_data[Libisoburn_tile_blockS * 2048]; uint32_t cache_lba; uint32_t last_error_lba; uint32_t last_aligned_error_lba; int cache_hits; int age; }; struct isoburn_cached_drive { struct burn_drive *drive; struct isoburn_cache_tile tiles[Libisoburn_cache_tileS]; int current_age; }; #define Libisoburn_max_agE 2000000 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag); int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) { int ret, i, oldest, oldest_age; struct burn_drive *d; off_t count; uint32_t aligned_lba; char msg[80]; struct isoburn_cache_tile *tiles; struct isoburn_cached_drive *icd; if(src == NULL || buffer == NULL) return -1; icd = (struct isoburn_cached_drive *) src->data; d = (struct burn_drive*) icd->drive; tiles = (struct isoburn_cache_tile *) icd->tiles; aligned_lba= lba & ~(Libisoburn_tile_blockS - 1); for(i=0; i 0) return 1; tiles[oldest].last_error_lba = lba; sprintf(msg, "ds_read_block(%lu) returns -1", (unsigned long) lba); burn_msgs_submit(0x00060000, msg, 0, "DEBUG", NULL); return -1; } #ifdef Libisoburn_read_cache_reporT fprintf(stderr, "Tile %2.2d : After %3d hits, new load from %8x , count= %d\n", oldest, tiles[oldest].cache_hits, aligned_lba, (int) count); #endif tiles[oldest].cache_lba= aligned_lba; tiles[oldest].cache_hits= 1; ds_inc_age(icd, oldest, 0); memcpy(buffer, tiles[oldest].cache_data + (lba - aligned_lba) * 2048, 2048); count= 2048; return 1; } static int ds_open(IsoDataSource *src) { /* nothing to do, device is always grabbed */ return 1; } static int ds_close(IsoDataSource *src) { /* nothing to do, device is always grabbed */ return 1; } static void ds_free_data(IsoDataSource *src) { /* nothing to do */; if(src->data != NULL) free(src->data); src->data= NULL; } IsoDataSource *isoburn_data_source_new(struct burn_drive *d) { IsoDataSource *ret; struct isoburn_cached_drive *icd= NULL; int i; if (d==NULL) return NULL; ret = malloc(sizeof(IsoDataSource)); icd = calloc(1,sizeof(struct isoburn_cached_drive)); if (ret == NULL || icd == NULL) return NULL; ret->refcount = 1; ret->read_block = ds_read_block; ret->open = ds_open; ret->close = ds_close; ret->free_data = ds_free_data; ret->data = icd; icd->drive = d; icd->current_age= 0; for(i= 0; itiles[i].cache_lba = 0xffffffff; icd->tiles[i].cache_hits = 0; icd->tiles[i].last_error_lba = 0xffffffff; icd->tiles[i].last_aligned_error_lba = 0xffffffff; icd->tiles[i].age= 0; } return ret; } static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag) { int i; (icd->current_age)++; if(icd->current_age>=Libisoburn_max_agE) { /* reset all ages (allow waste) */ for(i= 0; itiles)[i].age= 0; icd->current_age= 1; } (icd->tiles)[idx].age= icd->current_age; return(1); } #else /* Libisoburn_cache_tileS */ /* Single tile 128 kB */ struct isoburn_cached_drive { struct burn_drive *drive; char cache_data[Libisoburn_tile_blockS * 2048]; uint32_t cache_lba; uint32_t last_error_lba; uint32_t last_aligned_error_lba; int cache_hits; }; /* Debugging only: This reports cache loads on stderr. #define Libisoburn_read_cache_reporT 1 */ int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer) { int ret; struct burn_drive *d; off_t count; uint32_t aligned_lba; char msg[80]; struct isoburn_cached_drive *icd; if(src == NULL || buffer == NULL) return -1; icd = (struct isoburn_cached_drive *) src->data; d = (struct burn_drive*) icd->drive; aligned_lba= lba & ~(Libisoburn_tile_blockS - 1); if(aligned_lba == icd->cache_lba && icd->cache_lba != 0xffffffff) { (icd->cache_hits)++; memcpy(buffer, icd->cache_data + (lba - aligned_lba) * 2048, 2048); count= 2048; return 1; } icd->cache_lba= 0xffffffff; /* invalidate cache */ if(icd->last_aligned_error_lba == aligned_lba) { ret = 0; } else { ret = burn_read_data(d, (off_t) aligned_lba * (off_t) 2048, (char *) icd->cache_data, Libisoburn_tile_blockS * 2048, &count, 0); } if (ret <= 0 ) { icd->last_aligned_error_lba = aligned_lba; /* Read-ahead failure ? Try to read 2048 directly. */ if(icd->last_error_lba == lba) ret = 0; else ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer, 2048, &count, 0); if (ret > 0) return 1; icd->last_error_lba = lba; sprintf(msg, "ds_read_block(%lu) returns -1", (unsigned long) lba); burn_msgs_submit(0x00060000, msg, 0, "DEBUG", NULL); return -1; } #ifdef Libisoburn_read_cache_reporT fprintf(stderr, "After %3d hits, new load from %8x , count= %d\n", icd->cache_hits, aligned_lba, (int) count); #endif icd->cache_lba= aligned_lba; icd->cache_hits= 1; memcpy(buffer, icd->cache_data + (lba - aligned_lba) * 2048, 2048); count= 2048; return 1; } static int ds_open(IsoDataSource *src) { /* nothing to do, device is always grabbed */ return 1; } static int ds_close(IsoDataSource *src) { /* nothing to do, device is always grabbed */ return 1; } static void ds_free_data(IsoDataSource *src) { /* nothing to do */; if(src->data != NULL) free(src->data); src->data= NULL; } IsoDataSource * isoburn_data_source_new(struct burn_drive *d) { IsoDataSource *ret; struct isoburn_cached_drive *icd= NULL; if (d==NULL) return NULL; ret = malloc(sizeof(IsoDataSource)); icd = calloc(1,sizeof(struct isoburn_cached_drive)); if (ret == NULL || icd == NULL) return NULL; ret->refcount = 1; ret->read_block = ds_read_block; ret->open = ds_open; ret->close = ds_close; ret->free_data = ds_free_data; ret->data = icd; icd->drive = d; icd->cache_lba = 0xffffffff; icd->cache_hits = 0; icd->last_error_lba = 0xffffffff; icd->last_aligned_error_lba = 0xffffffff; return ret; } #endif /* ! Libisoburn_cache_tileS */