/* Currently ignored; set to 1 in new lookup table entries. */
u16 part_number;
- /* Number of times this lookup table entry is referenced by dentries. */
- u32 refcnt;
-
/* If %true, this lookup table entry corresponds to a symbolic link
* reparse buffer. @symlink_reparse_data_buf will give the target of
* the symbolic link. */
bool is_symlink;
+ /* Number of times this lookup table entry is referenced by dentries. */
+ u32 refcnt;
+
union {
/* SHA1 hash of the file resource pointed to by this lookup
* table entry */
*
* output_resource_entry is the struct resource_entry for the position of the
* file resource when written to the output file. */
+ u32 out_refcnt;
union {
- u32 out_refcnt;
- bool refcnt_is_incremented;
+ struct resource_entry output_resource_entry;
+ struct list_head staging_list;
};
- struct resource_entry output_resource_entry;
struct dentry *hard_link_sets;
};
extern int lookup_resource(WIMStruct *w, const char *path,
int lookup_flags, struct dentry **dentry_ret,
struct lookup_table_entry **lte_ret,
- u8 **hash_ret);
+ unsigned *stream_idx_ret);
extern int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore);
extern int write_lookup_table_entry(struct lookup_table_entry *lte, void *__out);
-static inline void free_lookup_table_entry(struct lookup_table_entry *lte)
-{
- if (lte) {
- FREE(lte->file_on_disk);
- FREE(lte);
- }
-}
+extern void free_lookup_table_entry(struct lookup_table_entry *lte);
/* Writes the lookup table to the output file. */
static inline int write_lookup_table(struct lookup_table *table, FILE *out)
* numbers. */
static u64 next_link_group_id;
+/* List of lookup table entries in the staging directory */
+static LIST_HEAD(staging_list);
static inline int get_lookup_flags()
{
}
}
+/* Change the hash value of the main or alternate file stream in a hard link
+ * group. This needs to be done if the hash of the corresponding lookup table
+ * entry was changed. */
+static void link_group_set_stream_hash(struct dentry *dentry,
+ unsigned stream_idx,
+ const u8 new_hash[])
+{
+ struct list_head *head, *cur;
+
+ if (stream_idx == 0) {
+ head = &dentry->link_group_list;
+ cur = head;
+ do {
+ dentry = container_of(cur, struct dentry, link_group_list);
+ memcpy(dentry->hash, new_hash, WIM_HASH_SIZE);
+ cur = cur->next;
+ } while (cur != head);
+ } else {
+ /* Dentries in the link group share their alternate stream
+ * entries. */
+ wimlib_assert(stream_idx <= dentry->num_ads);
+ memcpy(dentry->ads_entries[stream_idx - 1].hash, new_hash,
+ WIM_HASH_SIZE);
+ }
+}
+
/* Creates a new staging file and returns its file descriptor opened for
* writing.
*
new_lte->num_allocated_fds = num_transferred_fds;
}
} else {
+ /* No old_lte was supplied, so the resource had no lookup table
+ * entry before (it must be an empty resource) */
new_lte = new_lookup_table_entry();
if (!new_lte) {
ret = -ENOMEM;
new_lte->staging_file_name = staging_file_name;
lookup_table_insert(w->lookup_table, new_lte);
+ list_add(&new_lte->staging_list, &staging_list);
*lte = new_lte;
return 0;
out_delete_staging_file:
/* Closes the staging file descriptor associated with the lookup table entry, if
* it is opened. */
-static int close_lte_fds(struct lookup_table_entry *lte, void *ignore)
+static int close_lte_fds(struct lookup_table_entry *lte)
{
- for (u16 i = 0; i < lte->num_opened_fds; i++) {
+ for (u16 i = 0, j = 0; j < lte->num_opened_fds; i++) {
if (lte->fds[i] && lte->fds[i]->staging_fd != -1) {
if (close(lte->fds[i]->staging_fd) != 0) {
ERROR_WITH_ERRNO("Failed close file `%s'",
lte->staging_file_name);
return WIMLIB_ERR_WRITE;
}
+ j++;
}
}
return 0;
* file. Updates the SHA1 sum in the dentry and the lookup table entry. If
* there is already a lookup table entry with the same checksum, increment its
* reference count and destroy the lookup entry with the updated checksum. */
-static int calculate_sha1sum_for_staging_file(struct dentry *dentry,
- void *_lookup_table)
+static int calculate_sha1sum_of_staging_file(struct dentry *dentry,
+ void *__lookup_table)
{
- struct lookup_table *lookup_table = _lookup_table;
+ struct lookup_table *lookup_table = __lookup_table;
u8 *hash = dentry->hash;
u16 i = 0;
while (1) {
static int rebuild_wim(WIMStruct *w, bool check_integrity)
{
int ret;
- struct dentry *root;
-
- root = wim_root_dentry(w);
+ struct lookup_table_entry *lte;
- DEBUG("Closing all staging file descriptors.");
/* Close all the staging file descriptors. */
- ret = for_lookup_table_entry(w->lookup_table, close_lte_fds, NULL);
- if (ret != 0) {
- ERROR("Failed to close all staging files");
- return ret;
+ DEBUG("Closing all staging file descriptors.");
+ list_for_each_entry(lte, &staging_list, staging_list) {
+ ret = close_lte_fds(lte);
+ if (ret != 0)
+ return ret;
}
- DEBUG("Calculating SHA1 checksums for all new staging files.");
/* Calculate SHA1 checksums for all staging files, and merge unnecessary
* lookup table entries. */
- ret = for_dentry_in_tree(root, calculate_sha1sum_for_staging_file,
- w->lookup_table);
- if (ret != 0) {
- ERROR("Failed to calculate new SHA1 checksums");
+ DEBUG("Calculating SHA1 checksums for all new staging files.");
+ ret = for_dentry_in_tree(wim_root_dentry(w),
+ calculate_sha1sum_of_staging_file, w->lookup_table);
+ if (ret != 0)
return ret;
- }
xml_update_image_info(w, w->current_image);
u8 *dentry_hash;
int ret;
struct wimlib_fd *fd;
+ unsigned stream_idx;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry, <e,
- &dentry_hash);
+ &stream_idx);
if (ret != 0)
return ret;
ret = extract_resource_to_staging_dir(dentry, <e, 0);
if (ret != 0)
return ret;
- memcpy(dentry_hash, lte->hash, WIM_HASH_SIZE);
+ link_group_set_stream_hash(dentry, stream_idx, lte->hash);
}
ret = alloc_wimlib_fd(lte, &fd);
lte->resource_entry.original_size);
if (ret != 0)
return ret;
- memcpy(dentry_hash, lte->hash, WIM_HASH_SIZE);
+ link_group_set_stream_hash(dentry, stream_idx, lte->hash);
}
if (lte->staging_file_name) {
fd->staging_fd = open(lte->staging_file_name, fi->flags);
struct dentry *dentry;
struct lookup_table_entry *lte;
int ret;
- u8 *dentry_hash;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
- <e, &dentry_hash);
+ <e, NULL);
if (ret != 0)
return ret;
struct lookup_table_entry *lte;
int ret;
u8 *dentry_hash;
+ unsigned stream_idx;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
- <e, &dentry_hash);
+ <e, &stream_idx);
if (ret != 0)
return ret;
- if (dentry_hash == dentry->hash) {
+ if (stream_idx == 0) {
/* We are removing the full dentry including all alternate data
* streams. */
remove_dentry(dentry, w->lookup_table);
} else {
/* We are removing an alternate data stream. */
- struct ads_entry *cur_entry = dentry->ads_entries;
- while (cur_entry->hash != dentry_hash)
- cur_entry++;
- lookup_table_decrement_refcnt(w->lookup_table, cur_entry->hash);
+ struct ads_entry *ads_entry;
+
+ ads_entry = &dentry->ads_entries[stream_idx - 1];
+
+ lookup_table_decrement_refcnt(w->lookup_table, ads_entry->hash);
- dentry_remove_ads(dentry, cur_entry);
+ dentry_remove_ads(dentry, ads_entry);
}
/* Beware: The lookup table entry(s) may still be referenced by users
* that have opened the corresponding streams. They are freed later in