uint16_t iso9660_pathtable_m_add_entry (void *pt, const char name[], uint32_t extent, uint16_t parent) { iso_path_table_t *ipt = (iso_path_table_t *)((char *)pt + iso9660_pathtable_get_size (pt)); size_t name_len = strlen (name) ? strlen (name) : 1; unsigned int entrynum = 0; cdio_assert (iso9660_pathtable_get_size(pt) < ISO_BLOCKSIZE); /* fixme */ memset(ipt, 0, sizeof (iso_path_table_t) + name_len); /* paranoia */ ipt->name_len = to_711 (name_len); ipt->extent = to_732 (extent); ipt->parent = to_722 (parent); memcpy (ipt->name, name, name_len); pathtable_get_size_and_entries (pt, NULL, &entrynum); if (entrynum > 1) { const iso_path_table_t *ipt2 = pathtable_get_entry (pt, entrynum - 2); cdio_assert (ipt2 != NULL); cdio_assert (from_722 (ipt2->parent) <= parent); } return entrynum; }
/*! Reads a single mode1 form1 or form2 sector from cd device into data starting from lsn. Returns 0 if no error. */ int cdio_read_mode1_sector (const CdIo *cdio, void *data, lsn_t lsn, bool is_form2) { uint32_t size = is_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE ; char buf[M2RAW_SECTOR_SIZE] = { 0, }; int ret; cdio_assert (cdio != NULL); cdio_assert (data != NULL); if (cdio->op.lseek && cdio->op.read) { if (0 > cdio_lseek(cdio, CDIO_CD_FRAMESIZE*lsn, SEEK_SET)) return -1; if (0 > cdio_read(cdio, buf, CDIO_CD_FRAMESIZE)) return -1; memcpy (data, buf, size); return 0; } else { ret = cdio_read_mode2_sector(cdio, data, lsn, is_form2); if (ret == 0) memcpy (data, buf+CDIO_CD_SUBHEADER_SIZE, size); } return ret; }
static const iso_path_table_t * pathtable_get_entry (const void *pt, unsigned int entrynum) { const uint8_t *tmp = pt; unsigned int offset = 0; unsigned int count = 0; cdio_assert (pt != NULL); while (from_711 (*tmp)) { if (count == entrynum) break; cdio_assert (count < entrynum); offset += sizeof (iso_path_table_t); offset += from_711 (*tmp); if (offset % 2) offset++; tmp = (uint8_t *)pt + offset; count++; } if (!from_711 (*tmp)) return NULL; return (const void *) tmp; }
void iso9660_dir_init_new_su (void *dir, uint32_t self, uint32_t ssize, const void *ssu_data, unsigned int ssu_size, uint32_t parent, uint32_t psize, const void *psu_data, unsigned int psu_size, const time_t *dir_time) { cdio_assert (ssize > 0 && !(ssize % ISO_BLOCKSIZE)); cdio_assert (psize > 0 && !(psize % ISO_BLOCKSIZE)); cdio_assert (dir != NULL); memset (dir, 0, ssize); /* "\0" -- working hack due to padding */ iso9660_dir_add_entry_su (dir, "\0", self, ssize, ISO_DIRECTORY, ssu_data, ssu_size, dir_time); iso9660_dir_add_entry_su (dir, "\1", parent, psize, ISO_DIRECTORY, psu_data, psu_size, dir_time); }
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; } }
/* Zero's out pathable. Do this first. */ void iso9660_pathtable_init (void *pt) { cdio_assert (sizeof (iso_path_table_t) == 8); cdio_assert (pt != NULL); memset (pt, 0, ISO_BLOCKSIZE); /* fixme */ }
/*! Set the arg "key" with "value" in the source device. */ int cdio_set_arg (CdIo *cdio, const char key[], const char value[]) { cdio_assert (cdio != NULL); cdio_assert (cdio->op.set_arg != NULL); cdio_assert (key != NULL); return cdio->op.set_arg (cdio->env, key, value); }
int cdio_read_audio_sector (const CdIo *cdio, void *buf, lsn_t lsn) { cdio_assert (cdio != NULL); cdio_assert (buf != NULL); if (cdio->op.read_audio_sectors != NULL) return cdio->op.read_audio_sectors (cdio->env, buf, lsn, 1); return -1; }
int cdio_read_audio_sectors (const CdIo *cdio, void *buf, lsn_t lsn, unsigned int nblocks) { cdio_assert (cdio != NULL); cdio_assert (buf != NULL); if (cdio->op.read_audio_sectors != NULL) return cdio->op.read_audio_sectors (cdio->env, buf, lsn, nblocks); return -1; }
int cdio_read_mode2_sectors (const CdIo *cdio, void *buf, lsn_t lsn, bool mode2raw, unsigned num_sectors) { cdio_assert (cdio != NULL); cdio_assert (buf != NULL); cdio_assert (cdio->op.read_mode2_sectors != NULL); return cdio->op.read_mode2_sectors (cdio->env, buf, lsn, mode2raw, num_sectors); }
void _cdio_list_foreach (CdioList *list, _cdio_list_iterfunc func, void *user_data) { CdioListNode *node; cdio_assert (list != NULL); cdio_assert (func != 0); for (node = _cdio_list_begin (list); node != NULL; node = _cdio_list_node_next (node)) func (_cdio_list_node_data (node), user_data); }
void _cdio_list_foreach (CdioList_t *p_list, _cdio_list_iterfunc_t func, void *p_user_data) { CdioListNode_t *node; cdio_assert (p_list != NULL); cdio_assert (func != 0); for (node = _cdio_list_begin (p_list); node != NULL; node = _cdio_list_node_next (node)) func (_cdio_list_node_data (node), p_user_data); }
void _cdio_list_node_free (CdioListNode *node, int free_data) { CdioList *list; CdioListNode *prev_node; cdio_assert (node != NULL); list = node->list; cdio_assert (_cdio_list_length (list) > 0); if (free_data) free (_cdio_list_node_data (node)); if (_cdio_list_length (list) == 1) { cdio_assert (list->begin == list->end); list->end = list->begin = NULL; list->length = 0; free (node); return; } cdio_assert (list->begin != list->end); if (list->begin == node) { list->begin = node->next; free (node); list->length--; return; } for (prev_node = list->begin; prev_node->next; prev_node = prev_node->next) if (prev_node->next == node) break; cdio_assert (prev_node->next != NULL); if (list->end == node) list->end = prev_node; prev_node->next = node->next; list->length--; free (node); }
void _cdio_list_node_free (CdioListNode_t *p_node, int free_data) { CdioList_t *p_list; CdioListNode_t *prev_node; cdio_assert (p_node != NULL); p_list = p_node->list; cdio_assert (_cdio_list_length (p_list) > 0); if (free_data) free (_cdio_list_node_data (p_node)); if (_cdio_list_length (p_list) == 1) { cdio_assert (p_list->begin == p_list->end); p_list->end = p_list->begin = NULL; p_list->length = 0; free (p_node); return; } cdio_assert (p_list->begin != p_list->end); if (p_list->begin == p_node) { p_list->begin = p_node->next; free (p_node); p_list->length--; return; } for (prev_node = p_list->begin; prev_node->next; prev_node = prev_node->next) if (prev_node->next == p_node) break; cdio_assert (prev_node->next != NULL); if (p_list->end == p_node) p_list->end = prev_node; prev_node->next = p_node->next; p_list->length--; free (p_node); }
CdioListNode * _cdio_list_end (CdioList *list) { cdio_assert (list != NULL); return list->end; }
CdioListNode * _cdio_list_begin (const CdioList *list) { cdio_assert (list != NULL); return list->begin; }
CdioListNode * _cdio_list_find (CdioList *list, _cdio_list_iterfunc cmp_func, void *user_data) { CdioListNode *node; cdio_assert (list != NULL); cdio_assert (cmp_func != 0); for (node = _cdio_list_begin (list); node != NULL; node = _cdio_list_node_next (node)) if (cmp_func (_cdio_list_node_data (node), user_data)) break; return node; }
uint32_t cdio_stat_size (const CdIo *cdio) { cdio_assert (cdio != NULL); return cdio->op.stat_size (cdio->env); }
unsigned _cdio_list_length (const CdioList_t *p_list) { cdio_assert (p_list != NULL); return p_list->length; }
CdioListNode_t * _cdio_list_begin (const CdioList_t *p_list) { cdio_assert (p_list != NULL); return p_list->begin; }
CdioListNode_t * _cdio_list_end (CdioList_t *p_list) { cdio_assert (p_list != NULL); return p_list->end; }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_fs_read_superblock (CdIo_t *p_cdio, iso_extension_mask_t iso_extension_mask) { if (!p_cdio) return false; { generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env; iso9660_pvd_t *p_pvd = &(p_env->pvd); iso9660_svd_t *p_svd = &(p_env->svd); char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; driver_return_code_t driver_return; if ( !iso9660_fs_read_pvd(p_cdio, p_pvd) ) return false; p_env->i_joliet_level = 0; driver_return = cdio_read_data_sectors ( p_cdio, buf, ISO_PVD_SECTOR+1, ISO_BLOCKSIZE, 1 ); if (DRIVER_OP_SUCCESS == driver_return) { /* The size of a PVD or SVD is smaller than a sector. So we allocated a bigger block above (buf) and now we'll copy just the part we need to save. */ cdio_assert (sizeof(buf) >= sizeof (iso9660_svd_t)); memcpy(p_svd, buf, sizeof(iso9660_svd_t)); if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) { if (p_svd->escape_sequences[0] == 0x25 && p_svd->escape_sequences[1] == 0x2f) { switch (p_svd->escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_env->i_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_env->i_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_env->i_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_env->i_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_env->i_joliet_level); } } } } } return true; }
void cdio_lsn_to_msf (lsn_t lsn, msf_t *msf) { int m, s, f; cdio_assert (msf != 0); if ( lsn >= -CDIO_PREGAP_SECTORS ){ m = (lsn + CDIO_PREGAP_SECTORS) / CDIO_CD_FRAMES_PER_MIN; lsn -= m * CDIO_CD_FRAMES_PER_MIN; s = (lsn + CDIO_PREGAP_SECTORS) / CDIO_CD_FRAMES_PER_SEC; lsn -= s * CDIO_CD_FRAMES_PER_SEC; f = lsn + CDIO_PREGAP_SECTORS; } else { m = (lsn + CDIO_CD_MAX_LSN) / CDIO_CD_FRAMES_PER_MIN; lsn -= m * (CDIO_CD_FRAMES_PER_MIN); s = (lsn+CDIO_CD_MAX_LSN) / CDIO_CD_FRAMES_PER_SEC; lsn -= s * CDIO_CD_FRAMES_PER_SEC; f = lsn + CDIO_CD_MAX_LSN; } if (m > 6) { cdio_warn ("number of minutes (%d) truncated to 99.", m); m = 6; } msf->m = cdio_to_bcd8 (m); msf->s = cdio_to_bcd8 (s); msf->f = cdio_to_bcd8 (f); }
void pathtable_get_size_and_entries (const void *pt, unsigned int *size, unsigned int *entries) { const uint8_t *tmp = pt; unsigned int offset = 0; unsigned int count = 0; cdio_assert (pt != NULL); while (from_711 (*tmp)) { offset += sizeof (iso_path_table_t); offset += from_711 (*tmp); if (offset % 2) offset++; tmp = (uint8_t *)pt + offset; count++; } if (size) *size = offset; if (entries) *entries = count; }
/*! 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; } }
/*! Reads a single mode2 sector from cd device into data starting from lsn. Returns 0 if no error. */ int cdio_read_mode2_sector (const CdIo *cdio, void *buf, lsn_t lsn, bool is_form2) { cdio_assert (cdio != NULL); cdio_assert (buf != NULL); cdio_assert (cdio->op.read_mode2_sector != NULL || cdio->op.read_mode2_sectors != NULL); if (cdio->op.read_mode2_sector) return cdio->op.read_mode2_sector (cdio->env, buf, lsn, is_form2); /* fallback */ if (cdio->op.read_mode2_sectors != NULL) return cdio_read_mode2_sectors (cdio, buf, lsn, is_form2, 1); return 1; }
CdioListNode_t * _cdio_list_find (CdioList_t *p_list, _cdio_list_iterfunc_t cmp_func, void *p_user_data) { CdioListNode_t *p_node; cdio_assert (p_list != NULL); cdio_assert (cmp_func != 0); for (p_node = _cdio_list_begin (p_list); p_node != NULL; p_node = _cdio_list_node_next (p_node)) if (cmp_func (_cdio_list_node_data (p_node), p_user_data)) break; return p_node; }
/*! Check that pathname is a valid ISO-9660 pathname. A valid pathname contains a valid directory name, if one appears and the filename portion should be no more than 8 characters for the file prefix and 3 characters in the extension (or portion after a dot). There should be exactly one dot somewhere in the filename portion and the filename should be composed of only DCHARs. True is returned if pathname is valid. */ bool iso9660_pathname_valid_p (const char pathname[]) { const char *p = NULL; cdio_assert (pathname != NULL); if ((p = strrchr (pathname, '/'))) { bool rc; char *_tmp = strdup (pathname); *strrchr (_tmp, '/') = '\0'; rc = iso9660_dirname_valid_p (_tmp); free (_tmp); if (!rc) return false; p++; } else p = pathname; if (strlen (pathname) > (MAX_ISOPATHNAME - 6)) return false; { int len = 0; int dots = 0; for (; *p; p++) if (iso9660_is_dchar (*p)) { len++; if (dots == 0 ? len > 8 : len > 3) return false; } else if (*p == '.') { dots++; if (dots > 1) return false; if (!len) return false; len = 0; } else return false; if (dots != 1) return false; } return true; }
int main (int argc, const char *argv[]) { cdio_assert (argc < 2); cdio_assert_not_reached (); return 0; }
void iso9660_set_evd(void *pd) { iso_volume_descriptor_t ied; cdio_assert (sizeof(iso_volume_descriptor_t) == ISO_BLOCKSIZE); cdio_assert (pd != NULL); memset(&ied, 0, sizeof(ied)); ied.type = to_711(ISO_VD_END); iso9660_strncpy_pad (ied.id, ISO_STANDARD_ID, sizeof(ied.id), ISO9660_DCHARS); ied.version = to_711(ISO_VERSION); memcpy(pd, &ied, sizeof(ied)); }