1 /*
2 Copyright (C) 2004-2009, 2011-2013, 2017
3 Rocky Bernstein <rocky@gnu.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /* This file contains generic implementations of device-driver routines.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 # define __CDIO_CONFIG_H__ 1
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #include <fcntl.h>
37 #include <limits.h>
38
39 #ifdef HAVE_SYS_STAT_H
40 #include <sys/stat.h>
41 #endif
42 #ifdef HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45
46 #include <cdio/sector.h>
47 #include <cdio/util.h>
48 #include <cdio/logging.h>
49 #include "cdio_assert.h"
50 #include "cdio_private.h"
51 #include "_cdio_stdio.h"
52 #include "filemode.h"
53
54 #ifndef PATH_MAX
55 #define PATH_MAX 4096
56 #endif
57
58 /* If available and LFS is enabled, try to use lseek64 */
59 #if defined(HAVE_LSEEK64) && defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
60 #if defined(_MSC_VER)
61 #include <io.h>
62 #endif
63 #define CDIO_LSEEK lseek64
64 #else
65 #define CDIO_LSEEK lseek
66 #endif
67
68 /*!
69 Eject media -- there's nothing to do here. We always return -2.
70 Should we also free resources?
71 */
72 int
cdio_generic_unimplemented_eject_media(void * p_user_data)73 cdio_generic_unimplemented_eject_media (void *p_user_data) {
74 /* Sort of a stub here. Perhaps log a message? */
75 return DRIVER_OP_UNSUPPORTED;
76 }
77
78 /*!
79 Set the blocksize for subsequent reads.
80 */
81 int
cdio_generic_unimplemented_set_blocksize(void * p_user_data,uint16_t i_blocksize)82 cdio_generic_unimplemented_set_blocksize (void *p_user_data,
83 uint16_t i_blocksize) {
84 /* Sort of a stub here. Perhaps log a message? */
85 return DRIVER_OP_UNSUPPORTED;
86 }
87
88 /*!
89 Set the drive speed.
90 */
91 int
cdio_generic_unimplemented_set_speed(void * p_user_data,int i_speed)92 cdio_generic_unimplemented_set_speed (void *p_user_data, int i_speed) {
93 /* Sort of a stub here. Perhaps log a message? */
94 return DRIVER_OP_UNSUPPORTED;
95 }
96
97
98 /*!
99 Release and free resources associated with cd.
100 */
101 void
cdio_generic_free(void * p_user_data)102 cdio_generic_free (void *p_user_data)
103 {
104 generic_img_private_t *p_env = p_user_data;
105
106 if (NULL == p_env) return;
107 if (p_env->source_name) free (p_env->source_name);
108
109 if (NULL != p_env->cdtext) {
110 cdtext_destroy(p_env->cdtext);
111 p_env->cdtext = NULL;
112 }
113
114 if (p_env->fd >= 0)
115 close (p_env->fd);
116
117 if (p_env->scsi_tuple != NULL)
118 free (p_env->scsi_tuple);
119
120 free (p_env);
121 }
122
123 /*!
124 Initialize CD device.
125 */
126 bool
cdio_generic_init(void * user_data,int open_flags)127 cdio_generic_init (void *user_data, int open_flags)
128 {
129 generic_img_private_t *p_env = user_data;
130 if (p_env->init) {
131 cdio_warn ("init called more than once");
132 return false;
133 }
134
135 p_env->fd = open (p_env->source_name, open_flags, 0);
136
137 if (p_env->fd < 0)
138 {
139 cdio_warn ("open (%s): %s", p_env->source_name, strerror (errno));
140 return false;
141 }
142
143 p_env->init = true;
144 p_env->toc_init = false;
145 p_env->cdtext = NULL;
146 p_env->scsi_tuple = NULL;
147 p_env->b_cdtext_error = false;
148 p_env->u_joliet_level = 0; /* Assume no Joliet extensions initally */
149 return true;
150 }
151
152 /*!
153 Reads a single form1 sector from cd device into data starting
154 from lsn.
155 */
156 driver_return_code_t
cdio_generic_read_form1_sector(void * user_data,void * data,lsn_t lsn)157 cdio_generic_read_form1_sector (void * user_data, void *data, lsn_t lsn)
158 {
159 if (0 > cdio_generic_lseek(user_data, CDIO_CD_FRAMESIZE*lsn, SEEK_SET))
160 return DRIVER_OP_ERROR;
161 return cdio_generic_read(user_data, data, CDIO_CD_FRAMESIZE);
162 }
163
164 /*!
165 Reads into buf the next size bytes.
166 Returns -1 on error.
167 Is in fact libc's lseek()/lseek64().
168 */
169 off_t
cdio_generic_lseek(void * user_data,off_t offset,int whence)170 cdio_generic_lseek (void *user_data, off_t offset, int whence)
171 {
172 generic_img_private_t *p_env = user_data;
173 return CDIO_LSEEK(p_env->fd, offset, whence);
174 }
175
176 /*!
177 Reads into buf the next size bytes.
178 Returns -1 on error.
179 Is in fact libc's read().
180 */
181 ssize_t
cdio_generic_read(void * user_data,void * buf,size_t size)182 cdio_generic_read (void *user_data, void *buf, size_t size)
183 {
184 generic_img_private_t *p_env = user_data;
185 return read(p_env->fd, buf, size);
186 }
187
188 /*!
189 Release and free resources associated with stream or disk image.
190 */
191 void
cdio_generic_stdio_free(void * p_user_data)192 cdio_generic_stdio_free (void *p_user_data)
193 {
194 generic_img_private_t *p_env = p_user_data;
195
196 if (NULL == p_env) return;
197 if (NULL != p_env->source_name)
198 free (p_env->source_name);
199
200 if (p_env->data_source)
201 cdio_stdio_destroy (p_env->data_source);
202 }
203
204
205 /*!
206 Return true if source_name could be a device containing a CD-ROM.
207 */
208 bool
cdio_is_device_generic(const char * source_name)209 cdio_is_device_generic(const char *source_name)
210 {
211 struct stat buf;
212 if (0 != stat(source_name, &buf)) {
213 cdio_warn ("Can't get file status for %s:\n%s", source_name,
214 strerror(errno));
215 return false;
216 }
217 return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
218 }
219
220 /*!
221 Like above, but don't give a warning device doesn't exist.
222 */
223 bool
cdio_is_device_quiet_generic(const char * source_name)224 cdio_is_device_quiet_generic(const char *source_name)
225 {
226 struct stat buf;
227 if (0 != stat(source_name, &buf)) {
228 return false;
229 }
230 return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
231 }
232
233 /*!
234 Add/allocate a drive to the end of drives.
235 Use cdio_free_device_list() to free this device_list.
236 */
237 void
cdio_add_device_list(char ** device_list[],const char * drive,unsigned int * num_drives)238 cdio_add_device_list(char **device_list[], const char *drive,
239 unsigned int *num_drives)
240 {
241 if (NULL != drive) {
242 unsigned int j;
243 char real_device_1[PATH_MAX];
244 char real_device_2[PATH_MAX];
245 cdio_realpath(drive, real_device_1);
246 /* Check if drive is already in list. */
247 for (j=0; j<*num_drives; j++) {
248 cdio_realpath((*device_list)[j], real_device_2);
249 if (strcmp(real_device_1, real_device_2) == 0) break;
250 }
251
252 if (j==*num_drives) {
253 /* Drive not in list. Add it. */
254 (*num_drives)++;
255 *device_list = realloc(*device_list, (*num_drives) * sizeof(char *));
256 cdio_debug("Adding drive %s to list of devices", drive);
257 (*device_list)[*num_drives-1] = strdup(drive);
258 }
259
260 } else {
261 (*num_drives)++;
262 if (*device_list) {
263 *device_list = realloc(*device_list, (*num_drives) * sizeof(char *));
264 } else {
265 *device_list = malloc((*num_drives) * sizeof(char *));
266 }
267 cdio_debug("Adding NULL to end of drive list of size %d", (*num_drives)-1);
268 (*device_list)[*num_drives-1] = NULL;
269 }
270 }
271
272 /*
273 Get cdtext information in p_user_data for track i_track.
274 For disc information i_track is 0.
275
276 Return the CD-TEXT or NULL if obj is NULL, CD-TEXT information does
277 not exist, or we don't know how to get this implemented.
278 */
279 cdtext_t *
get_cdtext_generic(void * p_user_data)280 get_cdtext_generic (void *p_user_data)
281 {
282 generic_img_private_t *p_env = p_user_data;
283 uint8_t *p_cdtext_data = NULL;
284 size_t len;
285
286 if (!p_env) return NULL;
287
288 if (p_env->b_cdtext_error) return NULL;
289
290 if (NULL == p_env->cdtext) {
291 p_cdtext_data = read_cdtext_generic (p_env);
292
293 if (NULL != p_cdtext_data) {
294 len = CDIO_MMC_GET_LEN16(p_cdtext_data)-2;
295 p_env->cdtext = cdtext_init();
296
297 if(len <= 0 || 0 != cdtext_data_init (p_env->cdtext, &p_cdtext_data[4], len)) {
298 p_env->b_cdtext_error = true;
299 cdtext_destroy (p_env->cdtext);
300 p_env->cdtext = NULL;
301 }
302
303 free(p_cdtext_data);
304 }
305 }
306
307 return p_env->cdtext;
308 }
309
310 /*!
311 Get disc type associated with cd object.
312 */
313 discmode_t
get_discmode_generic(void * p_user_data)314 get_discmode_generic (void *p_user_data )
315 {
316 generic_img_private_t *p_env = p_user_data;
317
318 /* See if this is a DVD. */
319 cdio_dvd_struct_t dvd; /* DVD READ STRUCT for layer 0. */
320
321 memset(&dvd, 0, sizeof(dvd));
322
323 dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
324 dvd.physical.layer_num = 0;
325 if (0 == mmc_get_dvd_struct_physical (p_env->cdio, &dvd)) {
326 switch(dvd.physical.layer[0].book_type) {
327 case CDIO_DVD_BOOK_DVD_ROM: return CDIO_DISC_MODE_DVD_ROM;
328 case CDIO_DVD_BOOK_DVD_RAM: return CDIO_DISC_MODE_DVD_RAM;
329 case CDIO_DVD_BOOK_DVD_R: return CDIO_DISC_MODE_DVD_R;
330 case CDIO_DVD_BOOK_DVD_RW: return CDIO_DISC_MODE_DVD_RW;
331 case CDIO_DVD_BOOK_HD_DVD_ROM: return CDIO_DISC_MODE_HD_DVD_ROM;
332 case CDIO_DVD_BOOK_HD_DVD_RAM: return CDIO_DISC_MODE_HD_DVD_RAM;
333 case CDIO_DVD_BOOK_HD_DVD_R: return CDIO_DISC_MODE_HD_DVD_R;
334 case CDIO_DVD_BOOK_DVD_PR: return CDIO_DISC_MODE_DVD_PR;
335 case CDIO_DVD_BOOK_DVD_PRW: return CDIO_DISC_MODE_DVD_PRW;
336 case CDIO_DVD_BOOK_DVD_PRW_DL: return CDIO_DISC_MODE_DVD_PRW_DL;
337 case CDIO_DVD_BOOK_DVD_PR_DL: return CDIO_DISC_MODE_DVD_PR_DL;
338 default: return CDIO_DISC_MODE_DVD_OTHER;
339 }
340 }
341
342 return get_discmode_cd_generic(p_user_data);
343 }
344
345 /*!
346 Get disc type associated with cd object.
347 */
348 discmode_t
get_discmode_cd_generic(void * p_user_data)349 get_discmode_cd_generic (void *p_user_data )
350 {
351 generic_img_private_t *p_env = p_user_data;
352 track_t i_track;
353 discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
354
355 if (!p_env->toc_init)
356 p_env->cdio->op.read_toc (p_user_data);
357
358 if (!p_env->toc_init)
359 return CDIO_DISC_MODE_NO_INFO;
360
361 for (i_track = p_env->i_first_track;
362 i_track < p_env->i_first_track + p_env->i_tracks ;
363 i_track ++) {
364 track_format_t track_fmt =
365 p_env->cdio->op.get_track_format(p_env, i_track);
366
367 switch(track_fmt) {
368 case TRACK_FORMAT_AUDIO:
369 switch(discmode) {
370 case CDIO_DISC_MODE_NO_INFO:
371 discmode = CDIO_DISC_MODE_CD_DA;
372 break;
373 case CDIO_DISC_MODE_CD_DA:
374 case CDIO_DISC_MODE_CD_MIXED:
375 case CDIO_DISC_MODE_ERROR:
376 /* No change*/
377 break;
378 default:
379 discmode = CDIO_DISC_MODE_CD_MIXED;
380 }
381 break;
382 case TRACK_FORMAT_XA:
383 switch(discmode) {
384 case CDIO_DISC_MODE_NO_INFO:
385 discmode = CDIO_DISC_MODE_CD_XA;
386 break;
387 case CDIO_DISC_MODE_CD_XA:
388 case CDIO_DISC_MODE_CD_MIXED:
389 case CDIO_DISC_MODE_ERROR:
390 /* No change*/
391 break;
392 default:
393 discmode = CDIO_DISC_MODE_CD_MIXED;
394 }
395 break;
396 case TRACK_FORMAT_CDI:
397 case TRACK_FORMAT_DATA:
398 switch(discmode) {
399 case CDIO_DISC_MODE_NO_INFO:
400 discmode = CDIO_DISC_MODE_CD_DATA;
401 break;
402 case CDIO_DISC_MODE_CD_DATA:
403 case CDIO_DISC_MODE_CD_MIXED:
404 case CDIO_DISC_MODE_ERROR:
405 /* No change*/
406 break;
407 default:
408 discmode = CDIO_DISC_MODE_CD_MIXED;
409 }
410 break;
411 case TRACK_FORMAT_ERROR:
412 default:
413 discmode = CDIO_DISC_MODE_ERROR;
414 }
415 }
416 return discmode;
417 }
418
419 /*!
420 Return the number of of the first track.
421 CDIO_INVALID_TRACK is returned on error.
422 */
423 track_t
get_first_track_num_generic(void * p_user_data)424 get_first_track_num_generic(void *p_user_data)
425 {
426 const generic_img_private_t *p_env = p_user_data;
427
428 if (!p_env->toc_init)
429 p_env->cdio->op.read_toc (p_user_data);
430
431 return p_env->toc_init ? p_env->i_first_track : CDIO_INVALID_TRACK;
432 }
433
434
435 /*!
436 Return the number of tracks in the current medium.
437 */
438 track_t
get_num_tracks_generic(void * p_user_data)439 get_num_tracks_generic(void *p_user_data)
440 {
441 generic_img_private_t *p_env = p_user_data;
442
443 if (!p_env->toc_init)
444 p_env->cdio->op.read_toc (p_user_data);
445
446 return p_env->toc_init ? p_env->i_tracks : CDIO_INVALID_TRACK;
447 }
448
449
450 /*!
451 Read CD-Text information for a CdIo_t object .
452
453 return pointer to raw cdtext on success,
454 NULL on failure
455 free when done and not NULL
456 */
457 uint8_t *
read_cdtext_generic(void * p_env)458 read_cdtext_generic(void *p_env)
459 {
460 generic_img_private_t *p_user_data = p_env;
461 return mmc_read_cdtext ( p_user_data->cdio );
462 }
463
464 /*! Return number of channels in track: 2 or 4; -2 if not
465 implemented or -1 for error.
466 Not meaningful if track is not an audio track.
467 */
468 int
get_track_channels_generic(const void * p_user_data,track_t i_track)469 get_track_channels_generic(const void *p_user_data, track_t i_track)
470 {
471 const generic_img_private_t *p_env = p_user_data;
472 return p_env->track_flags[i_track].channels;
473 }
474
475 /*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
476 Is this meaningful if not an audio track?
477 */
478 track_flag_t
get_track_copy_permit_generic(void * p_user_data,track_t i_track)479 get_track_copy_permit_generic(void *p_user_data, track_t i_track)
480 {
481 const generic_img_private_t *p_env = p_user_data;
482 return p_env->track_flags[i_track].copy_permit;
483 }
484
485 /*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
486 Is this meaningful if not an audio track?
487
488 pre-emphasis is a non linear frequency response.
489 */
490 track_flag_t
get_track_preemphasis_generic(const void * p_user_data,track_t i_track)491 get_track_preemphasis_generic(const void *p_user_data, track_t i_track)
492 {
493 const generic_img_private_t *p_env = p_user_data;
494 return p_env->track_flags[i_track].preemphasis;
495 }
496
497 void
set_track_flags(track_flags_t * p_track_flag,uint8_t i_flag)498 set_track_flags(track_flags_t *p_track_flag, uint8_t i_flag)
499 {
500 p_track_flag->preemphasis = ( i_flag & CDIO_TRACK_FLAG_PRE_EMPHASIS )
501 ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
502
503 p_track_flag->copy_permit = ( i_flag & CDIO_TRACK_FLAG_COPY_PERMITTED )
504 ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
505
506 p_track_flag->channels = ( i_flag & CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO )
507 ? 4 : 2;
508 }
509
510 driver_return_code_t
read_data_sectors_generic(void * p_user_data,void * p_buf,lsn_t i_lsn,uint16_t i_blocksize,uint32_t i_blocks)511 read_data_sectors_generic (void *p_user_data, void *p_buf, lsn_t i_lsn,
512 uint16_t i_blocksize, uint32_t i_blocks)
513 {
514 int rc;
515 if (0 > cdio_generic_lseek(p_user_data, i_blocksize*i_lsn, SEEK_SET))
516 return DRIVER_OP_ERROR;
517 rc = cdio_generic_read(p_user_data, p_buf, i_blocksize*i_blocks);
518 if (rc > 0) return DRIVER_OP_SUCCESS;
519 return DRIVER_OP_ERROR;
520 }
521
522
523 /*
524 * Local variables:
525 * c-file-style: "gnu"
526 * tab-width: 8
527 * indent-tabs-mode: nil
528 * End:
529 */
530