|
|
|
@ -27,6 +27,7 @@
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "volume.h"
|
|
|
|
|
#include "tree.h"
|
|
|
|
|
#include "messages.h"
|
|
|
|
|
|
|
|
|
|
#define BLOCK_SIZE 2048
|
|
|
|
|
|
|
|
|
@ -153,20 +154,22 @@ iso_read_single_directory_record(struct iso_read_info *info,
|
|
|
|
|
*/
|
|
|
|
|
relocated_dir = iso_read_bb(sue->data.CL.child_loc, 4, NULL);
|
|
|
|
|
} else if (SUSP_SIG(sue, 'S', 'F')) {
|
|
|
|
|
printf("[ERROR] Sparse files not supported.\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_RR_UNSUPPORTED, "Sparse files not supported.");
|
|
|
|
|
info->error = LIBISOFS_UNSUPPORTED_IMAGE;
|
|
|
|
|
break;
|
|
|
|
|
} else if (SUSP_SIG(sue, 'R', 'R')) {
|
|
|
|
|
/* TODO I've seen this RR on mkisofs images. what's this? */
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
printf("[DEBUG] Unhandled SUSP entry %c%c\n", sue->sig[0], sue->sig[1]);
|
|
|
|
|
char msg[28];
|
|
|
|
|
sprintf(msg, "Unhandled SUSP entry %c%c.", sue->sig[0], sue->sig[1]);
|
|
|
|
|
iso_msg_hint(LIBISO_SUSP_UNHANLED, msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !info->error && !relocated_dir && atts.st_mode == (mode_t) 0 ) {
|
|
|
|
|
printf("[ERROR] Mandatory Rock Ridge PX entry is not present "
|
|
|
|
|
"or it contains invalid values.\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_RR_ERROR, "Mandatory Rock Ridge PX entry is "
|
|
|
|
|
"not present or it contains invalid values.");
|
|
|
|
|
info->error = LIBISOFS_WRONG_RR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -179,22 +182,30 @@ iso_read_single_directory_record(struct iso_read_info *info,
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* RR extensions are not read / used */
|
|
|
|
|
//TODO allow to specify suitable values
|
|
|
|
|
atts.st_mode = 0555;
|
|
|
|
|
atts.st_gid = 0;
|
|
|
|
|
atts.st_uid = 0;
|
|
|
|
|
atts.st_mode = info->mode;
|
|
|
|
|
atts.st_gid = info->gid;
|
|
|
|
|
atts.st_uid = info->uid;
|
|
|
|
|
if (record->flags[0] & 0x02)
|
|
|
|
|
atts.st_mode |= S_IFDIR;
|
|
|
|
|
else
|
|
|
|
|
atts.st_mode |= S_IFREG;
|
|
|
|
|
atts.st_ino = ++info->ino;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if we haven't RR extensions, or no NM entry is present,
|
|
|
|
|
* we use the plain ISO name
|
|
|
|
|
* we use the name in directory record
|
|
|
|
|
*/
|
|
|
|
|
if (!name)
|
|
|
|
|
name = strcopy((char*)record->file_id, record->len_fi[0]);
|
|
|
|
|
if (!name) {
|
|
|
|
|
size_t len;
|
|
|
|
|
name = info->get_name((char*)record->file_id, record->len_fi[0]);
|
|
|
|
|
|
|
|
|
|
/* remove trailing version number */
|
|
|
|
|
len = strlen(name);
|
|
|
|
|
if (len > 2 && name[len-2] == ';' && name[len-1] == '1') {
|
|
|
|
|
name[len-2] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if we haven't RR extensions, or a needed TF time stamp is not present,
|
|
|
|
@ -255,7 +266,7 @@ iso_read_single_directory_record(struct iso_read_info *info,
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("[ERROR] File type not supported.\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_RR_UNSUPPORTED, "File type not supported.");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -354,7 +365,7 @@ iso_read_dir(struct iso_read_info *info, struct iso_tree_node_dir *dir,
|
|
|
|
|
|
|
|
|
|
/* check for unsupported multiextend */
|
|
|
|
|
if (record->flags[0] & 0x80) {
|
|
|
|
|
printf("[ERROR] Unsupported image.\n"
|
|
|
|
|
iso_msg_fatal(LIBISO_IMG_UNSUPPORTED, "Unsupported image.\n"
|
|
|
|
|
"This image makes use of Multi-Extend features, that "
|
|
|
|
|
"are not supported at this time.\n"
|
|
|
|
|
"If you need support for that, please request us this feature.\n"
|
|
|
|
@ -364,7 +375,7 @@ iso_read_dir(struct iso_read_info *info, struct iso_tree_node_dir *dir,
|
|
|
|
|
}
|
|
|
|
|
/* check for unsupported interleaved mode */
|
|
|
|
|
if ( record->file_unit_size[0] || record->interleave_gap_size[0] ) {
|
|
|
|
|
printf("[ERROR] Unsupported image.\n"
|
|
|
|
|
iso_msg_fatal(LIBISO_IMG_UNSUPPORTED, "Unsupported image.\n"
|
|
|
|
|
"This image has at least one file recorded in "
|
|
|
|
|
"interleaved mode.\n"
|
|
|
|
|
"We don't support this mode, as we think it's not used.\n"
|
|
|
|
@ -410,7 +421,7 @@ read_root_susp_entries(struct iso_read_info *info,
|
|
|
|
|
record = (struct ecma119_dir_record *)buffer;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* FIXME
|
|
|
|
|
* TODO
|
|
|
|
|
* SUSP specification claims that for CD-ROM XA the SP entry
|
|
|
|
|
* is not at position BP 1, but at BP 15. Is that used?
|
|
|
|
|
* In that case, we need to set info->len_skp to 15!!
|
|
|
|
@ -424,7 +435,7 @@ read_root_susp_entries(struct iso_read_info *info,
|
|
|
|
|
susp_iter_free(iter);
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (!sue || !SUSP_SIG(sue, 'S', 'P') ) {
|
|
|
|
|
printf("[DEBUG] SUSP/RR is not being used.\n");
|
|
|
|
|
iso_msg_debug("SUSP/RR is not being used.");
|
|
|
|
|
susp_iter_free(iter);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -433,13 +444,13 @@ read_root_susp_entries(struct iso_read_info *info,
|
|
|
|
|
if ( sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE
|
|
|
|
|
|| sue->data.SP.ef[0] != 0xEF) {
|
|
|
|
|
|
|
|
|
|
printf("[WARN] SUSP SP system use entry seems to be wrong.\n"
|
|
|
|
|
"Ignoring Rock Ridge Extensions.\n");
|
|
|
|
|
iso_msg_sorry(LIBISO_SUSP_WRONG, "SUSP SP system use entry seems to "
|
|
|
|
|
"be wrong. Ignoring Rock Ridge Extensions.");
|
|
|
|
|
susp_iter_free(iter);
|
|
|
|
|
return 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("[DEBUG] SUSP is being used.\n");
|
|
|
|
|
iso_msg_debug("SUSP/RR is being used.");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The LEN_SKP field, defined in IEEE 1281, SUSP. 5.3, specifies the
|
|
|
|
@ -469,10 +480,10 @@ read_root_susp_entries(struct iso_read_info *info,
|
|
|
|
|
if (SUSP_SIG(sue, 'E', 'R')) {
|
|
|
|
|
|
|
|
|
|
if (info->rr) {
|
|
|
|
|
printf("[WARN] More than one ER has found. "
|
|
|
|
|
"This is not supported.\n"
|
|
|
|
|
"It will be ignored, but can cause problems. "
|
|
|
|
|
"Please notify us about this.\n");
|
|
|
|
|
iso_msg_warn(LIBISO_SUSP_MULTIPLE_ER,
|
|
|
|
|
"More than one ER has found. This is not supported.\n"
|
|
|
|
|
"It will be ignored, but can cause problems. "
|
|
|
|
|
"Please notify us about this.\n");
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* it seems that Rock Ridge can be identified with any
|
|
|
|
@ -481,27 +492,23 @@ read_root_susp_entries(struct iso_read_info *info,
|
|
|
|
|
if ( sue->data.ER.len_id[0] == 10 &&
|
|
|
|
|
!strncmp((char*)sue->data.ER.ext_id, "RRIP_1991A", 10) ) {
|
|
|
|
|
|
|
|
|
|
printf("[DEBUG] suitable Rock Ridge ER found. Version 1.10.\n");
|
|
|
|
|
iso_msg_debug("Suitable Rock Ridge ER found. Version 1.10.");
|
|
|
|
|
info->rr = RR_EXT_110;
|
|
|
|
|
|
|
|
|
|
} else if ( ( sue->data.ER.len_id[0] == 10 &&
|
|
|
|
|
!strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10) )
|
|
|
|
|
|| ( sue->data.ER.len_id[0] == 9 &&
|
|
|
|
|
!strncmp((char*)sue->data.ER.ext_id, "IEEE_1282", 9) ) ) {
|
|
|
|
|
|
|
|
|
|
printf("[DEBUG] suitable Rock Ridge ER found. Version 1.12.\n");
|
|
|
|
|
|
|
|
|
|
iso_msg_debug("Suitable Rock Ridge ER found. Version 1.12.");
|
|
|
|
|
info->rr = RR_EXT_112;
|
|
|
|
|
//TODO check also version?
|
|
|
|
|
} else {
|
|
|
|
|
printf("[WARN] Not Rock Ridge ER (%s) found.\n"
|
|
|
|
|
"That will be ignored, but can cause problems in "
|
|
|
|
|
"image reading. Please notify us about this.\n",
|
|
|
|
|
sue->data.ER.ext_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
//TODO look also for other RR entries???
|
|
|
|
|
//printf("[DEBUG] Unhandled SUSP entry %c%c\n", sue->sig[0], sue->sig[1]);
|
|
|
|
|
iso_msg_warn(LIBISO_SUSP_MULTIPLE_ER,
|
|
|
|
|
"Not Rock Ridge ER found.\n"
|
|
|
|
|
"That will be ignored, but can cause problems in "
|
|
|
|
|
"image reading. Please notify us about this");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -536,8 +543,8 @@ read_pvm(struct iso_read_info *info, uint32_t block)
|
|
|
|
|
|| pvm->vol_desc_version[0] != 1
|
|
|
|
|
|| pvm->file_structure_version[0] != 1 ) {
|
|
|
|
|
|
|
|
|
|
printf("Wrong file.\n"
|
|
|
|
|
"Maybe this is a damaged image, or it's not an ISO-9660 image.\n");
|
|
|
|
|
iso_msg_fatal(LIBISO_WRONG_IMG, "Wrong PVM. Maybe this is a damaged "
|
|
|
|
|
"image, or it's not an ISO-9660 image.\n");
|
|
|
|
|
info->error = LIBISOFS_WRONG_PVM;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@ -556,11 +563,13 @@ read_pvm(struct iso_read_info *info, uint32_t block)
|
|
|
|
|
|
|
|
|
|
volset_id = strcopy((char*)pvm->vol_set_id, 128);
|
|
|
|
|
|
|
|
|
|
*(info->size) = iso_read_bb(pvm->vol_space_size, 4, NULL);
|
|
|
|
|
|
|
|
|
|
volset = iso_volset_new(volume, volset_id);
|
|
|
|
|
free(volset_id);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* FIXME
|
|
|
|
|
* TODO
|
|
|
|
|
* I don't like the way the differences volset - volume are hanled now.
|
|
|
|
|
* While theorically right (a volset can contain several volumes), in
|
|
|
|
|
* practice it seems that this never happen. Current implementation, with
|
|
|
|
@ -584,20 +593,10 @@ read_pvm(struct iso_read_info *info, uint32_t block)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we want to read RR? */
|
|
|
|
|
/* are RR ext present */
|
|
|
|
|
info->hasRR = info->rr ? 1 : 0;
|
|
|
|
|
if (info->norock)
|
|
|
|
|
info->rr = RR_EXT_NO;
|
|
|
|
|
|
|
|
|
|
/* Now, read the tree */
|
|
|
|
|
if ( iso_read_dir(info, volume->root,
|
|
|
|
|
iso_read_bb(rootdr->block, 4, NULL)) ) {
|
|
|
|
|
|
|
|
|
|
/* error, cleanup and return */
|
|
|
|
|
iso_volset_free(volset);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info->iso_root_block = iso_read_bb(rootdr->block, 4, NULL);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PVM has things that can be interested, but don't have a member in
|
|
|
|
@ -613,6 +612,8 @@ iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
|
|
|
|
|
{
|
|
|
|
|
struct iso_read_info info;
|
|
|
|
|
struct iso_volset *volset;
|
|
|
|
|
uint32_t block, root_dir_block;
|
|
|
|
|
unsigned char buffer[BLOCK_SIZE];
|
|
|
|
|
|
|
|
|
|
assert(src && opts);
|
|
|
|
|
|
|
|
|
@ -623,6 +624,11 @@ iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
|
|
|
|
|
info.len_skp = 0;
|
|
|
|
|
info.ino = 0;
|
|
|
|
|
info.norock = opts->norock;
|
|
|
|
|
info.uid = opts->uid;
|
|
|
|
|
info.gid = opts->gid;
|
|
|
|
|
info.mode = opts->mode & ~S_IFMT;
|
|
|
|
|
info.size = &opts->size;
|
|
|
|
|
root_dir_block = 0;
|
|
|
|
|
|
|
|
|
|
/* read primary volume description */
|
|
|
|
|
volset = read_pvm(&info, opts->block + 16);
|
|
|
|
@ -632,15 +638,108 @@ iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opts->hasRR = info.hasRR;
|
|
|
|
|
block = opts->block + 17;
|
|
|
|
|
do {
|
|
|
|
|
if ( info.src->read_block(info.src, block, buffer) < 0 ) {
|
|
|
|
|
info.error = LIBISOFS_READ_FAILURE;
|
|
|
|
|
iso_volset_free(volset);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
switch (buffer[0]) {
|
|
|
|
|
case 0:
|
|
|
|
|
/* boot record */
|
|
|
|
|
//TODO handle el-torito
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
/* suplementary volume descritor */
|
|
|
|
|
{
|
|
|
|
|
struct ecma119_sup_vol_desc *sup;
|
|
|
|
|
struct ecma119_dir_record *root;
|
|
|
|
|
|
|
|
|
|
sup = (struct ecma119_sup_vol_desc*)buffer;
|
|
|
|
|
if (sup->esc_sequences[0] == 0x25 &&
|
|
|
|
|
sup->esc_sequences[1] == 0x2F &&
|
|
|
|
|
(sup->esc_sequences[2] == 0x40 ||
|
|
|
|
|
sup->esc_sequences[2] == 0x43 ||
|
|
|
|
|
sup->esc_sequences[2] == 0x45) ) {
|
|
|
|
|
|
|
|
|
|
/* it's a Joliet Sup. Vol. Desc. */
|
|
|
|
|
info.hasJoliet = 1;
|
|
|
|
|
root = (struct ecma119_dir_record*)sup->root_dir_record;
|
|
|
|
|
root_dir_block = iso_read_bb(root->block, 4, NULL);
|
|
|
|
|
//TODO maybe we can set the volume attribs from this
|
|
|
|
|
//descriptor
|
|
|
|
|
} else {
|
|
|
|
|
iso_msg_hint(LIBISO_UNSUPPORTED_VD,
|
|
|
|
|
"Not supported Sup. Vol. Desc found.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 255:
|
|
|
|
|
/*
|
|
|
|
|
* volume set terminator
|
|
|
|
|
* ignore, as it's checked in loop end condition
|
|
|
|
|
*/
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
char msg[32];
|
|
|
|
|
sprintf(msg, "Ignoring Volume descriptor %d.", buffer[0]);
|
|
|
|
|
iso_msg_hint(LIBISO_UNSUPPORTED_VD, msg);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
block++;
|
|
|
|
|
} while (buffer[0] != 255);
|
|
|
|
|
|
|
|
|
|
// TODO read other volume descriptors
|
|
|
|
|
// - supplementary: for joliet
|
|
|
|
|
// - boot: el-torito
|
|
|
|
|
// Read all volume descriptor till Volume Descriptor Set Terminator
|
|
|
|
|
|
|
|
|
|
opts->hasRR = info.hasRR;
|
|
|
|
|
opts->hasJoliet = info.hasJoliet;
|
|
|
|
|
|
|
|
|
|
/* user doesn't want to read RR extensions */
|
|
|
|
|
if (info.norock)
|
|
|
|
|
info.rr = RR_EXT_NO;
|
|
|
|
|
|
|
|
|
|
/* select what tree to read */
|
|
|
|
|
if (info.rr) {
|
|
|
|
|
/* RR extensions are available */
|
|
|
|
|
if (opts->preferjoliet && info.hasJoliet) {
|
|
|
|
|
/* if user prefers joliet, that is used */
|
|
|
|
|
iso_msg_debug("Reading Joliet extensions.");
|
|
|
|
|
info.get_name = ucs2str;
|
|
|
|
|
info.rr = RR_EXT_NO;
|
|
|
|
|
/* root_dir_block already contains root for joliet */
|
|
|
|
|
} else {
|
|
|
|
|
/* RR will be used */
|
|
|
|
|
iso_msg_debug("Reading Rock Ridge extensions.");
|
|
|
|
|
root_dir_block = info.iso_root_block;
|
|
|
|
|
info.get_name = strcopy;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* RR extensions are not available */
|
|
|
|
|
if (info.hasJoliet && !opts->nojoliet) {
|
|
|
|
|
/* joliet will be used */
|
|
|
|
|
iso_msg_debug("Reading Joliet extensions.");
|
|
|
|
|
info.get_name = ucs2str;
|
|
|
|
|
/* root_dir_block already contains root for joliet */
|
|
|
|
|
} else {
|
|
|
|
|
/* default to plain iso */
|
|
|
|
|
iso_msg_debug("Reading plain ISO-9660 tree.");
|
|
|
|
|
root_dir_block = info.iso_root_block;
|
|
|
|
|
info.get_name = strcopy;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read the ISO/RR or Joliet tree */
|
|
|
|
|
if ( iso_read_dir(&info, volset->volume[0]->root, root_dir_block) ) {
|
|
|
|
|
|
|
|
|
|
/* error, cleanup and return */
|
|
|
|
|
iso_volset_free(volset);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO merge tree info
|
|
|
|
|
|
|
|
|
|
// TODO free here? data_source_free(src);
|
|
|
|
|
return volset;
|
|
|
|
|
}
|
|
|
|
|