00001
00002
00003
00004
00005
00006
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
00022
00023 #include "../libisofs/libisofs.h"
00024 #include "../libburn/libburn.h"
00025
00026 #endif
00027
00028
00029 #include "isoburn.h"
00030
00031
00032
00033
00034
00035
00036
00037
00038 #define Libisoburn_tile_blockS 32
00039
00040
00041
00042 #define Libisoburn_cache_tileS 32
00043
00044
00045
00046
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
00082
00083
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
00092
00093
00094
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
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;
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
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
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
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
00195 return 1;
00196 }
00197
00198 static int ds_close(IsoDataSource *src)
00199 {
00200
00201 return 1;
00202 }
00203
00204 static void ds_free_data(IsoDataSource *src)
00205 {
00206 ;
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) {
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