xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

data_source.c
Go to the documentation of this file.
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 
45  char *cache_data;
46  uint32_t cache_lba;
47  uint32_t last_error_lba;
50  int age;
51 };
52 
54  struct burn_drive *drive;
56  int num_tiles;
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;
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 
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 
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:;
244  return(-1);
245 }
246 
247 
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 
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:;
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;
308  }
309  src->data= NULL;
310 }
311 
312 
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 
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;
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 
int isoburn_msgs_submit(struct isoburn *o, int error_code, char msg_text[], int os_errno, char severity[], int flag)
Definition: isoburn.c:340
int burn_read_data(struct burn_drive *d, off_t byte_address, char data[], off_t data_size, off_t *data_count, int flag)
Definition: read.c:441
IsoDataSource * isoburn_data_source_new(struct burn_drive *d, uint32_t displacement, int displacement_sign, int cache_tiles, int tile_blocks)
Definition: data_source.c:325
static int ds_close(IsoDataSource *src)
Definition: data_source.c:202
int isoburn_data_source_shutdown(IsoDataSource *src, int flag)
Definition: data_source.c:313
#define Libisoburn_max_agE
Definition: data_source.c:75
static int ds_open(IsoDataSource *src)
Definition: data_source.c:196
static int isoburn_cache_tile_destroy(struct isoburn_cache_tile **o, int flag)
Definition: data_source.c:209
static int isoburn_cached_drive_destroy(struct isoburn_cached_drive **o, int flag)
Definition: data_source.c:248
static void ds_free_data(IsoDataSource *src)
Definition: data_source.c:301
static int isoburn_cached_drive_new(struct isoburn_cached_drive **o, struct burn_drive *d, int cache_tiles, int tile_blocks, int flag)
Definition: data_source.c:268
static int ds_inc_age(struct isoburn_cached_drive *icd, int idx, int flag)
Definition: data_source.c:356
int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
Definition: data_source.c:80
static int isoburn_cache_tile_new(struct isoburn_cache_tile **o, int tile_blocks, int flag)
Definition: data_source.c:222
#define ISO_DISPLACE_ROLLOVER
Definition: libisofs.h:9081
#define ISO_DATA_SOURCE_MISHAP
Definition: libisofs.h:9271
#define ISO_NULL_POINTER
Definition: libisofs.h:8742
#define ISO_ASSERT_FAILURE
Definition: libisofs.h:8737
int(* close)(IsoDataSource *src)
Definition: libisofs.h:442
int(* open)(IsoDataSource *src)
Definition: libisofs.h:433
int(* read_block)(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
Definition: libisofs.h:459
unsigned int refcount
Definition: libisofs.h:423
void(* free_data)(IsoDataSource *src)
Definition: libisofs.h:466
uint32_t last_error_lba
Definition: data_source.c:47
uint32_t cache_lba
Definition: data_source.c:46
uint32_t last_aligned_error_lba
Definition: data_source.c:48
struct burn_drive * drive
Definition: data_source.c:54
struct isoburn_cache_tile ** tiles
Definition: data_source.c:55