filename | src/drivers/cdrom/sector.c |
changeset | 1178:e55ec927d55d |
prev | 1121:c2d827cbdf37 |
next | 1296:30ecee61f811 |
author | Nathan Keynes <nkeynes@lxdream.org> |
date | Sat Sep 17 22:39:36 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Fix structure packing on v55 nero images (64-bit) Add basic support for track mode 16 (CDDA + subchannel data, 2448 bytes) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * low-level 'block device' for input to gdrom discs.
5 *
6 * Copyright (c) 2009 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include <sys/stat.h>
20 #include <glib/gmem.h>
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
28 #include "lxpaths.h"
29 #include "drivers/cdrom/sector.h"
30 #include "drivers/cdrom/cdrom.h"
31 #include "drivers/cdrom/ecc.h"
33 #define CHECK_READ(dev,lba,count) \
34 if( !IS_SECTOR_SOURCE(dev) ) { \
35 return CDROM_ERROR_NODISC; \
36 } else if( (dev)->size != 0 && ((lba) >= (dev)->size || (lba+block_count) > (dev)->size) ) { \
37 return CDROM_ERROR_BADREAD; \
38 }
40 /* Default read mode for each sector mode */
41 const uint32_t cdrom_sector_read_mode[] = { 0,
42 CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
43 CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
44 CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
45 CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
46 CDROM_READ_RAW, CDROM_READ_RAW,
47 CDROM_READ_CDDA|CDROM_READ_DATA};
49 /* Block size for each sector mode */
50 const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352, 2448 };
52 const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
53 "Mode 2 semiraw", "XA Raw", "Non-XA Raw", "CDDA+Subchan" };
56 /********************* Public functions *************************/
57 cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
58 {
59 CHECK_READ(device,lba,block_count);
60 return device->read_blocks(device, lba, block_count, buf);
61 }
63 cdrom_error_t sector_source_read_sectors( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
64 unsigned char *buf, size_t *length )
65 {
66 CHECK_READ(device,lba,block_count);
67 return device->read_sectors(device, lba, block_count, mode, buf, length);
68 }
70 void sector_source_ref( sector_source_t device )
71 {
72 assert( IS_SECTOR_SOURCE(device) );
73 device->ref_count++;
74 }
76 void sector_source_unref( sector_source_t device )
77 {
78 if( device == NULL )
79 return;
80 assert( IS_SECTOR_SOURCE(device) );
81 if( device->ref_count > 0 )
82 device->ref_count--;
83 if( device->ref_count == 0 )
84 device->destroy(device);
85 }
87 void sector_source_release( sector_source_t device )
88 {
89 assert( IS_SECTOR_SOURCE(device) );
90 if( device->ref_count == 0 )
91 device->destroy(device);
92 }
94 /************************** Sector mangling ***************************/
95 /*
96 * Private functions used to pack/unpack sectors, determine mode, and
97 * evaluate sector reads.
98 */
100 /** Basic data sector header structure */
101 struct cdrom_sector_header {
102 uint8_t sync[12];
103 uint8_t msf[3];
104 uint8_t mode;
105 uint8_t subhead[8]; // Mode-2 XA sectors only
106 };
108 static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
110 /* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
111 static const uint8_t legal_nonxa_fields[] =
112 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
113 TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
114 TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
115 FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
117 /* Field combinations that are legal for mode 2 form 1 or form 2 reads */
118 static const uint8_t legal_xa_fields[] =
119 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
120 TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
121 TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
122 FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
124 /**
125 * Position per sector mode of each of the fields
126 * sync, header, subheader, data, ecc.
127 *
128 */
129 static const uint32_t sector_field_positions[][6] = {
130 { 0, 0, 0, 0, 0, 0 }, /* Unknown */
131 { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
132 { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
133 { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
134 { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
135 { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
139 /**
140 * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
141 * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
142 * will return BADREADMODE, as it's impossible to tell.
143 *
144 * @param track_mode one of the CDROM_MODE* constants
145 * @param read_mode the full read mode
146 */
147 static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
148 {
149 int read_sector_type = CDROM_READ_TYPE(read_mode);
150 int read_sector_fields = CDROM_READ_FIELDS(read_mode);
152 /* Check the sector type is consistent */
153 switch( read_sector_type ) {
154 case CDROM_READ_ANY: break;
155 case CDROM_READ_CDDA:
156 if( sector_mode != SECTOR_CDDA && sector_mode != SECTOR_CDDA_SUBCHANNEL )
157 return CDROM_ERROR_BADREADMODE;
158 break;
159 case CDROM_READ_MODE1:
160 case CDROM_READ_MODE2_FORM1:
161 if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
162 return CDROM_ERROR_BADREADMODE;
163 break;
164 case CDROM_READ_MODE2_FORM2:
165 if( sector_mode != SECTOR_MODE2_FORM2 )
166 return CDROM_ERROR_BADREADMODE;
167 break;
168 case CDROM_READ_MODE2:
169 if( sector_mode != SECTOR_MODE2_FORMLESS )
170 return CDROM_ERROR_BADREADMODE;
171 break;
172 default: /* Illegal read mode */
173 return CDROM_ERROR_BADFIELD;
174 }
176 /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
177 switch( sector_mode ) {
178 case SECTOR_CDDA:
179 case SECTOR_CDDA_SUBCHANNEL:
180 return CDROM_ERROR_OK; /* Everything is OK */
181 case SECTOR_MODE2_FORM1:
182 case SECTOR_MODE2_FORM2:
183 if( !legal_xa_fields[read_sector_fields>>11] )
184 return CDROM_ERROR_BADFIELD;
185 else
186 return CDROM_ERROR_OK;
187 case SECTOR_MODE1:
188 case SECTOR_MODE2_FORMLESS:
189 if( !legal_nonxa_fields[read_sector_fields>>11] )
190 return CDROM_ERROR_BADFIELD;
191 else
192 return CDROM_ERROR_OK;
193 default:
194 return CDROM_ERROR_BADFIELD;
195 }
196 }
198 static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
199 {
200 struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
202 switch( raw_mode ) {
203 case SECTOR_SEMIRAW_MODE2: /* XA sectors */
204 case SECTOR_RAW_XA:
205 switch( header->mode ) {
206 case 1: return SECTOR_MODE1;
207 case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
208 default: return SECTOR_UNKNOWN;
209 }
210 case SECTOR_RAW_NONXA:
211 switch( header->mode ) {
212 case 1: return SECTOR_MODE1;
213 case 2: return SECTOR_MODE2_FORMLESS;
214 default: return SECTOR_UNKNOWN;
215 }
216 default:
217 return raw_mode;
218 }
219 }
221 /**
222 * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
223 * necessary.
224 */
225 static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
226 {
227 cdrom_error_t err;
229 switch( device->mode ) {
230 case SECTOR_RAW_XA:
231 case SECTOR_RAW_NONXA:
232 return device->read_blocks(device, lba, 1, buf);
233 case SECTOR_SEMIRAW_MODE2:
234 memcpy( buf, cdrom_sync_data, 12 );
235 cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
236 return device->read_blocks(device, lba, 1, &buf[16]);
237 case SECTOR_MODE1:
238 case SECTOR_MODE2_FORMLESS:
239 err = device->read_blocks(device, lba, 1, &buf[16]);
240 if( err == CDROM_ERROR_OK ) {
241 do_encode_L2( buf, device->mode, lba );
242 }
243 return err;
244 case SECTOR_MODE2_FORM1:
245 *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
246 err = device->read_blocks(device, lba, 1, &buf[24]);
247 if( err == CDROM_ERROR_OK ) {
248 do_encode_L2( buf, device->mode, lba );
249 }
250 return err;
251 case SECTOR_MODE2_FORM2:
252 *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
253 err = device->read_blocks(device, lba, 1, &buf[24]);
254 if( err == CDROM_ERROR_OK ) {
255 do_encode_L2( buf, device->mode, lba );
256 }
257 return err;
258 default:
259 abort();
260 }
261 }
263 static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
264 {
265 int start=-1,end=0;
266 int i;
268 for( i=0; i<5; i++ ) {
269 if( fields & (0x8000>>i) ) {
270 if( start == -1 )
271 start = sector_field_positions[mode][i];
272 else if( end != sector_field_positions[mode][i] )
273 return CDROM_ERROR_BADFIELD;
274 end = sector_field_positions[mode][i+1];
275 }
276 }
277 if( start == -1 ) {
278 *length = 0;
279 } else {
280 memcpy( buf, &raw_sector[start], end-start );
281 *length = end-start;
282 }
283 return CDROM_ERROR_OK;
284 }
286 cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
287 {
288 sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
289 if( sector_mode == SECTOR_UNKNOWN )
290 return CDROM_ERROR_BADREAD;
291 cdrom_error_t status = is_legal_read( sector_mode, mode );
292 if( status != CDROM_ERROR_OK )
293 return status;
294 return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
295 }
297 /**
298 * This is horribly complicated by the need to handle mapping between all possible
299 * sector modes + read modes, but fortunately most sources can just supply
300 * a single block type and not care about the details here.
301 */
302 cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
303 cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
304 unsigned char *buf, size_t *length )
305 {
306 unsigned char tmp[2448];
307 int read_sector_type = CDROM_READ_TYPE(mode);
308 int read_sector_fields = CDROM_READ_FIELDS(mode);
309 int i;
310 size_t len = 0;
311 cdrom_error_t err;
313 CHECK_READ(device, lba, count);
315 switch(device->mode) {
316 case SECTOR_CDDA:
317 if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
318 return CDROM_ERROR_BADREADMODE;
319 if( read_sector_fields != 0 ) {
320 len = block_count * CDROM_MAX_SECTOR_SIZE;
321 device->read_blocks( device, lba, block_count, buf );
322 }
323 break;
324 case SECTOR_CDDA_SUBCHANNEL:
325 if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
326 return CDROM_ERROR_BADREADMODE;
327 if( read_sector_fields != 0 ) {
328 len = block_count * 2352;
329 for( i=0; i<block_count; i++ ) {
330 device->read_blocks( device, lba+i, 1, tmp );
331 memcpy( &buf[2352*i], tmp, 2352 );
332 }
333 }
334 break;
335 case SECTOR_RAW_XA:
336 case SECTOR_RAW_NONXA:
337 case SECTOR_SEMIRAW_MODE2:
338 /* We (may) have to break the raw sector up into requested fields.
339 * Process sectors one at a time
340 */
341 for( i=0; i<block_count; i++ ) {
342 size_t tmplen;
343 err = read_raw_sector( device, lba+i, tmp );
344 if( err != CDROM_ERROR_OK )
345 return err;
346 err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
347 if( err != CDROM_ERROR_OK )
348 return err;
349 len += tmplen;
350 }
351 break;
352 default: /* Data-only blocks */
353 err = is_legal_read( device->mode, mode );
354 if( err != CDROM_ERROR_OK )
355 return err;
356 if( read_sector_fields == 0 ) { /* Read nothing */
357 if( length != NULL )
358 *length = 0;
359 return CDROM_ERROR_OK;
360 } else if( read_sector_fields == CDROM_READ_DATA ) {
361 /* Data-only */
362 if( length != NULL )
363 *length = block_count * CDROM_SECTOR_SIZE(device->mode);
364 return device->read_blocks( device, lba, block_count, buf );
365 } else if( read_sector_fields == CDROM_READ_RAW ) {
366 for( i=0; i<block_count; i++ ) {
367 err = read_raw_sector( device, lba+i, &buf[2352*i] );
368 if( err != CDROM_ERROR_OK )
369 return err;
370 }
371 len = block_count * CDROM_MAX_SECTOR_SIZE;
372 } else {
373 for( i=0; i<block_count; i++ ) {
374 size_t tmplen;
375 err = read_raw_sector( device, lba+i, tmp );
376 if( err != CDROM_ERROR_OK )
377 return err;
378 err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
379 if( err != CDROM_ERROR_OK )
380 return err;
381 len += tmplen;
382 }
383 }
384 }
385 if( length != NULL )
386 *length = len;
387 return CDROM_ERROR_OK;
389 }
391 /************************ Base implementation *************************/
393 /**
394 * Default destroy implementation - clears the tag and frees memory.
395 */
396 void default_sector_source_destroy( sector_source_t device )
397 {
398 assert( device != NULL && device->ref_count == 0 );
399 device->tag = 0;
400 g_free( device );
401 }
403 sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
404 sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
405 {
406 device->tag = SECTOR_SOURCE_TAG;
407 device->ref_count = 0;
408 device->type = type;
409 device->mode = mode;
410 device->size = size;
411 device->read_blocks = readfn;
412 device->read_sectors = default_sector_source_read_sectors;
413 if( destroyfn == NULL )
414 device->destroy = default_sector_source_destroy;
415 else
416 device->destroy = destroyfn;
417 return device;
418 }
420 /************************ Null device implementation *************************/
421 cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
422 {
423 memset( buf, 0, block_count*CDROM_SECTOR_SIZE(device->mode) );
424 return CDROM_ERROR_OK;
425 }
427 sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
428 {
429 return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
430 null_sector_source_read, default_sector_source_destroy );
431 }
433 /************************ File device implementation *************************/
434 typedef struct file_sector_source {
435 struct sector_source dev;
436 FILE *file;
437 uint32_t offset; /* offset in file where source begins */
438 sector_source_t ref; /* Parent source reference */
439 gboolean closeOnDestroy;
440 } *file_sector_source_t;
442 void file_sector_source_destroy( sector_source_t dev )
443 {
444 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
445 file_sector_source_t fdev = (file_sector_source_t)dev;
447 if( fdev->closeOnDestroy && fdev->file != NULL ) {
448 fclose( fdev->file );
449 }
450 sector_source_unref( fdev->ref );
451 fdev->file = NULL;
452 default_sector_source_destroy(dev);
453 }
455 cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
456 {
457 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
458 file_sector_source_t fdev = (file_sector_source_t)dev;
460 uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
461 uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
462 fseek( fdev->file, off, SEEK_SET );
464 size_t len = fread( buf, 1, size, fdev->file );
465 if( len == -1 ) {
466 return CDROM_ERROR_READERROR;
467 } else if( len < size ) {
468 /* zero-fill */
469 memset( buf + len, 0, size-len );
470 }
471 return CDROM_ERROR_OK;
472 }
474 sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
475 cdrom_count_t sector_count, gboolean closeOnDestroy )
476 {
477 if( sector_count == FILE_SECTOR_FULL_FILE ) {
478 unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
479 if( sector_size == 0 )
480 sector_size = 2048;
481 struct stat st;
483 if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
484 /* can't stat file? */
485 return NULL;
486 }
488 sector_count = (st.st_size + sector_size-1) / sector_size;
489 }
491 file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
492 dev->file = f;
493 dev->offset = offset;
494 dev->closeOnDestroy = closeOnDestroy;
495 dev->ref = NULL;
496 return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode, sector_count, file_sector_source_read, file_sector_source_destroy );
497 }
499 sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
500 {
501 return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
502 }
504 sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
505 cdrom_count_t sector_count )
506 {
507 int fd = open( filename, O_RDONLY|O_NONBLOCK );
508 if( fd == -1 ) {
509 return NULL;
510 }
511 FILE *f = fdopen( fd , "ro" );
512 if( f == NULL ) {
513 close(fd);
514 return NULL;
515 } else {
516 return file_sector_source_new( f, mode, offset, sector_count, TRUE );
517 }
518 }
520 sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
521 cdrom_count_t sector_count )
522 {
523 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
524 file_sector_source_t fref = (file_sector_source_t)ref;
526 sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
527 ((file_sector_source_t)source)->ref = ref;
528 sector_source_ref(ref);
529 return source;
530 }
532 FILE *file_sector_source_get_file( sector_source_t ref )
533 {
534 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
535 file_sector_source_t fref = (file_sector_source_t)ref;
536 return fref->file;
537 }
539 int file_sector_source_get_fd( sector_source_t ref )
540 {
541 return fileno(file_sector_source_get_file(ref));
542 }
544 void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
545 {
546 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
547 file_sector_source_t fref = (file_sector_source_t)ref;
548 fref->closeOnDestroy = closeOnDestroy;
549 }
551 /********************** Temporary file implementation ************************/
552 /**
553 * The tmpfile source behaves exactly like a regular file source, except that
554 * it creates a new temporary file, which is deleted on destruction or program
555 * exit. The file is initially empty, so the user will need to get the fd and
556 * write something to it before use.
557 */
559 typedef struct tmpfile_sector_source {
560 struct file_sector_source file;
561 const char *filename;
562 } *tmpfile_sector_source_t;
564 static GList *tmpfile_open_list = NULL;
565 static gboolean tmpfile_atexit_installed = 0; /* TRUE to indicate atexit hook is registered */
567 static void tmpfile_sector_close( sector_source_t dev )
568 {
569 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
570 tmpfile_sector_source_t fdev = (tmpfile_sector_source_t)dev;
572 if( fdev->file.file != NULL ) {
573 fclose( fdev->file.file );
574 fdev->file.file = NULL;
575 }
576 if( fdev->filename != NULL ) {
577 unlink(fdev->filename);
578 g_free((char *)fdev->filename);
579 fdev->filename = NULL;
580 }
581 }
584 /**
585 * atexit hook to close any open tmpfiles - make sure they're deleted.
586 */
587 static void tmpfile_atexit_hook(void)
588 {
589 GList *ptr;
590 for( ptr = tmpfile_open_list; ptr != NULL; ptr = ptr->next ) {
591 sector_source_t source = (sector_source_t)ptr->data;
592 tmpfile_sector_close(source);
593 }
594 }
597 static void tmpfile_sector_source_destroy( sector_source_t dev )
598 {
599 tmpfile_sector_close(dev);
600 tmpfile_open_list = g_list_remove(tmpfile_open_list, dev);
601 default_sector_source_destroy(dev);
602 }
604 sector_source_t tmpfile_sector_source_new( sector_mode_t mode )
605 {
606 if( !tmpfile_atexit_installed ) {
607 atexit(tmpfile_atexit_hook);
608 }
610 gchar *tmpdir = getenv("TMPDIR");
611 if( tmpdir == NULL ) {
612 tmpdir = "/tmp";
613 }
614 gchar *tempfile = get_filename_at(tmpdir, "cd.XXXXXXX");
615 int fd = mkstemp( tempfile );
616 if( fd == -1 ) {
617 g_free(tempfile);
618 return FALSE;
619 }
621 FILE *f = fdopen( fd, "w+" );
622 if( f == NULL ) {
623 close(fd);
624 unlink(tempfile);
625 g_free(tempfile);
626 return NULL;
627 }
629 tmpfile_sector_source_t dev = g_malloc0(sizeof(struct tmpfile_sector_source));
630 dev->file.file = f;
631 dev->filename = tempfile;
632 sector_source_t source = sector_source_init( &dev->file.dev, FILE_SECTOR_SOURCE, mode, 0, file_sector_source_read, tmpfile_sector_source_destroy );
633 tmpfile_open_list = g_list_append(tmpfile_open_list, source);
634 return source;
635 }
637 /************************ Memory device implementation *************************/
638 typedef struct mem_sector_source {
639 struct sector_source dev;
640 unsigned char *buffer;
641 gboolean freeOnDestroy;
642 } *mem_sector_source_t;
644 static void mem_sector_source_destroy( sector_source_t dev )
645 {
646 assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
647 mem_sector_source_t mdev = (mem_sector_source_t)dev;
649 if( mdev->freeOnDestroy ) {
650 free(mdev->buffer);
651 }
652 mdev->buffer = NULL;
653 default_sector_source_destroy(dev);
654 }
656 static cdrom_error_t mem_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
657 {
658 assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
659 mem_sector_source_t mdev = (mem_sector_source_t)dev;
661 if( (lba + block_count) >= dev->size )
662 return CDROM_ERROR_BADREAD;
663 uint32_t off = lba * CDROM_SECTOR_SIZE(dev->mode);
664 uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
666 memcpy( buf, mdev->buffer + off, size );
667 return CDROM_ERROR_OK;
668 }
670 sector_source_t mem_sector_source_new_buffer( unsigned char *buffer, sector_mode_t mode,
671 cdrom_count_t sector_count, gboolean freeOnDestroy )
672 {
673 assert( mode != SECTOR_UNKNOWN );
674 assert( buffer != NULL );
675 mem_sector_source_t dev = g_malloc(sizeof(struct mem_sector_source));
676 dev->buffer = buffer;
677 dev->freeOnDestroy = freeOnDestroy;
678 return sector_source_init( &dev->dev, MEM_SECTOR_SOURCE, mode, sector_count, mem_sector_source_read, mem_sector_source_destroy );
679 }
681 sector_source_t mem_sector_source_new( sector_mode_t mode, cdrom_count_t sector_count )
682 {
683 return mem_sector_source_new_buffer( g_malloc( sector_count * CDROM_SECTOR_SIZE(mode) ), mode,
684 sector_count, TRUE );
685 }
687 unsigned char *mem_sector_source_get_buffer( sector_source_t dev )
688 {
689 assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
690 mem_sector_source_t mdev = (mem_sector_source_t)dev;
691 return mdev->buffer;
692 }
695 /************************ Track device implementation *************************/
696 typedef struct track_sector_source {
697 struct sector_source dev;
698 cdrom_disc_t disc;
699 uint32_t start_lba;
700 } *track_sector_source_t;
702 cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
703 unsigned char *out )
704 {
705 size_t length;
706 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
707 assert( dev->mode != SECTOR_UNKNOWN );
708 track_sector_source_t tdev = (track_sector_source_t)dev;
709 return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
710 }
712 cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
713 cdrom_read_mode_t mode, unsigned char *out, size_t *length )
714 {
715 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
716 track_sector_source_t tdev = (track_sector_source_t)dev;
718 return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
719 }
721 void track_sector_source_destroy( sector_source_t dev )
722 {
723 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
724 track_sector_source_t tdev = (track_sector_source_t)dev;
725 sector_source_unref( &tdev->disc->source );
726 default_sector_source_destroy(dev);
727 }
729 sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
730 {
731 if( disc == NULL ) {
732 return NULL;
733 }
734 track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
735 dev->disc = disc;
736 dev->start_lba = lba;
737 sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
738 track_sector_source_read_blocks, track_sector_source_destroy );
739 dev->dev.read_sectors = track_sector_source_read_sectors;
740 sector_source_ref( &disc->source );
741 return &dev->dev;
742 }
.