|
libisoburn 0.5.6
|
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
1.7.3