Sorted the data file content extents by ECMA-119 tree rather than
by the red-black tree which shall consolidate files with identical source object. Discovered and repaired a flaw in transitivity of iso_stream_cmp_ino().
This commit is contained in:
parent
94f8503b57
commit
6947bfe5ec
@ -88,6 +88,8 @@ void ecma119_image_free(Ecma119Image *t)
|
||||
iso_image_unref(t->image);
|
||||
if (t->files != NULL)
|
||||
iso_rbtree_destroy(t->files, iso_file_src_free);
|
||||
if (t->ecma119_hidden_list != NULL)
|
||||
iso_filesrc_list_destroy(&(t->ecma119_hidden_list));
|
||||
if (t->buffer != NULL)
|
||||
iso_ring_buffer_free(t->buffer);
|
||||
|
||||
@ -2343,6 +2345,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img)
|
||||
if (ret < 0) {
|
||||
goto target_cleanup;
|
||||
}
|
||||
target->ecma119_hidden_list = NULL;
|
||||
|
||||
target->image = src;
|
||||
iso_image_ref(src);
|
||||
@ -4252,3 +4255,83 @@ ex:
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void ecma119_filesrc_array(Ecma119Node *dir,
|
||||
int (*include_item)(void *),
|
||||
IsoFileSrc **filelist, size_t *size, int just_count)
|
||||
{
|
||||
size_t i;
|
||||
Ecma119Node *child;
|
||||
|
||||
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||
child = dir->info.dir->children[i];
|
||||
if (child->type == ECMA119_DIR) {
|
||||
ecma119_filesrc_array(child, include_item, filelist, size,
|
||||
just_count);
|
||||
} else if (child->type == ECMA119_FILE) {
|
||||
if (include_item != NULL)
|
||||
if (!include_item((void *) child->info.file))
|
||||
continue;
|
||||
if (just_count) {
|
||||
(*size)++;
|
||||
} else {
|
||||
if (!child->info.file->taken) {
|
||||
filelist[*size] = child->info.file;
|
||||
child->info.file->taken = 1;
|
||||
(*size)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void hidden_filesrc_array(Ecma119Image *t,
|
||||
int (*include_item)(void *),
|
||||
IsoFileSrc **filelist, size_t *size, int just_count)
|
||||
{
|
||||
struct iso_filesrc_list_item *item;
|
||||
|
||||
for (item = t->ecma119_hidden_list; item != NULL; item = item->next) {
|
||||
if (include_item != NULL)
|
||||
if (!include_item((void *) item->src))
|
||||
continue;
|
||||
if (just_count) {
|
||||
(*size)++;
|
||||
} else {
|
||||
if (!item->src->taken) {
|
||||
filelist[*size] = item->src;
|
||||
item->src->taken = 1;
|
||||
(*size)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IsoFileSrc **iso_ecma119_to_filesrc_array(Ecma119Image *t,
|
||||
int (*include_item)(void *),
|
||||
size_t *size)
|
||||
{
|
||||
IsoFileSrc **filelist = NULL;
|
||||
|
||||
/* Count nodes */
|
||||
*size = 0;
|
||||
ecma119_filesrc_array(t->root, include_item, filelist, size, 1);
|
||||
hidden_filesrc_array(t, include_item, filelist, size, 1);
|
||||
|
||||
LIBISO_ALLOC_MEM_VOID(filelist, IsoFileSrc *, *size + 1);
|
||||
|
||||
/* Fill array */
|
||||
*size = 0;
|
||||
ecma119_filesrc_array(t->root, include_item, filelist, size, 0);
|
||||
hidden_filesrc_array(t, include_item, filelist, size, 0);
|
||||
filelist[*size] = NULL;
|
||||
return filelist;
|
||||
|
||||
ex: /* LIBISO_ALLOC_MEM failed */
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -702,6 +702,8 @@ struct ecma119_image
|
||||
/* tree of files sources */
|
||||
IsoRBTree *files;
|
||||
|
||||
struct iso_filesrc_list_item *ecma119_hidden_list;
|
||||
|
||||
unsigned int checksum_idx_counter;
|
||||
void *checksum_ctx;
|
||||
off_t checksum_counter;
|
||||
|
@ -365,6 +365,35 @@ void ecma119_node_free(Ecma119Node *node)
|
||||
free(node);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int add_to_hidden_list(Ecma119Image *image, IsoFileSrc *src)
|
||||
{
|
||||
int ret;
|
||||
struct iso_filesrc_list_item *item;
|
||||
|
||||
LIBISO_ALLOC_MEM(item, struct iso_filesrc_list_item, 1);
|
||||
item->src = src;
|
||||
item->next = image->ecma119_hidden_list;
|
||||
image->ecma119_hidden_list = item;
|
||||
ret = ISO_SUCCESS;
|
||||
ex:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int iso_filesrc_list_destroy(struct iso_filesrc_list_item **start_item)
|
||||
{
|
||||
struct iso_filesrc_list_item *item, *next;
|
||||
|
||||
for (item = *start_item; item != NULL; item = next) {
|
||||
next = item->next;
|
||||
LIBISO_FREE_MEM(item);
|
||||
}
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param flag
|
||||
* bit0= iso is in a hidden directory. Thus hide it.
|
||||
@ -430,6 +459,9 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
case LIBISO_FILE:
|
||||
if (hidden) {
|
||||
ret = create_file_src(image, (IsoFile *) iso, &src);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
ret = add_to_hidden_list(image, src);
|
||||
} else {
|
||||
ret = create_file(image, (IsoFile*)iso, &node);
|
||||
}
|
||||
@ -470,6 +502,9 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||
if (image->eltorito) {
|
||||
if (hidden) {
|
||||
ret = el_torito_catalog_file_src_create(image, &src);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
ret = add_to_hidden_list(image, src);
|
||||
} else {
|
||||
ret = create_boot_cat(image, (IsoBoot*)iso, &node);
|
||||
}
|
||||
|
@ -79,6 +79,17 @@ struct ecma119_node
|
||||
} info;
|
||||
};
|
||||
|
||||
|
||||
/* For recording files which are hidden in ECMA-119 */
|
||||
struct iso_filesrc_list_item
|
||||
{
|
||||
IsoFileSrc *src;
|
||||
struct iso_filesrc_list_item *next;
|
||||
};
|
||||
|
||||
int iso_filesrc_list_destroy(struct iso_filesrc_list_item **start_item);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -229,12 +229,23 @@ int shall_be_written(void *arg)
|
||||
return f->no_write ? 0 : 1;
|
||||
}
|
||||
|
||||
static
|
||||
int shall_be_written_if_not_taken(void *arg)
|
||||
{
|
||||
IsoFileSrc *f = (IsoFileSrc *)arg;
|
||||
return f->no_write || f->taken ? 0 : 1;
|
||||
}
|
||||
|
||||
int filesrc_writer_pre_compute(IsoImageWriter *writer)
|
||||
{
|
||||
size_t i, size, is_external;
|
||||
Ecma119Image *t;
|
||||
IsoFileSrc **filelist;
|
||||
int (*inc_item)(void *);
|
||||
size_t omitted_count;
|
||||
IsoFileSrc **iso_ecma119_to_filesrc_array(Ecma119Image *t,
|
||||
int (*include_item)(void *),
|
||||
size_t *size);
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
@ -257,7 +268,16 @@ int filesrc_writer_pre_compute(IsoImageWriter *writer)
|
||||
}
|
||||
|
||||
/* store the filesrcs in a array */
|
||||
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size);
|
||||
filelist = (IsoFileSrc**) iso_ecma119_to_filesrc_array(t, inc_item, &size);
|
||||
omitted_count = iso_rbtree_count_array(t->files, (size_t) 0,
|
||||
shall_be_written_if_not_taken);
|
||||
if (omitted_count > 0) {
|
||||
iso_msg_submit(t->image->id, ISO_NOT_REPRODUCIBLE, 0,
|
||||
"Cannot arrange content of data files in surely reproducible way");
|
||||
LIBISO_FREE_MEM(filelist);
|
||||
filelist = (IsoFileSrc**)iso_rbtree_to_array(
|
||||
t->files, inc_item, &size);
|
||||
}
|
||||
if (filelist == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ struct Iso_File_Src
|
||||
*/
|
||||
unsigned int no_write :1;
|
||||
|
||||
/* Is 1 if the object was already put into the filelist array.
|
||||
*/
|
||||
unsigned int taken :1;
|
||||
|
||||
unsigned int checksum_index :31;
|
||||
|
||||
/** File Sections of the file in the image */
|
||||
|
@ -655,14 +655,41 @@ IsoStreamIface extf_stream_class = {
|
||||
static
|
||||
int extf_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int i;
|
||||
ExternalFilterStreamData *data1, *data2;
|
||||
IsoExternalFilterCommand *cmd1, *cmd2;
|
||||
|
||||
/* This function may rely on being called by iso_stream_cmp_ino()
|
||||
only with s1, s2 which both point to it as their .cmp_ino() function.
|
||||
It would be a programming error to let any other than extf_stream_class
|
||||
point to extf_cmp_ino(). This fallback endangers transitivity of
|
||||
iso_stream_cmp_ino().
|
||||
*/
|
||||
if (s1->class != &extf_stream_class || s2->class != &extf_stream_class)
|
||||
return iso_stream_cmp_ino(s1, s2, 1);
|
||||
|
||||
data1 = (ExternalFilterStreamData*) s1->data;
|
||||
data2 = (ExternalFilterStreamData*) s2->data;
|
||||
if (data1->cmd != data2->cmd)
|
||||
return (data1->cmd < data2->cmd ? -1 : 1);
|
||||
cmd1 = data1->cmd;
|
||||
cmd2 = data2->cmd;
|
||||
if (cmd1 != cmd2) {
|
||||
if (strcmp(cmd1->name, cmd2->name) != 0)
|
||||
return strcmp(cmd1->name, cmd2->name);
|
||||
if (strcmp(cmd1->path, cmd2->path) != 0)
|
||||
return strcmp(cmd1->path, cmd2->path);
|
||||
if (cmd1->argc != cmd2->argc)
|
||||
return cmd1->argc < cmd2->argc ? -1 : 1;
|
||||
for (i = 0; i < cmd1->argc; i++) {
|
||||
if (strcmp(cmd1->argv[i], cmd2->argv[i]) != 0)
|
||||
return strcmp(cmd1->argv[i], cmd2->argv[i]);
|
||||
}
|
||||
if (cmd1->behavior != cmd2->behavior)
|
||||
return cmd1->behavior < cmd2->behavior ? -1 : 1;
|
||||
if (strcmp(cmd1->suffix, cmd2->suffix) != 0)
|
||||
return strcmp(cmd1->suffix, cmd2->suffix);
|
||||
}
|
||||
|
||||
/* Both streams apply the same treatment to their input streams */
|
||||
return iso_stream_cmp_ino(data1->orig, data2->orig, 0);
|
||||
}
|
||||
|
||||
|
@ -573,6 +573,9 @@ int gzip_clone_stream(IsoStream *old_stream, IsoStream **new_stream, int flag)
|
||||
static
|
||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
|
||||
static
|
||||
int gzip_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
|
||||
|
||||
IsoStreamIface gzip_stream_compress_class = {
|
||||
4,
|
||||
@ -603,17 +606,44 @@ IsoStreamIface gzip_stream_uncompress_class = {
|
||||
gzip_stream_free,
|
||||
gzip_update_size,
|
||||
gzip_get_input_stream,
|
||||
gzip_cmp_ino,
|
||||
gzip_uncompress_cmp_ino,
|
||||
gzip_clone_stream
|
||||
};
|
||||
|
||||
|
||||
|
||||
static
|
||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
/* This function may rely on being called by iso_stream_cmp_ino()
|
||||
only with s1, s2 which both point to it as their .cmp_ino() function.
|
||||
It would be a programming error to let any other than
|
||||
gzip_stream_compress_class point to gzip_cmp_ino().
|
||||
This fallback endangers transitivity of iso_stream_cmp_ino().
|
||||
*/
|
||||
if (s1->class != s2->class || (s1->class != &gzip_stream_compress_class &&
|
||||
s2->class != &gzip_stream_compress_class))
|
||||
return iso_stream_cmp_ino(s1, s2, 1);
|
||||
|
||||
/* Both streams apply the same treatment to their input streams */
|
||||
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||
iso_stream_get_input_stream(s2, 0), 0);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int gzip_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
/* This function may rely on being called by iso_stream_cmp_ino()
|
||||
only with s1, s2 which both point to it as their .cmp_ino() function.
|
||||
It would be a programming error to let any other than
|
||||
gzip_stream_uncompress_class point to gzip_uncompress_cmp_ino().
|
||||
*/
|
||||
if (s1->class != s2->class ||
|
||||
(s1->class != &gzip_stream_uncompress_class &&
|
||||
s2->class != &gzip_stream_uncompress_class))
|
||||
return iso_stream_cmp_ino(s1, s2, 1);
|
||||
|
||||
/* Both streams apply the same treatment to their input streams */
|
||||
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||
iso_stream_get_input_stream(s2, 0), 0);
|
||||
}
|
||||
|
@ -838,6 +838,9 @@ no_mem:
|
||||
static
|
||||
int ziso_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
|
||||
static
|
||||
int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||
|
||||
|
||||
IsoStreamIface ziso_stream_compress_class = {
|
||||
4,
|
||||
@ -868,7 +871,7 @@ IsoStreamIface ziso_stream_uncompress_class = {
|
||||
ziso_stream_free,
|
||||
ziso_update_size,
|
||||
ziso_get_input_stream,
|
||||
ziso_cmp_ino,
|
||||
ziso_uncompress_cmp_ino,
|
||||
ziso_clone_stream
|
||||
};
|
||||
|
||||
@ -876,9 +879,36 @@ IsoStreamIface ziso_stream_uncompress_class = {
|
||||
static
|
||||
int ziso_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
/* This function may rely on being called by iso_stream_cmp_ino()
|
||||
only with s1, s2 which both point to it as their .cmp_ino() function.
|
||||
It would be a programming error to let any other than
|
||||
ziso_stream_compress_class point to ziso_cmp_ino().
|
||||
*/
|
||||
if (s1->class != s2->class || (s1->class != &ziso_stream_compress_class &&
|
||||
s2->class != &ziso_stream_uncompress_class))
|
||||
iso_stream_cmp_ino(s1, s2, 1);
|
||||
|
||||
/* Both streams apply the same treatment to their input streams */
|
||||
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||
iso_stream_get_input_stream(s2, 0), 0);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
/* This function may rely on being called by iso_stream_cmp_ino()
|
||||
only with s1, s2 which both point to it as their .cmp_ino() function.
|
||||
It would be a programming error to let any other than
|
||||
ziso_stream_uncompress_class point to ziso_uncompress_cmp_ino().
|
||||
This fallback endangers transitivity of iso_stream_cmp_ino().
|
||||
*/
|
||||
if (s1->class != s2->class ||
|
||||
(s1->class != &ziso_stream_uncompress_class &&
|
||||
s2->class != &ziso_stream_uncompress_class))
|
||||
iso_stream_cmp_ino(s1, s2, 1);
|
||||
|
||||
/* Both streams apply the same treatment to their input streams */
|
||||
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||
iso_stream_get_input_stream(s2, 0), 0);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <langinfo.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
/* Enable this and write the correct absolute path into the include statement
|
||||
@ -1439,6 +1440,18 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
|
||||
memset(&atts, 0, sizeof(struct stat));
|
||||
atts.st_nlink = 1;
|
||||
|
||||
#ifdef Libisofs_for_bsd_inst_isoS
|
||||
|
||||
/* >>> ??? see read_rr_TF : shall libisofs follow a Linux inconsistency ? */
|
||||
/* Set preliminary file type */
|
||||
if (record->flags[0] & 0x02) {
|
||||
atts.st_mode = S_IFDIR;
|
||||
} else {
|
||||
atts.st_mode = S_IFREG;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_for_bsd_inst_isoS */
|
||||
|
||||
/*
|
||||
* First of all, check for unsupported ECMA-119 features
|
||||
*/
|
||||
@ -1915,6 +1928,18 @@ if (name != NULL && !namecont) {
|
||||
name[len-2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Libisofs_for_bsd_inst_isoS
|
||||
|
||||
{ char *cpt;
|
||||
for (cpt = name; *cpt != 0; cpt++)
|
||||
if (isupper(*cpt))
|
||||
*cpt = tolower(*cpt);
|
||||
}
|
||||
|
||||
#endif /* Libisofs_for_bsd_inst_isoS */
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -6320,35 +6345,76 @@ int iso_file_get_old_image_sections(IsoFile *file, int *section_count,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Rank two IsoFileSource by their eventual old image LBAs.
|
||||
Other IsoFileSource classes will be ranked only roughly.
|
||||
/* Rank two IsoFileSource by their eventual old image LBAs if still non-zero.
|
||||
Other IsoFileSource classes and zeroized LBAs will be ranked only roughly.
|
||||
flag bit0 preserves transitivity of the caller by evaluating ifs_class with
|
||||
non-zero block address as smaller than anything else.
|
||||
flag bit1 could harm reproducibility of ISO image output.
|
||||
@param flag bit0= if s1 exor s2 is of applicable class, then enforce
|
||||
a valid test result by comparing classes
|
||||
bit1= if both are applicable but also have sections[].block == 0
|
||||
then enforce a valid test result by comparing object addresses.
|
||||
*/
|
||||
int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret,
|
||||
int flag)
|
||||
{
|
||||
int i;
|
||||
ImageFileSourceData *d1, *d2;
|
||||
ImageFileSourceData *d1 = NULL, *d2 = NULL;
|
||||
IsoFileSourceIface *class1 = NULL, *class2 = NULL;
|
||||
|
||||
if (s1->class != s2->class) {
|
||||
*cmp_ret = (s1->class < s2->class ? -1 : 1);
|
||||
return 0;
|
||||
/* Newly created IsoFileSrc from imported IsoFile (e.g. boot image)
|
||||
is not an applicable source. It must be kept from causing a decision
|
||||
with other non-applicables.
|
||||
*/
|
||||
if (s1 != NULL) {
|
||||
class1 = (IsoFileSourceIface *) s1->class;
|
||||
if (class1 == &ifs_class) {
|
||||
d1 = (ImageFileSourceData *) s1->data;
|
||||
if (d1->nsections > 0)
|
||||
if (d1->sections[0].block == 0)
|
||||
class1 = NULL;
|
||||
}
|
||||
}
|
||||
if (s1->class != &ifs_class) {
|
||||
if (s2 != NULL) {
|
||||
class2 = (IsoFileSourceIface *) s2->class;
|
||||
if (class2 == &ifs_class) {
|
||||
d2 = (ImageFileSourceData *) s2->data;
|
||||
if (d2->nsections > 0)
|
||||
if (d2->sections[0].block == 0)
|
||||
class2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (class1 != &ifs_class && class2 != &ifs_class) {
|
||||
*cmp_ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
d1 = s1->data;
|
||||
d2 = s2->data;
|
||||
if (d1->nsections < 1)
|
||||
return 0;
|
||||
if (d1->sections[0].size < 1)
|
||||
return 0;
|
||||
for (i = 0; i < d1->nsections; i++) {
|
||||
if (i >= d2->nsections) {
|
||||
*cmp_ret = 1;
|
||||
if (class1 != class2) {
|
||||
*cmp_ret = (class1 == &ifs_class ? -1 : 1);
|
||||
if (flag & 1)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d1->nsections != d2->nsections) {
|
||||
*cmp_ret = d1->nsections < d2->nsections ? -1 : 1;
|
||||
return 1;
|
||||
}
|
||||
if (d1->nsections == 0) {
|
||||
*cmp_ret = 0;
|
||||
return 1;
|
||||
}
|
||||
if (d1->sections[0].size < 1 || d2->sections[0].size < 1) {
|
||||
if (d1->sections[0].size > d2->sections[0].size)
|
||||
*cmp_ret = 1;
|
||||
else if (d1->sections[0].size < d2->sections[0].size)
|
||||
*cmp_ret = -1;
|
||||
else
|
||||
*cmp_ret = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < d1->nsections; i++) {
|
||||
if (d1->sections[i].block != d2->sections[i].block) {
|
||||
*cmp_ret = (d1->sections[i].block < d2->sections[i].block ? -1 : 1);
|
||||
return 1;
|
||||
@ -6358,10 +6424,6 @@ int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret,
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (i < d2->nsections) {
|
||||
*cmp_ret = -1;
|
||||
return 1;
|
||||
}
|
||||
*cmp_ret = 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -985,7 +985,7 @@ struct IsoStream_Iface
|
||||
* get_input_stream() added.
|
||||
* A filter stream must have version 2 at least.
|
||||
* Version 3 (since 0.6.20)
|
||||
* compare() added.
|
||||
* cmp_ino() added.
|
||||
* A filter stream should have version 3 at least.
|
||||
* Version 4 (since 1.0.2)
|
||||
* clone_stream() added.
|
||||
@ -1107,11 +1107,15 @@ struct IsoStream_Iface
|
||||
* produce the same output. If in any doubt, then this comparison should
|
||||
* indicate no match. A match might allow hardlinking of IsoFile objects.
|
||||
*
|
||||
* If this function cannot accept one of the given stream types, then
|
||||
* the decision must be delegated to
|
||||
* iso_stream_cmp_ino(s1, s2, 1);
|
||||
* This is also appropriate if one has reason to implement stream.cmp_ino()
|
||||
* without having an own special comparison algorithm.
|
||||
* A pointer value of NULL is permissible. In this case, function
|
||||
* iso_stream_cmp_ino() will decide on its own.
|
||||
*
|
||||
* If not NULL, this function .cmp_ino() will be called by
|
||||
* iso_stream_cmp_ino() if both compared streams point to it, and if not
|
||||
* flag bit0 of iso_stream_cmp_ino() prevents it.
|
||||
* So a .cmp_ino() function must be able to compare any pair of streams
|
||||
* which name it as their .cmp_ino(). A fallback to iso_stream_cmp_ino(,,1)
|
||||
* would endanger transitivity of iso_stream_cmp_ino(,,0).
|
||||
*
|
||||
* With filter streams, the decision whether the underlying chains of
|
||||
* streams match, should be delegated to
|
||||
@ -1123,16 +1127,9 @@ struct IsoStream_Iface
|
||||
* cmp_ino(A,A) == 0
|
||||
* cmp_ino(A,B) == -cmp_ino(B,A)
|
||||
* if cmp_ino(A,B) == 0 && cmp_ino(B,C) == 0 then cmp_ino(A,C) == 0
|
||||
* Most tricky is the demand for transitivity:
|
||||
* if cmp_ino(A,B) < 0 && cmp_ino(B,C) < 0 then cmp_ino(A,C) < 0
|
||||
*
|
||||
* A big hazard to the last constraint are tests which do not apply to some
|
||||
* types of streams.Thus it is mandatory to let iso_stream_cmp_ino(s1,s2,1)
|
||||
* decide in this case.
|
||||
*
|
||||
* A function s1.(*cmp_ino)() must only accept stream s2 if function
|
||||
* s2.(*cmp_ino)() would accept s1. Best is to accept only the own stream
|
||||
* type or to have the same function for a family of similar stream types.
|
||||
*
|
||||
* @param s1
|
||||
* The first stream to compare. Expect foreign stream types.
|
||||
* @param s2
|
||||
@ -6639,9 +6636,7 @@ char *iso_stream_get_source_path(IsoStream *stream, int flag);
|
||||
* @return
|
||||
* -1 if s1 is smaller s2 , 0 if s1 matches s2 , 1 if s1 is larger s2
|
||||
* @param flag
|
||||
* bit0= do not use s1->class->compare() even if available
|
||||
* (e.g. because iso_stream_cmp_ino(0 is called as fallback
|
||||
* from said stream->class->compare())
|
||||
* bit0= do not use s1->class->cmp_ino() even if available
|
||||
*
|
||||
* @since 0.6.20
|
||||
*/
|
||||
@ -8313,6 +8308,10 @@ int iso_conv_name_chars(IsoWriteOpts *opts, char *name, size_t name_len,
|
||||
(WARNING, HIGH, -408) */
|
||||
#define ISO_INTVL_READ_PROBLEM 0xD030FE68
|
||||
|
||||
/** Cannot arrange content of data files in surely reproducible way
|
||||
(NOTE, HIGH, -409) */
|
||||
#define ISO_NOT_REPRODUCIBLE 0xB030FE67
|
||||
|
||||
|
||||
/* Internal developer note:
|
||||
Place new error codes directly above this comment.
|
||||
@ -8510,5 +8509,14 @@ struct burn_source {
|
||||
#define Libisofs_with_rrip_rR yes
|
||||
*/
|
||||
|
||||
/* Experiment : bring representation of BSD installation ISOs near to
|
||||
their representation by the Linux kernel.
|
||||
Rock Ridge TF has ctime in CREATE rather than ATTRIBUTES.
|
||||
Linux accepts this, but not for directories.
|
||||
Some files only have ECMA-119 names, which Linux maps
|
||||
to lowercase.
|
||||
#define Libisofs_for_bsd_inst_isoS yes
|
||||
*/
|
||||
|
||||
|
||||
#endif /*LIBISO_LIBISOFS_H_*/
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "node.h"
|
||||
#include "stream.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -232,6 +233,7 @@ void iso_finish()
|
||||
{
|
||||
libiso_msgs_destroy(&libiso_msgr, 0);
|
||||
iso_node_xinfo_dispose_cloners(0);
|
||||
iso_stream_destroy_cmpranks(0);
|
||||
}
|
||||
|
||||
int iso_set_abort_severity(char *severity)
|
||||
@ -527,6 +529,8 @@ const char *iso_error_to_msg(int errcode)
|
||||
return "Malformed description string for interval reader";
|
||||
case ISO_INTVL_READ_PROBLEM:
|
||||
return "Unreadable file, premature EOF, or failure to seek for interval reader";
|
||||
case ISO_NOT_REPRODUCIBLE:
|
||||
return "Cannot arrange content of data files in surely reproducible way";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
@ -211,10 +211,29 @@ int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
|
||||
|
||||
/* 1. Creation time */
|
||||
if (tf->data.TF.flags[0] & (1 << 0)) {
|
||||
|
||||
/* the creation is the recording time. we ignore this */
|
||||
/* TODO maybe it would be good to manage it in ms discs, where
|
||||
* the recording time could be different than now!! */
|
||||
|
||||
#ifdef Libisofs_for_bsd_inst_isoS
|
||||
|
||||
/* FreeBSD installation ISOs represent ctime by Creation time rather
|
||||
* than by Attributes time. If both are given, then Attribute time
|
||||
* will win. Linux 3.16 does not do this for directories.
|
||||
*/
|
||||
/* >>> ??? shall libisofs follow a Linux inconsistency ? */
|
||||
if ((st->st_mode & S_IFMT) != S_IFDIR) {
|
||||
if (tf->len_sue[0] < 5 + (nts+1) * s) {
|
||||
/* RR TF entry too short. */
|
||||
return ISO_WRONG_RR;
|
||||
}
|
||||
if (s == 7) {
|
||||
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
|
||||
} else {
|
||||
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
|
||||
}
|
||||
st->st_ctime = time;
|
||||
}
|
||||
|
||||
#endif /* Libisofs_for_bsd_inst_isoS */
|
||||
|
||||
++nts;
|
||||
}
|
||||
|
||||
|
@ -164,15 +164,6 @@ IsoStream *fsrc_get_input_stream(IsoStream *stream, int flag)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int fsrc_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fsrc_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||
int flag)
|
||||
{
|
||||
@ -227,7 +218,7 @@ IsoStreamIface fsrc_stream_class = {
|
||||
fsrc_free,
|
||||
fsrc_update_size,
|
||||
fsrc_get_input_stream,
|
||||
fsrc_cmp_ino,
|
||||
NULL,
|
||||
fsrc_clone_stream
|
||||
};
|
||||
|
||||
@ -448,15 +439,6 @@ IsoStream* cut_out_get_input_stream(IsoStream *stream, int flag)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int cut_out_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||
int flag)
|
||||
@ -517,7 +499,7 @@ IsoStreamIface cut_out_stream_class = {
|
||||
cut_out_free,
|
||||
cut_out_update_size,
|
||||
cut_out_get_input_stream,
|
||||
cut_out_cmp_ino,
|
||||
NULL,
|
||||
cut_out_clone_stream
|
||||
|
||||
};
|
||||
@ -698,15 +680,6 @@ IsoStream* mem_get_input_stream(IsoStream *stream, int flag)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int mem_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int mem_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||
int flag)
|
||||
@ -763,7 +736,7 @@ IsoStreamIface mem_stream_class = {
|
||||
mem_free,
|
||||
mem_update_size,
|
||||
mem_get_input_stream,
|
||||
mem_cmp_ino,
|
||||
NULL,
|
||||
mem_clone_stream
|
||||
|
||||
};
|
||||
@ -972,18 +945,99 @@ int iso_stream_cmp_ifs_sections(IsoStream *s1, IsoStream *s2, int *cmp_ret,
|
||||
{
|
||||
int ret;
|
||||
FSrcStreamData *fssd1, *fssd2;
|
||||
IsoFileSource *src1, *src2;
|
||||
|
||||
if (s1->class != &fsrc_stream_class || s2->class != &fsrc_stream_class)
|
||||
/* Must keep any suspect in the game to preserve transitivity of the
|
||||
calling function by ranking applicable streams lower than
|
||||
non-applicable. ones.
|
||||
*/
|
||||
if (s1->class != &fsrc_stream_class && s2->class != &fsrc_stream_class)
|
||||
return 0;
|
||||
|
||||
/* Compare eventual image data section LBA and sizes */
|
||||
fssd1= (FSrcStreamData *) s1->data;
|
||||
fssd2= (FSrcStreamData *) s2->data;
|
||||
ret = iso_ifs_sections_cmp(fssd1->src, fssd2->src, cmp_ret, 0);
|
||||
if (s1->class == &fsrc_stream_class) {
|
||||
fssd1= (FSrcStreamData *) s1->data;
|
||||
src1 = fssd1->src;
|
||||
} else {
|
||||
src1 = NULL;
|
||||
}
|
||||
if (s2->class == &fsrc_stream_class) {
|
||||
fssd2= (FSrcStreamData *) s2->data;
|
||||
src2 = fssd2->src;
|
||||
} else {
|
||||
src2 = NULL;
|
||||
}
|
||||
ret = iso_ifs_sections_cmp(src1, src2, cmp_ret, 1);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Maintain and exploit a list of stream compare functions seen by
|
||||
iso_stream_cmp_ino(). This is needed to separate stream comparison
|
||||
families in order to keep iso_stream_cmp_ino() transitive while
|
||||
alternative stream->class->cmp_ino() decide inside the families.
|
||||
*/
|
||||
struct iso_streamcmprank {
|
||||
int (*cmp_func)(IsoStream *s1, IsoStream *s2);
|
||||
struct iso_streamcmprank *next;
|
||||
};
|
||||
|
||||
static struct iso_streamcmprank *streamcmpranks = NULL;
|
||||
|
||||
static
|
||||
int iso_get_streamcmprank(int (*cmp_func)(IsoStream *s1, IsoStream *s2),
|
||||
int flag)
|
||||
{
|
||||
int idx;
|
||||
struct iso_streamcmprank *cpr, *last_cpr = NULL;
|
||||
|
||||
idx = 0;
|
||||
for (cpr = streamcmpranks; cpr != NULL; cpr = cpr->next) {
|
||||
if (cpr->cmp_func == cmp_func)
|
||||
break;
|
||||
idx++;
|
||||
last_cpr = cpr;
|
||||
}
|
||||
if (cpr != NULL)
|
||||
return idx;
|
||||
LIBISO_ALLOC_MEM_VOID(cpr, struct iso_streamcmprank, 1);
|
||||
cpr->cmp_func = cmp_func;
|
||||
cpr->next = NULL;
|
||||
if (last_cpr != NULL)
|
||||
last_cpr->next = cpr;
|
||||
if (streamcmpranks == NULL)
|
||||
streamcmpranks = cpr;
|
||||
return idx;
|
||||
ex:;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static
|
||||
int iso_cmp_streamcmpranks(int (*cf1)(IsoStream *s1, IsoStream *s2),
|
||||
int (*cf2)(IsoStream *s1, IsoStream *s2))
|
||||
{
|
||||
int rank1, rank2;
|
||||
|
||||
rank1 = iso_get_streamcmprank(cf1, 0);
|
||||
rank2 = iso_get_streamcmprank(cf2, 0);
|
||||
return rank1 < rank2 ? -1 : 1;
|
||||
}
|
||||
|
||||
int iso_stream_destroy_cmpranks(int flag)
|
||||
{
|
||||
struct iso_streamcmprank *cpr, *next;
|
||||
|
||||
for (cpr = streamcmpranks; cpr != NULL; cpr = next) {
|
||||
next = cpr->next;
|
||||
LIBISO_FREE_MEM(cpr);
|
||||
}
|
||||
streamcmpranks = NULL;
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* API */
|
||||
int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
|
||||
{
|
||||
@ -1008,13 +1062,72 @@ int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
|
||||
if (s2 == NULL)
|
||||
return 1;
|
||||
|
||||
/* This stays transitive by the fact that
|
||||
iso_stream_cmp_ifs_sections() is transitive,
|
||||
returns > 0 if s1 or s2 are applicable,
|
||||
ret is -1 if s1 is applicable but s2 is not,
|
||||
ret is 1 if s1 is not applicable but s2 is.
|
||||
|
||||
Proof:
|
||||
Be A the set of applicable streams, S and G transitive and
|
||||
antisymmetric relations in respect to outcome {-1, 0, 1}.
|
||||
The combined relation R shall be defined by
|
||||
I. R(a,b) = S(a,b) if a in A or b in A, else G(a,b)
|
||||
Further S shall have the property
|
||||
II. S(a,b) = -1 if a in A and b not in A
|
||||
Then R can be proven to be transitive:
|
||||
By enumerating the 8 combinations of a,b,c being in A or not, we get
|
||||
5 cases of pure S or pure G. Three cases are mixed:
|
||||
a,b not in A, c in A : G(a,b) == -1, S(b,c) == -1 -> S(a,c) == -1
|
||||
Impossible because S(b,c) == -1 contradicts II.
|
||||
a,c not in A, b in A : S(a,b) == -1, S(b,c) == -1 -> G(a,c) == -1
|
||||
Impossible because S(a,b) == -1 contradicts II.
|
||||
b,c not in A, a in A : S(a,b) == -1, G(b,c) == -1 -> S(a,c) == -1
|
||||
Always true because S(a,c) == -1 by definition II.
|
||||
*/
|
||||
if (iso_stream_cmp_ifs_sections(s1, s2, &ret, 0) > 0)
|
||||
return ret; /* Both are unfiltered from loaded ISO filesystem */
|
||||
|
||||
if (s1->class->version >= 3 && !(flag & 1)) {
|
||||
/* Filters may have smarter methods to compare themselves with others */
|
||||
ret = s1->class->cmp_ino(s1, s2);
|
||||
return ret;
|
||||
if (!(flag & 1)) {
|
||||
/* Filters may have smarter methods to compare themselves with others.
|
||||
Transitivity is ensured by ranking mixed pairs by the rank of their
|
||||
comparison functions, and by ranking streams with .cmp_ino lower
|
||||
than streams without.
|
||||
(One could merge (class->version < 3) and (cmp_ino == NULL).)
|
||||
|
||||
Here we define S for "and" rather than "or"
|
||||
I. R(a,b) = S(a,b) if a in A and b in A, else G(a,b)
|
||||
and the function ranking in case of "exor" makes sure that
|
||||
II. G(a,b) = -1 if a in A and b not in A
|
||||
Again we get three mixed cases:
|
||||
a not in A, b,c in A : G(a,b) == -1, S(b,c) == -1 -> G(a,c) == -1
|
||||
Impossible because G(a,b) == -1 contradicts II.
|
||||
b not in A, a,c in A : G(a,b) == -1, G(b,c) == -1 -> S(a,c) == -1
|
||||
Impossible because G(b,c) == -1 contradicts II.
|
||||
c not in A, a,b in A : S(a,b) == -1, G(b,c) == -1 -> G(a,c) == -1
|
||||
Always true because G(a,c) == -1 by definition II.
|
||||
*/
|
||||
if ((s1->class->version >= 3) ^ (s2->class->version >= 3)) {
|
||||
/* One of both has no own com_ino function. Rank it as larger. */
|
||||
return s1->class->version >= 3 ? -1 : 1;
|
||||
} else if (s1->class->version >= 3) {
|
||||
if (s1->class->cmp_ino == s2->class->cmp_ino) {
|
||||
if (s1->class->cmp_ino == NULL) {
|
||||
/* Both are NULL. No decision by .cmp_ino(). */;
|
||||
} else {
|
||||
/* Both are compared by the same function */
|
||||
ret = s1->class->cmp_ino(s1, s2);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* Not the same cmp_ino() function. Decide by list rank of
|
||||
function while building the list on the fly.
|
||||
*/
|
||||
ret = iso_cmp_streamcmpranks(s1->class->cmp_ino,
|
||||
s2->class->cmp_ino);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iso_stream_get_id(s1, &fs_id1, &dev_id1, &ino_id1);
|
||||
|
@ -112,4 +112,13 @@ int iso_stream_clone_filter_common(IsoStream *old_stream,
|
||||
IsoStream **new_stream,
|
||||
IsoStream **new_input, int flag);
|
||||
|
||||
|
||||
/**
|
||||
* Dispose the internal list of stream class cmp_ino() functions. It is
|
||||
* a static global of stream.c, created and used by iso_stream_cmp_ino().
|
||||
* This function is supposed to be called by iso_finish() only.
|
||||
*/
|
||||
int iso_stream_destroy_cmpranks(int flag);
|
||||
|
||||
|
||||
#endif /*STREAM_H_*/
|
||||
|
@ -407,6 +407,12 @@ size_t iso_rbtree_get_size(IsoRBTree *tree);
|
||||
void **iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||
size_t *size);
|
||||
|
||||
/** Predict the size of the array which gets returned by iso_rbtree_to_array().
|
||||
*/
|
||||
size_t iso_rbtree_count_array(IsoRBTree *tree, size_t initial_count,
|
||||
int (*include_item)(void *));
|
||||
|
||||
|
||||
/**
|
||||
* Create a new hash table.
|
||||
*
|
||||
|
@ -308,3 +308,38 @@ void ** iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
size_t rbtree_count_array_aux(struct iso_rbnode *root, size_t pos,
|
||||
int (*include_item)(void *))
|
||||
{
|
||||
if (root == NULL) {
|
||||
return pos;
|
||||
}
|
||||
pos = rbtree_count_array_aux(root->ch[0], pos, include_item);
|
||||
if (include_item == NULL || include_item(root->data)) {
|
||||
|
||||
/*
|
||||
{
|
||||
IsoFileSrc* src = (IsoFileSrc*) root->data;
|
||||
fprintf(stderr, "libisofs_DEBUG: rbtree_count_array_aux : not taken : '%s'\n",
|
||||
iso_stream_get_source_path(src->stream, 0));
|
||||
}
|
||||
*/
|
||||
|
||||
pos++;
|
||||
}
|
||||
pos = rbtree_count_array_aux(root->ch[1], pos, include_item);
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
size_t iso_rbtree_count_array(IsoRBTree *tree, size_t initial_count,
|
||||
int (*include_item)(void *))
|
||||
{
|
||||
size_t pos;
|
||||
|
||||
pos = rbtree_count_array_aux(tree->root, initial_count, include_item);
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user