-static int
-init_wimlib_dentry(struct wimlib_dir_entry *wdentry,
- struct wim_dentry *dentry,
- const WIMStruct *wim)
-{
- int ret;
- size_t dummy;
- const struct wim_inode *inode = dentry->d_inode;
- struct wim_lookup_table_entry *lte;
-
-#if TCHAR_IS_UTF16LE
- wdentry->filename = dentry->file_name;
- wdentry->dos_name = dentry->short_name;
-#else
- if (dentry_has_long_name(dentry)) {
- ret = utf16le_to_tstr(dentry->file_name,
- dentry->file_name_nbytes,
- (tchar**)&wdentry->filename,
- &dummy);
- if (ret)
- return ret;
- }
- if (dentry_has_short_name(dentry)) {
- ret = utf16le_to_tstr(dentry->short_name,
- dentry->short_name_nbytes,
- (tchar**)&wdentry->dos_name,
- &dummy);
- if (ret)
- return ret;
- }
-#endif
- ret = calculate_dentry_full_path(dentry);
- if (ret)
- return ret;
- wdentry->full_path = dentry->_full_path;
-
- for (struct wim_dentry *d = dentry; !dentry_is_root(d); d = d->parent)
- wdentry->depth++;
-
- if (inode->i_security_id >= 0) {
- const struct wim_security_data *sd = wim_const_security_data(wim);
- wdentry->security_descriptor = sd->descriptors[inode->i_security_id];
- wdentry->security_descriptor_size = sd->sizes[inode->i_security_id];
- }
- wdentry->reparse_tag = inode->i_reparse_tag;
- wdentry->num_links = inode->i_nlink;
- wdentry->attributes = inode->i_attributes;
- wdentry->hard_link_group_id = inode->i_ino;
- wdentry->creation_time = wim_timestamp_to_timespec(inode->i_creation_time);
- wdentry->last_write_time = wim_timestamp_to_timespec(inode->i_last_write_time);
- wdentry->last_access_time = wim_timestamp_to_timespec(inode->i_last_access_time);
-
- lte = inode_unnamed_lte(inode, wim->lookup_table);
- if (lte)
- lte_to_wimlib_resource_entry(lte, &wdentry->streams[0].resource);
-
- for (unsigned i = 0; i < inode->i_num_ads; i++) {
- if (inode->i_ads_entries[i].stream_name == NULL)
- continue;
- lte = inode_stream_lte(inode, i + 1, wim->lookup_table);
- wdentry->num_named_streams++;
- if (lte) {
- lte_to_wimlib_resource_entry(lte, &wdentry->streams[
- wdentry->num_named_streams].resource);
- }
- #if TCHAR_IS_UTF16LE
- wdentry->streams[wdentry->num_named_streams].stream_name =
- inode->i_ads_entries[i].stream_name;
- #else
- size_t dummy;
-
- ret = utf16le_to_tstr(inode->i_ads_entries[i].stream_name,
- inode->i_ads_entries[i].stream_name_nbytes,
- (tchar**)&wdentry->streams[
- wdentry->num_named_streams].stream_name,
- &dummy);
- if (ret)
- return ret;
- #endif
- }
- return 0;
-}
-
-static void
-free_wimlib_dentry(struct wimlib_dir_entry *wdentry)
-{
-#if !TCHAR_IS_UTF16LE
- FREE((tchar*)wdentry->filename);
- FREE((tchar*)wdentry->dos_name);
- for (unsigned i = 1; i <= wdentry->num_named_streams; i++)
- FREE((tchar*)wdentry->streams[i].stream_name);
-#endif
- FREE(wdentry);
-}
-
-struct iterate_dir_tree_ctx {
- WIMStruct *wim;
- int flags;
- wimlib_iterate_dir_tree_callback_t cb;
- void *user_ctx;
-};
-
-static int
-do_iterate_dir_tree(WIMStruct *wim,
- struct wim_dentry *dentry, int flags,
- wimlib_iterate_dir_tree_callback_t cb,
- void *user_ctx);
-
-static int
-call_do_iterate_dir_tree(struct wim_dentry *dentry, void *_ctx)
-{
- struct iterate_dir_tree_ctx *ctx = _ctx;
- return do_iterate_dir_tree(ctx->wim, dentry, ctx->flags,
- ctx->cb, ctx->user_ctx);
-}
-
-static int
-do_iterate_dir_tree(WIMStruct *wim,
- struct wim_dentry *dentry, int flags,
- wimlib_iterate_dir_tree_callback_t cb,
- void *user_ctx)
-{
- struct wimlib_dir_entry *wdentry;
- int ret = WIMLIB_ERR_NOMEM;
-
-
- wdentry = CALLOC(1, sizeof(struct wimlib_dir_entry) +
- (1 + dentry->d_inode->i_num_ads) *
- sizeof(struct wimlib_stream_entry));
- if (!wdentry)
- goto out;
-
- ret = init_wimlib_dentry(wdentry, dentry, wim);
- if (ret)
- goto out_free_wimlib_dentry;
-
- if (!(flags & WIMLIB_ITERATE_DIR_TREE_FLAG_CHILDREN)) {
- ret = (*cb)(wdentry, user_ctx);
- if (ret)
- goto out_free_wimlib_dentry;
- }
-
- if (flags & (WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE |
- WIMLIB_ITERATE_DIR_TREE_FLAG_CHILDREN))
- {
- struct iterate_dir_tree_ctx ctx = {
- .wim = wim,
- .flags = flags &= ~WIMLIB_ITERATE_DIR_TREE_FLAG_CHILDREN,
- .cb = cb,
- .user_ctx = user_ctx,
- };
- ret = for_dentry_child(dentry, call_do_iterate_dir_tree, &ctx);
- }
-out_free_wimlib_dentry:
- free_wimlib_dentry(wdentry);
-out:
- return ret;
-}
-
-struct image_iterate_dir_tree_ctx {
- const tchar *path;
- int flags;
- wimlib_iterate_dir_tree_callback_t cb;
- void *user_ctx;
-};
-
-
-static int
-image_do_iterate_dir_tree(WIMStruct *wim)
-{
- struct image_iterate_dir_tree_ctx *ctx = wim->private;
- struct wim_dentry *dentry;
-
- dentry = get_dentry(wim, ctx->path);
- if (!dentry)
- return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
- return do_iterate_dir_tree(wim, dentry, ctx->flags, ctx->cb, ctx->user_ctx);
-}
-
-/* API function documented in wimlib.h */
-WIMLIBAPI int
-wimlib_iterate_dir_tree(WIMStruct *wim, int image, const tchar *path,
- int flags,
- wimlib_iterate_dir_tree_callback_t cb, void *user_ctx)
-{
- struct image_iterate_dir_tree_ctx ctx = {
- .path = path,
- .flags = flags,
- .cb = cb,
- .user_ctx = user_ctx,
- };
- wim->private = &ctx;
- return for_image(wim, image, image_do_iterate_dir_tree);
-}
-
-static bool
-inode_stream_sizes_consistent(const struct wim_inode *inode_1,
- const struct wim_inode *inode_2,
- const struct wim_lookup_table *lookup_table)
-{
- if (inode_1->i_num_ads != inode_2->i_num_ads)
- return false;
- for (unsigned i = 0; i <= inode_1->i_num_ads; i++) {
- const struct wim_lookup_table_entry *lte_1, *lte_2;
-
- lte_1 = inode_stream_lte(inode_1, i, lookup_table);
- lte_2 = inode_stream_lte(inode_2, i, lookup_table);
- if (lte_1 && lte_2) {
- if (wim_resource_size(lte_1) != wim_resource_size(lte_2))
- return false;
- } else if (lte_1 && wim_resource_size(lte_1)) {
- return false;
- } else if (lte_2 && wim_resource_size(lte_2)) {
- return false;
- }
- }
- return true;
-}
-
-static void
-inode_replace_ltes(struct wim_inode *inode,
- struct wim_inode *template_inode,
- struct wim_lookup_table *lookup_table)
-{
- for (unsigned i = 0; i <= inode->i_num_ads; i++) {
- struct wim_lookup_table_entry *lte, *lte_template;
-
- lte = inode_stream_lte(inode, i, lookup_table);
- if (lte) {
- for (unsigned j = 0; j < inode->i_nlink; j++)
- lte_decrement_refcnt(lte, lookup_table);
- lte_template = inode_stream_lte(template_inode, i,
- lookup_table);
- if (i == 0)
- inode->i_lte = lte_template;
- else
- inode->i_ads_entries[i - 1].lte = lte_template;
- if (lte_template)
- lte_template->refcnt += inode->i_nlink;
- }
- }
- inode->i_resolved = 1;
-}
-
-static int
-dentry_reference_template(struct wim_dentry *dentry, void *_wim)
-{
- int ret;
- struct wim_dentry *template_dentry;
- struct wim_inode *inode, *template_inode;
- WIMStruct *wim = _wim;
-
- if (dentry->d_inode->i_visited)
- return 0;
-
- ret = calculate_dentry_full_path(dentry);
- if (ret)
- return ret;
-
- template_dentry = get_dentry(wim, dentry->_full_path);
- if (!template_dentry) {
- DEBUG("\"%"TS"\": newly added file", dentry->_full_path);
- return 0;
- }
-
- inode = dentry->d_inode;
- template_inode = template_dentry->d_inode;
-
- if (inode->i_last_write_time == template_inode->i_last_write_time
- && inode->i_creation_time == template_inode->i_creation_time
- && inode->i_last_access_time >= template_inode->i_last_access_time
- && inode_stream_sizes_consistent(inode, template_inode,
- wim->lookup_table))
- {
- /*DEBUG("\"%"TS"\": No change detected", dentry->_full_path);*/
- inode_replace_ltes(inode, template_inode, wim->lookup_table);
- inode->i_visited = 1;
- } else {
- DEBUG("\"%"TS"\": change detected!", dentry->_full_path);
- }
- return 0;
-}
-
-/* API function documented in wimlib.h */
-WIMLIBAPI int
-wimlib_reference_template_image(WIMStruct *wim, int new_image, int template_image,
- int flags, wimlib_progress_func_t progress_func)
-{
- int ret;
- struct wim_image_metadata *new_imd;
-
- if (wim->hdr.part_number != 1)
- return WIMLIB_ERR_SPLIT_UNSUPPORTED;
-
- if (new_image < 1 || new_image > wim->hdr.image_count)
- return WIMLIB_ERR_INVALID_IMAGE;
-
- if (template_image < 1 || template_image > wim->hdr.image_count)
- return WIMLIB_ERR_INVALID_IMAGE;
-
- if (new_image == template_image)
- return WIMLIB_ERR_INVALID_PARAM;
-
- new_imd = wim->image_metadata[new_image - 1];
- if (!new_imd->modified)
- return WIMLIB_ERR_INVALID_PARAM;
-
- ret = select_wim_image(wim, template_image);
- if (ret)
- return ret;
-
- ret = for_dentry_in_tree(new_imd->root_dentry,
- dentry_reference_template, wim);
- dentry_tree_clear_inode_visited(new_imd->root_dentry);
- return ret;