diff --git a/doc/zisofs_format.txt b/doc/zisofs_format.txt index ffa6fd4..659e4c9 100644 --- a/doc/zisofs_format.txt +++ b/doc/zisofs_format.txt @@ -90,7 +90,7 @@ Its fields are: ISO 9660:7.1.1. (This is a copy of header byte 13, resp. header BP 14.) Implementations shall be able to handle values 15, 16 and 17 i.e. - block sizes 32 kB, 64 kB, and 128 kB. + block sizes 32 kiB, 64 kiB, and 128 kiB. [7] "BP 9 to BP 16 - Uncompressed Size" shall tell the number of uncompressed bytes represented by the given extent. This field shall be recorded @@ -103,8 +103,8 @@ Its fields are: ISO 9660:7.3.3 means 4-byte word in both byte orders, first little endian, then big endian. -Example (block size 32 kB, uncompressed file size = 1,234,567 bytes): - { 'Z', "F', 16, 1, 'p', 'z', 16, 15, +Example (block size 32 kiB, uncompressed file size = 1,234,567 bytes): + { 'Z', "F', 16, 1, 'p', 'z', 4, 15, 0x87, 0xD6, 0x12, 0x00, 0x00, 0x12, 0xD6, 0x87 } ------------------------------------------------------------------------------- @@ -112,10 +112,8 @@ Revoked specification aspects: The comments in zisofs-tools-1.0.8 indicate a special case of output block: "a block the length of which is equal to the block size is unencoded." -This was not implemented in zisofs-tools and in the Linux kernel. It has to -be doubted that it can be added to the existing reader implementations in an -unambigous way. -Therefore that rule is not part of this description and shall not be +This is not implemented in zisofs-tools and in the Linux kernel. +Therefore that rule is not part of this description and must not be implemented. ------------------------------------------------------------------------------- diff --git a/libisofs/filters/zisofs.c b/libisofs/filters/zisofs.c index 07e82fe..7433998 100644 --- a/libisofs/filters/zisofs.c +++ b/libisofs/filters/zisofs.c @@ -51,10 +51,14 @@ typedef struct { int state; /* processing: 0= header, 1= block pointers, 2= data blocks */ - int block_size; + int block_size; int block_pointer_fill; int block_pointer_rpos; + uint32_t *block_pointers; /* These are in use only with uncompression. + Compression streams hold the pointer in + their persistent data. + */ char *read_buffer; char *block_buffer; @@ -77,6 +81,8 @@ int ziso_running_destroy(ZisofsFilterRuntime **running, int flag) ZisofsFilterRuntime *o= *running; if (o == NULL) return 0; + if (o->block_pointers != NULL) + free(o->block_pointers); if (o->read_buffer != NULL) free(o->read_buffer); if (o->block_buffer != NULL) @@ -99,9 +105,10 @@ int ziso_running_new(ZisofsFilterRuntime **running, int flag) return ISO_OUT_OF_MEM; } o->state = 0; + o->block_size= 0; o->block_pointer_fill = 0; o->block_pointer_rpos = 0; - o->block_size= 0; + o->block_pointers = NULL; o->read_buffer = NULL; o->block_buffer = NULL; o->buffer_size = 0; @@ -140,25 +147,47 @@ static unsigned char zisofs_magic[9] = /* - * The data payload of an individual Zisofs Filter IsoStream + * The common data payload of an individual Zisofs Filter IsoStream */ typedef struct { - ino_t id; - IsoStream *orig; off_t size; /* -1 means that the size is unknown yet */ + ZisofsFilterRuntime *running; /* is non-NULL when open */ + + ino_t id; + +} ZisofsFilterStreamData; + + +/* + * The data payload of an individual Zisofs Filter Compressor IsoStream + */ +typedef struct +{ + ZisofsFilterStreamData std; + uint32_t orig_size; uint32_t *block_pointers; /* Cache for output block addresses. They get written before the data and so need 2 passes. This cache avoids surplus passes. */ +} ZisofsComprStreamData; - ZisofsFilterRuntime *running; /* is non-NULL when open */ -} ZisofsFilterStreamData; +/* + * The data payload of an individual Zisofs Filter Uncompressor IsoStream + */ +typedef struct +{ + ZisofsFilterStreamData std; + + unsigned char header_size_div4; + unsigned char block_size_log2; + +} ZisofsUncomprStreamData; /* Each individual ZisofsFilterStreamData needs a unique id number. */ @@ -194,13 +223,6 @@ int ziso_stream_close_flag(IsoStream *stream, int flag) ziso_running_destroy(&(data->running), 0); if (flag & 1) return 1; - - if (stream->class->read == ziso_stream_uncompress && - data->block_pointers != NULL) { - /* No permanent block pointers needed for uncompression */ - free(data->block_pointers); - data->block_pointers = NULL; - } return iso_stream_close(data->orig); } @@ -237,7 +259,7 @@ int ziso_stream_open_flag(IsoStream *stream, int flag) } ret = ziso_running_new(&running, - stream->class->read == ziso_stream_uncompress); + stream->class->read == &ziso_stream_uncompress); if (ret < 0) { return ret; } @@ -265,7 +287,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired) #ifdef Libisofs_with_zliB int ret, todo, i; - ZisofsFilterStreamData *data; + ZisofsComprStreamData *data; ZisofsFilterRuntime *rng; size_t fill = 0; off_t orig_size, next_pt; @@ -276,7 +298,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired) return ISO_NULL_POINTER; } data = stream->data; - rng= data->running; + rng= data->std.running; if (rng == NULL) { return ISO_FILE_NOT_OPENED; } @@ -290,7 +312,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired) if (rng->buffer_fill == 0) { memcpy(rng->block_buffer, zisofs_magic, 8); - orig_size = iso_stream_get_size(data->orig); + orig_size = iso_stream_get_size(data->std.orig); if (orig_size > 4294967295.0) { return (rng->error_ret = ISO_ZISOFS_TOO_LARGE); } @@ -347,7 +369,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired) if (rng->state == 2 && rng->buffer_rpos >= rng->buffer_fill) { /* Delivering data blocks */; - ret = iso_stream_read(data->orig, rng->read_buffer, + ret = iso_stream_read(data->std.orig, rng->read_buffer, rng->block_size); if (ret > 0) { rng->in_counter += ret; @@ -374,7 +396,7 @@ int ziso_stream_compress(IsoStream *stream, void *buf, size_t desired) next_pt = data->block_pointers[rng->block_counter] + buf_len; - if (data->size >= 0 && next_pt > data->size) { + if (data->std.size >= 0 && next_pt > data->std.size) { /* Compression yields more bytes than on first run */ return (rng->error_ret = ISO_FILTER_WRONG_INPUT); } @@ -443,6 +465,7 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired) int ret, todo, i, header_size, bs_log2, block_max = 1; ZisofsFilterStreamData *data; ZisofsFilterRuntime *rng; + ZisofsUncomprStreamData *nstd; size_t fill = 0; char *cbuf = buf; uLongf buf_len; @@ -452,6 +475,7 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired) return ISO_NULL_POINTER; } data = stream->data; + nstd = stream->data; rng= data->running; if (rng == NULL) { return ISO_FILE_NOT_OPENED; @@ -482,6 +506,8 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired) return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT); } data->size = iso_read_lsb(((uint8_t *) zisofs_head) + 8, 4); + nstd->header_size_div4 = header_size / 4; + nstd->block_size_log2 = bs_log2; if (desired == 0) { return 0; @@ -491,25 +517,25 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired) rng->block_pointer_rpos = 0; rng->block_pointer_fill = data->size / rng->block_size + 1 + !!(data->size % rng->block_size); - data->block_pointers = calloc(rng->block_pointer_fill, 4); - if (data->block_pointers == NULL) { + rng->block_pointers = calloc(rng->block_pointer_fill, 4); + if (rng->block_pointers == NULL) { rng->block_pointer_fill = 0; return (rng->error_ret = ISO_OUT_OF_MEM); } - ret = iso_stream_read(data->orig, data->block_pointers, + ret = iso_stream_read(data->orig, rng->block_pointers, rng->block_pointer_fill * 4); if (ret < 0) return (rng->error_ret = ret); if (ret != rng->block_pointer_fill * 4) return (rng->error_ret = ISO_ZISOFS_WRONG_INPUT); for (i = 0; i < rng->block_pointer_fill; i++) { - data->block_pointers[i] = - iso_read_lsb((uint8_t *) (data->block_pointers + i), 4); + rng->block_pointers[i] = + iso_read_lsb((uint8_t *) (rng->block_pointers + i), 4); if (i > 0) - if (data->block_pointers[i] - data->block_pointers[i - 1] + if (rng->block_pointers[i] - rng->block_pointers[i - 1] > block_max) - block_max = data->block_pointers[i] - - data->block_pointers[i - 1]; + block_max = rng->block_pointers[i] + - rng->block_pointers[i - 1]; } rng->read_buffer = calloc(block_max, 1); @@ -527,9 +553,9 @@ int ziso_stream_uncompress(IsoStream *stream, void *buf, size_t desired) /* More data blocks than announced */ return (rng->error_ret = ISO_FILTER_WRONG_INPUT); } - todo = data->block_pointers[i] - data->block_pointers[i- 1]; + todo = rng->block_pointers[i] - rng->block_pointers[i- 1]; if (todo == 0) { - memset(rng->read_buffer, 0, rng->block_size); + memset(rng->block_buffer, 0, rng->block_size); rng->buffer_fill = rng->block_size; if (rng->in_counter + rng->buffer_fill > data->size && i == rng->block_pointer_fill - 1) @@ -616,7 +642,7 @@ off_t ziso_stream_get_size(IsoStream *stream) if (ret < 0) { return ret; } - if (stream->class->read == ziso_stream_uncompress) { + if (stream->class->read == &ziso_stream_uncompress) { /* It is enough to read the header part of a compressed file */ ret = ziso_stream_uncompress(stream, buf, 0); count = data->size; @@ -673,8 +699,11 @@ void ziso_stream_free(IsoStream *stream) if (data->running != NULL) { ziso_stream_close(stream); } - if (data->block_pointers != NULL) { - free((char *) data->block_pointers); + if (stream->class->read != &ziso_stream_uncompress) { + ZisofsComprStreamData *nstd; + nstd = stream->data; + if (nstd->block_pointers != NULL) + free((char *) nstd->block_pointers); } iso_stream_unref(data->orig); free(data); @@ -748,6 +777,8 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original, { IsoStream *str; ZisofsFilterStreamData *data; + ZisofsComprStreamData *cnstd; + ZisofsUncomprStreamData *unstd; if (filter == NULL || original == NULL || filtered == NULL) { return ISO_NULL_POINTER; @@ -757,7 +788,13 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original, if (str == NULL) { return ISO_OUT_OF_MEM; } - data = calloc(sizeof(ZisofsFilterStreamData), 1); + if (flag & 2) { + unstd = calloc(sizeof(ZisofsUncomprStreamData), 1); + data = (ZisofsFilterStreamData *) unstd; + } else { + cnstd = calloc(sizeof(ZisofsComprStreamData), 1); + data = (ZisofsFilterStreamData *) cnstd; + } if (data == NULL) { free(str); return ISO_OUT_OF_MEM; @@ -767,8 +804,6 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original, data->id = ++ziso_ino_id; data->orig = original; data->size = -1; - data->orig_size = 0; - data->block_pointers = NULL; data->running = NULL; /* get reference to the source */ @@ -777,8 +812,12 @@ int ziso_filter_get_filter(FilterContext *filter, IsoStream *original, str->refcount = 1; str->data = data; if (flag & 2) { + unstd->header_size_div4 = 0; + unstd->block_size_log2 = 0; str->class = &ziso_stream_uncompress_class; } else { + cnstd->orig_size = 0; + cnstd->block_pointers = NULL; str->class = &ziso_stream_compress_class; } @@ -878,8 +917,9 @@ int iso_file_add_zisofs_filter(IsoFile *file, int flag) iso_file_remove_filter(file, 0); return filtered_size; } - if (((filtered_size >= original_size && !(flag & 1)) || - filtered_size / 2048 >= original_size / 2048) && !(flag & 2)){ + if ((filtered_size >= original_size || + ((flag & 1) && filtered_size / 2048 >= original_size / 2048)) + && !(flag & 2)){ ret = iso_file_remove_filter(file, 0); if (ret < 0) { return ret; @@ -897,3 +937,34 @@ int iso_file_add_zisofs_filter(IsoFile *file, int flag) } +/* Determine stream type : 1=ziso , -1=osiz , 0=other + and eventual ZF field parameters +*/ +int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type, + int *header_size_div4, int *block_size_log2, + uint32_t *uncompressed_size, int flag) +{ + ZisofsFilterStreamData *data; + ZisofsComprStreamData *cnstd; + ZisofsUncomprStreamData *unstd; + + *stream_type = 0; + if (stream->class == &ziso_stream_compress_class) { + *stream_type = 1; + cnstd = stream->data; + *header_size_div4 = 4; + *block_size_log2 = Libisofs_zisofs_block_log2; + *uncompressed_size = cnstd->orig_size; + return 1; + } else if(stream->class == &ziso_stream_uncompress_class) { + *stream_type = -1; + data = stream->data; + unstd = stream->data; + *header_size_div4 = unstd->header_size_div4; + *block_size_log2 = unstd->block_size_log2; + *uncompressed_size = data->size; + return 1; + } + return 0; +} + diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index a4dcace..44d4ebb 100644 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -767,6 +767,109 @@ int susp_add_ES(Ecma119Image *t, struct susp_info *susp, int to_ce, int seqno) } +/** + * see doc/zisofs_format.txt : "ZF System Use Entry Format" + */ +static +int zisofs_add_ZF(Ecma119Image *t, struct susp_info *susp, int to_ce, + int header_size_div4, int block_size_log2, + uint32_t uncompressed_size, int flag) +{ + unsigned char *ZF = malloc(16); + + if (ZF == NULL) { + return ISO_OUT_OF_MEM; + } + ZF[0] = 'Z'; + ZF[1] = 'F'; + ZF[2] = (unsigned char) 16; + ZF[3] = (unsigned char) 1; + ZF[4] = (unsigned char) 'p'; + ZF[5] = (unsigned char) 'z'; + ZF[6] = (unsigned char) header_size_div4; + ZF[7] = (unsigned char) block_size_log2; + iso_bb(&ZF[8], uncompressed_size, 4); + if (to_ce) { + return susp_append_ce(t, susp, ZF); + } else { + return susp_append(t, susp, ZF); + } +} + + +/* @param flag bit0= Do not add data but only count sua_free and ce_len +*/ +static +int add_zf_field(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, + size_t *sua_free, size_t *ce_len, int flag) +{ + int ret, will_copy = 1, stream_type = 0, do_zf = 0; + int header_size_div4 = 0, block_size_log2 = 0; + uint32_t uncompressed_size = 0; + IsoStream *stream = NULL, *input_stream; + IsoFile *file; + + /* Intimate friendship with this function in filters/zisofs.c */ + int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type, + int *header_size_div4, int *block_size_log2, + uint32_t *uncompressed_size, int flag); + + + if (iso_node_get_type(n->node) != LIBISO_FILE) + return 2; + file = (IsoFile *) n->node; + + if (t->appendable && file->from_old_session) + will_copy = 0; + + stream = iso_file_get_stream(file); + while (!will_copy) { /* Obtain most original stream (image stream) */ + input_stream = iso_stream_get_input_stream(stream, 0); + if (input_stream == NULL) + break; + stream = input_stream; + } + + /* Determine stream type : 1=ziso , -1=osiz , 0=other */ + ret = ziso_is_zisofs_stream(stream, &stream_type, &header_size_div4, + &block_size_log2, &uncompressed_size, 0); + if (ret < 0) + return ret; + + if (stream_type == 1 && will_copy) { + do_zf = 1; + } else if (stream_type == -1 && !will_copy) { + do_zf = 1; + + /* >>> } else if (t->zisofs_magic) { */ + + /* >>> open stream via temporary osiz filter and read 0 bytes. + If no error: do_zf = 1; */; + /* >>> obtain + header_size_div4, block_size_log2, uncompressed_size */; + + } + if (!do_zf) + return 2; + + /* Account for field size */ + if (*sua_free < 16 || *ce_len > 0) { + *ce_len += 16; + } else { + *sua_free -= 16; + } + if (flag & 1) + return 1; + + /* write ZF field */ + ret = zisofs_add_ZF(t, info, (*ce_len > 0), header_size_div4, + block_size_log2, uncompressed_size, 0); + if (ret < 0) + return ret; + return 1; +} + + int aaip_xinfo_func(void *data, int flag) { if (flag & 1) { @@ -932,6 +1035,13 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, } + /* Find out whether ZF is to be added and account for its bytes */ + sua_free = space - *su_size; + add_zf_field(t, n, NULL, &sua_free, ce, 1); + *su_size = space - sua_free; + if (*ce > 0 && !(flag & 1)) + goto unannounced_ca; + /* obtain num_aapt from node */ xipt = NULL; num_aapt = 0; @@ -949,6 +1059,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, if (*ce > 0 && !(flag & 1)) goto unannounced_ca; } + return 1; unannounced_ca:; @@ -1096,6 +1207,9 @@ int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, void *xipt; size_t num_aapt= 0; + if (!t->aaip) + return 1; + ret = iso_node_get_xinfo(n->node, aaip_xinfo_func, &xipt); if (ret == 1) { num_aapt = aaip_count_bytes((unsigned char *) xipt, 0); @@ -1483,16 +1597,18 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, } } - /* Obtain AAIP field string from node + /* Eventually write zisofs ZF field */ + ret = add_zf_field(t, n, info, &sua_free, &ce_len, 0); + if (ret < 0) + goto add_susp_cleanup; + + /* Eventually obtain AAIP field string from node and write it to directory entry or CE area. */ - ret = ISO_SUCCESS; + ret = add_aa_string(t, n, info, &sua_free, &ce_len, 0); + if (ret < 0) + goto add_susp_cleanup; - if (t->aaip) { - ret = add_aa_string(t, n, info, &sua_free, &ce_len, 0); - if (ret < 0) - goto add_susp_cleanup; - } } else {