X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwrite.c;h=7c4d985c7885903faaca9c0d0b9c73707ae5f4b4;hp=9aa8116c0b3dbb8b84b2c22e3c08eb3d85a04890;hb=79b64b516e5bdb486832f88788362dbe9deb1b61;hpb=3efd3c749f6cef737951769ace2fc802d8d8e61c;ds=sidebyside diff --git a/src/write.c b/src/write.c index 9aa8116c..7c4d985c 100644 --- a/src/write.c +++ b/src/write.c @@ -12,16 +12,16 @@ * This file is part of wimlib, a library for working with WIM files. * * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) + * terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) * any later version. * * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * - * You should have received a copy of the GNU Lesser General Public License + * You should have received a copy of the GNU General Public License * along with wimlib; if not, see http://www.gnu.org/licenses/. */ @@ -32,6 +32,7 @@ #include "xml.h" #include + /* Reopens the FILE* for a WIM read-write. */ static int reopen_rw(WIMStruct *w) { @@ -39,6 +40,7 @@ static int reopen_rw(WIMStruct *w) if (fclose(w->fp) != 0) ERROR_WITH_ERRNO("Failed to close the file `%s'", w->filename); + w->fp = NULL; fp = fopen(w->filename, "r+b"); if (!fp) { ERROR_WITH_ERRNO("Failed to open `%s' for reading and writing", @@ -51,15 +53,20 @@ static int reopen_rw(WIMStruct *w) -/* +/* * Writes a WIM file to the original file that it was read from, overwriting it. */ -WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int flags) +WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int write_flags) { const char *wimfile_name; size_t wim_name_len; int ret; - + + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + + write_flags &= ~WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE; + wimfile_name = w->filename; DEBUG("Replacing WIM file `%s'.", wimfile_name); @@ -75,9 +82,11 @@ WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int flags) randomize_char_array_with_alnum(tmpfile + wim_name_len, 9); tmpfile[wim_name_len + 9] = '\0'; - ret = wimlib_write(w, tmpfile, WIM_ALL_IMAGES, flags); + ret = wimlib_write(w, tmpfile, WIM_ALL_IMAGES, write_flags); if (ret != 0) { ERROR("Failed to write the WIM file `%s'", tmpfile); + if (unlink(tmpfile) != 0) + WARNING("Failed to remove `%s'", tmpfile); return ret; } @@ -105,8 +114,18 @@ WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int flags) return 0; } +static int check_resource_offset(struct lookup_table_entry *lte, void *arg) +{ + u64 xml_data_offset = *(u64*)arg; + if (lte->resource_entry.offset > xml_data_offset) { + ERROR("The following resource is *after* the XML data:"); + print_lookup_table_entry(lte); + return WIMLIB_ERR_RESOURCE_ORDER; + } + return 0; +} -WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int flags) +WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int write_flags) { int ret; FILE *fp; @@ -115,11 +134,35 @@ WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int flags) off_t xml_size; size_t bytes_written; - DEBUG("Overwriting XML and header of `%s', flags = %d", - w->filename, flags); + DEBUG("Overwriting XML and header of `%s', write_flags = %#x", + w->filename, write_flags); + if (!w->filename) return WIMLIB_ERR_NO_FILENAME; + write_flags &= ~WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE; + + /* Make sure that the integrity table (if present) is after the XML + * data, and that there are no stream resources, metadata resources, or + * lookup tables after the XML data. Otherwise, these data would be + * destroyed by this function. */ + if (w->hdr.integrity.offset != 0 && + w->hdr.integrity.offset < w->hdr.xml_res_entry.offset) { + ERROR("Didn't expect the integrity table to be before the XML data"); + return WIMLIB_ERR_RESOURCE_ORDER; + } + + if (w->hdr.lookup_table_res_entry.offset > + w->hdr.xml_res_entry.offset) { + ERROR("Didn't expect the lookup table to be after the XML data"); + return WIMLIB_ERR_RESOURCE_ORDER; + } + + ret = for_lookup_table_entry(w->lookup_table, check_resource_offset, + &w->hdr.xml_res_entry.offset); + if (ret != 0) + return ret; + ret = reopen_rw(w); if (ret != 0) return ret; @@ -130,8 +173,9 @@ WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int flags) * the integrity table include neither the header nor the XML data. * Save it for later if it exists and an integrity table was required. * */ - if (flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY && - w->hdr.integrity.offset != 0) { + if ((write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) + && w->hdr.integrity.offset != 0) + { DEBUG("Reading existing integrity table."); integrity_table = MALLOC(w->hdr.integrity.size); if (!integrity_table) @@ -167,13 +211,14 @@ WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int flags) xml_size = xml_end - w->hdr.xml_res_entry.offset; w->hdr.xml_res_entry.size = xml_size; w->hdr.xml_res_entry.original_size = xml_size; + /* XML data offset is unchanged. */ - if (flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) { + if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) { DEBUG("Writing integrity table."); - w->hdr.integrity.offset = xml_end; + w->hdr.integrity.offset = xml_end; if (integrity_table) { /* The existing integrity table was saved. */ - bytes_written = fwrite(integrity_table, 1, + bytes_written = fwrite(integrity_table, 1, w->hdr.integrity.size, fp); if (bytes_written != w->hdr.integrity.size) { ERROR_WITH_ERRNO("Failed to write integrity " @@ -186,13 +231,17 @@ WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int flags) /* There was no existing integrity table, so a new one * must be calculated. */ ret = write_integrity_table(fp, WIM_HEADER_DISK_SIZE, - w->hdr.lookup_table_res_entry.offset + + w->hdr.lookup_table_res_entry.offset + w->hdr.lookup_table_res_entry.size, - flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS); + write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS); if (ret != 0) - goto err; + return ret; + + off_t end_integrity = ftello(fp); + if (end_integrity == -1) + return WIMLIB_ERR_WRITE; - off_t integrity_size = ftello(fp) - xml_end; + off_t integrity_size = end_integrity - xml_end; w->hdr.integrity.size = integrity_size; w->hdr.integrity.original_size = integrity_size; w->hdr.integrity.flags = 0; @@ -245,17 +294,15 @@ err: /* Write the file resources for the current image. */ static int write_file_resources(WIMStruct *w) { - DEBUG("Writing file resources for image %u.", w->current_image); return for_dentry_in_tree(wim_root_dentry(w), write_dentry_resources, w); } -/* Write the lookup table, xml data, and integrity table, then overwrite the WIM +/* + * Write the lookup table, xml data, and integrity table, then overwrite the WIM * header. - * - * write_lt is zero iff the lookup table is not to be written; i.e. it is - * handled elsewhere. */ -int finish_write(WIMStruct *w, int image, int flags, int write_lt) + */ +int finish_write(WIMStruct *w, int image, int write_flags) { off_t lookup_table_offset; off_t xml_data_offset; @@ -268,39 +315,40 @@ int finish_write(WIMStruct *w, int image, int flags, int write_lt) struct wim_header hdr; FILE *out = w->out_fp; - if (write_lt) { + if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) { + /* Write the lookup table. */ lookup_table_offset = ftello(out); if (lookup_table_offset == -1) return WIMLIB_ERR_WRITE; - DEBUG("Writing lookup table (offset %"PRIu64")", lookup_table_offset); - /* Write the lookup table. */ + DEBUG("Writing lookup table (offset %"PRIu64")", + lookup_table_offset); ret = write_lookup_table(w->lookup_table, out); if (ret != 0) return ret; } - xml_data_offset = ftello(out); if (xml_data_offset == -1) return WIMLIB_ERR_WRITE; - DEBUG("Writing XML data (offset %"PRIu64")", xml_data_offset); /* @hdr will be the header for the new WIM. First copy all the data * from the header in the WIMStruct; then set all the fields that may * have changed, including the resource entries, boot index, and image * count. */ memcpy(&hdr, &w->hdr, sizeof(struct wim_header)); - if (write_lt) { + if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) { lookup_table_size = xml_data_offset - lookup_table_offset; - hdr.lookup_table_res_entry.offset = lookup_table_offset; - hdr.lookup_table_res_entry.size = lookup_table_size; + hdr.lookup_table_res_entry.offset = lookup_table_offset; + hdr.lookup_table_res_entry.size = lookup_table_size; } hdr.lookup_table_res_entry.original_size = hdr.lookup_table_res_entry.size; - hdr.lookup_table_res_entry.flags = WIM_RESHDR_FLAG_METADATA; + hdr.lookup_table_res_entry.flags = WIM_RESHDR_FLAG_METADATA; - ret = write_xml_data(w->wim_info, image, out, - write_lt ? 0 : wim_info_get_total_bytes(w->wim_info)); + DEBUG("Writing XML data (offset %"PRIu64")", xml_data_offset); + ret = write_xml_data(w->wim_info, image, out, + (write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE) ? + wim_info_get_total_bytes(w->wim_info) : 0); if (ret != 0) return ret; @@ -314,18 +362,18 @@ int finish_write(WIMStruct *w, int image, int flags, int write_lt) hdr.xml_res_entry.original_size = xml_data_size; hdr.xml_res_entry.flags = 0; - if (flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) { - ret = write_integrity_table(out, WIM_HEADER_DISK_SIZE, - xml_data_offset, - flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS); + if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) { + ret = write_integrity_table(out, WIM_HEADER_DISK_SIZE, + xml_data_offset, + write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS); if (ret != 0) return ret; end_offset = ftello(out); if (end_offset == -1) return WIMLIB_ERR_WRITE; - integrity_size = end_offset - integrity_offset; - hdr.integrity.offset = integrity_offset; - hdr.integrity.size = integrity_size; + integrity_size = end_offset - integrity_offset; + hdr.integrity.offset = integrity_offset; + hdr.integrity.size = integrity_size; hdr.integrity.original_size = integrity_size; } else { hdr.integrity.offset = 0; @@ -336,7 +384,7 @@ int finish_write(WIMStruct *w, int image, int flags, int write_lt) DEBUG("Updating WIM header."); - /* + /* * In the WIM header, there is room for the resource entry for a * metadata resource labeled as the "boot metadata". This entry should * be zeroed out if there is no bootable image (boot_idx 0). Otherwise, @@ -345,10 +393,10 @@ int finish_write(WIMStruct *w, int image, int flags, int write_lt) */ if (hdr.boot_idx == 0 || !w->image_metadata || (image != WIM_ALL_IMAGES && image != hdr.boot_idx)) { - memset(&hdr.boot_metadata_res_entry, 0, + memset(&hdr.boot_metadata_res_entry, 0, sizeof(struct resource_entry)); } else { - memcpy(&hdr.boot_metadata_res_entry, + memcpy(&hdr.boot_metadata_res_entry, &w->image_metadata[ hdr.boot_idx - 1].metadata_lte->output_resource_entry, sizeof(struct resource_entry)); @@ -371,16 +419,16 @@ int finish_write(WIMStruct *w, int image, int flags, int write_lt) } /* Open file stream and write dummy header for WIM. */ -int begin_write(WIMStruct *w, const char *path, int flags) +int begin_write(WIMStruct *w, const char *path, int write_flags) { const char *mode; DEBUG("Opening `%s' for new WIM", path); /* checking the integrity requires going back over the file to read it. - * XXX - * (It also would be possible to keep a running sha1sum as the file - * as written-- this would be faster, but a bit more complicated) */ - if (flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) + * XXX + * (It also would be possible to keep a running sha1sum as the file is + * written-- this would be faster, but a bit more complicated) */ + if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) mode = "w+b"; else mode = "wb"; @@ -396,44 +444,57 @@ int begin_write(WIMStruct *w, const char *path, int flags) return write_header(&w->hdr, w->out_fp); } -/* Writes the WIM to a file. */ -WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags) +/* Writes a stand-alone WIM to a file. */ +WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, + int image, int write_flags) { int ret; - if (image != WIM_ALL_IMAGES && + if (!w || !path) + return WIMLIB_ERR_INVALID_PARAM; + + write_flags &= ~WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE; + + if (image != WIM_ALL_IMAGES && (image < 1 || image > w->hdr.image_count)) return WIMLIB_ERR_INVALID_IMAGE; + + if (w->hdr.total_parts != 1) { + ERROR("Cannot call wimlib_write() on part of a split WIM"); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } + if (image == WIM_ALL_IMAGES) DEBUG("Writing all images to `%s'.", path); else DEBUG("Writing image %d to `%s'.", image, path); - ret = begin_write(w, path, flags); + ret = begin_write(w, path, write_flags); if (ret != 0) - goto done; + goto out; - for_lookup_table_entry(w->lookup_table, zero_out_refcnts, NULL); + for_lookup_table_entry(w->lookup_table, lte_zero_out_refcnt, NULL); - w->write_flags = flags; + w->write_flags = write_flags; ret = for_image(w, image, write_file_resources); if (ret != 0) { ERROR("Failed to write WIM file resources to `%s'", path); - goto done; + goto out; } ret = for_image(w, image, write_metadata_resource); if (ret != 0) { - ERROR("Failed to write WIM image metadata to `%s'", path); - goto done; + /*ERROR("Failed to write WIM image metadata to `%s'", path);*/ + goto out; } - ret = finish_write(w, image, flags, 1); -done: + ret = finish_write(w, image, write_flags); + +out: DEBUG("Closing output file."); if (w->out_fp != NULL) { if (fclose(w->out_fp) != 0) {