00001
00002
00003
00004
00005
00006
00007
00008 #include <stdlib.h>
00009 #include <string.h>
00010
00011 #include <stdio.h>
00012
00013
00014 #ifndef Xorriso_standalonE
00015
00016 #include <libburn/libburn.h>
00017
00018 #include <libisofs/libisofs.h>
00019
00020 #else
00021
00022 #include "../libisofs/libisofs.h"
00023 #include "../libburn/libburn.h"
00024
00025 #endif
00026
00027
00028 #include "isoburn.h"
00029
00030
00031
00032
00033
00034
00035
00036
00037 #define Libisoburn_tile_blockS 32
00038
00039
00040
00041 #define Libisoburn_cache_tileS 32
00042
00043
00044
00045
00046
00047
00048
00049 struct isoburn_cache_tile {
00050 char cache_data[Libisoburn_tile_blockS * 2048];
00051 uint32_t cache_lba;
00052 uint32_t last_error_lba;
00053 uint32_t last_aligned_error_lba;
00054 int cache_hits;
00055 int age;
00056 };
00057
00058 struct isoburn_cached_drive {
00059 struct burn_drive *drive;
00060 struct isoburn_cache_tile tiles[Libisoburn_cache_tileS];
00061 int current_age;
00062 };
00063
00064 #define Libisoburn_max_agE 2000000000
00065
00066 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag);
00067
00068
00069 int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
00070 {
00071 int ret, i, oldest, oldest_age;
00072 struct burn_drive *d;
00073 off_t count;
00074 uint32_t aligned_lba;
00075 char msg[80];
00076 struct isoburn_cache_tile *tiles;
00077 struct isoburn_cached_drive *icd;
00078
00079 if(src == NULL || buffer == NULL)
00080
00081
00082
00083
00084 return ISO_NULL_POINTER;
00085
00086 icd = (struct isoburn_cached_drive *) src->data;
00087 d = (struct burn_drive*) icd->drive;
00088
00089 if(d == NULL) {
00090
00091
00092
00093
00094
00095 isoburn_msgs_submit(NULL, 0x00060000,
00096 "Programming error: Drive released while libisofs still attempts to read",
00097 0, "FATAL", 0);
00098 return ISO_ASSERT_FAILURE;
00099 }
00100
00101 tiles = (struct isoburn_cache_tile *) icd->tiles;
00102
00103 aligned_lba= lba & ~(Libisoburn_tile_blockS - 1);
00104
00105 for(i=0; i<Libisoburn_cache_tileS; i++) {
00106 if(aligned_lba == tiles[i].cache_lba && tiles[i].cache_lba != 0xffffffff) {
00107 (tiles[i].cache_hits)++;
00108 memcpy(buffer, tiles[i].cache_data + (lba - aligned_lba) * 2048, 2048);
00109 count= 2048;
00110 ds_inc_age(icd, i, 0);
00111 return 1;
00112 }
00113 }
00114
00115
00116 oldest_age= Libisoburn_max_agE;
00117 oldest= 0;
00118 for(i= 0; i<Libisoburn_cache_tileS; i++) {
00119 if(tiles[i].cache_lba == 0xffffffff) {
00120 oldest= i;
00121 break;
00122 }
00123 if(tiles[i].age<oldest_age) {
00124 oldest_age= tiles[i].age;
00125 oldest= i;
00126 }
00127 }
00128
00129 tiles[oldest].cache_lba= 0xffffffff;
00130 if(tiles[oldest].last_aligned_error_lba == aligned_lba) {
00131 ret = 0;
00132 } else {
00133 ret = burn_read_data(d, (off_t) aligned_lba * (off_t) 2048,
00134 (char *) tiles[oldest].cache_data,
00135 Libisoburn_tile_blockS * 2048, &count, 2);
00136 }
00137 if (ret <= 0 ) {
00138 tiles[oldest].last_aligned_error_lba = aligned_lba;
00139
00140
00141 if(tiles[oldest].last_error_lba == lba)
00142 ret = 0;
00143 else
00144 ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer,
00145 2048, &count, 0);
00146 if (ret > 0)
00147 return 1;
00148 tiles[oldest].last_error_lba = lba;
00149
00150 #ifdef ISO_DATA_SOURCE_MISHAP
00151 ret= ISO_DATA_SOURCE_MISHAP;
00152 #else
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 ret= ISO_FILE_CANT_WRITE;
00166 #endif
00167
00168 if(ret >= 0)
00169 ret = -1;
00170 sprintf(msg, "ds_read_block(%lu) returns %d", (unsigned long) lba, ret);
00171 isoburn_msgs_submit(NULL, 0x00060000, msg, 0, "DEBUG", 0);
00172 return ret;
00173 }
00174
00175 #ifdef Libisoburn_read_cache_reporT
00176 fprintf(stderr, "Tile %2.2d : After %3d hits, new load from %8x , count= %d\n",
00177 oldest, tiles[oldest].cache_hits, aligned_lba, (int) count);
00178 #endif
00179
00180 tiles[oldest].cache_lba= aligned_lba;
00181 tiles[oldest].cache_hits= 1;
00182 ds_inc_age(icd, oldest, 0);
00183
00184 memcpy(buffer, tiles[oldest].cache_data + (lba - aligned_lba) * 2048, 2048);
00185 count= 2048;
00186
00187 return 1;
00188 }
00189
00190
00191 static int ds_open(IsoDataSource *src)
00192 {
00193
00194 return 1;
00195 }
00196
00197 static int ds_close(IsoDataSource *src)
00198 {
00199
00200 return 1;
00201 }
00202
00203 static void ds_free_data(IsoDataSource *src)
00204 {
00205 ;
00206 if(src->data != NULL)
00207 free(src->data);
00208 src->data= NULL;
00209 }
00210
00211
00212 int isoburn_data_source_shutdown(IsoDataSource *src, int flag)
00213 {
00214 struct isoburn_cached_drive *icd;
00215
00216 if(src==NULL)
00217 return(0);
00218 icd= (struct isoburn_cached_drive *) src->data;
00219 icd->drive= NULL;
00220 return(1);
00221 }
00222
00223
00224 IsoDataSource *isoburn_data_source_new(struct burn_drive *d)
00225 {
00226 IsoDataSource *ret;
00227 struct isoburn_cached_drive *icd= NULL;
00228 int i;
00229
00230 if (d==NULL)
00231 return NULL;
00232 ret = malloc(sizeof(IsoDataSource));
00233 icd = calloc(1,sizeof(struct isoburn_cached_drive));
00234 if (ret == NULL || icd == NULL)
00235 return NULL;
00236 ret->refcount = 1;
00237 ret->read_block = ds_read_block;
00238 ret->open = ds_open;
00239 ret->close = ds_close;
00240 ret->free_data = ds_free_data;
00241 ret->data = icd;
00242 icd->drive = d;
00243 icd->current_age= 0;
00244 for(i= 0; i<Libisoburn_cache_tileS; i++) {
00245 icd->tiles[i].cache_lba = 0xffffffff;
00246 icd->tiles[i].cache_hits = 0;
00247 icd->tiles[i].last_error_lba = 0xffffffff;
00248 icd->tiles[i].last_aligned_error_lba = 0xffffffff;
00249 icd->tiles[i].age= 0;
00250 }
00251 return ret;
00252 }
00253
00254
00255 static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag)
00256 {
00257 int i;
00258
00259 (icd->current_age)++;
00260 if(icd->current_age>=Libisoburn_max_agE) {
00261 for(i= 0; i<Libisoburn_cache_tileS; i++)
00262 (icd->tiles)[i].age= 0;
00263 icd->current_age= 1;
00264 }
00265 (icd->tiles)[idx].age= icd->current_age;
00266 return(1);
00267 }
00268
00269