CdioList * _cdio_list_new (void) { CdioList *new_obj = _cdio_malloc (sizeof (CdioList)); return new_obj; }
/*! Open an ISO 9660 image for reading. Maybe in the future we will have a mode. NULL is returned on error. */ iso9660_t * iso9660_open_ext (const char *pathname, iso_extension_mask_t iso_extension_mask) { iso9660_t *p_iso = (iso9660_t *) _cdio_malloc(sizeof(struct _iso9660)) ; if (NULL == p_iso) return NULL; p_iso->stream = cdio_stdio_new( pathname ); if (NULL == p_iso->stream) goto error; if ( !iso9660_ifs_read_superblock(p_iso, iso_extension_mask) ) goto error; /* Determine if image has XA attributes. */ p_iso->b_xa = !strncmp ((char *) &(p_iso->pvd) + ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING, strlen (ISO_XA_MARKER_STRING)); p_iso->iso_extension_mask = iso_extension_mask; return p_iso; error: free(p_iso); return NULL; }
/*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the ones to set that up. */ CdIo * cdio_open_linux (const char *orig_source_name) { #ifdef HAVE_LINUX_CDROM CdIo *ret; _img_private_t *_data; char *source_name; cdio_funcs _funcs = { .eject_media = _cdio_eject_media, .free = cdio_generic_free, .get_arg = _cdio_get_arg, .get_devices = cdio_get_devices_linux, .get_default_device = cdio_get_default_device_linux, .get_first_track_num= _cdio_get_first_track_num, .get_mcn = _cdio_get_mcn, .get_num_tracks = _cdio_get_num_tracks, .get_track_format = _cdio_get_track_format, .get_track_green = _cdio_get_track_green, .get_track_lba = NULL, /* This could be implemented if need be. */ .get_track_msf = _cdio_get_track_msf, .lseek = cdio_generic_lseek, .read = cdio_generic_read, .read_audio_sectors = _cdio_read_audio_sectors, .read_mode2_sector = _cdio_read_mode2_sector, .read_mode2_sectors = _cdio_read_mode2_sectors, .set_arg = _cdio_set_arg, .stat_size = _cdio_stat_size }; _data = _cdio_malloc (sizeof (_img_private_t)); _data->access_mode = _AM_READ_CD; _data->gen.init = false; _data->gen.fd = -1; if (NULL == orig_source_name) { source_name=cdio_get_default_device_linux(); if (NULL == source_name) return NULL; _cdio_set_arg(_data, "source", source_name); free(source_name); } else _cdio_set_arg(_data, "source", orig_source_name); ret = cdio_new (_data, &_funcs); if (ret == NULL) return NULL; if (cdio_generic_init(_data)) return ret; else { cdio_generic_free (_data); return NULL; } #else return NULL; #endif /* HAVE_LINUX_CDROM */ }
/*! Read pathname (a directory) and return a list of iso9660_stat_t of the files inside that. The caller must free the returned result. */ CdioList_t * iso9660_ifs_readdir (iso9660_t *p_iso, const char pathname[]) { iso9660_stat_t *p_stat; if (!p_iso) return NULL; if (!pathname) return NULL; p_stat = iso9660_ifs_stat (p_iso, pathname); if (!p_stat) return NULL; if (p_stat->type != _STAT_DIR) { free(p_stat); return NULL; } { long int ret; unsigned offset = 0; uint8_t *_dirbuf = NULL; CdioList_t *retval = _cdio_list_new (); if (p_stat->size != ISO_BLOCKSIZE * p_stat->secsize) { cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", (unsigned int) p_stat->size, (unsigned long int) ISO_BLOCKSIZE * p_stat->secsize); } _dirbuf = _cdio_malloc (p_stat->secsize * ISO_BLOCKSIZE); ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize); if (ret != ISO_BLOCKSIZE*p_stat->secsize) return NULL; while (offset < (p_stat->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_iso9660_stat; if (!iso9660_get_dir_len(p_iso9660_dir)) { offset++; continue; } p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, true, p_iso->i_joliet_level); _cdio_list_append (retval, p_iso9660_stat); offset += iso9660_get_dir_len(p_iso9660_dir); } cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE)); free (_dirbuf); free (p_stat); return retval; } }
void * /* list of char* -- caller must free it */ iso9660_fs_readdir (const CdIo *cdio, const char pathname[], bool is_mode2) { iso9660_stat_t stat; cdio_assert (cdio != NULL); cdio_assert (pathname != NULL); if (iso9660_fs_stat (cdio, pathname, &stat, is_mode2)) return NULL; if (stat.type != _STAT_DIR) return NULL; { unsigned offset = 0; uint8_t *_dirbuf = NULL; CdioList *retval = _cdio_list_new (); if (stat.size != ISO_BLOCKSIZE * stat.secsize) { cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", (unsigned) stat.size, (unsigned long int) ISO_BLOCKSIZE * stat.secsize); } _dirbuf = _cdio_malloc (stat.secsize * ISO_BLOCKSIZE); if (is_mode2) { if (cdio_read_mode2_sectors (cdio, _dirbuf, stat.lsn, false, stat.secsize)) cdio_assert_not_reached (); } else { if (cdio_read_mode1_sectors (cdio, _dirbuf, stat.lsn, false, stat.secsize)) cdio_assert_not_reached (); } while (offset < (stat.secsize * ISO_BLOCKSIZE)) { const iso9660_dir_t *idr = (void *) &_dirbuf[offset]; if (!iso9660_get_dir_len(idr)) { offset++; continue; } _cdio_list_append (retval, _idr2name (idr)); offset += iso9660_get_dir_len(idr); } cdio_assert (offset == (stat.secsize * ISO_BLOCKSIZE)); free (_dirbuf); return retval; } }
CdIo * cdio_new (void *env, const cdio_funcs *funcs) { CdIo *new_cdio; new_cdio = _cdio_malloc (sizeof (CdIo)); new_cdio->env = env; new_cdio->op = *funcs; return new_cdio; }
void _cdio_list_prepend (CdioList *list, void *data) { CdioListNode *new_node; cdio_assert (list != NULL); new_node = _cdio_malloc (sizeof (CdioListNode)); new_node->list = list; new_node->next = list->begin; new_node->data = data; list->begin = new_node; if (list->length == 0) list->end = new_node; list->length++; }
void _cdio_list_append (CdioList *list, void *data) { cdio_assert (list != NULL); if (list->length == 0) { _cdio_list_prepend (list, data); } else { CdioListNode *new_node = _cdio_malloc (sizeof (CdioListNode)); new_node->list = list; new_node->next = NULL; new_node->data = data; list->end->next = new_node; list->end = new_node; list->length++; } }
static iso9660_stat_t * find_fs_lsn_recurse (CdIo_t *p_cdio, const char pathname[], lsn_t lsn) { CdioList_t *entlist = iso9660_fs_readdir (p_cdio, pathname, true); CdioList_t *dirlist = _cdio_list_new (); CdioListNode_t *entnode; cdio_assert (entlist != NULL); /* iterate over each entry in the directory */ _CDIO_LIST_FOREACH (entnode, entlist) { iso9660_stat_t *statbuf = _cdio_list_node_data (entnode); char _fullname[4096] = { 0, }; char *filename = (char *) statbuf->filename; snprintf (_fullname, sizeof (_fullname), "%s%s", pathname, filename); strncat (_fullname, "/", sizeof (_fullname)); if (statbuf->type == _STAT_DIR && strcmp ((char *) statbuf->filename, ".") && strcmp ((char *) statbuf->filename, "..")) _cdio_list_append (dirlist, strdup (_fullname)); if (statbuf->lsn == lsn) { unsigned int len=sizeof(iso9660_stat_t)+strlen(statbuf->filename)+1; iso9660_stat_t *ret_stat = _cdio_malloc(len); memcpy(ret_stat, statbuf, len); _cdio_list_free (entlist, true); _cdio_list_free (dirlist, true); return ret_stat; } }
/*! Initialization routine. This is the only thing that doesn't get called via a function pointer. In fact *we* are the ones to set that up. */ CdIo * cdio_open_am_win32 (const char *psz_orig_source, const char *psz_access_mode) { #ifdef HAVE_WIN32_CDROM CdIo *ret; _img_private_t *_data; char *psz_source; cdio_funcs_t _funcs; memset( &_funcs, 0, sizeof(_funcs) ); _funcs.eject_media = _cdio_eject_media; _funcs.free = _free_win32; _funcs.get_arg = _get_arg_win32; _funcs.get_cdtext = get_cdtext_generic; _funcs.get_default_device = cdio_get_default_device_win32; _funcs.get_devices = cdio_get_devices_win32; _funcs.get_disc_last_lsn = get_disc_last_lsn_win32; _funcs.get_discmode = get_discmode_win32; _funcs.get_drive_cap = get_drive_cap_mmc; _funcs.get_first_track_num= get_first_track_num_generic; _funcs.get_hwinfo = NULL; _funcs.get_mcn = _cdio_get_mcn; _funcs.get_num_tracks = get_num_tracks_generic; _funcs.get_track_channels = get_track_channels_generic, _funcs.get_track_copy_permit = get_track_copy_permit_generic, _funcs.get_track_format = _cdio_get_track_format; _funcs.get_track_green = _cdio_get_track_green; _funcs.get_track_lba = NULL; /* This could be done if need be. */ _funcs.get_track_msf = _cdio_get_track_msf; _funcs.get_track_preemphasis = get_track_preemphasis_generic, _funcs.lseek = NULL; _funcs.read = NULL; _funcs.read_audio_sectors = _cdio_read_audio_sectors; _funcs.read_mode1_sector = _cdio_read_mode1_sector; _funcs.read_mode1_sectors = _cdio_read_mode1_sectors; _funcs.read_mode2_sector = _cdio_read_mode2_sector; _funcs.read_mode2_sectors = _cdio_read_mode2_sectors; _funcs.read_toc = &read_toc_win32; _funcs.run_scsi_mmc_cmd = &run_scsi_cmd_win32; _funcs.set_arg = set_arg_win32; _funcs.set_blocksize = set_blocksize_mmc; _funcs.set_speed = set_speed_mmc; _data = _cdio_malloc (sizeof (_img_private_t)); _data->access_mode = str_to_access_mode_win32(psz_access_mode); _data->gen.init = false; _data->gen.fd = -1; if (NULL == psz_orig_source) { psz_source=cdio_get_default_device_win32(); if (NULL == psz_source) return NULL; set_arg_win32(_data, "source", psz_source); free(psz_source); } else { if (cdio_is_device_win32(psz_orig_source)) set_arg_win32(_data, "source", psz_orig_source); else { /* The below would be okay if all device drivers worked this way. */ #if 0 cdio_info ("source %s is a not a device", psz_orig_source); #endif free(_data); return NULL; } } ret = cdio_new ((void *)_data, &_funcs); if (ret == NULL) return NULL; if (_cdio_init_win32(_data)) return ret; else { _free_win32 (_data); return NULL; } #else return NULL; #endif /* HAVE_WIN32_CDROM */ }
static iso9660_stat_t * _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root, char **splitpath, bool translate) { unsigned offset = 0; uint8_t *_dirbuf = NULL; int ret; if (!splitpath[0]) { iso9660_stat_t *p_stat; unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1; p_stat = _cdio_malloc(len); memcpy(p_stat, _root, len); return p_stat; } if (_root->type == _STAT_FILE) return NULL; cdio_assert (_root->type == _STAT_DIR); if (_root->size != ISO_BLOCKSIZE * _root->secsize) { cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", (unsigned) _root->size, (unsigned long int) ISO_BLOCKSIZE * _root->secsize); } _dirbuf = _cdio_malloc (_root->secsize * ISO_BLOCKSIZE); ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize); if (ret!=ISO_BLOCKSIZE*_root->secsize) return NULL; while (offset < (_root->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_stat; int cmp; if (!iso9660_get_dir_len(p_iso9660_dir)) { offset++; continue; } p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, true, p_iso->i_joliet_level); if (translate) { char *trans_fname = malloc(strlen(p_stat->filename)+1); int trans_len; if (trans_fname == NULL) { cdio_warn("can't allocate %lu bytes", (long unsigned int) strlen(p_stat->filename)); return NULL; } trans_len = iso9660_name_translate_ext(p_stat->filename, trans_fname, p_iso->i_joliet_level); cmp = strcmp(splitpath[0], trans_fname); free(trans_fname); } else { cmp = strcmp(splitpath[0], p_stat->filename); } if (!cmp) { iso9660_stat_t *ret_stat = _fs_iso_stat_traverse (p_iso, p_stat, &splitpath[1], translate); free(p_stat); free (_dirbuf); return ret_stat; } free(p_stat); offset += iso9660_get_dir_len(p_iso9660_dir); } cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE)); /* not found */ free (_dirbuf); return NULL; }
static iso9660_stat_t * _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool b_mode2, uint8_t i_joliet_level) { iso9660_xa_t *xa_data = NULL; uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir); unsigned int filename_len; unsigned int stat_len; iso9660_stat_t *stat; if (!dir_len) return NULL; filename_len = from_711(p_iso9660_dir->filename_len); /* .. string in statbuf is one longer than in p_iso9660_dir's listing '\1' */ stat_len = sizeof(iso9660_stat_t)+filename_len+2; stat = _cdio_malloc(stat_len); stat->type = (p_iso9660_dir->file_flags & ISO_DIRECTORY) ? _STAT_DIR : _STAT_FILE; stat->lsn = from_733 (p_iso9660_dir->extent); stat->size = from_733 (p_iso9660_dir->size); stat->secsize = _cdio_len2blocks (stat->size, ISO_BLOCKSIZE); if ('\0' == p_iso9660_dir->filename[0] && 1 == filename_len) strcpy (stat->filename, "."); else if ('\1' == p_iso9660_dir->filename[0] && 1 == filename_len) strcpy (stat->filename, ".."); else { #ifdef HAVE_JOLIET if (i_joliet_level) { int i_inlen = filename_len; int i_outlen = (i_inlen / 2); char *p_psz_out = NULL; ucs2be_to_locale(p_iso9660_dir->filename, i_inlen, &p_psz_out, i_outlen); strncpy(stat->filename, p_psz_out, filename_len); free(p_psz_out); } else #endif /*HAVE_JOLIET*/ strncpy (stat->filename, p_iso9660_dir->filename, filename_len); } iso9660_get_dtime(&(p_iso9660_dir->recording_time), true, &(stat->tm)); cdio_assert (dir_len >= sizeof (iso9660_dir_t)); if (b_mode2) { int su_length = iso9660_get_dir_len(p_iso9660_dir) - sizeof (iso9660_dir_t); su_length -= filename_len; if (su_length % 2) su_length--; if (su_length < 0 || su_length < sizeof (iso9660_xa_t)) return stat; xa_data = (void *) (((char *) p_iso9660_dir) + (iso9660_get_dir_len(p_iso9660_dir) - su_length)); if (xa_data->signature[0] != 'X' || xa_data->signature[1] != 'A') { cdio_warn ("XA signature not found in ISO9660's system use area;" " ignoring XA attributes for this file entry."); cdio_debug ("%d %d %d, '%c%c' (%d, %d)", iso9660_get_dir_len(p_iso9660_dir), filename_len, su_length, xa_data->signature[0], xa_data->signature[1], xa_data->signature[0], xa_data->signature[1]); return stat; } stat->xa = *xa_data; } return stat; }
/*! Read pathname (a directory) and return a list of iso9660_stat_t of the files inside that. The caller must free the returned result. */ CdioList_t * iso9660_fs_readdir (CdIo_t *p_cdio, const char pathname[], bool b_mode2) { iso9660_stat_t *p_stat; generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env; if (!p_cdio) return NULL; if (!pathname) return NULL; p_stat = iso9660_fs_stat (p_cdio, pathname); if (!p_stat) return NULL; if (p_stat->type != _STAT_DIR) { free(p_stat); return NULL; } { unsigned offset = 0; uint8_t *_dirbuf = NULL; CdioList_t *retval = _cdio_list_new (); if (p_stat->size != ISO_BLOCKSIZE * p_stat->secsize) { cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", (unsigned) p_stat->size, (unsigned long int) ISO_BLOCKSIZE * p_stat->secsize); } _dirbuf = _cdio_malloc (p_stat->secsize * ISO_BLOCKSIZE); if (b_mode2) { if (cdio_read_mode2_sectors (p_cdio, _dirbuf, p_stat->lsn, false, p_stat->secsize)) cdio_assert_not_reached (); } else { if (cdio_read_mode1_sectors (p_cdio, _dirbuf, p_stat->lsn, false, p_stat->secsize)) cdio_assert_not_reached (); } while (offset < (p_stat->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_iso9660_stat; if (!iso9660_get_dir_len(p_iso9660_dir)) { offset++; continue; } p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, b_mode2, p_env->i_joliet_level); _cdio_list_append (retval, p_iso9660_stat); offset += iso9660_get_dir_len(p_iso9660_dir); } cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE)); free (_dirbuf); free (p_stat); return retval; } }
static int _fs_stat_traverse (const CdIo *cdio, const iso9660_stat_t *_root, char **splitpath, /*out*/ iso9660_stat_t *buf, bool is_mode2) { unsigned offset = 0; uint8_t *_dirbuf = NULL; if (!splitpath[0]) { *buf = *_root; return 0; } if (_root->type == _STAT_FILE) return -1; cdio_assert (_root->type == _STAT_DIR); if (_root->size != ISO_BLOCKSIZE * _root->secsize) { cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", (unsigned) _root->size, (unsigned long int) ISO_BLOCKSIZE * _root->secsize); } _dirbuf = _cdio_malloc (_root->secsize * ISO_BLOCKSIZE); if (is_mode2) { if (cdio_read_mode2_sectors (cdio, _dirbuf, _root->lsn, false, _root->secsize)) cdio_assert_not_reached (); } else { if (cdio_read_mode1_sectors (cdio, _dirbuf, _root->lsn, false, _root->secsize)) cdio_assert_not_reached (); } while (offset < (_root->secsize * ISO_BLOCKSIZE)) { const iso9660_dir_t *idr = (void *) &_dirbuf[offset]; iso9660_stat_t stat; char *name; if (!iso9660_get_dir_len(idr)) { offset++; continue; } name = _idr2name (idr); _idr2statbuf (idr, &stat, is_mode2); if (!strcmp (splitpath[0], name)) { int retval = _fs_stat_traverse (cdio, &stat, &splitpath[1], buf, is_mode2); free (name); free (_dirbuf); return retval; } free (name); offset += iso9660_get_dir_len(idr); } cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE)); /* not found */ free (_dirbuf); return -1; }