+static void inode_update_lte_ptr(struct wim_inode *inode,
+ struct wim_lookup_table_entry *old_lte,
+ struct wim_lookup_table_entry *new_lte)
+{
+ if (inode->i_lte == old_lte) {
+ inode->i_lte = new_lte;
+ } else {
+ for (unsigned i = 0; i < inode->i_num_ads; i++) {
+ if (inode->i_ads_entries[i].lte == old_lte) {
+ inode->i_ads_entries[i].lte = new_lte;
+ break;
+ }
+ }
+ }
+}
+
+static int update_lte_of_staging_file(struct wim_lookup_table_entry *lte,
+ struct wim_lookup_table *table)
+{
+ struct wim_lookup_table_entry *duplicate_lte;
+ int ret;
+ u8 hash[SHA1_HASH_SIZE];
+ struct stat stbuf;
+
+ ret = sha1sum(lte->staging_file_name, hash);
+ if (ret != 0)
+ return ret;
+ lookup_table_unlink(table, lte);
+ duplicate_lte = __lookup_resource(table, hash);
+ if (duplicate_lte) {
+ /* Merge duplicate lookup table entries */
+ duplicate_lte->refcnt += lte->refcnt;
+ inode_update_lte_ptr(lte->lte_inode, lte, duplicate_lte);
+ free_lookup_table_entry(lte);
+ } else {
+ if (stat(lte->staging_file_name, &stbuf) != 0) {
+ ERROR_WITH_ERRNO("Failed to stat `%s'", lte->staging_file_name);
+ return WIMLIB_ERR_STAT;
+ }
+ if (stbuf.st_size == 0) {
+ /* Zero-length stream. No lookup table entry needed. */
+ inode_update_lte_ptr(lte->lte_inode, lte, NULL);
+ free_lookup_table_entry(lte);
+ } else {
+ BUILD_BUG_ON(<e->file_on_disk != <e->staging_file_name);
+ lte->resource_entry.original_size = stbuf.st_size;
+ lte->resource_entry.size = stbuf.st_size;
+ lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
+ lte->file_on_disk_fp = NULL;
+ copy_hash(lte->hash, hash);
+ lookup_table_insert(table, lte);
+ }
+ }
+ return 0;
+}
+
+static int inode_close_fds(struct wim_inode *inode)
+{
+ u16 num_opened_fds = inode->i_num_opened_fds;
+ for (u16 i = 0, j = 0; j < num_opened_fds; i++) {
+ struct wimfs_fd *fd = inode->i_fds[i];
+ if (fd) {
+ wimlib_assert(fd->f_inode == inode);
+ int ret = close_wimfs_fd(fd);
+ if (ret != 0)
+ return ret;
+ j++;
+ }
+ }
+ return 0;
+}
+
+/* Overwrites the WIM file, with changes saved. */
+static int rebuild_wim(struct wimfs_context *ctx, int write_flags,
+ wimlib_progress_func_t progress_func)
+{
+ int ret;
+ struct wim_lookup_table_entry *lte, *tmp;
+ WIMStruct *w = ctx->wim;
+
+ DEBUG("Closing all staging file descriptors.");
+ list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
+ ret = inode_close_fds(lte->lte_inode);
+ if (ret != 0)
+ return ret;
+ }
+
+ DEBUG("Calculating SHA1 checksums for all new staging files.");
+ list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
+ ret = update_lte_of_staging_file(lte, w->lookup_table);
+ if (ret != 0)
+ return ret;
+ }
+
+ xml_update_image_info(w, w->current_image);
+ ret = wimlib_overwrite(w, write_flags, 0, progress_func);
+ if (ret != 0)
+ ERROR("Failed to commit changes to mounted WIM image");
+ return ret;
+}
+
+