filename | src/drivers/cdrom/sector.c |
changeset | 1121:c2d827cbdf37 |
prev | 1108:305ef2082079 |
next | 1178:e55ec927d55d |
author | nkeynes |
date | Fri Sep 10 21:42:41 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Close tmpfiles at exit rather than destroying them, to avoid triggering the assertion due to the source still being referenced |
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 };
48 /* Block size for each sector mode */
49 const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352 };
51 const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
52 "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
55 /********************* Public functions *************************/
56 cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
57 {
58 CHECK_READ(device,lba,block_count);
59 return device->read_blocks(device, lba, block_count, buf);
60 }
62 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,
63 unsigned char *buf, size_t *length )
64 {
65 CHECK_READ(device,lba,block_count);
66 return device->read_sectors(device, lba, block_count, mode, buf, length);
67 }
69 void sector_source_ref( sector_source_t device )
70 {
71 assert( IS_SECTOR_SOURCE(device) );
72 device->ref_count++;
73 }
75 void sector_source_unref( sector_source_t device )
76 {
77 if( device == NULL )
78 return;
79 assert( IS_SECTOR_SOURCE(device) );
80 if( device->ref_count > 0 )
81 device->ref_count--;
82 if( device->ref_count == 0 )
83 device->destroy(device);
84 }
86 void sector_source_release( sector_source_t device )
87 {
88 assert( IS_SECTOR_SOURCE(device) );
89 if( device->ref_count == 0 )
90 device->destroy(device);
91 }
93 /************************** Sector mangling ***************************/
94 /*
95 * Private functions used to pack/unpack sectors, determine mode, and
96 * evaluate sector reads.
97 */
99 /** Basic data sector header structure */
100 struct cdrom_sector_header {
101 uint8_t sync[12];
102 uint8_t msf[3];
103 uint8_t mode;
104 uint8_t subhead[8]; // Mode-2 XA sectors only
105 };
107 static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
109 /* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
110 static const uint8_t legal_nonxa_fields[] =
111 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
112 TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
113 TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
114 FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
116 /* Field combinations that are legal for mode 2 form 1 or form 2 reads */
117 static const uint8_t legal_xa_fields[] =
118 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
119 TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
120 TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
121 FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
123 /**
124 * Position per sector mode of each of the fields
125 * sync, header, subheader, data, ecc.
126 *
127 */
128 static const uint32_t sector_field_positions[][6] = {
129 { 0, 0, 0, 0, 0, 0 }, /* Unknown */
130 { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
131 { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
132 { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
133 { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
134 { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
138 /**
139 * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
140 * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
141 * will return BADREADMODE, as it's impossible to tell.
142 *
143 * @param track_mode one of the CDROM_MODE* constants
144 * @param read_mode the full read mode
145 */
146 static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
147 {
148 int read_sector_type = CDROM_READ_TYPE(read_mode);
149 int read_sector_fields = CDROM_READ_FIELDS(read_mode);
151 /* Check the sector type is consistent */
152 switch( read_sector_type ) {
153 case CDROM_READ_ANY: break;
154 case CDROM_READ_CDDA:
155 if( sector_mode != SECTOR_CDDA )
156 return CDROM_ERROR_BADREADMODE;
157 break;
158 case CDROM_READ_MODE1:
159 case CDROM_READ_MODE2_FORM1:
160 if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
161 return CDROM_ERROR_BADREADMODE;
162 break;
163 case CDROM_READ_MODE2_FORM2:
164 if( sector_mode != SECTOR_MODE2_FORM2 )
165 return CDROM_ERROR_BADREADMODE;
166 break;
167 case CDROM_READ_MODE2:
168 if( sector_mode != SECTOR_MODE2_FORMLESS )
169 return CDROM_ERROR_BADREADMODE;
170 break;
171 default: /* Illegal read mode */
172 return CDROM_ERROR_BADFIELD;
173 }
175 /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
176 switch( sector_mode ) {
177 case SECTOR_CDDA:
178 return CDROM_ERROR_OK; /* Everything is OK */
179 case SECTOR_MODE2_FORM1:
180 case SECTOR_MODE2_FORM2:
181 if( !legal_xa_fields[read_sector_fields>>11] )
182 return CDROM_ERROR_BADFIELD;
183 else
184 return CDROM_ERROR_OK;
185 case SECTOR_MODE1:
186 case SECTOR_MODE2_FORMLESS:
187 if( !legal_nonxa_fields[read_sector_fields>>11] )
188 return CDROM_ERROR_BADFIELD;
189 else
190 return CDROM_ERROR_OK;
191 default:
192 return CDROM_ERROR_BADFIELD;
193 }
194 }
196 static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
197 {
198 struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
200 switch( raw_mode ) {
201 case SECTOR_SEMIRAW_MODE2: /* XA sectors */
202 case SECTOR_RAW_XA:
203 switch( header->mode ) {
204 case 1: return SECTOR_MODE1;
205 case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
206 default: return SECTOR_UNKNOWN;
207 }
208 case SECTOR_RAW_NONXA:
209 switch( header->mode ) {
210 case 1: return SECTOR_MODE1;
211 case 2: return SECTOR_MODE2_FORMLESS;
212 default: return SECTOR_UNKNOWN;
213 }
214 default:
215 return raw_mode;
216 }
217 }
219 /**
220 * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
221 * necessary.
222 */
223 static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
224 {
225 cdrom_error_t err;
227 switch( device->mode ) {
228 case SECTOR_RAW_XA:
229 case SECTOR_RAW_NONXA:
230 return device->read_blocks(device, lba, 1, buf);
231 case SECTOR_SEMIRAW_MODE2:
232 memcpy( buf, cdrom_sync_data, 12 );
233 cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
234 return device->read_blocks(device, lba, 1, &buf[16]);
235 case SECTOR_MODE1:
236 case SECTOR_MODE2_FORMLESS:
237 err = device->read_blocks(device, lba, 1, &buf[16]);
238 if( err == CDROM_ERROR_OK ) {
239 do_encode_L2( buf, device->mode, lba );
240 }
241 return err;
242 case SECTOR_MODE2_FORM1:
243 *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
244 err = device->read_blocks(device, lba, 1, &buf[24]);
245 if( err == CDROM_ERROR_OK ) {
246 do_encode_L2( buf, device->mode, lba );
247 }
248 return err;
249 case SECTOR_MODE2_FORM2:
250 *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
251 err = device->read_blocks(device, lba, 1, &buf[24]);
252 if( err == CDROM_ERROR_OK ) {
253 do_encode_L2( buf, device->mode, lba );
254 }
255 return err;
256 default:
257 abort();
258 }
259 }
261 static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
262 {
263 int start=-1,end=0;
264 int i;
266 for( i=0; i<5; i++ ) {
267 if( fields & (0x8000>>i) ) {
268 if( start == -1 )
269 start = sector_field_positions[mode][i];
270 else if( end != sector_field_positions[mode][i] )
271 return CDROM_ERROR_BADFIELD;
272 end = sector_field_positions[mode][i+1];
273 }
274 }
275 if( start == -1 ) {
276 *length = 0;
277 } else {
278 memcpy( buf, &raw_sector[start], end-start );
279 *length = end-start;
280 }
281 return CDROM_ERROR_OK;
282 }
284 cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
285 {
286 sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
287 if( sector_mode == SECTOR_UNKNOWN )
288 return CDROM_ERROR_BADREAD;
289 cdrom_error_t status = is_legal_read( sector_mode, mode );
290 if( status != CDROM_ERROR_OK )
291 return status;
292 return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
293 }
295 /**
296 * This is horribly complicated by the need to handle mapping between all possible
297 * sector modes + read modes, but fortunately most sources can just supply
298 * a single block type and not care about the details here.
299 */
300 cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
301 cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
302 unsigned char *buf, size_t *length )
303 {
304 unsigned char tmp[CDROM_MAX_SECTOR_SIZE];
305 int read_sector_type = CDROM_READ_TYPE(mode);
306 int read_sector_fields = CDROM_READ_FIELDS(mode);
307 int i;
308 size_t len = 0;
309 cdrom_error_t err;
311 CHECK_READ(device, lba, count);
313 switch(device->mode) {
314 case SECTOR_CDDA:
315 if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
316 return CDROM_ERROR_BADREADMODE;
317 if( read_sector_fields != 0 ) {
318 len = block_count * CDROM_MAX_SECTOR_SIZE;
319 device->read_blocks( device, lba, block_count, buf );
320 }
321 break;
322 case SECTOR_RAW_XA:
323 case SECTOR_RAW_NONXA:
324 case SECTOR_SEMIRAW_MODE2:
325 /* We (may) have to break the raw sector up into requested fields.
326 * Process sectors one at a time
327 */
328 for( i=0; i<block_count; i++ ) {
329 size_t tmplen;
330 err = read_raw_sector( device, lba+i, tmp );
331 if( err != CDROM_ERROR_OK )
332 return err;
333 err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
334 if( err != CDROM_ERROR_OK )
335 return err;
336 len += tmplen;
337 }
338 break;
339 default: /* Data-only blocks */
340 err = is_legal_read( device->mode, mode );
341 if( err != CDROM_ERROR_OK )
342 return err;
343 if( read_sector_fields == 0 ) { /* Read nothing */
344 if( length != NULL )
345 *length = 0;
346 return CDROM_ERROR_OK;
347 } else if( read_sector_fields == CDROM_READ_DATA ) {
348 /* Data-only */
349 if( length != NULL )
350 *length = block_count * CDROM_SECTOR_SIZE(device->mode);
351 return device->read_blocks( device, lba, block_count, buf );
352 } else if( read_sector_fields == CDROM_READ_RAW ) {
353 for( i=0; i<block_count; i++ ) {
354 err = read_raw_sector( device, lba+i, &buf[2352*i] );
355 if( err != CDROM_ERROR_OK )
356 return err;
357 }
358 len = block_count * CDROM_MAX_SECTOR_SIZE;
359 } else {
360 for( i=0; i<block_count; i++ ) {
361 size_t tmplen;
362 err = read_raw_sector( device, lba+i, tmp );
363 if( err != CDROM_ERROR_OK )
364 return err;
365 err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
366 if( err != CDROM_ERROR_OK )
367 return err;
368 len += tmplen;
369 }
370 }
371 }
372 if( length != NULL )
373 *length = len;
374 return CDROM_ERROR_OK;
376 }
378 /************************ Base implementation *************************/
380 /**
381 * Default destroy implementation - clears the tag and frees memory.
382 */
383 void default_sector_source_destroy( sector_source_t device )
384 {
385 assert( device != NULL && device->ref_count == 0 );
386 device->tag = 0;
387 g_free( device );
388 }
390 sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
391 sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
392 {
393 device->tag = SECTOR_SOURCE_TAG;
394 device->ref_count = 0;
395 device->type = type;
396 device->mode = mode;
397 device->size = size;
398 device->read_blocks = readfn;
399 device->read_sectors = default_sector_source_read_sectors;
400 if( destroyfn == NULL )
401 device->destroy = default_sector_source_destroy;
402 else
403 device->destroy = destroyfn;
404 return device;
405 }
407 /************************ Null device implementation *************************/
408 cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
409 {
410 memset( buf, 0, block_count*CDROM_SECTOR_SIZE(device->mode) );
411 return CDROM_ERROR_OK;
412 }
414 sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
415 {
416 return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
417 null_sector_source_read, default_sector_source_destroy );
418 }
420 /************************ File device implementation *************************/
421 typedef struct file_sector_source {
422 struct sector_source dev;
423 FILE *file;
424 uint32_t offset; /* offset in file where source begins */
425 sector_source_t ref; /* Parent source reference */
426 gboolean closeOnDestroy;
427 } *file_sector_source_t;
429 void file_sector_source_destroy( sector_source_t dev )
430 {
431 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
432 file_sector_source_t fdev = (file_sector_source_t)dev;
434 if( fdev->closeOnDestroy && fdev->file != NULL ) {
435 fclose( fdev->file );
436 }
437 sector_source_unref( fdev->ref );
438 fdev->file = NULL;
439 default_sector_source_destroy(dev);
440 }
442 cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
443 {
444 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
445 file_sector_source_t fdev = (file_sector_source_t)dev;
447 uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
448 uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
449 fseek( fdev->file, off, SEEK_SET );
451 size_t len = fread( buf, 1, size, fdev->file );
452 if( len == -1 ) {
453 return CDROM_ERROR_READERROR;
454 } else if( len < size ) {
455 /* zero-fill */
456 memset( buf + len, 0, size-len );
457 }
458 return CDROM_ERROR_OK;
459 }
461 sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
462 cdrom_count_t sector_count, gboolean closeOnDestroy )
463 {
464 if( sector_count == FILE_SECTOR_FULL_FILE ) {
465 unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
466 if( sector_size == 0 )
467 sector_size = 2048;
468 struct stat st;
470 if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
471 /* can't stat file? */
472 return NULL;
473 }
475 sector_count = (st.st_size + sector_size-1) / sector_size;
476 }
478 file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
479 dev->file = f;
480 dev->offset = offset;
481 dev->closeOnDestroy = closeOnDestroy;
482 dev->ref = NULL;
483 return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode, sector_count, file_sector_source_read, file_sector_source_destroy );
484 }
486 sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
487 {
488 return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
489 }
491 sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
492 cdrom_count_t sector_count )
493 {
494 int fd = open( filename, O_RDONLY|O_NONBLOCK );
495 if( fd == -1 ) {
496 return NULL;
497 }
498 FILE *f = fdopen( fd , "ro" );
499 if( f == NULL ) {
500 close(fd);
501 return NULL;
502 } else {
503 return file_sector_source_new( f, mode, offset, sector_count, TRUE );
504 }
505 }
507 sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
508 cdrom_count_t sector_count )
509 {
510 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
511 file_sector_source_t fref = (file_sector_source_t)ref;
513 sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
514 ((file_sector_source_t)source)->ref = ref;
515 sector_source_ref(ref);
516 return source;
517 }
519 FILE *file_sector_source_get_file( sector_source_t ref )
520 {
521 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
522 file_sector_source_t fref = (file_sector_source_t)ref;
523 return fref->file;
524 }
526 int file_sector_source_get_fd( sector_source_t ref )
527 {
528 return fileno(file_sector_source_get_file(ref));
529 }
531 void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
532 {
533 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
534 file_sector_source_t fref = (file_sector_source_t)ref;
535 fref->closeOnDestroy = closeOnDestroy;
536 }
538 /********************** Temporary file implementation ************************/
539 /**
540 * The tmpfile source behaves exactly like a regular file source, except that
541 * it creates a new temporary file, which is deleted on destruction or program
542 * exit. The file is initially empty, so the user will need to get the fd and
543 * write something to it before use.
544 */
546 typedef struct tmpfile_sector_source {
547 struct file_sector_source file;
548 const char *filename;
549 } *tmpfile_sector_source_t;
551 static GList *tmpfile_open_list = NULL;
552 static gboolean tmpfile_atexit_installed = 0; /* TRUE to indicate atexit hook is registered */
554 static void tmpfile_sector_close( sector_source_t dev )
555 {
556 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
557 tmpfile_sector_source_t fdev = (tmpfile_sector_source_t)dev;
559 if( fdev->file.file != NULL ) {
560 fclose( fdev->file.file );
561 fdev->file.file = NULL;
562 }
563 if( fdev->filename != NULL ) {
564 unlink(fdev->filename);
565 g_free((char *)fdev->filename);
566 fdev->filename = NULL;
567 }
568 }
571 /**
572 * atexit hook to close any open tmpfiles - make sure they're deleted.
573 */
574 static void tmpfile_atexit_hook(void)
575 {
576 GList *ptr;
577 for( ptr = tmpfile_open_list; ptr != NULL; ptr = ptr->next ) {
578 sector_source_t source = (sector_source_t)ptr->data;
579 tmpfile_sector_close(source);
580 }
581 }
584 static void tmpfile_sector_source_destroy( sector_source_t dev )
585 {
586 tmpfile_sector_close(dev);
587 tmpfile_open_list = g_list_remove(tmpfile_open_list, dev);
588 default_sector_source_destroy(dev);
589 }
591 sector_source_t tmpfile_sector_source_new( sector_mode_t mode )
592 {
593 if( !tmpfile_atexit_installed ) {
594 atexit(tmpfile_atexit_hook);
595 }
597 gchar *tmpdir = getenv("TMPDIR");
598 if( tmpdir == NULL ) {
599 tmpdir = "/tmp";
600 }
601 gchar *tempfile = get_filename_at(tmpdir, "cd.XXXXXXX");
602 int fd = mkstemp( tempfile );
603 if( fd == -1 ) {
604 g_free(tempfile);
605 return FALSE;
606 }
608 FILE *f = fdopen( fd, "w+" );
609 if( f == NULL ) {
610 close(fd);
611 unlink(tempfile);
612 g_free(tempfile);
613 return NULL;
614 }
616 tmpfile_sector_source_t dev = g_malloc0(sizeof(struct tmpfile_sector_source));
617 dev->file.file = f;
618 dev->filename = tempfile;
619 sector_source_t source = sector_source_init( &dev->file.dev, FILE_SECTOR_SOURCE, mode, 0, file_sector_source_read, tmpfile_sector_source_destroy );
620 tmpfile_open_list = g_list_append(tmpfile_open_list, source);
621 return source;
622 }
624 /************************ Memory device implementation *************************/
625 typedef struct mem_sector_source {
626 struct sector_source dev;
627 unsigned char *buffer;
628 gboolean freeOnDestroy;
629 } *mem_sector_source_t;
631 static void mem_sector_source_destroy( sector_source_t dev )
632 {
633 assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
634 mem_sector_source_t mdev = (mem_sector_source_t)dev;
636 if( mdev->freeOnDestroy ) {
637 free(mdev->buffer);
638 }
639 mdev->buffer = NULL;
640 default_sector_source_destroy(dev);
641 }
643 static cdrom_error_t mem_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
644 {
645 assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
646 mem_sector_source_t mdev = (mem_sector_source_t)dev;
648 if( (lba + block_count) >= dev->size )
649 return CDROM_ERROR_BADREAD;
650 uint32_t off = lba * CDROM_SECTOR_SIZE(dev->mode);
651 uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
653 memcpy( buf, mdev->buffer + off, size );
654 return CDROM_ERROR_OK;
655 }
657 sector_source_t mem_sector_source_new_buffer( unsigned char *buffer, sector_mode_t mode,
658 cdrom_count_t sector_count, gboolean freeOnDestroy )
659 {
660 assert( mode != SECTOR_UNKNOWN );
661 assert( buffer != NULL );
662 mem_sector_source_t dev = g_malloc(sizeof(struct mem_sector_source));
663 dev->buffer = buffer;
664 dev->freeOnDestroy = freeOnDestroy;
665 return sector_source_init( &dev->dev, MEM_SECTOR_SOURCE, mode, sector_count, mem_sector_source_read, mem_sector_source_destroy );
666 }
668 sector_source_t mem_sector_source_new( sector_mode_t mode, cdrom_count_t sector_count )
669 {
670 return mem_sector_source_new_buffer( g_malloc( sector_count * CDROM_SECTOR_SIZE(mode) ), mode,
671 sector_count, TRUE );
672 }
674 unsigned char *mem_sector_source_get_buffer( sector_source_t dev )
675 {
676 assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
677 mem_sector_source_t mdev = (mem_sector_source_t)dev;
678 return mdev->buffer;
679 }
682 /************************ Track device implementation *************************/
683 typedef struct track_sector_source {
684 struct sector_source dev;
685 cdrom_disc_t disc;
686 uint32_t start_lba;
687 } *track_sector_source_t;
689 cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
690 unsigned char *out )
691 {
692 size_t length;
693 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
694 assert( dev->mode != SECTOR_UNKNOWN );
695 track_sector_source_t tdev = (track_sector_source_t)dev;
696 return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
697 }
699 cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
700 cdrom_read_mode_t mode, unsigned char *out, size_t *length )
701 {
702 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
703 track_sector_source_t tdev = (track_sector_source_t)dev;
705 return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
706 }
708 void track_sector_source_destroy( sector_source_t dev )
709 {
710 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
711 track_sector_source_t tdev = (track_sector_source_t)dev;
712 sector_source_unref( &tdev->disc->source );
713 default_sector_source_destroy(dev);
714 }
716 sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
717 {
718 if( disc == NULL ) {
719 return NULL;
720 }
721 track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
722 dev->disc = disc;
723 dev->start_lba = lba;
724 sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
725 track_sector_source_read_blocks, track_sector_source_destroy );
726 dev->dev.read_sectors = track_sector_source_read_sectors;
727 sector_source_ref( &disc->source );
728 return &dev->dev;
729 }
.