From: Michihiro NAKAJIMA Date: Sun, 19 Jun 2011 11:32:03 +0000 (-0400) Subject: This is first step to reduce use of both read() and write() system-calls in the iso96... X-Git-Tag: v3.0.0a~283 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51cd99385bd90202983ed3aace70fe5e6f58721b;p=thirdparty%2Flibarchive.git This is first step to reduce use of both read() and write() system-calls in the iso9660 writer. - Use only one temporary file to be simple structure. - When enabling zisofs, almost all files except a small(<2048 bytes) file are, consequently, always compressed even if it is a boot file. The boot file will be uncompressed later. - Write those files to the temporary file by 2048 bytes, though currently this is no effect. SVN-Revision: 3404 --- diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c index 54494cc27..8f29bad89 100644 --- a/libarchive/archive_write_set_format_iso9660.c +++ b/libarchive/archive_write_set_format_iso9660.c @@ -22,10 +22,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * The implemation of red black tree routine is based on - * /usr/include/sys/tree.h of FreeBSD - */ #include "archive_platform.h" @@ -168,7 +164,6 @@ struct isofile { struct isofile *hardlink_target; struct archive_entry *entry; - int temp_fd; /* * Used for making a directory tree. @@ -208,8 +203,6 @@ struct isofile { unsigned char header_size; unsigned char log2_bs; uint32_t uncompressed_size; - int keep_original; - int64_t original_offset_of_temp; } zisofs; }; @@ -659,16 +652,9 @@ struct iso_option { * : Make files zisofs file and generate RRIP 'ZF' * : extension. So you do not need mkzftree utility * : for making zisofs. - * : Sometimes we will choose an original file data - * : insteadof zisofs file data when following - * : condition: - * : o If zisofsed file size is more than an - * : original file size. - * : o If the number of Logical Blocks which an - * : original file will use in ISO-image file - * : is the same as or less than the number of - * : Logical Blocks which a zisofsed file will use. - * : Those won't reduce ISO-image size. + * : When the file size is less than one Logical Block + * : size, that file will not zisofs'ed since it does + * : reduece an ISO-image size. * : * : When you specify option 'boot=', that * : 'boot-image' file won't be converted to zisofs file. @@ -756,13 +742,12 @@ struct iso9660 { /* Used for making zisofs. */ struct { int detect_magic:1; + int making:1; + int allzero:1; unsigned char magic_buffer[64]; int magic_cnt; #ifdef HAVE_ZLIB_H - int making:1; - int allzero:1; - /* * Copy a compressed file to iso9660.zisofs.temp_fd * and also copy a uncompressed file(original file) to @@ -773,14 +758,12 @@ struct iso9660 { * but if not, we use uncompressed file and remove * the copy of the compressed file. */ - int temp_fd; - int64_t offset_of_temp; uint32_t *block_pointers; size_t block_pointers_allocated; int block_pointers_cnt; int block_pointers_idx; - uint64_t total_size; - uint64_t offset_of_block; + int64_t total_size; + int64_t block_offset; z_stream stream; int stream_valid; @@ -957,10 +940,6 @@ static struct isofile * isofile_new(struct archive_write *, struct archive_entry static void isofile_free(struct isofile *); static int isofile_gen_utility_names(struct archive_write *, struct isofile *); -#ifdef HAVE_ZLIB_H -static void get_parent_and_base(struct archive_string *, - struct archive_string *, const char *); -#endif static int isofile_register_hardlink(struct archive_write *, struct isofile *); static void isofile_connect_hardlink_files(struct iso9660 *); @@ -1030,13 +1009,12 @@ static int setup_boot_information(struct archive_write *); static int zisofs_init(struct archive_write *, struct isofile *); static void zisofs_detect_magic(struct archive_write *, const void *, size_t); -#ifdef HAVE_ZLIB_H -static void zisofs_cancel(struct iso9660 *, struct isofile *); +static int zisofs_write_out_boot_file(struct archive_write *); static int zisofs_write_to_temp(struct archive_write *, const void *, size_t); static int zisofs_finish_entry(struct archive_write *); static int zisofs_fix_bootfile(struct archive_write *); -#endif +static int zisofs_free(struct archive_write *); int archive_write_set_format_iso9660(struct archive *_a) @@ -1108,7 +1086,6 @@ archive_write_set_format_iso9660(struct archive *_a) * Init zisofs variables. */ #ifdef HAVE_ZLIB_H - iso9660->zisofs.temp_fd = -1; iso9660->zisofs.block_pointers = NULL; iso9660->zisofs.block_pointers_allocated = 0; iso9660->zisofs.stream_valid = 0; @@ -1596,8 +1573,7 @@ iso9660_write_header(struct archive_write *a, struct archive_entry *entry) } } - /* Save a offset of current file in temporary file. */ - file->temp_fd = iso9660->temp_fd; + /* Save an offset of current file in temporary file. */ file->content.offset_of_temp = lseek(iso9660->temp_fd, 0, SEEK_CUR); file->cur_content = &(file->content); r = zisofs_init(a, file); @@ -1609,14 +1585,15 @@ iso9660_write_header(struct archive_write *a, struct archive_entry *entry) } static int -write_to_temp(struct archive_write *a, int fd, const void *buff, size_t s) +write_to_temp(struct archive_write *a, const void *buff, size_t s) { + struct iso9660 *iso9660 = a->format_data; ssize_t written; const unsigned char *b; b = (const unsigned char *)buff; while (s) { - written = write(fd, b, s); + written = write(iso9660->temp_fd, b, s); if (written < 0) { archive_set_error(&a->archive, errno, "Can't write to temporary file"); @@ -1628,6 +1605,24 @@ write_to_temp(struct archive_write *a, int fd, const void *buff, size_t s) return (ARCHIVE_OK); } +static int +write_padding_to_temp(struct archive_write *a, int64_t csize) +{ + size_t ns, nts; + + ns = csize % LOGICAL_BLOCK_SIZE; + if (ns != 0) { + ns = LOGICAL_BLOCK_SIZE - ns; + while (ns > 0) { + nts = (ns > a->null_length)? a->null_length: ns; + if (write_to_temp(a, a->nulls, nts) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + ns -= nts; + } + } + return (ARCHIVE_OK); +} + static ssize_t write_iso9660_data(struct archive_write *a, const void *buff, size_t s) { @@ -1649,18 +1644,24 @@ write_iso9660_data(struct archive_write *a, const void *buff, size_t s) ts = MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE - iso9660->cur_file->cur_content->size; - if (write_to_temp(a, iso9660->temp_fd, buff, ts) - != ARCHIVE_OK) - return (ARCHIVE_FATAL); - iso9660->cur_file->cur_content->size += ts; if (iso9660->zisofs.detect_magic) zisofs_detect_magic(a, buff, ts); -#ifdef HAVE_ZLIB_H - if (iso9660->zisofs.making && - zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK) + + if (iso9660->zisofs.making) { + if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } else { + if (write_to_temp(a, buff, ts) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + iso9660->cur_file->cur_content->size += ts; + } + + /* Write padding. */ + if (write_padding_to_temp(a, + iso9660->cur_file->cur_content->size) != ARCHIVE_OK) return (ARCHIVE_FATAL); -#endif + /* * Make next extent. */ @@ -1673,23 +1674,26 @@ write_iso9660_data(struct archive_write *a, const void *buff, size_t s) "Can't allocate content data"); return (ARCHIVE_FATAL); } - con->offset_of_temp = - lseek(iso9660->cur_file->temp_fd, 0, SEEK_CUR); + con->offset_of_temp = lseek(iso9660->temp_fd, 0, SEEK_CUR); iso9660->cur_file->cur_content->next = con; iso9660->cur_file->cur_content = con; +#ifdef HAVE_ZLIB_H + iso9660->zisofs.block_offset = 0; +#endif } - if (write_to_temp(a, iso9660->temp_fd, buff, ws) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - iso9660->cur_file->cur_content->size += ws; - if (iso9660->zisofs.detect_magic) zisofs_detect_magic(a, buff, ws); -#ifdef HAVE_ZLIB_H - if (iso9660->zisofs.making && - zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK) - return (ARCHIVE_FATAL); -#endif + + if (iso9660->zisofs.making) { + if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + } else { + if (write_to_temp(a, buff, ws) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + iso9660->cur_file->cur_content->size += ws; + } + return (s); } @@ -1735,11 +1739,13 @@ iso9660_finish_entry(struct archive_write *a) iso9660->bytes_remaining -= s; } -#ifdef HAVE_ZLIB_H - if (iso9660->zisofs.making && - zisofs_finish_entry(a) != ARCHIVE_OK) + if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK) + return (ARCHIVE_FATAL); + + /* Write padding. */ + if (write_padding_to_temp(a, iso9660->cur_file->cur_content->size) + != ARCHIVE_OK) return (ARCHIVE_FATAL); -#endif return (ARCHIVE_OK); } @@ -1764,12 +1770,10 @@ iso9660_close(struct archive_write *a) iso9660->primary.rootent); if (ret < 0) return (ret); + ret = zisofs_fix_bootfile(a); + if (ret < 0) + return (ret); } -#ifdef HAVE_ZLIB_H - ret = zisofs_fix_bootfile(a); - if (ret < 0) - return (ret); -#endif if (iso9660->opt.joliet) { /* Make a new tree for joliet. */ ret = isoent_clone_tree(a, &(iso9660->joliet.rootent), @@ -1987,21 +1991,8 @@ iso9660_free(struct archive_write *a) if (iso9660->temp_fd >= 0) close(iso9660->temp_fd); -#ifdef HAVE_ZLIB_H - if (iso9660->zisofs.temp_fd >= 0) - close(iso9660->zisofs.temp_fd); - free(iso9660->zisofs.block_pointers); - if (iso9660->zisofs.stream_valid) { - switch (deflateEnd(&(iso9660->zisofs.stream))) { - case Z_OK: - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Failed to clean up compressor"); - ret = ARCHIVE_FATAL; - } - } -#endif + /* Free some stuff for zisofs operations. */ + ret = zisofs_free(a); /* Remove directory entries in tree which includes file entries. */ isoent_free_all(iso9660->primary.rootent); @@ -3512,7 +3503,7 @@ wb_consume(struct archive_write *a, size_t size) if (size > iso9660->wbuff_remaining || iso9660->wbuff_remaining == 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Internal Program error: iso9660:wb_consume()" + "Internal Programing error: iso9660:wb_consume()" " size=%jd, wbuff_remaining=%jd", (intmax_t)size, (intmax_t)iso9660->wbuff_remaining); return (ARCHIVE_FATAL); @@ -4275,6 +4266,7 @@ write_directory_descriptors(struct archive_write *a, struct vdd *vdd) static int _write_file_descriptors(struct archive_write *a, struct isoent *isoent) { + struct iso9660 *iso9660 = a->format_data; struct isoent **enttbl; int i, r; @@ -4290,6 +4282,8 @@ _write_file_descriptors(struct archive_write *a, struct isoent *isoent) np = enttbl[i]; if (np->dir) continue; + if (np == iso9660->el_torito.boot) + continue; file = np->file; if (file->boot || file->content.size == 0) continue; @@ -4299,9 +4293,8 @@ _write_file_descriptors(struct archive_write *a, struct isoent *isoent) int64_t size; int64_t pad_size; - lseek(file->temp_fd, - file->cur_content->offset_of_temp, - SEEK_SET); + lseek(iso9660->temp_fd, + file->cur_content->offset_of_temp, SEEK_SET); size = file->cur_content->size; pad_size = size % LOGICAL_BLOCK_SIZE; if (pad_size) @@ -4317,7 +4310,7 @@ _write_file_descriptors(struct archive_write *a, struct isoent *isoent) else rsize = (size_t)size; - rs = read(file->temp_fd, wb, rsize); + rs = read(iso9660->temp_fd, wb, rsize); if (rs <= 0) { archive_set_error(&a->archive, errno, @@ -4342,6 +4335,44 @@ _write_file_descriptors(struct archive_write *a, struct isoent *isoent) return (ARCHIVE_OK); } +static int +write_out_boot_file(struct archive_write *a) +{ + struct iso9660 *iso9660 = a->format_data; + struct isoent *np; + int64_t size; + int r; + + np = iso9660->el_torito.boot; + size = archive_entry_size(np->file->entry); + lseek(iso9660->temp_fd, + np->file->content.offset_of_temp, SEEK_SET); + while (size) { + size_t rsize; + ssize_t rs; + unsigned char *wb; + + wb = wb_buffptr(a); + if (size > wb_remaining(a)) + rsize = wb_remaining(a); + else + rsize = (size_t)size; + + rs = read(iso9660->temp_fd, wb, rsize); + if (rs <= 0) { + archive_set_error(&a->archive, errno, + "Can't read temporary file(%jd)", + (intmax_t)rs); + return (ARCHIVE_FATAL); + } + size -= rs; + r = wb_consume(a, rs); + if (r < 0) + return (r); + } + return (ARCHIVE_OK); +} + static int write_file_descriptors(struct archive_write *a) { @@ -4358,48 +4389,33 @@ write_file_descriptors(struct archive_write *a) } if (iso9660->el_torito.boot != NULL) { int64_t size, padsize; + struct isofile *file; - np = iso9660->el_torito.boot; - size = archive_entry_size(np->file->entry); - lseek(np->file->temp_fd, - np->file->content.offset_of_temp, SEEK_SET); - while (size) { - size_t rsize; - ssize_t rs; - unsigned char *wb; - - wb = wb_buffptr(a); - if (size > wb_remaining(a)) - rsize = wb_remaining(a); - else - rsize = (size_t)size; - - rs = read(np->file->temp_fd, wb, rsize); - if (rs <= 0) { - archive_set_error(&a->archive, errno, - "Can't read temporary file(%jd)", - (intmax_t)rs); - return (ARCHIVE_FATAL); - } - size -= rs; - r = wb_consume(a, rs); - if (r < 0) - return (r); - } - + file = iso9660->el_torito.boot->file; + /* + * If the boot file is being zisofs'ed, we should uncompress + * it and write out the result. + */ + if (file->zisofs.uncompressed_size != 0 && + file->zisofs.log2_bs != 0) + r = zisofs_write_out_boot_file(a); + else + r = write_out_boot_file(a); + if (r < 0) + return (r); /* * Write padding if needed. */ padsize = 0; size = fd_boot_image_size(iso9660->el_torito.media_type); if (size == 0) - size = archive_entry_size(np->file->entry); - else if (size > archive_entry_size(np->file->entry)) { + size = archive_entry_size(file->entry); + else if (size > archive_entry_size(file->entry)) { /* * If the boot image size is not just 1200KB, * 1440KB,or 2880KB, add padding data. */ - padsize = size - archive_entry_size(np->file->entry); + padsize = size - archive_entry_size(file->entry); } size = size % LOGICAL_BLOCK_SIZE; if (size != 0) @@ -4833,63 +4849,6 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file) return (ret); } -#ifdef HAVE_ZLIB_H -static void -get_parent_and_base(struct archive_string *parentdir, - struct archive_string *basename, const char *pathname) -{ - char *p, *slash; - - archive_strcpy(parentdir, pathname); -#if defined(_WIN32) || defined(__CYGWIN__) - /* - * Convert a path-separator from '\' to '/' - */ - if (cleanup_backslash_1(parentdir->s) != 0) { - struct archive_wstring ws; - - archive_string_init(&ws); - if (archive_wstring_append_from_mbs(&ws, - parentdir->s, parentdir->length) == 0) { - cleanup_backslash_2(ws.s); - archive_string_empty(parentdir); - archive_string_append_from_wcs(parentdir, - ws.s, ws.length); - } - archive_wstring_free(&ws); - } -#endif - /* - * - Count up directory elements. - * - Find out the position which points the last position of - * path separator('/'). - */ - slash = NULL; - p = parentdir->s + parentdir->length -1; - if (*p == '/') { - /* Remove '/' from the end of path. */ - *p-- = '\0'; - parentdir->length--; - } - for (;p >= parentdir->s; p--) - if (*p == '/') { - slash = p; - break; - } - if (slash == NULL) { - /* The pathname doesn't have a parent directory. */ - archive_string_copy(basename, parentdir); - archive_string_empty(parentdir); - parentdir->s = '\0'; - } else { - /* Make a basename from dirname and slash */ - *slash = '\0'; - parentdir->length = slash - parentdir->s; - archive_strcpy(basename, slash + 1); - } -} -#endif /* HAVE_ZLIB_H */ - /* * Register a entry to get a hardlink target. */ @@ -5340,6 +5299,8 @@ _isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent, np = children[n]; if (np->dir) continue; + if (np == iso9660->el_torito.boot) + continue; file = np->file; if (file->boot || file->hardlink_target != NULL) continue; @@ -6077,12 +6038,12 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent, } } } - /* Save a offset of a file name extension to sort files. */ + /* Save an offset of a file name extension to sort files. */ np->ext_off = ext_off; np->ext_len = strlen(&p[ext_off]); np->id_len = l = ext_off + np->ext_len; - /* Make a offset of the number which is used to be set + /* Make an offset of the number which is used to be set * hexadecimal number to avoid duplicate identififier. */ if (iso9660->opt.iso_level == 1) { if (ext_off >= 5) @@ -6226,7 +6187,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent, return (ARCHIVE_FATAL); } - /* Make a offset of the number which is used to be set + /* Make an offset of the number which is used to be set * hexadecimal number to avoid duplicate identififier. */ if ((int)l == ffmax) noff = ext_off - 6; @@ -7205,12 +7166,12 @@ setup_boot_information(struct archive_write *a) if (iso9660->wbuff_remaining != 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Internal Program error: " + "Internal Programing error: " "iso9660:setup_boot_information()"); return (ARCHIVE_FATAL); } np = iso9660->el_torito.boot; - lseek(np->file->temp_fd, + lseek(iso9660->temp_fd, np->file->content.offset_of_temp + 64, SEEK_SET); size = archive_entry_size(np->file->entry) - 64; if (size <= 0) { @@ -7228,7 +7189,7 @@ setup_boot_information(struct archive_write *a) else rsize = (size_t)size; - rs = read(np->file->temp_fd, iso9660->wbuff, rsize); + rs = read(iso9660->temp_fd, iso9660->wbuff, rsize); if (rs <= 0) { archive_set_error(&a->archive, errno, "Can't read temporary file(%jd)", @@ -7254,9 +7215,9 @@ setup_boot_information(struct archive_write *a) memset(iso9660->wbuff+16, 0, 40); /* Overwrite the boot file. */ - lseek(np->file->temp_fd, + lseek(iso9660->temp_fd, np->file->content.offset_of_temp + 8, SEEK_SET); - return (write_to_temp(a, iso9660->temp_fd, iso9660->wbuff, 56)); + return (write_to_temp(a, iso9660->wbuff, 56)); } #ifdef HAVE_ZLIB_H @@ -7303,104 +7264,22 @@ zisofs_init_zstream(struct archive_write *a) return (ARCHIVE_OK); } -static void -zisofs_check_bootfile(struct archive_write *a, struct isofile *file) -{ - struct iso9660 *iso9660 = a->format_data; - const char *np, *cp; - struct archive_string parentdir; - struct archive_string basename; - int len, match; - - if (!iso9660->opt.boot) - return; - - archive_string_init(&parentdir); - archive_string_init(&basename); - get_parent_and_base(&parentdir, &basename, - iso9660->el_torito.boot_filename.s); - - if (basename.length != file->basename.length) - goto exit; - if (strcmp(basename.s, file->basename.s) != 0) - goto exit; - if (parentdir.length > file->parentdir.length) - goto exit; - len = parentdir.length; - np = parentdir.s + parentdir.length; - cp = file->parentdir.s + file->parentdir.length; - match = 1; - while (len--) { - if (*--np != *--cp) { - match = 0; - break; - } - } - if (match) { - --cp; - if ((cp >= file->parentdir.s && *cp == '/') || - cp < file->parentdir.s) - file->zisofs.keep_original = 1; - } -exit: - archive_string_free(&parentdir); - archive_string_free(&basename); -} - static int zisofs_fix_bootfile(struct archive_write *a) { struct iso9660 *iso9660 = a->format_data; struct isoent *isoent; struct isofile *file; - struct archive_string parentdir; - struct archive_string basename; - struct archive_string str; - if (!iso9660->opt.boot) - return (ARCHIVE_OK); - - archive_string_init(&str); - archive_string_init(&parentdir); - archive_string_init(&basename); - get_parent_and_base(&parentdir, &basename, - iso9660->el_torito.boot_filename.s); - archive_string_empty(&str); - if (parentdir.length) { - archive_string_copy(&str, &parentdir); - archive_strappend_char(&str, '/'); - } - archive_string_concat(&str, &basename); - isoent = isoent_find_entry(iso9660->primary.rootent, - str.s); - if (isoent == NULL) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Specified file ``%s'' which disable to " - " be zisofs is not found.", - str.s); - archive_string_free(&str); - archive_string_free(&parentdir); - archive_string_free(&basename); - return (ARCHIVE_FATAL); - } - if (isoent->file->zisofs.keep_original) { + isoent = iso9660->el_torito.boot; + if (isoent != NULL && isoent->file->zisofs.header_size != 0) { file = isoent->file; - file->temp_fd = iso9660->temp_fd; - file->content.offset_of_temp = - file->zisofs.original_offset_of_temp; archive_entry_set_size(file->entry, file->zisofs.uncompressed_size); - file->content.size = file->zisofs.uncompressed_size; /* Remark file->zisofs not to create * RRIP 'ZF' Use Entry. */ file->zisofs.header_size = 0; - file->zisofs.log2_bs = 0; - file->zisofs.uncompressed_size = 0; } - archive_string_free(&str); - archive_string_free(&parentdir); - archive_string_free(&basename); return (ARCHIVE_OK); } @@ -7412,14 +7291,14 @@ zisofs_init(struct archive_write *a, struct isofile *file) { struct iso9660 *iso9660 = a->format_data; #ifdef HAVE_ZLIB_H + uint64_t tsize; size_t ceil, bpsize; int r; #endif iso9660->zisofs.detect_magic = 0; -#ifdef HAVE_ZLIB_H iso9660->zisofs.making = 0; -#endif + if (!iso9660->opt.rr || !iso9660->opt.zisofs) return (ARCHIVE_OK); @@ -7440,19 +7319,6 @@ zisofs_init(struct archive_write *a, struct isofile *file) if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE) return (ARCHIVE_OK); - /* - * Create a temporary file, which will be used for saving - * compressed data. - */ - if (iso9660->zisofs.temp_fd < 0) { - iso9660->zisofs.temp_fd = __archive_mktemp(NULL); - if (iso9660->zisofs.temp_fd < 0) { - archive_set_error( &a->archive, errno, - "Can't create temporary file"); - return (ARCHIVE_FATAL); - } - } - /* Initialize compression library */ r = zisofs_init_zstream(a); if (r != ARCHIVE_OK) @@ -7483,30 +7349,24 @@ zisofs_init(struct archive_write *a, struct isofile *file) iso9660->zisofs.block_pointers_allocated = bpsize; } - /* Save a offset of current file in zisofs temporary file. */ - iso9660->zisofs.offset_of_temp = - lseek(iso9660->zisofs.temp_fd, 0, SEEK_CUR); - iso9660->zisofs.total_size = ZF_HEADER_SIZE + bpsize; - /* * Skip zisofs header and Block Pointers, which we will write * after all compressed data of a file written to the temporary * file. */ - lseek(iso9660->zisofs.temp_fd, iso9660->zisofs.total_size, SEEK_CUR); + tsize = ZF_HEADER_SIZE + bpsize; + lseek(iso9660->temp_fd, tsize, SEEK_CUR); /* * Initialize some variables to make zisofs. */ - archive_le32enc(&(iso9660->zisofs.block_pointers[0]), - iso9660->zisofs.total_size); + archive_le32enc(&(iso9660->zisofs.block_pointers[0]), tsize); iso9660->zisofs.remaining = file->zisofs.uncompressed_size; iso9660->zisofs.making = 1; iso9660->zisofs.allzero = 1; - iso9660->zisofs.offset_of_block = iso9660->zisofs.total_size; - - /* Check if this file does not need to be zisofs. */ - zisofs_check_bootfile(a, file); + iso9660->zisofs.block_offset = tsize; + iso9660->zisofs.total_size = tsize; + iso9660->cur_file->cur_content->size = tsize; #endif return (ARCHIVE_OK); @@ -7555,7 +7415,7 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s) iso9660->zisofs.detect_magic = 0; p = magic_buff; - /* Check magic code of zisofs. */ + /* Check the magic code of zisofs. */ if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0) /* This is not zisofs file which made by mkzftree. */ return; @@ -7590,30 +7450,17 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s) doff += bed - bst; ceil--; } -#ifdef HAVE_ZLIB_H - if (file->zisofs.header_size != 0) - zisofs_cancel(iso9660, file); -#endif + file->zisofs.uncompressed_size = uncompressed_size; file->zisofs.header_size = header_size; file->zisofs.log2_bs = log2_bs; -} - -#ifdef HAVE_ZLIB_H - -static void -zisofs_cancel(struct iso9660 *iso9660, struct isofile *file) -{ - /* Remark file->zisofs not to create RRIP 'ZF' Use Entry. */ - file->zisofs.header_size = 0; - file->zisofs.log2_bs = 0; - file->zisofs.uncompressed_size = 0; - lseek(iso9660->zisofs.temp_fd, - iso9660->zisofs.offset_of_temp, SEEK_SET); + /* Disable making a zisofs image. */ iso9660->zisofs.making = 0; } +#ifdef HAVE_ZLIB_H + /* * Compress data and write it to a temporary file. */ @@ -7665,14 +7512,18 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s) */ if (flush == Z_FINISH && iso9660->zisofs.allzero && avail + zstrm->total_in == ZF_BLOCK_SIZE) { - if (iso9660->zisofs.offset_of_block != - iso9660->zisofs.total_size) { - lseek(iso9660->zisofs.temp_fd, - iso9660->zisofs.offset_of_temp + - iso9660->zisofs.offset_of_block, + if (iso9660->zisofs.block_offset != + file->cur_content->size) { + int64_t diff; + + lseek(iso9660->temp_fd, + file->cur_content->offset_of_temp + + iso9660->zisofs.block_offset, SEEK_SET); - iso9660->zisofs.total_size = - iso9660->zisofs.offset_of_block; + diff = file->cur_content->size - + iso9660->zisofs.block_offset; + file->cur_content->size -= diff; + iso9660->zisofs.total_size -= diff; } zstrm->avail_in = 0; } @@ -7687,10 +7538,11 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s) case Z_OK: case Z_STREAM_END: csize = zstrm->total_out - csize; - if (write_to_temp(a, iso9660->zisofs.temp_fd, - iso9660->wbuff, csize) != ARCHIVE_OK) + if (write_to_temp(a, iso9660->wbuff, csize) + != ARCHIVE_OK) return (ARCHIVE_FATAL); iso9660->zisofs.total_size += csize; + iso9660->cur_file->cur_content->size += csize; zstrm->next_out = iso9660->wbuff; zstrm->avail_out = sizeof(iso9660->wbuff); break; @@ -7704,16 +7556,6 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s) } } - /* - * If a size of zisofs data is more than uncompressed size, - * we do not need to make a zisofs extension. - */ - if (iso9660->zisofs.total_size > - file->zisofs.uncompressed_size) { - zisofs_cancel(iso9660, file); - return (ARCHIVE_OK); - } - if (flush == Z_FINISH) { /* * Save the information of one zisofs block. @@ -7726,8 +7568,7 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s) if (r != ARCHIVE_OK) return (ARCHIVE_FATAL); iso9660->zisofs.allzero = 1; - iso9660->zisofs.offset_of_block = - iso9660->zisofs.total_size; + iso9660->zisofs.block_offset = file->cur_content->size; } } while (s); @@ -7742,42 +7583,14 @@ zisofs_finish_entry(struct archive_write *a) unsigned char buff[16]; size_t s; int64_t tail; - int bk1, bk2; - - bk1 = (file->zisofs.uncompressed_size + - LOGICAL_BLOCK_SIZE -1) / LOGICAL_BLOCK_SIZE; - bk2 = (iso9660->zisofs.total_size + - LOGICAL_BLOCK_SIZE -1) / LOGICAL_BLOCK_SIZE; - - /* The number of Logical Blocks which uncompressed data - * will use in iso-image file is the same as the number of - * Logical Blocks which zisofs(compressed) data will use - * in ISO-image file. It won't reduce iso-image file size. */ - if (bk1 == bk2) { - zisofs_cancel(iso9660, file); - return (ARCHIVE_OK); - } - - if (file->zisofs.keep_original) - /* Maybe we will use the original data, which is - * uncompressed but we cannot decide it now. */ - file->zisofs.original_offset_of_temp = - file->content.offset_of_temp; - else - /* Remove the original data, which is uncompressed. */ - lseek(iso9660->temp_fd, file->content.offset_of_temp, - SEEK_SET); /* Direct temp file stream to zisofs temp file stream. */ - file->temp_fd = iso9660->zisofs.temp_fd; - file->content.offset_of_temp = iso9660->zisofs.offset_of_temp; archive_entry_set_size(file->entry, iso9660->zisofs.total_size); - file->content.size = iso9660->zisofs.total_size; /* * Save a file pointer which points the end of current zisofs data. */ - tail = lseek(file->temp_fd, 0, SEEK_CUR); + tail = lseek(iso9660->temp_fd, 0, SEEK_CUR); /* * Make a header. @@ -7813,9 +7626,9 @@ zisofs_finish_entry(struct archive_write *a) buff[14] = buff[15] = 0;/* Reserved */ /* Get the right position to write the header. */ - lseek(file->temp_fd, file->content.offset_of_temp, SEEK_SET); + lseek(iso9660->temp_fd, file->content.offset_of_temp, SEEK_SET); /* Write the header. */ - if (write_to_temp(a, file->temp_fd, buff, 16) != ARCHIVE_OK) + if (write_to_temp(a, buff, 16) != ARCHIVE_OK) return (ARCHIVE_FATAL); /* @@ -7823,15 +7636,342 @@ zisofs_finish_entry(struct archive_write *a) */ s = iso9660->zisofs.block_pointers_cnt * sizeof(iso9660->zisofs.block_pointers[0]); - if (write_to_temp(a, file->temp_fd, iso9660->zisofs.block_pointers, s) + if (write_to_temp(a, iso9660->zisofs.block_pointers, s) != ARCHIVE_OK) return (ARCHIVE_FATAL); /* Set the file pointer to the end of current zisofs data. */ - lseek(file->temp_fd, tail, SEEK_SET); + lseek(iso9660->temp_fd, tail, SEEK_SET); return (ARCHIVE_OK); } +static int +zisofs_free(struct archive_write *a) +{ + struct iso9660 *iso9660 = a->format_data; + int ret = ARCHIVE_OK; + + free(iso9660->zisofs.block_pointers); + if (iso9660->zisofs.stream_valid && + deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Failed to clean up compressor"); + ret = ARCHIVE_FATAL; + } + iso9660->zisofs.block_pointers = NULL; + iso9660->zisofs.stream_valid = 0; + return (ret); +} + +struct zisofs_extract { + int pz_log2_bs; /* Log2 of block size */ + uint64_t pz_uncompressed_size; + size_t uncompressed_buffer_size; + + int initialized:1; + int header_passed:1; + + uint32_t pz_offset; + unsigned char *block_pointers; + size_t block_pointers_size; + size_t block_pointers_avail; + size_t block_off; + uint32_t block_avail; + + z_stream stream; + int stream_valid; +}; + +static ssize_t +zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs, + const unsigned char *p, size_t bytes) +{ + size_t avail = bytes; + size_t ceil, xsize; + + /* Allocate block pointers buffer. */ + ceil = (zisofs->pz_uncompressed_size + + (1LL << zisofs->pz_log2_bs) - 1) + >> zisofs->pz_log2_bs; + xsize = (ceil + 1) * 4; + if (zisofs->block_pointers == NULL) { + size_t alloc = ((xsize >> 10) + 1) << 10; + zisofs->block_pointers = malloc(alloc); + if (zisofs->block_pointers == NULL) { + archive_set_error(&a->archive, ENOMEM, + "No memory for zisofs decompression"); + return (ARCHIVE_FATAL); + } + } + zisofs->block_pointers_size = xsize; + + /* Allocate uncompressed data buffer. */ + zisofs->uncompressed_buffer_size = 1UL << zisofs->pz_log2_bs; + + /* + * Read the file header, and check the magic code of zisofs. + */ + if (!zisofs->header_passed) { + int err = 0; + if (avail < 16) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Illegal zisofs file body"); + return (ARCHIVE_FATAL); + } + + if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0) + err = 1; + else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size) + err = 1; + else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs) + err = 1; + if (err) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Illegal zisofs file body"); + return (ARCHIVE_FATAL); + } + avail -= 16; + p += 16; + zisofs->header_passed = 1; + } + + /* + * Read block pointers. + */ + if (zisofs->header_passed && + zisofs->block_pointers_avail < zisofs->block_pointers_size) { + xsize = zisofs->block_pointers_size + - zisofs->block_pointers_avail; + if (avail < xsize) + xsize = avail; + memcpy(zisofs->block_pointers + + zisofs->block_pointers_avail, p, xsize); + zisofs->block_pointers_avail += xsize; + avail -= xsize; + p += xsize; + if (zisofs->block_pointers_avail + == zisofs->block_pointers_size) { + /* We've got all block pointers and initialize + * related variables. */ + zisofs->block_off = 0; + zisofs->block_avail = 0; + /* Complete a initialization */ + zisofs->initialized = 1; + } + } + return ((ssize_t)avail); +} + +static ssize_t +zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs, + const unsigned char *p, size_t bytes) +{ + size_t avail; + int r; + + if (!zisofs->initialized) { + ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes); + if (rs < 0) + return (rs); + if (!zisofs->initialized) { + /* We need more data. */ + zisofs->pz_offset += bytes; + return (bytes); + } + avail = rs; + p += bytes - avail; + } else + avail = bytes; + + /* + * Get block offsets from block pointers. + */ + if (zisofs->block_avail == 0) { + uint32_t bst, bed; + + if (zisofs->block_off + 4 >= zisofs->block_pointers_size) { + /* There isn't a pair of offsets. */ + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Illegal zisofs block pointers"); + return (ARCHIVE_FATAL); + } + bst = archive_le32dec( + zisofs->block_pointers + zisofs->block_off); + if (bst != zisofs->pz_offset + (bytes - avail)) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Illegal zisofs block pointers(cannot seek)"); + return (ARCHIVE_FATAL); + } + bed = archive_le32dec( + zisofs->block_pointers + zisofs->block_off + 4); + if (bed < bst) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Illegal zisofs block pointers"); + return (ARCHIVE_FATAL); + } + zisofs->block_avail = bed - bst; + zisofs->block_off += 4; + + /* Initialize compression library for new block. */ + if (zisofs->stream_valid) + r = inflateReset(&zisofs->stream); + else + r = inflateInit(&zisofs->stream); + if (r != Z_OK) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can't initialize zisofs decompression."); + return (ARCHIVE_FATAL); + } + zisofs->stream_valid = 1; + zisofs->stream.total_in = 0; + zisofs->stream.total_out = 0; + } + + /* + * Make uncompressed data. + */ + if (zisofs->block_avail == 0) { + /* + * It's basically 32K bytes NUL data. + */ + unsigned char *wb; + size_t size, wsize; + + size = zisofs->uncompressed_buffer_size; + while (size) { + wb = wb_buffptr(a); + if (size > wb_remaining(a)) + wsize = wb_remaining(a); + else + wsize = size; + memset(wb, 0, wsize); + r = wb_consume(a, wsize); + if (r < 0) + return (r); + size -= wsize; + } + } else { + zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p; + if (avail > zisofs->block_avail) + zisofs->stream.avail_in = zisofs->block_avail; + else + zisofs->stream.avail_in = avail; + zisofs->stream.next_out = wb_buffptr(a); + zisofs->stream.avail_out = wb_remaining(a); + + r = inflate(&zisofs->stream, 0); + switch (r) { + case Z_OK: /* Decompressor made some progress.*/ + case Z_STREAM_END: /* Found end of stream. */ + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "zisofs decompression failed (%d)", r); + return (ARCHIVE_FATAL); + } + avail -= zisofs->stream.next_in - p; + zisofs->block_avail -= zisofs->stream.next_in - p; + r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out); + if (r < 0) + return (r); + } + zisofs->pz_offset += bytes; + return (bytes - avail); +} + +static int +zisofs_write_out_boot_file(struct archive_write *a) +{ + struct iso9660 *iso9660 = a->format_data; + struct isofile *file; + ssize_t r; + size_t remaining; + struct zisofs_extract zext; + int ret = ARCHIVE_OK; + + file = iso9660->el_torito.boot->file; + memset(&zext, 0, sizeof(zext)); + zext.pz_uncompressed_size = file->zisofs.uncompressed_size; + zext.pz_log2_bs = file->zisofs.log2_bs; + + lseek(iso9660->temp_fd, file->content.offset_of_temp, SEEK_SET); + remaining = file->content.size; + while (remaining) { + size_t rsize; + ssize_t rs; + unsigned char rbuff[LOGICAL_BLOCK_SIZE * 2]; + + rsize = sizeof(rbuff); + if (rsize > remaining) + rsize = remaining; + rs = read(iso9660->temp_fd, rbuff, rsize); + if (rs <= 0) { + archive_set_error(&a->archive, errno, + "Can't read temporary file(%jd)", + (intmax_t)rs); + return (ARCHIVE_FATAL); + } + remaining -= rs; + r = zisofs_extract(a, &zext, rbuff, rs); + if (r < 0) { + ret = (int)r; + break; + } + } + free(zext.block_pointers); + if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Failed to clean up compressor"); + ret = ARCHIVE_FATAL; + } + return (ARCHIVE_OK); +} + +#else + +static int +zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s) +{ + (void)buff; /* UNUSED */ + (void)s; /* UNUSED */ + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programing error"); + return (ARCHIVE_FATAL); +} + +static int +zisofs_fix_bootfile(struct archive_write *a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_OK); +} + +static int +zisofs_finish_entry(struct archive_write *a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_OK); +} + +static int +zisofs_free(struct archive_write *a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_OK); +} + +static int +zisofs_write_out_boot_file(struct archive_write *a) +{ + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "zisofs decompression is not supported on this platform"); + return (ARCHIVE_FATAL); +} + #endif /* HAVE_ZLIB_H */