From: Eric Biggers Date: Sun, 28 Oct 2012 02:59:10 +0000 (-0500) Subject: Cleanup WIM writing X-Git-Tag: v1.0.4~31 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=16e3b6e5615abcefc9e5bb9607e2804b64d19cc2 Cleanup WIM writing --- diff --git a/src/dentry.c b/src/dentry.c index bca9f35e..7d17fb9c 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -40,6 +40,9 @@ #include "wimlib_internal.h" +/* Calculates the unaligned length, in bytes, of an on-disk WIM dentry that has + * a file name and short name that take the specified numbers of bytes. This + * excludes any alternate data stream entries that may follow the dentry. */ static u64 __dentry_correct_length_unaligned(u16 file_name_len, u16 short_name_len) { @@ -51,23 +54,25 @@ static u64 __dentry_correct_length_unaligned(u16 file_name_len, return length; } +/* Calculates the unaligned length, in bytes, of an on-disk WIM dentry, based on + * the file name length and short name length. Note that dentry->length is + * ignored; also, this excludes any alternate data stream entries that may + * follow the dentry. */ static u64 dentry_correct_length_unaligned(const struct dentry *dentry) { return __dentry_correct_length_unaligned(dentry->file_name_len, dentry->short_name_len); } -/* Return the "correct" value to write in the length field of the dentry, based - * on the file name length and short name length */ +/* Return the "correct" value to write in the length field of a WIM dentry, + * based on the file name length and short name length. */ static u64 dentry_correct_length(const struct dentry *dentry) { return (dentry_correct_length_unaligned(dentry) + 7) & ~7; } -/* - * Returns true if @dentry has the UTF-8 file name @name that has length - * @name_len. - */ +/* Return %true iff @dentry has the UTF-8 file name @name that has length + * @name_len bytes. */ static bool dentry_has_name(const struct dentry *dentry, const char *name, size_t name_len) { @@ -76,6 +81,8 @@ static bool dentry_has_name(const struct dentry *dentry, const char *name, return memcmp(dentry->file_name_utf8, name, name_len) == 0; } +/* Return %true iff the alternate data stream entry @entry has the UTF-8 stream + * name @name that has length @name_len bytes. */ static inline bool ads_entry_has_name(const struct ads_entry *entry, const char *name, size_t name_len) { @@ -163,14 +170,16 @@ static u64 __dentry_total_length(const struct dentry *dentry, u64 length) return (length + 7) & ~7; } +/* Calculate the aligned *total* length of an on-disk WIM dentry. This includes + * all alternate data streams. */ u64 dentry_correct_total_length(const struct dentry *dentry) { return __dentry_total_length(dentry, dentry_correct_length_unaligned(dentry)); } -/* Real length of a dentry, including the alternate data stream entries, which - * are not included in the dentry->length field... */ +/* Like dentry_correct_total_length(), but use the existing dentry->length field + * instead of calculating its "correct" value. */ static u64 dentry_total_length(const struct dentry *dentry) { return __dentry_total_length(dentry, dentry->length); @@ -352,13 +361,14 @@ oom: * * @dentry: The root of the directory tree. * @subdir_offset_p: The current subdirectory offset; i.e., the subdirectory - * offset for @dentry. + * offset for @dentry. */ void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p) { - struct dentry *child; + struct dentry *child, *children; - child = dentry->d_inode->children; + children = dentry->d_inode->children; + child = children; dentry->subdir_offset = *subdir_offset_p; if (child) { @@ -367,7 +377,7 @@ void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p) do { *subdir_offset_p += dentry_correct_total_length(child); child = child->next; - } while (child != dentry->d_inode->children); + } while (child != children); /* End-of-directory dentry on disk. */ *subdir_offset_p += 8; @@ -377,7 +387,7 @@ void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p) do { calculate_subdir_offsets(child, subdir_offset_p); child = child->next; - } while (child != dentry->d_inode->children); + } while (child != children); } else { /* On disk, childless directories have a valid subdir_offset * that points to an 8-byte end-of-directory dentry. Regular @@ -1675,7 +1685,7 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p) * @parent itself, which has already been written. */ static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p) { - const struct dentry *child; + const struct dentry *child, *children; /* Nothing to do if this dentry has no children. */ if (parent->subdir_offset == 0) @@ -1687,12 +1697,13 @@ static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p) * recursively writing the directory trees rooted at each of the child * dentries, since the on-disk dentries for a dentry's children are * always located at consecutive positions in the metadata resource! */ - child = parent->d_inode->children; + children = parent->d_inode->children; + child = children; if (child) { do { p = write_dentry(child, p); child = child->next; - } while (child != parent->d_inode->children); + } while (child != children); } /* write end of directory entry */ @@ -1703,7 +1714,7 @@ static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p) do { p = write_dentry_tree_recursive(child, p); child = child->next; - } while (child != parent->d_inode->children); + } while (child != children); } return p; } @@ -1717,6 +1728,7 @@ static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p) */ u8 *write_dentry_tree(const struct dentry *root, u8 *p) { + DEBUG("Writing dentry tree."); wimlib_assert(dentry_is_root(root)); /* If we're the root dentry, we have no parent that already diff --git a/src/integrity.c b/src/integrity.c index 73dd94f6..f1e208f1 100644 --- a/src/integrity.c +++ b/src/integrity.c @@ -252,16 +252,16 @@ out: int write_integrity_table(FILE *out, u64 end_header_offset, u64 end_lookup_table_offset, int show_progress) { - u64 bytes_to_check; - u64 bytes_remaining; - u8 *buf; - u8 *p; - u8 *chunk_buf; - u32 num_entries; - u32 integrity_table_size; - int ret; - - DEBUG("Writing integrity table"); + u64 bytes_to_check; + u64 bytes_remaining; + u8 *buf; + u8 *p; + u8 *chunk_buf; + u32 num_entries; + u32 integrity_table_size; + int ret; + + DEBUG("Calculating integrity table"); if (fseeko(out, end_header_offset, SEEK_SET) != 0) { ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" of WIM to " "calculate integrity data", end_header_offset); @@ -269,12 +269,11 @@ int write_integrity_table(FILE *out, u64 end_header_offset, } bytes_to_check = end_lookup_table_offset - end_header_offset; - num_entries = bytes_to_check / INTEGRITY_CHUNK_SIZE + - (bytes_to_check % INTEGRITY_CHUNK_SIZE != 0); + num_entries = (bytes_to_check + INTEGRITY_CHUNK_SIZE - 1) / + INTEGRITY_CHUNK_SIZE; integrity_table_size = num_entries * SHA1_HASH_SIZE + 3 * sizeof(u32); - DEBUG("integrity table size = %u", integrity_table_size); - + DEBUG("integrity_table_size = %u", integrity_table_size); buf = MALLOC(integrity_table_size); if (!buf) { @@ -292,7 +291,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset, ERROR("Failed to allocate %u bytes for integrity chunk buffer", INTEGRITY_CHUNK_SIZE); ret = WIMLIB_ERR_NOMEM; - goto err2; + goto out_free_buf; } bytes_remaining = bytes_to_check; @@ -325,7 +324,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset, "checksums"); } ret = WIMLIB_ERR_READ; - goto err2; + goto out_free_chunk_buf; } sha1_buffer(chunk_buf, bytes_read, p); p += SHA1_HASH_SIZE; @@ -340,19 +339,19 @@ int write_integrity_table(FILE *out, u64 end_header_offset, ERROR_WITH_ERRNO("Failed to seek to end of WIM to write " "integrity table"); ret = WIMLIB_ERR_WRITE; - goto err1; + goto out_free_chunk_buf; } if (fwrite(buf, 1, integrity_table_size, out) != integrity_table_size) { ERROR_WITH_ERRNO("Failed to write integrity table to end of " "WIM"); ret = WIMLIB_ERR_WRITE; - goto err1; + goto out_free_chunk_buf; } ret = 0; -err1: +out_free_chunk_buf: FREE(chunk_buf); -err2: +out_free_buf: FREE(buf); return ret; } diff --git a/src/join.c b/src/join.c index 8bdd24be..d32fc1fe 100644 --- a/src/join.c +++ b/src/join.c @@ -272,7 +272,8 @@ static int join_wims(WIMStruct **swms, uint num_swms, WIMStruct *joined_wim, * attached to it. */ swms[0]->hdr.flags &= ~WIM_HDR_FLAG_SPANNED; swms[0]->hdr.total_parts = 1; - return finish_write(swms[0], WIM_ALL_IMAGES, write_flags, 0); + return finish_write(swms[0], WIM_ALL_IMAGES, + write_flags | WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE); } diff --git a/src/resource.c b/src/resource.c index ffcd7530..69ccf384 100644 --- a/src/resource.c +++ b/src/resource.c @@ -435,6 +435,10 @@ u8 *put_resource_entry(u8 *p, const struct resource_entry *entry) int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], size_t size, u64 offset, bool raw) { + int ctype; + int ret = 0; + FILE *fp; + /* We shouldn't be allowing read over-runs in any part of the library. * */ if (raw) @@ -442,16 +446,13 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], else wimlib_assert(offset + size <= lte->resource_entry.original_size); - int ctype; - int ret; - FILE *fp; switch (lte->resource_location) { case RESOURCE_IN_WIM: /* The resource is in a WIM file, and its WIMStruct is given by * the lte->wim member. The resource may be either compressed * or uncompressed. */ - wimlib_assert(lte->wim); - wimlib_assert(lte->wim->fp); + wimlib_assert(lte->wim != NULL); + wimlib_assert(lte->wim->fp != NULL); ctype = wim_resource_compression_type(lte); wimlib_assert(ctype != WIM_COMPRESSION_TYPE_NONE || @@ -459,15 +460,15 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], lte->resource_entry.size)); if (raw || ctype == WIM_COMPRESSION_TYPE_NONE) - return read_uncompressed_resource(lte->wim->fp, - lte->resource_entry.offset + offset, - size, buf); + ret = read_uncompressed_resource(lte->wim->fp, + lte->resource_entry.offset + offset, + size, buf); else - return read_compressed_resource(lte->wim->fp, - lte->resource_entry.size, - lte->resource_entry.original_size, - lte->resource_entry.offset, - ctype, size, offset, buf); + ret = read_compressed_resource(lte->wim->fp, + lte->resource_entry.size, + lte->resource_entry.original_size, + lte->resource_entry.offset, + ctype, size, offset, buf); break; case RESOURCE_IN_STAGING_FILE: case RESOURCE_IN_FILE_ON_DISK: @@ -484,46 +485,45 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], if (!fp) { ERROR_WITH_ERRNO("Failed to open the file " "`%s'", lte->file_on_disk); - return WIMLIB_ERR_OPEN; + ret = WIMLIB_ERR_OPEN; + break; } } ret = read_uncompressed_resource(fp, offset, size, buf); if (fp != lte->file_on_disk_fp) fclose(fp); - return ret; break; case RESOURCE_IN_ATTACHED_BUFFER: /* The resource is directly attached uncompressed in an * in-memory buffer. */ - wimlib_assert(lte->attached_buffer); + wimlib_assert(lte->attached_buffer != NULL); memcpy(buf, lte->attached_buffer + offset, size); - return 0; break; #ifdef WITH_NTFS_3G case RESOURCE_IN_NTFS_VOLUME: - wimlib_assert(lte->ntfs_loc); - if (lte->attr) { + wimlib_assert(lte->ntfs_loc != NULL); + wimlib_assert(lte->attr != NULL); + { u64 adjusted_offset; if (lte->ntfs_loc->is_reparse_point) adjusted_offset = offset + 8; else adjusted_offset = offset; - if (ntfs_attr_pread(lte->attr, offset, size, buf) == size) { - return 0; - } else { + if (ntfs_attr_pread(lte->attr, offset, size, buf) != size) { ERROR_WITH_ERRNO("Error reading NTFS attribute " "at `%s'", lte->ntfs_loc->path_utf8); - return WIMLIB_ERR_NTFS_3G; + ret = WIMLIB_ERR_NTFS_3G; } - } else { - wimlib_assert(0); + break; } - break; #endif default: - assert(0); + wimlib_assert(0); + ret = -1; + break; } + return ret; } /* @@ -571,7 +571,6 @@ begin_wim_resource_chunk_tab(const struct lookup_table_entry *lte, struct chunk_table *chunk_tab = CALLOC(1, alloc_size); int ret; - if (!chunk_tab) { ERROR("Failed to allocate chunk table for %"PRIu64" byte " "resource", size); @@ -757,8 +756,8 @@ static int write_wim_resource(struct lookup_table_entry *lte, u64 original_size; u64 old_compressed_size; u64 new_compressed_size; - u64 offset = 0; - int ret = 0; + u64 offset; + int ret; struct chunk_table *chunk_tab = NULL; bool raw; off_t file_offset; @@ -859,6 +858,7 @@ static int write_wim_resource(struct lookup_table_entry *lte, /* While there are still bytes remaining in the WIM resource, read a * chunk of the resource, update SHA1, then write that chunk using the * desired compression type. */ + offset = 0; do { u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE); ret = read_wim_resource(lte, buf, to_read, offset, raw); @@ -941,22 +941,23 @@ static int write_wim_resource(struct lookup_table_entry *lte, if (ftruncate(fileno(out_fp), file_offset + out_res_entry->size) != 0) { ERROR_WITH_ERRNO("Failed to truncate output WIM file"); ret = WIMLIB_ERR_WRITE; + goto out_fclose; + } + } else { + if (out_res_entry) { + out_res_entry->size = new_compressed_size; + out_res_entry->original_size = original_size; + out_res_entry->offset = file_offset; + out_res_entry->flags = lte->resource_entry.flags + & ~WIM_RESHDR_FLAG_COMPRESSED; + if (out_ctype != WIM_COMPRESSION_TYPE_NONE) + out_res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED; } - goto out_fclose; - } - wimlib_assert(new_compressed_size <= original_size || raw); - if (out_res_entry) { - out_res_entry->size = new_compressed_size; - out_res_entry->original_size = original_size; - out_res_entry->offset = file_offset; - out_res_entry->flags = lte->resource_entry.flags - & ~WIM_RESHDR_FLAG_COMPRESSED; - if (out_ctype != WIM_COMPRESSION_TYPE_NONE) - out_res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED; } + ret = 0; out_fclose: if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK - && lte->file_on_disk_fp) { + && lte->file_on_disk_fp) { fclose(lte->file_on_disk_fp); lte->file_on_disk_fp = NULL; } @@ -965,9 +966,9 @@ out_fclose: if (lte->attr) { ntfs_attr_close(lte->attr); lte->attr = NULL; - } if (ni) { - ntfs_inode_close(ni); } + if (ni) + ntfs_inode_close(ni); } #endif out: @@ -983,7 +984,7 @@ static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size, struct resource_entry *out_res_entry, u8 hash[SHA1_HASH_SIZE]) { - /* Set up a temporary lookup table entry that we provide to + /* Set up a temporary lookup table entry to provide to * write_wim_resource(). */ struct lookup_table_entry lte; int ret; @@ -1286,7 +1287,8 @@ int write_metadata_resource(WIMStruct *w) /* We do not allow the security data pointer to be NULL, although it may * point to an empty security data with no entries. */ - wimlib_assert(sd); + wimlib_assert(root != NULL); + wimlib_assert(sd != NULL); /* Offset of first child of the root dentry. It's equal to: * - The total length of the security data, rounded to the next 8-byte @@ -1316,7 +1318,6 @@ int write_metadata_resource(WIMStruct *w) p = write_security_data(sd, buf); /* Write the dentry tree into the resource buffer */ - DEBUG("Writing dentry tree."); p = write_dentry_tree(root, p); /* @@ -1336,6 +1337,8 @@ int write_metadata_resource(WIMStruct *w) * it. */ lte = wim_metadata_lookup_table_entry(w); + wimlib_assert(lte != NULL); + /* Write the metadata resource to the output WIM using the proper * compression type. The lookup table entry for the metadata resource * is updated. */ diff --git a/src/split.c b/src/split.c index 2cb5a8e4..971306c3 100644 --- a/src/split.c +++ b/src/split.c @@ -67,7 +67,8 @@ static int finish_swm(WIMStruct *w, struct lookup_table_entry *lte_chain_head, w->hdr.lookup_table_res_entry.offset = lookup_table_offset; w->hdr.lookup_table_res_entry.size = xml_data_offset - lookup_table_offset; - ret = finish_write(w, WIM_ALL_IMAGES, write_flags, 0); + ret = finish_write(w, WIM_ALL_IMAGES, + write_flags | WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE); if (ret != 0) return ret; diff --git a/src/util.c b/src/util.c index b68db910..c0167826 100644 --- a/src/util.c +++ b/src/util.c @@ -180,6 +180,8 @@ static const char *error_strings[] = { = "Could not read the target of a symbolic link", [WIMLIB_ERR_RENAME] = "Could not rename a file", + [WIMLIB_ERR_RESOURCE_ORDER] + = "The components of the WIM were arranged in an unexpected order", [WIMLIB_ERR_SPECIAL_FILE] = "Encountered a special file that cannot be archived", [WIMLIB_ERR_SPLIT_INVALID] diff --git a/src/wimlib.h b/src/wimlib.h index dddfd2ad..076aee17 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -346,6 +346,7 @@ enum wimlib_error_code { WIMLIB_ERR_READLINK, WIMLIB_ERR_READ, WIMLIB_ERR_RENAME, + WIMLIB_ERR_RESOURCE_ORDER, WIMLIB_ERR_SPECIAL_FILE, WIMLIB_ERR_SPLIT_INVALID, WIMLIB_ERR_SPLIT_UNSUPPORTED, @@ -1113,6 +1114,11 @@ extern int wimlib_overwrite(WIMStruct *wim, int flags); * from the WIM file associated with @a wim could not be read to compute * the SHA1 message digests, or the old integrity table (if it existed) * could not be read. + * @retval ::WIMLIB_ERR_RESOURCE_ORDER + * Stream resources appeared in the WIM after the XML data or integrity + * table, so we could not safely overwrite the XML data and integrity + * table. Note: this error should never be received from WIMs that were + * written by this library. * @retval ::WIMLIB_ERR_WRITE * Failed to write the WIM header, the XML data, or the integrity table to * the WIM file associated with @a wim. diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 08d764d1..edadad2a 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -470,11 +470,12 @@ extern int select_wim_image(WIMStruct *w, int image); extern int wim_hdr_flags_compression_type(int wim_hdr_flags); extern int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)); -/* write.c */ -extern int finish_write(WIMStruct *w, int image, int flags, - int write_lookup_table); +/* Internal use only */ +#define WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE 0x80000000 -extern int begin_write(WIMStruct *w, const char *path, int flags); +/* write.c */ +extern int begin_write(WIMStruct *w, const char *path, int write_flags); +extern int finish_write(WIMStruct *w, int image, int write_flags); #include "wimlib.h" diff --git a/src/write.c b/src/write.c index 124e1bbc..fd61ae1d 100644 --- a/src/write.c +++ b/src/write.c @@ -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", @@ -54,7 +56,7 @@ 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; @@ -63,6 +65,8 @@ WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int flags) 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); @@ -78,7 +82,7 @@ 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); return ret; @@ -108,8 +112,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; @@ -118,11 +132,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; @@ -133,8 +171,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) @@ -170,10 +209,11 @@ 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, @@ -191,11 +231,15 @@ WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *w, int flags) ret = write_integrity_table(fp, WIM_HEADER_DISK_SIZE, 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; @@ -252,12 +296,11 @@ static int write_file_resources(WIMStruct *w) 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; @@ -270,39 +313,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; + DEBUG("Writing XML data (offset %"PRIu64")", xml_data_offset); ret = write_xml_data(w->wim_info, image, out, - write_lt ? 0 : wim_info_get_total_bytes(w->wim_info)); + (write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE) ? + wim_info_get_total_bytes(w->wim_info) : 0); if (ret != 0) return ret; @@ -316,18 +360,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) { + if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) { ret = write_integrity_table(out, WIM_HEADER_DISK_SIZE, xml_data_offset, - flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS); + 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; @@ -373,16 +417,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) + * (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"; @@ -398,14 +442,17 @@ 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 (!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; @@ -421,30 +468,30 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags) 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, 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; + goto out; } - ret = finish_write(w, image, flags, 1); + ret = finish_write(w, image, write_flags); -done: +out: DEBUG("Closing output file."); if (w->out_fp != NULL) { if (fclose(w->out_fp) != 0) {