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);
|
iso_image_unref(t->image);
|
||||||
if (t->files != NULL)
|
if (t->files != NULL)
|
||||||
iso_rbtree_destroy(t->files, iso_file_src_free);
|
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)
|
if (t->buffer != NULL)
|
||||||
iso_ring_buffer_free(t->buffer);
|
iso_ring_buffer_free(t->buffer);
|
||||||
|
|
||||||
@ -2343,6 +2345,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto target_cleanup;
|
goto target_cleanup;
|
||||||
}
|
}
|
||||||
|
target->ecma119_hidden_list = NULL;
|
||||||
|
|
||||||
target->image = src;
|
target->image = src;
|
||||||
iso_image_ref(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 */
|
/* tree of files sources */
|
||||||
IsoRBTree *files;
|
IsoRBTree *files;
|
||||||
|
|
||||||
|
struct iso_filesrc_list_item *ecma119_hidden_list;
|
||||||
|
|
||||||
unsigned int checksum_idx_counter;
|
unsigned int checksum_idx_counter;
|
||||||
void *checksum_ctx;
|
void *checksum_ctx;
|
||||||
off_t checksum_counter;
|
off_t checksum_counter;
|
||||||
|
@ -365,6 +365,35 @@ void ecma119_node_free(Ecma119Node *node)
|
|||||||
free(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
|
* @param flag
|
||||||
* bit0= iso is in a hidden directory. Thus hide it.
|
* 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:
|
case LIBISO_FILE:
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
ret = create_file_src(image, (IsoFile *) iso, &src);
|
ret = create_file_src(image, (IsoFile *) iso, &src);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = add_to_hidden_list(image, src);
|
||||||
} else {
|
} else {
|
||||||
ret = create_file(image, (IsoFile*)iso, &node);
|
ret = create_file(image, (IsoFile*)iso, &node);
|
||||||
}
|
}
|
||||||
@ -470,6 +502,9 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
|||||||
if (image->eltorito) {
|
if (image->eltorito) {
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
ret = el_torito_catalog_file_src_create(image, &src);
|
ret = el_torito_catalog_file_src_create(image, &src);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = add_to_hidden_list(image, src);
|
||||||
} else {
|
} else {
|
||||||
ret = create_boot_cat(image, (IsoBoot*)iso, &node);
|
ret = create_boot_cat(image, (IsoBoot*)iso, &node);
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,17 @@ struct ecma119_node
|
|||||||
} info;
|
} 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;
|
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)
|
int filesrc_writer_pre_compute(IsoImageWriter *writer)
|
||||||
{
|
{
|
||||||
size_t i, size, is_external;
|
size_t i, size, is_external;
|
||||||
Ecma119Image *t;
|
Ecma119Image *t;
|
||||||
IsoFileSrc **filelist;
|
IsoFileSrc **filelist;
|
||||||
int (*inc_item)(void *);
|
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) {
|
if (writer == NULL) {
|
||||||
return ISO_ASSERT_FAILURE;
|
return ISO_ASSERT_FAILURE;
|
||||||
@ -257,7 +268,16 @@ int filesrc_writer_pre_compute(IsoImageWriter *writer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* store the filesrcs in a array */
|
/* 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) {
|
if (filelist == NULL) {
|
||||||
return ISO_OUT_OF_MEM;
|
return ISO_OUT_OF_MEM;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,10 @@ struct Iso_File_Src
|
|||||||
*/
|
*/
|
||||||
unsigned int no_write :1;
|
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;
|
unsigned int checksum_index :31;
|
||||||
|
|
||||||
/** File Sections of the file in the image */
|
/** File Sections of the file in the image */
|
||||||
|
@ -655,14 +655,41 @@ IsoStreamIface extf_stream_class = {
|
|||||||
static
|
static
|
||||||
int extf_cmp_ino(IsoStream *s1, IsoStream *s2)
|
int extf_cmp_ino(IsoStream *s1, IsoStream *s2)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
ExternalFilterStreamData *data1, *data2;
|
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)
|
if (s1->class != &extf_stream_class || s2->class != &extf_stream_class)
|
||||||
return iso_stream_cmp_ino(s1, s2, 1);
|
return iso_stream_cmp_ino(s1, s2, 1);
|
||||||
|
|
||||||
data1 = (ExternalFilterStreamData*) s1->data;
|
data1 = (ExternalFilterStreamData*) s1->data;
|
||||||
data2 = (ExternalFilterStreamData*) s2->data;
|
data2 = (ExternalFilterStreamData*) s2->data;
|
||||||
if (data1->cmd != data2->cmd)
|
cmd1 = data1->cmd;
|
||||||
return (data1->cmd < data2->cmd ? -1 : 1);
|
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);
|
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
|
static
|
||||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
|
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||||
|
|
||||||
|
static
|
||||||
|
int gzip_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||||
|
|
||||||
|
|
||||||
IsoStreamIface gzip_stream_compress_class = {
|
IsoStreamIface gzip_stream_compress_class = {
|
||||||
4,
|
4,
|
||||||
@ -603,7 +606,7 @@ IsoStreamIface gzip_stream_uncompress_class = {
|
|||||||
gzip_stream_free,
|
gzip_stream_free,
|
||||||
gzip_update_size,
|
gzip_update_size,
|
||||||
gzip_get_input_stream,
|
gzip_get_input_stream,
|
||||||
gzip_cmp_ino,
|
gzip_uncompress_cmp_ino,
|
||||||
gzip_clone_stream
|
gzip_clone_stream
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -611,9 +614,36 @@ IsoStreamIface gzip_stream_uncompress_class = {
|
|||||||
static
|
static
|
||||||
int gzip_cmp_ino(IsoStream *s1, IsoStream *s2)
|
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 &&
|
if (s1->class != s2->class || (s1->class != &gzip_stream_compress_class &&
|
||||||
s2->class != &gzip_stream_compress_class))
|
s2->class != &gzip_stream_compress_class))
|
||||||
return iso_stream_cmp_ino(s1, s2, 1);
|
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),
|
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||||
iso_stream_get_input_stream(s2, 0), 0);
|
iso_stream_get_input_stream(s2, 0), 0);
|
||||||
}
|
}
|
||||||
|
@ -838,6 +838,9 @@ no_mem:
|
|||||||
static
|
static
|
||||||
int ziso_cmp_ino(IsoStream *s1, IsoStream *s2);
|
int ziso_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||||
|
|
||||||
|
static
|
||||||
|
int ziso_uncompress_cmp_ino(IsoStream *s1, IsoStream *s2);
|
||||||
|
|
||||||
|
|
||||||
IsoStreamIface ziso_stream_compress_class = {
|
IsoStreamIface ziso_stream_compress_class = {
|
||||||
4,
|
4,
|
||||||
@ -868,7 +871,7 @@ IsoStreamIface ziso_stream_uncompress_class = {
|
|||||||
ziso_stream_free,
|
ziso_stream_free,
|
||||||
ziso_update_size,
|
ziso_update_size,
|
||||||
ziso_get_input_stream,
|
ziso_get_input_stream,
|
||||||
ziso_cmp_ino,
|
ziso_uncompress_cmp_ino,
|
||||||
ziso_clone_stream
|
ziso_clone_stream
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -876,9 +879,36 @@ IsoStreamIface ziso_stream_uncompress_class = {
|
|||||||
static
|
static
|
||||||
int ziso_cmp_ino(IsoStream *s1, IsoStream *s2)
|
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 &&
|
if (s1->class != s2->class || (s1->class != &ziso_stream_compress_class &&
|
||||||
s2->class != &ziso_stream_uncompress_class))
|
s2->class != &ziso_stream_uncompress_class))
|
||||||
iso_stream_cmp_ino(s1, s2, 1);
|
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),
|
return iso_stream_cmp_ino(iso_stream_get_input_stream(s1, 0),
|
||||||
iso_stream_get_input_stream(s2, 0), 0);
|
iso_stream_get_input_stream(s2, 0), 0);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
/* Enable this and write the correct absolute path into the include statement
|
/* 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));
|
memset(&atts, 0, sizeof(struct stat));
|
||||||
atts.st_nlink = 1;
|
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
|
* First of all, check for unsupported ECMA-119 features
|
||||||
*/
|
*/
|
||||||
@ -1915,6 +1928,18 @@ if (name != NULL && !namecont) {
|
|||||||
name[len-2] = '\0';
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rank two IsoFileSource by their eventual old image LBAs.
|
/* Rank two IsoFileSource by their eventual old image LBAs if still non-zero.
|
||||||
Other IsoFileSource classes will be ranked only roughly.
|
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 iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret,
|
||||||
int flag)
|
int flag)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
ImageFileSourceData *d1, *d2;
|
ImageFileSourceData *d1 = NULL, *d2 = NULL;
|
||||||
|
IsoFileSourceIface *class1 = NULL, *class2 = NULL;
|
||||||
|
|
||||||
if (s1->class != s2->class) {
|
/* Newly created IsoFileSrc from imported IsoFile (e.g. boot image)
|
||||||
*cmp_ret = (s1->class < s2->class ? -1 : 1);
|
is not an applicable source. It must be kept from causing a decision
|
||||||
return 0;
|
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;
|
*cmp_ret = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (class1 != class2) {
|
||||||
d1 = s1->data;
|
*cmp_ret = (class1 == &ifs_class ? -1 : 1);
|
||||||
d2 = s2->data;
|
if (flag & 1)
|
||||||
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;
|
|
||||||
return 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) {
|
if (d1->sections[i].block != d2->sections[i].block) {
|
||||||
*cmp_ret = (d1->sections[i].block < d2->sections[i].block ? -1 : 1);
|
*cmp_ret = (d1->sections[i].block < d2->sections[i].block ? -1 : 1);
|
||||||
return 1;
|
return 1;
|
||||||
@ -6358,10 +6424,6 @@ int iso_ifs_sections_cmp(IsoFileSource *s1, IsoFileSource *s2, int *cmp_ret,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i < d2->nsections) {
|
|
||||||
*cmp_ret = -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
*cmp_ret = 0;
|
*cmp_ret = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -985,7 +985,7 @@ struct IsoStream_Iface
|
|||||||
* get_input_stream() added.
|
* get_input_stream() added.
|
||||||
* A filter stream must have version 2 at least.
|
* A filter stream must have version 2 at least.
|
||||||
* Version 3 (since 0.6.20)
|
* Version 3 (since 0.6.20)
|
||||||
* compare() added.
|
* cmp_ino() added.
|
||||||
* A filter stream should have version 3 at least.
|
* A filter stream should have version 3 at least.
|
||||||
* Version 4 (since 1.0.2)
|
* Version 4 (since 1.0.2)
|
||||||
* clone_stream() added.
|
* clone_stream() added.
|
||||||
@ -1107,11 +1107,15 @@ struct IsoStream_Iface
|
|||||||
* produce the same output. If in any doubt, then this comparison should
|
* produce the same output. If in any doubt, then this comparison should
|
||||||
* indicate no match. A match might allow hardlinking of IsoFile objects.
|
* indicate no match. A match might allow hardlinking of IsoFile objects.
|
||||||
*
|
*
|
||||||
* If this function cannot accept one of the given stream types, then
|
* A pointer value of NULL is permissible. In this case, function
|
||||||
* the decision must be delegated to
|
* iso_stream_cmp_ino() will decide on its own.
|
||||||
* iso_stream_cmp_ino(s1, s2, 1);
|
*
|
||||||
* This is also appropriate if one has reason to implement stream.cmp_ino()
|
* If not NULL, this function .cmp_ino() will be called by
|
||||||
* without having an own special comparison algorithm.
|
* 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
|
* With filter streams, the decision whether the underlying chains of
|
||||||
* streams match, should be delegated to
|
* streams match, should be delegated to
|
||||||
@ -1123,16 +1127,9 @@ struct IsoStream_Iface
|
|||||||
* cmp_ino(A,A) == 0
|
* cmp_ino(A,A) == 0
|
||||||
* cmp_ino(A,B) == -cmp_ino(B,A)
|
* 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
|
* 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
|
* 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
|
* @param s1
|
||||||
* The first stream to compare. Expect foreign stream types.
|
* The first stream to compare. Expect foreign stream types.
|
||||||
* @param s2
|
* @param s2
|
||||||
@ -6639,9 +6636,7 @@ char *iso_stream_get_source_path(IsoStream *stream, int flag);
|
|||||||
* @return
|
* @return
|
||||||
* -1 if s1 is smaller s2 , 0 if s1 matches s2 , 1 if s1 is larger s2
|
* -1 if s1 is smaller s2 , 0 if s1 matches s2 , 1 if s1 is larger s2
|
||||||
* @param flag
|
* @param flag
|
||||||
* bit0= do not use s1->class->compare() even if available
|
* bit0= do not use s1->class->cmp_ino() even if available
|
||||||
* (e.g. because iso_stream_cmp_ino(0 is called as fallback
|
|
||||||
* from said stream->class->compare())
|
|
||||||
*
|
*
|
||||||
* @since 0.6.20
|
* @since 0.6.20
|
||||||
*/
|
*/
|
||||||
@ -8313,6 +8308,10 @@ int iso_conv_name_chars(IsoWriteOpts *opts, char *name, size_t name_len,
|
|||||||
(WARNING, HIGH, -408) */
|
(WARNING, HIGH, -408) */
|
||||||
#define ISO_INTVL_READ_PROBLEM 0xD030FE68
|
#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:
|
/* Internal developer note:
|
||||||
Place new error codes directly above this comment.
|
Place new error codes directly above this comment.
|
||||||
@ -8510,5 +8509,14 @@ struct burn_source {
|
|||||||
#define Libisofs_with_rrip_rR yes
|
#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_*/
|
#endif /*LIBISO_LIBISOFS_H_*/
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -232,6 +233,7 @@ void iso_finish()
|
|||||||
{
|
{
|
||||||
libiso_msgs_destroy(&libiso_msgr, 0);
|
libiso_msgs_destroy(&libiso_msgr, 0);
|
||||||
iso_node_xinfo_dispose_cloners(0);
|
iso_node_xinfo_dispose_cloners(0);
|
||||||
|
iso_stream_destroy_cmpranks(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int iso_set_abort_severity(char *severity)
|
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";
|
return "Malformed description string for interval reader";
|
||||||
case ISO_INTVL_READ_PROBLEM:
|
case ISO_INTVL_READ_PROBLEM:
|
||||||
return "Unreadable file, premature EOF, or failure to seek for interval reader";
|
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:
|
default:
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
@ -212,9 +212,28 @@ int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
|
|||||||
/* 1. Creation time */
|
/* 1. Creation time */
|
||||||
if (tf->data.TF.flags[0] & (1 << 0)) {
|
if (tf->data.TF.flags[0] & (1 << 0)) {
|
||||||
|
|
||||||
/* the creation is the recording time. we ignore this */
|
#ifdef Libisofs_for_bsd_inst_isoS
|
||||||
/* TODO maybe it would be good to manage it in ms discs, where
|
|
||||||
* the recording time could be different than now!! */
|
/* 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;
|
++nts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,15 +164,6 @@ IsoStream *fsrc_get_input_stream(IsoStream *stream, int flag)
|
|||||||
return NULL;
|
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 fsrc_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||||
int flag)
|
int flag)
|
||||||
{
|
{
|
||||||
@ -227,7 +218,7 @@ IsoStreamIface fsrc_stream_class = {
|
|||||||
fsrc_free,
|
fsrc_free,
|
||||||
fsrc_update_size,
|
fsrc_update_size,
|
||||||
fsrc_get_input_stream,
|
fsrc_get_input_stream,
|
||||||
fsrc_cmp_ino,
|
NULL,
|
||||||
fsrc_clone_stream
|
fsrc_clone_stream
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -448,15 +439,6 @@ IsoStream* cut_out_get_input_stream(IsoStream *stream, int flag)
|
|||||||
return NULL;
|
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
|
static
|
||||||
int cut_out_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
int cut_out_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||||
int flag)
|
int flag)
|
||||||
@ -517,7 +499,7 @@ IsoStreamIface cut_out_stream_class = {
|
|||||||
cut_out_free,
|
cut_out_free,
|
||||||
cut_out_update_size,
|
cut_out_update_size,
|
||||||
cut_out_get_input_stream,
|
cut_out_get_input_stream,
|
||||||
cut_out_cmp_ino,
|
NULL,
|
||||||
cut_out_clone_stream
|
cut_out_clone_stream
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -698,15 +680,6 @@ IsoStream* mem_get_input_stream(IsoStream *stream, int flag)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
int mem_cmp_ino(IsoStream *s1, IsoStream *s2)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = iso_stream_cmp_ino(s1, s2, 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int mem_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
int mem_clone_stream(IsoStream *old_stream, IsoStream **new_stream,
|
||||||
int flag)
|
int flag)
|
||||||
@ -763,7 +736,7 @@ IsoStreamIface mem_stream_class = {
|
|||||||
mem_free,
|
mem_free,
|
||||||
mem_update_size,
|
mem_update_size,
|
||||||
mem_get_input_stream,
|
mem_get_input_stream,
|
||||||
mem_cmp_ino,
|
NULL,
|
||||||
mem_clone_stream
|
mem_clone_stream
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -972,18 +945,99 @@ int iso_stream_cmp_ifs_sections(IsoStream *s1, IsoStream *s2, int *cmp_ret,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
FSrcStreamData *fssd1, *fssd2;
|
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;
|
return 0;
|
||||||
|
|
||||||
/* Compare eventual image data section LBA and sizes */
|
/* Compare eventual image data section LBA and sizes */
|
||||||
fssd1= (FSrcStreamData *) s1->data;
|
if (s1->class == &fsrc_stream_class) {
|
||||||
fssd2= (FSrcStreamData *) s2->data;
|
fssd1= (FSrcStreamData *) s1->data;
|
||||||
ret = iso_ifs_sections_cmp(fssd1->src, fssd2->src, cmp_ret, 0);
|
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)
|
if (ret <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
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 */
|
/* API */
|
||||||
int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag)
|
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)
|
if (s2 == NULL)
|
||||||
return 1;
|
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)
|
if (iso_stream_cmp_ifs_sections(s1, s2, &ret, 0) > 0)
|
||||||
return ret; /* Both are unfiltered from loaded ISO filesystem */
|
return ret; /* Both are unfiltered from loaded ISO filesystem */
|
||||||
|
|
||||||
if (s1->class->version >= 3 && !(flag & 1)) {
|
if (!(flag & 1)) {
|
||||||
/* Filters may have smarter methods to compare themselves with others */
|
/* Filters may have smarter methods to compare themselves with others.
|
||||||
ret = s1->class->cmp_ino(s1, s2);
|
Transitivity is ensured by ranking mixed pairs by the rank of their
|
||||||
return ret;
|
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);
|
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_stream,
|
||||||
IsoStream **new_input, int flag);
|
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_*/
|
#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 *),
|
void **iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||||
size_t *size);
|
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.
|
* Create a new hash table.
|
||||||
*
|
*
|
||||||
|
@ -308,3 +308,38 @@ void ** iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
|||||||
return array;
|
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…
x
Reference in New Issue
Block a user