* (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"
struct isofile *hardlink_target;
struct archive_entry *entry;
- int temp_fd;
/*
* Used for making a directory tree.
unsigned char header_size;
unsigned char log2_bs;
uint32_t uncompressed_size;
- int keep_original;
- int64_t original_offset_of_temp;
} zisofs;
};
* : 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=<boot-image>', that
* : 'boot-image' file won't be converted to zisofs file.
/* 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
* 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;
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 *);
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)
* 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;
}
}
- /* 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);
}
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");
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)
{
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.
*/
"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);
}
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);
}
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),
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);
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);
static int
_write_file_descriptors(struct archive_write *a, struct isoent *isoent)
{
+ struct iso9660 *iso9660 = a->format_data;
struct isoent **enttbl;
int i, r;
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;
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)
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,
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)
{
}
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)
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.
*/
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;
}
}
}
- /* 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)
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;
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) {
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)",
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
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);
}
{
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);
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)
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);
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;
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.
*/
*/
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;
}
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;
}
}
- /*
- * 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.
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);
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.
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);
/*
*/
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 */