X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fdentry.c;h=bc1a524f8b1c3ee0acb07a3dbfb9ee322d152dc2;hp=435a7c919665f89ee3736069e7f4f432b233d87b;hb=4d9742676317b6c0d62739bc7167ea70adf95440;hpb=b0a6bbcba9dc23f4722827cb13fb0efff5e2799d diff --git a/src/dentry.c b/src/dentry.c index 435a7c91..bc1a524f 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -38,6 +38,7 @@ #include "wimlib/lookup_table.h" #include "wimlib/metadata.h" #include "wimlib/resource.h" +#include "wimlib/security.h" #include "wimlib/sha1.h" #include "wimlib/timestamp.h" @@ -79,7 +80,9 @@ struct wim_dentry_on_disk { /* Length of this directory entry in bytes, not including any alternate * data stream entries. Should be a multiple of 8 so that the following * dentry or alternate data stream entry is aligned on an 8-byte - * boundary. (If not, wimlib will round it up.) + * boundary. (If not, wimlib will round it up.) It must be at least as + * long as the fixed-length fields of the dentry (WIM_DENTRY_DISK_SIZE), + * plus the lengths of the file name and/or short name if present. * * It is also possible for this field to be 0. This situation, which is * undocumented, indicates the end of a list of sibling nodes in a @@ -98,26 +101,23 @@ struct wim_dentry_on_disk { * security descriptors (see: `struct wim_security_data') */ sle32 security_id; - /* Offset from the start of the uncompressed metadata resource of this - * directory's child directory entries, or 0 if this directory entry - * does not correspond to a directory or otherwise does not have any - * children. */ + /* Offset, in bytes, from the start of the uncompressed metadata + * resource of this directory's child directory entries, or 0 if this + * directory entry does not correspond to a directory or otherwise does + * not have any children. */ le64 subdir_offset; /* Reserved fields */ le64 unused_1; le64 unused_2; - /* The following three time fields should correspond to those gotten by - * calling GetFileTime() on Windows. */ - /* Creation time, in 100-nanosecond intervals since January 1, 1601. */ + /* Creation time, last access time, and last write time, in + * 100-nanosecond intervals since 12:00 a.m UTC January 1, 1601. They + * should correspond to the times gotten by calling GetFileTime() on + * Windows. */ le64 creation_time; - - /* Last access time, in 100-nanosecond intervals since January 1, 1601. */ le64 last_access_time; - - /* Last write time, in 100-nanosecond intervals since January 1, 1601. */ le64 last_write_time; /* Vaguely, the SHA-1 message digest ("hash") of the file's contents. @@ -153,7 +153,7 @@ struct wim_dentry_on_disk { * version of the following fields containing the reparse tag is valid. * Furthermore, the field notated as not_rpfixed, as far as I can tell, * is supposed to be set to 1 if reparse point fixups (a.k.a. fixing the - * targets of absolute symbolic links) were done, and otherwise 0. + * targets of absolute symbolic links) were *not* done, and otherwise 0. * * If this directory entry is not for a reparse point, then the version * of the following fields containing the hard_link_group_id is valid. @@ -170,9 +170,9 @@ struct wim_dentry_on_disk { * guaranteed that directory entries that share the same hard link * group ID are actually hard linked to each either. We have to * handle this by using special code to use distinguishing features - * (possible because some information about the underlying inode is - * repeated in each dentry) to split up these fake hard link groups - * into what they actually are supposed to be. + * (which is possible because some information about the underlying + * inode is repeated in each dentry) to split up these fake hard link + * groups into what they actually are supposed to be. */ union { struct { @@ -202,9 +202,9 @@ struct wim_dentry_on_disk { * set to 0. */ le16 file_name_nbytes; - /* Follewed by variable length file name, in UTF16-LE, if + /* Followed by variable length file name, in UTF16-LE, if * file_name_nbytes != 0. Includes null terminator. */ - utf16lechar file_name[]; + /*utf16lechar file_name[];*/ /* Followed by variable length short name, in UTF16-LE, if * short_name_nbytes != 0. Includes null terminator. */ @@ -984,13 +984,6 @@ new_timeless_inode(void) inode->i_next_stream_id = 1; inode->i_not_rpfixed = 1; INIT_LIST_HEAD(&inode->i_list); - #ifdef WITH_FUSE - if (pthread_mutex_init(&inode->i_mutex, NULL) != 0) { - ERROR_WITH_ERRNO("Error initializing mutex"); - FREE(inode); - return NULL; - } - #endif INIT_LIST_HEAD(&inode->i_dentry); } return inode; @@ -1129,16 +1122,10 @@ free_inode(struct wim_inode *inode) destroy_ads_entry(&inode->i_ads_entries[i]); FREE(inode->i_ads_entries); } - #ifdef WITH_FUSE - wimlib_assert(inode->i_num_opened_fds == 0); - FREE(inode->i_fds); - pthread_mutex_destroy(&inode->i_mutex); - #endif /* HACK: This may instead delete the inode from i_list, but the * hlist_del() behaves the same as list_del(). */ if (!hlist_unhashed(&inode->i_hlist)) hlist_del(&inode->i_hlist); - FREE(inode->i_extracted_file); FREE(inode); } } @@ -1827,7 +1814,7 @@ read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len, * fixed-length fields */ if (dentry->length < sizeof(struct wim_dentry_on_disk)) { ERROR("Directory entry has invalid length of %"PRIu64" bytes", - entry->length); + dentry->length); return WIMLIB_ERR_INVALID_DENTRY; } @@ -2004,8 +1991,9 @@ dentry_get_file_type_string(const struct wim_dentry *dentry) * Returns zero on success; nonzero on failure. */ int -read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, - struct wim_dentry *dentry) +read_dentry_tree(const u8 * restrict metadata_resource, + u64 metadata_resource_len, + struct wim_dentry * restrict dentry) { u64 cur_offset = dentry->subdir_offset; struct wim_dentry *child; @@ -2251,7 +2239,7 @@ write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p) * Returns pointer to the byte after the last byte we wrote. */ u8 * -write_dentry_tree(const struct wim_dentry *root, u8 *p) +write_dentry_tree(const struct wim_dentry * restrict root, u8 * restrict p) { DEBUG("Writing dentry tree."); wimlib_assert(dentry_is_root(root)); @@ -2268,3 +2256,201 @@ write_dentry_tree(const struct wim_dentry *root, u8 *p) /* Recursively write the rest of the dentry tree. */ return write_dentry_tree_recursive(root, p); } + + +static int +init_wimlib_dentry(struct wimlib_wim_dentry *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) + wdentry->streams[0].stream_size = wim_resource_size(lte); + + 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) { + wdentry->streams[wdentry->num_named_streams].stream_size = + wim_resource_size(lte); + } + #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_wim_dentry *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) +{ + u32 level; + struct wimlib_wim_dentry *wdentry; + int ret = WIMLIB_ERR_NOMEM; + + + wdentry = CALLOC(1, sizeof(struct wimlib_wim_dentry) + + (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); +} + +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) +{ + int ret; + struct wim_dentry *dentry; + 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); +}