"Fossies" - the Fresh Open Source Software Archive 
Member "libisoburn-1.5.6/libisoburn/data_source.c" (8 Jul 2020, 8813 Bytes) of package /linux/misc/libisoburn-1.5.6.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