4 * A dentry (directory entry) contains the metadata for a file. In the WIM file
5 * format, the dentries are stored in the "metadata resource" section right
6 * after the security data. Each image in the WIM file has its own metadata
7 * resource with its own security data and dentry tree. Dentries in different
8 * images may share file resources by referring to the same lookup table
13 * Copyright (C) 2012 Eric Biggers
15 * This file is part of wimlib, a library for working with WIM files.
17 * wimlib is free software; you can redistribute it and/or modify it under the
18 * terms of the GNU General Public License as published by the Free Software
19 * Foundation; either version 3 of the License, or (at your option) any later
22 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
23 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
24 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License along with
27 * wimlib; if not, see http://www.gnu.org/licenses/.
37 #include "lookup_table.h"
39 #include "timestamp.h"
40 #include "wimlib_internal.h"
43 * Returns true if @dentry has the UTF-8 file name @name that has length
46 static bool dentry_has_name(const struct dentry *dentry, const char *name,
49 if (dentry->file_name_utf8_len != name_len)
51 return memcmp(dentry->file_name_utf8, name, name_len) == 0;
54 static u64 __dentry_correct_length_unaligned(u16 file_name_len,
57 u64 length = WIM_DENTRY_DISK_SIZE;
59 length += file_name_len + 2;
61 length += short_name_len + 2;
65 static u64 dentry_correct_length_unaligned(const struct dentry *dentry)
67 return __dentry_correct_length_unaligned(dentry->file_name_len,
68 dentry->short_name_len);
71 /* Return the "correct" value to write in the length field of the dentry, based
72 * on the file name length and short name length */
73 static u64 dentry_correct_length(const struct dentry *dentry)
75 return (dentry_correct_length_unaligned(dentry) + 7) & ~7;
78 static u64 __dentry_total_length(const struct dentry *dentry, u64 length)
80 const struct inode *inode = dentry->inode;
81 for (u16 i = 0; i < inode->num_ads; i++)
82 length += ads_entry_total_length(&inode->ads_entries[i]);
83 return (length + 7) & ~7;
86 u64 dentry_correct_total_length(const struct dentry *dentry)
88 return __dentry_total_length(dentry,
89 dentry_correct_length_unaligned(dentry));
92 /* Real length of a dentry, including the alternate data stream entries, which
93 * are not included in the dentry->length field... */
94 u64 dentry_total_length(const struct dentry *dentry)
96 return __dentry_total_length(dentry, dentry->length);
99 /* Transfers file attributes from a `stat' buffer to an inode. */
100 void stbuf_to_inode(const struct stat *stbuf, struct inode *inode)
102 if (S_ISLNK(stbuf->st_mode)) {
103 inode->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
104 inode->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
105 } else if (S_ISDIR(stbuf->st_mode)) {
106 inode->attributes = FILE_ATTRIBUTE_DIRECTORY;
108 inode->attributes = FILE_ATTRIBUTE_NORMAL;
110 if (sizeof(ino_t) >= 8)
111 inode->ino = (u64)stbuf->st_ino;
113 inode->ino = (u64)stbuf->st_ino |
114 ((u64)stbuf->st_dev << (sizeof(ino_t) * 8));
116 inode->creation_time = timespec_to_wim_timestamp(&stbuf->st_mtim);
117 inode->last_write_time = timespec_to_wim_timestamp(&stbuf->st_mtim);
118 inode->last_access_time = timespec_to_wim_timestamp(&stbuf->st_atim);
122 /* Transfers file attributes from a struct inode to a `stat' buffer.
124 * The lookup table entry tells us which stream in the inode we are statting.
125 * For a named data stream, everything returned is the same as the unnamed data
126 * stream except possibly the size and block count. */
127 int inode_to_stbuf(const struct inode *inode, struct lookup_table_entry *lte,
130 if (inode_is_symlink(inode))
131 stbuf->st_mode = S_IFLNK | 0777;
132 else if (inode_is_directory(inode))
133 stbuf->st_mode = S_IFDIR | 0755;
135 stbuf->st_mode = S_IFREG | 0644;
137 stbuf->st_ino = (ino_t)inode->ino;
138 stbuf->st_nlink = inode->link_count;
139 stbuf->st_uid = getuid();
140 stbuf->st_gid = getgid();
143 if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
144 wimlib_assert(lte->staging_file_name);
145 struct stat native_stat;
146 if (stat(lte->staging_file_name, &native_stat) != 0) {
147 DEBUG("Failed to stat `%s': %m",
148 lte->staging_file_name);
151 stbuf->st_size = native_stat.st_size;
153 stbuf->st_size = wim_resource_size(lte);
159 stbuf->st_atime = wim_timestamp_to_unix(inode->last_access_time);
160 stbuf->st_mtime = wim_timestamp_to_unix(inode->last_write_time);
161 stbuf->st_ctime = wim_timestamp_to_unix(inode->creation_time);
162 stbuf->st_blocks = (stbuf->st_size + 511) / 512;
168 /* Returns the alternate data stream entry belonging to @inode that has the
169 * stream name @stream_name. */
170 struct ads_entry *inode_get_ads_entry(struct inode *inode,
171 const char *stream_name,
174 size_t stream_name_len;
177 if (inode->num_ads) {
179 stream_name_len = strlen(stream_name);
181 if (ads_entry_has_name(&inode->ads_entries[i],
182 stream_name, stream_name_len))
186 return &inode->ads_entries[i];
188 } while (++i != inode->num_ads);
195 static int init_ads_entry(struct ads_entry *ads_entry, const char *name)
198 memset(ads_entry, 0, sizeof(*ads_entry));
200 ret = change_ads_name(ads_entry, name);
204 static void destroy_ads_entry(struct ads_entry *ads_entry)
206 FREE(ads_entry->stream_name);
207 FREE(ads_entry->stream_name_utf8);
211 void inode_free_ads_entries(struct inode *inode)
213 if (inode->ads_entries) {
214 for (u16 i = 0; i < inode->num_ads; i++)
215 destroy_ads_entry(&inode->ads_entries[i]);
216 FREE(inode->ads_entries);
220 #if defined(WITH_FUSE) || defined(WITH_NTFS_3G)
222 * Add an alternate stream entry to an inode and return a pointer to it, or NULL
223 * if memory could not be allocated.
225 struct ads_entry *inode_add_ads(struct inode *inode, const char *stream_name)
228 struct ads_entry *ads_entries;
229 struct ads_entry *new_entry;
231 if (inode->num_ads >= 0xfffe) {
232 ERROR("Too many alternate data streams in one inode!");
235 num_ads = inode->num_ads + 1;
236 ads_entries = REALLOC(inode->ads_entries,
237 num_ads * sizeof(inode->ads_entries[0]));
239 ERROR("Failed to allocate memory for new alternate data stream");
242 inode->ads_entries = ads_entries;
244 new_entry = &inode->ads_entries[num_ads - 1];
245 if (init_ads_entry(new_entry, stream_name) != 0)
248 new_entry->stream_id = inode->next_stream_id++;
255 /* Remove an alternate data stream from the inode */
256 void inode_remove_ads(struct inode *inode, u16 idx,
257 struct lookup_table *lookup_table)
259 struct ads_entry *ads_entry;
260 struct lookup_table_entry *lte;
262 ads_entry = &inode->ads_entries[idx];
264 wimlib_assert(ads_entry);
265 wimlib_assert(inode->resolved);
267 lte = ads_entry->lte;
270 lte_decrement_refcnt(lte, lookup_table);
272 destroy_ads_entry(ads_entry);
274 wimlib_assert(inode->num_ads);
275 memcpy(&inode->ads_entries[idx],
276 &inode->ads_entries[idx + 1],
277 (inode->num_ads - idx - 1) * sizeof(inode->ads_entries[0]));
283 * Calls a function on all directory entries in a directory tree. It is called
284 * on a parent before its children.
286 int for_dentry_in_tree(struct dentry *root,
287 int (*visitor)(struct dentry*, void*), void *arg)
290 struct dentry *child;
292 ret = visitor(root, arg);
297 child = root->inode->children;
303 ret = for_dentry_in_tree(child, visitor, arg);
307 } while (child != root->inode->children);
312 * Like for_dentry_in_tree(), but the visitor function is always called on a
313 * dentry's children before on itself.
315 int for_dentry_in_tree_depth(struct dentry *root,
316 int (*visitor)(struct dentry*, void*), void *arg)
319 struct dentry *child;
322 child = root->inode->children;
326 ret = for_dentry_in_tree_depth(child, visitor, arg);
330 } while (child != root->inode->children);
332 return visitor(root, arg);
336 * Calculate the full path of @dentry, based on its parent's full path and on
337 * its UTF-8 file name.
339 int calculate_dentry_full_path(struct dentry *dentry, void *ignore)
343 if (dentry_is_root(dentry)) {
344 full_path = MALLOC(2);
351 char *parent_full_path;
352 u32 parent_full_path_len;
353 const struct dentry *parent = dentry->parent;
355 if (dentry_is_root(parent)) {
356 parent_full_path = "";
357 parent_full_path_len = 0;
359 parent_full_path = parent->full_path_utf8;
360 parent_full_path_len = parent->full_path_utf8_len;
363 full_path_len = parent_full_path_len + 1 +
364 dentry->file_name_utf8_len;
365 full_path = MALLOC(full_path_len + 1);
369 memcpy(full_path, parent_full_path, parent_full_path_len);
370 full_path[parent_full_path_len] = '/';
371 memcpy(full_path + parent_full_path_len + 1,
372 dentry->file_name_utf8,
373 dentry->file_name_utf8_len);
374 full_path[full_path_len] = '\0';
376 FREE(dentry->full_path_utf8);
377 dentry->full_path_utf8 = full_path;
378 dentry->full_path_utf8_len = full_path_len;
381 ERROR("Out of memory while calculating dentry full path");
382 return WIMLIB_ERR_NOMEM;
386 * Recursively calculates the subdir offsets for a directory tree.
388 * @dentry: The root of the directory tree.
389 * @subdir_offset_p: The current subdirectory offset; i.e., the subdirectory
390 * offset for @dentry.
392 void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p)
394 struct dentry *child;
396 child = dentry->inode->children;
397 dentry->subdir_offset = *subdir_offset_p;
400 /* Advance the subdir offset by the amount of space the children
401 * of this dentry take up. */
403 *subdir_offset_p += dentry_correct_total_length(child);
405 } while (child != dentry->inode->children);
407 /* End-of-directory dentry on disk. */
408 *subdir_offset_p += 8;
410 /* Recursively call calculate_subdir_offsets() on all the
413 calculate_subdir_offsets(child, subdir_offset_p);
415 } while (child != dentry->inode->children);
417 /* On disk, childless directories have a valid subdir_offset
418 * that points to an 8-byte end-of-directory dentry. Regular
419 * files or reparse points have a subdir_offset of 0. */
420 if (dentry_is_directory(dentry))
421 *subdir_offset_p += 8;
423 dentry->subdir_offset = 0;
428 /* Returns the child of @dentry that has the file name @name.
429 * Returns NULL if no child has the name. */
430 struct dentry *get_dentry_child_with_name(const struct dentry *dentry,
433 struct dentry *child;
436 child = dentry->inode->children;
438 name_len = strlen(name);
440 if (dentry_has_name(child, name, name_len))
443 } while (child != dentry->inode->children);
448 /* Retrieves the dentry that has the UTF-8 @path relative to the dentry
449 * @cur_dir. Returns NULL if no dentry having the path is found. */
450 static struct dentry *get_dentry_relative_path(struct dentry *cur_dir,
453 struct dentry *child;
455 const char *new_path;
460 child = cur_dir->inode->children;
462 new_path = path_next_part(path, &base_len);
464 if (dentry_has_name(child, path, base_len))
465 return get_dentry_relative_path(child, new_path);
467 } while (child != cur_dir->inode->children);
472 /* Returns the dentry corresponding to the UTF-8 @path, or NULL if there is no
474 struct dentry *get_dentry(WIMStruct *w, const char *path)
476 struct dentry *root = wim_root_dentry(w);
479 return get_dentry_relative_path(root, path);
482 struct inode *wim_pathname_to_inode(WIMStruct *w, const char *path)
484 struct dentry *dentry;
485 dentry = get_dentry(w, path);
489 return dentry->inode;
492 /* Returns the dentry that corresponds to the parent directory of @path, or NULL
493 * if the dentry is not found. */
494 struct dentry *get_parent_dentry(WIMStruct *w, const char *path)
496 size_t path_len = strlen(path);
497 char buf[path_len + 1];
499 memcpy(buf, path, path_len + 1);
501 to_parent_name(buf, path_len);
503 return get_dentry(w, buf);
506 /* Prints the full path of a dentry. */
507 int print_dentry_full_path(struct dentry *dentry, void *ignore)
509 if (dentry->full_path_utf8)
510 puts(dentry->full_path_utf8);
514 /* We want to be able to show the names of the file attribute flags that are
516 struct file_attr_flag {
520 struct file_attr_flag file_attr_flags[] = {
521 {FILE_ATTRIBUTE_READONLY, "READONLY"},
522 {FILE_ATTRIBUTE_HIDDEN, "HIDDEN"},
523 {FILE_ATTRIBUTE_SYSTEM, "SYSTEM"},
524 {FILE_ATTRIBUTE_DIRECTORY, "DIRECTORY"},
525 {FILE_ATTRIBUTE_ARCHIVE, "ARCHIVE"},
526 {FILE_ATTRIBUTE_DEVICE, "DEVICE"},
527 {FILE_ATTRIBUTE_NORMAL, "NORMAL"},
528 {FILE_ATTRIBUTE_TEMPORARY, "TEMPORARY"},
529 {FILE_ATTRIBUTE_SPARSE_FILE, "SPARSE_FILE"},
530 {FILE_ATTRIBUTE_REPARSE_POINT, "REPARSE_POINT"},
531 {FILE_ATTRIBUTE_COMPRESSED, "COMPRESSED"},
532 {FILE_ATTRIBUTE_OFFLINE, "OFFLINE"},
533 {FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,"NOT_CONTENT_INDEXED"},
534 {FILE_ATTRIBUTE_ENCRYPTED, "ENCRYPTED"},
535 {FILE_ATTRIBUTE_VIRTUAL, "VIRTUAL"},
538 /* Prints a directory entry. @lookup_table is a pointer to the lookup table, if
539 * available. If the dentry is unresolved and the lookup table is NULL, the
540 * lookup table entries will not be printed. Otherwise, they will be. */
541 int print_dentry(struct dentry *dentry, void *lookup_table)
544 struct lookup_table_entry *lte;
545 const struct inode *inode = dentry->inode;
549 printf("[DENTRY]\n");
550 printf("Length = %"PRIu64"\n", dentry->length);
551 printf("Attributes = 0x%x\n", inode->attributes);
552 for (unsigned i = 0; i < ARRAY_LEN(file_attr_flags); i++)
553 if (file_attr_flags[i].flag & inode->attributes)
554 printf(" FILE_ATTRIBUTE_%s is set\n",
555 file_attr_flags[i].name);
556 printf("Security ID = %d\n", inode->security_id);
557 printf("Subdir offset = %"PRIu64"\n", dentry->subdir_offset);
559 /* Translate the timestamps into something readable */
560 time = wim_timestamp_to_unix(inode->creation_time);
561 p = asctime(gmtime(&time));
562 *(strrchr(p, '\n')) = '\0';
563 printf("Creation Time = %s UTC\n", p);
565 time = wim_timestamp_to_unix(inode->last_access_time);
566 p = asctime(gmtime(&time));
567 *(strrchr(p, '\n')) = '\0';
568 printf("Last Access Time = %s UTC\n", p);
570 time = wim_timestamp_to_unix(inode->last_write_time);
571 p = asctime(gmtime(&time));
572 *(strrchr(p, '\n')) = '\0';
573 printf("Last Write Time = %s UTC\n", p);
575 printf("Reparse Tag = 0x%"PRIx32"\n", inode->reparse_tag);
576 printf("Hard Link Group = 0x%"PRIx64"\n", inode->ino);
577 printf("Hard Link Group Size = %"PRIu32"\n", inode->link_count);
578 printf("Number of Alternate Data Streams = %hu\n", inode->num_ads);
579 printf("Filename = \"");
580 print_string(dentry->file_name, dentry->file_name_len);
582 printf("Filename Length = %hu\n", dentry->file_name_len);
583 printf("Filename (UTF-8) = \"%s\"\n", dentry->file_name_utf8);
584 printf("Filename (UTF-8) Length = %hu\n", dentry->file_name_utf8_len);
585 printf("Short Name = \"");
586 print_string(dentry->short_name, dentry->short_name_len);
588 printf("Short Name Length = %hu\n", dentry->short_name_len);
589 printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8);
590 lte = inode_stream_lte(dentry->inode, 0, lookup_table);
592 print_lookup_table_entry(lte);
594 hash = inode_stream_hash(inode, 0);
602 for (u16 i = 0; i < inode->num_ads; i++) {
603 printf("[Alternate Stream Entry %u]\n", i);
604 printf("Name = \"%s\"\n", inode->ads_entries[i].stream_name_utf8);
605 printf("Name Length (UTF-16) = %u\n",
606 inode->ads_entries[i].stream_name_len);
607 hash = inode_stream_hash(inode, i + 1);
613 print_lookup_table_entry(inode_stream_lte(inode, i + 1,
619 /* Initializations done on every `struct dentry'. */
620 static void dentry_common_init(struct dentry *dentry)
622 memset(dentry, 0, sizeof(struct dentry));
626 struct inode *new_timeless_inode()
628 struct inode *inode = CALLOC(1, sizeof(struct inode));
631 inode->security_id = -1;
632 inode->link_count = 1;
633 INIT_LIST_HEAD(&inode->dentry_list);
637 struct inode *new_inode()
639 struct inode *inode = new_timeless_inode();
642 u64 now = get_wim_timestamp();
643 inode->creation_time = now;
644 inode->last_access_time = now;
645 inode->last_write_time = now;
650 * Creates an unlinked directory entry.
652 * @name: The UTF-8 filename of the new dentry.
654 * Returns a pointer to the new dentry, or NULL if out of memory.
656 struct dentry *new_dentry(const char *name)
658 struct dentry *dentry;
660 dentry = MALLOC(sizeof(struct dentry));
664 dentry_common_init(dentry);
665 if (change_dentry_name(dentry, name) != 0)
668 dentry->next = dentry;
669 dentry->prev = dentry;
670 dentry->parent = dentry;
675 ERROR("Failed to allocate new dentry");
680 static struct dentry *__new_dentry_with_inode(const char *name, bool timeless)
682 struct dentry *dentry;
683 dentry = new_dentry(name);
686 dentry->inode = new_timeless_inode();
688 dentry->inode = new_inode();
690 inode_add_dentry(dentry, dentry->inode);
699 struct dentry *new_dentry_with_timeless_inode(const char *name)
701 return __new_dentry_with_inode(name, true);
704 struct dentry *new_dentry_with_inode(const char *name)
706 return __new_dentry_with_inode(name, false);
710 /* Frees an inode. */
711 void free_inode(struct inode *inode)
714 inode_free_ads_entries(inode);
716 wimlib_assert(inode->num_opened_fds == 0);
723 /* Decrements link count on an inode and frees it if the link count reaches 0.
725 struct inode *put_inode(struct inode *inode)
728 wimlib_assert(inode->link_count);
729 if (--inode->link_count == 0) {
731 if (inode->num_opened_fds == 0)
742 /* Frees a WIM dentry.
744 * The inode is freed only if its link count is decremented to 0.
746 struct inode *free_dentry(struct dentry *dentry)
748 wimlib_assert(dentry);
751 FREE(dentry->file_name);
752 FREE(dentry->file_name_utf8);
753 FREE(dentry->short_name);
754 FREE(dentry->full_path_utf8);
755 inode = put_inode(dentry->inode);
760 void put_dentry(struct dentry *dentry)
762 wimlib_assert(dentry);
763 wimlib_assert(dentry->refcnt);
765 if (--dentry->refcnt == 0)
770 * This function is passed as an argument to for_dentry_in_tree_depth() in order
771 * to free a directory tree. __args is a pointer to a `struct free_dentry_args'.
773 static int do_free_dentry(struct dentry *dentry, void *__lookup_table)
775 struct lookup_table *lookup_table = __lookup_table;
776 struct lookup_table_entry *lte;
777 struct inode *inode = dentry->inode;
781 wimlib_assert(inode->link_count);
782 for (i = 0; i <= inode->num_ads; i++) {
783 lte = inode_stream_lte(inode, i, lookup_table);
784 lte_decrement_refcnt(lte, lookup_table);
788 wimlib_assert(dentry->refcnt != 0);
789 if (--dentry->refcnt == 0)
795 * Unlinks and frees a dentry tree.
797 * @root: The root of the tree.
798 * @lookup_table: The lookup table for dentries. If non-NULL, the
799 * reference counts in the lookup table for the lookup
800 * table entries corresponding to the dentries will be
803 void free_dentry_tree(struct dentry *root, struct lookup_table *lookup_table)
805 if (!root || !root->parent)
807 for_dentry_in_tree_depth(root, do_free_dentry, lookup_table);
810 int increment_dentry_refcnt(struct dentry *dentry, void *ignore)
817 * Links a dentry into the directory tree.
819 * @dentry: The dentry to link.
820 * @parent: The dentry that will be the parent of @dentry.
822 void link_dentry(struct dentry *dentry, struct dentry *parent)
824 wimlib_assert(dentry_is_directory(parent));
825 dentry->parent = parent;
826 if (parent->inode->children) {
827 /* Not an only child; link to siblings. */
828 dentry->next = parent->inode->children;
829 dentry->prev = parent->inode->children->prev;
830 dentry->next->prev = dentry;
831 dentry->prev->next = dentry;
833 /* Only child; link to parent. */
834 parent->inode->children = dentry;
835 dentry->next = dentry;
836 dentry->prev = dentry;
842 * Unlink a dentry from the directory tree.
844 * Note: This merely removes it from the in-memory tree structure.
846 void unlink_dentry(struct dentry *dentry)
848 if (dentry_is_root(dentry))
850 if (dentry_is_only_child(dentry)) {
851 dentry->parent->inode->children = NULL;
853 if (dentry_is_first_sibling(dentry))
854 dentry->parent->inode->children = dentry->next;
855 dentry->next->prev = dentry->prev;
856 dentry->prev->next = dentry->next;
860 /* Duplicates a UTF-8 name into UTF-8 and UTF-16 strings and returns the strings
861 * and their lengths in the pointer arguments */
862 int get_names(char **name_utf16_ret, char **name_utf8_ret,
863 u16 *name_utf16_len_ret, u16 *name_utf8_len_ret,
868 char *name_utf16, *name_utf8;
870 utf8_len = strlen(name);
872 name_utf16 = utf8_to_utf16(name, utf8_len, &utf16_len);
875 return WIMLIB_ERR_NOMEM;
877 name_utf8 = MALLOC(utf8_len + 1);
880 return WIMLIB_ERR_NOMEM;
882 memcpy(name_utf8, name, utf8_len + 1);
883 FREE(*name_utf8_ret);
884 FREE(*name_utf16_ret);
885 *name_utf8_ret = name_utf8;
886 *name_utf16_ret = name_utf16;
887 *name_utf8_len_ret = utf8_len;
888 *name_utf16_len_ret = utf16_len;
892 /* Changes the name of a dentry to @new_name. Only changes the file_name and
893 * file_name_utf8 fields; does not change the short_name, short_name_utf8, or
894 * full_path_utf8 fields. Also recalculates its length. */
895 int change_dentry_name(struct dentry *dentry, const char *new_name)
899 ret = get_names(&dentry->file_name, &dentry->file_name_utf8,
900 &dentry->file_name_len, &dentry->file_name_utf8_len,
902 FREE(dentry->short_name);
903 dentry->short_name_len = 0;
905 dentry->length = dentry_correct_length(dentry);
910 * Changes the name of an alternate data stream */
911 int change_ads_name(struct ads_entry *entry, const char *new_name)
913 return get_names(&entry->stream_name, &entry->stream_name_utf8,
914 &entry->stream_name_len,
915 &entry->stream_name_utf8_len,
919 /* Parameters for calculate_dentry_statistics(). */
920 struct image_statistics {
921 struct lookup_table *lookup_table;
925 u64 *hard_link_bytes;
928 static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
930 struct image_statistics *stats;
931 struct lookup_table_entry *lte;
935 if (dentry_is_directory(dentry) && !dentry_is_root(dentry))
938 ++*stats->file_count;
940 for (unsigned i = 0; i <= dentry->inode->num_ads; i++) {
941 lte = inode_stream_lte(dentry->inode, i, stats->lookup_table);
943 *stats->total_bytes += wim_resource_size(lte);
944 if (++lte->out_refcnt == 1)
945 *stats->hard_link_bytes += wim_resource_size(lte);
951 /* Calculates some statistics about a dentry tree. */
952 void calculate_dir_tree_statistics(struct dentry *root, struct lookup_table *table,
953 u64 *dir_count_ret, u64 *file_count_ret,
954 u64 *total_bytes_ret,
955 u64 *hard_link_bytes_ret)
957 struct image_statistics stats;
960 *total_bytes_ret = 0;
961 *hard_link_bytes_ret = 0;
962 stats.lookup_table = table;
963 stats.dir_count = dir_count_ret;
964 stats.file_count = file_count_ret;
965 stats.total_bytes = total_bytes_ret;
966 stats.hard_link_bytes = hard_link_bytes_ret;
967 for_lookup_table_entry(table, lte_zero_out_refcnt, NULL);
968 for_dentry_in_tree(root, calculate_dentry_statistics, &stats);
973 * Reads the alternate data stream entries for a dentry.
975 * @p: Pointer to buffer that starts with the first alternate stream entry.
977 * @inode: Inode to load the alternate data streams into.
978 * @inode->num_ads must have been set to the number of
979 * alternate data streams that are expected.
981 * @remaining_size: Number of bytes of data remaining in the buffer pointed
984 * The format of the on-disk alternate stream entries is as follows:
986 * struct ads_entry_on_disk {
987 * u64 length; // Length of the entry, in bytes. This includes
988 * all fields (including the stream name and
989 * null terminator if present, AND the padding!).
990 * u64 reserved; // Seems to be unused
991 * u8 hash[20]; // SHA1 message digest of the uncompressed stream
992 * u16 stream_name_len; // Length of the stream name, in bytes
993 * char stream_name[]; // Stream name in UTF-16LE, @stream_name_len bytes long,
994 * not including null terminator
995 * u16 zero; // UTF-16 null terminator for the stream name, NOT
996 * included in @stream_name_len. Based on what
997 * I've observed from filenames in dentries,
998 * this field should not exist when
999 * (@stream_name_len == 0), but you can't
1000 * actually tell because of the padding anyway
1001 * (provided that the padding is zeroed, which
1002 * it always seems to be).
1003 * char padding[]; // Padding to make the size a multiple of 8 bytes.
1006 * In addition, the entries are 8-byte aligned.
1008 * Return 0 on success or nonzero on failure. On success, inode->ads_entries
1009 * is set to an array of `struct ads_entry's of length inode->num_ads. On
1010 * failure, @inode is not modified.
1012 static int read_ads_entries(const u8 *p, struct inode *inode,
1016 struct ads_entry *ads_entries;
1019 num_ads = inode->num_ads;
1020 ads_entries = CALLOC(num_ads, sizeof(inode->ads_entries[0]));
1022 ERROR("Could not allocate memory for %"PRIu16" "
1023 "alternate data stream entries", num_ads);
1024 return WIMLIB_ERR_NOMEM;
1027 for (u16 i = 0; i < num_ads; i++) {
1028 struct ads_entry *cur_entry;
1030 u64 length_no_padding;
1033 const u8 *p_save = p;
1035 cur_entry = &ads_entries[i];
1038 ads_entries[i].stream_id = i + 1;
1041 /* Read the base stream entry, excluding the stream name. */
1042 if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) {
1043 ERROR("Stream entries go past end of metadata resource");
1044 ERROR("(remaining_size = %"PRIu64")", remaining_size);
1045 ret = WIMLIB_ERR_INVALID_DENTRY;
1046 goto out_free_ads_entries;
1049 p = get_u64(p, &length);
1050 p += 8; /* Skip the reserved field */
1051 p = get_bytes(p, SHA1_HASH_SIZE, (u8*)cur_entry->hash);
1052 p = get_u16(p, &cur_entry->stream_name_len);
1054 cur_entry->stream_name = NULL;
1055 cur_entry->stream_name_utf8 = NULL;
1057 /* Length including neither the null terminator nor the padding
1059 length_no_padding = WIM_ADS_ENTRY_DISK_SIZE +
1060 cur_entry->stream_name_len;
1062 /* Length including the null terminator and the padding */
1063 total_length = ((length_no_padding + 2) + 7) & ~7;
1065 wimlib_assert(total_length == ads_entry_total_length(cur_entry));
1067 if (remaining_size < length_no_padding) {
1068 ERROR("Stream entries go past end of metadata resource");
1069 ERROR("(remaining_size = %"PRIu64" bytes, "
1070 "length_no_padding = %"PRIu64" bytes)",
1071 remaining_size, length_no_padding);
1072 ret = WIMLIB_ERR_INVALID_DENTRY;
1073 goto out_free_ads_entries;
1076 /* The @length field in the on-disk ADS entry is expected to be
1077 * equal to @total_length, which includes all of the entry and
1078 * the padding that follows it to align the next ADS entry to an
1079 * 8-byte boundary. However, to be safe, we'll accept the
1080 * length field as long as it's not less than the un-padded
1081 * total length and not more than the padded total length. */
1082 if (length < length_no_padding || length > total_length) {
1083 ERROR("Stream entry has unexpected length "
1084 "field (length field = %"PRIu64", "
1085 "unpadded total length = %"PRIu64", "
1086 "padded total length = %"PRIu64")",
1087 length, length_no_padding, total_length);
1088 ret = WIMLIB_ERR_INVALID_DENTRY;
1089 goto out_free_ads_entries;
1092 if (cur_entry->stream_name_len) {
1093 cur_entry->stream_name = MALLOC(cur_entry->stream_name_len);
1094 if (!cur_entry->stream_name) {
1095 ret = WIMLIB_ERR_NOMEM;
1096 goto out_free_ads_entries;
1098 get_bytes(p, cur_entry->stream_name_len,
1099 (u8*)cur_entry->stream_name);
1100 cur_entry->stream_name_utf8 = utf16_to_utf8(cur_entry->stream_name,
1101 cur_entry->stream_name_len,
1103 cur_entry->stream_name_utf8_len = utf8_len;
1105 if (!cur_entry->stream_name_utf8) {
1106 ret = WIMLIB_ERR_NOMEM;
1107 goto out_free_ads_entries;
1110 /* It's expected that the size of every ADS entry is a multiple
1111 * of 8. However, to be safe, I'm allowing the possibility of
1112 * an ADS entry at the very end of the metadata resource ending
1113 * un-aligned. So although we still need to increment the input
1114 * pointer by @total_length to reach the next ADS entry, it's
1115 * possible that less than @total_length is actually remaining
1116 * in the metadata resource. We should set the remaining size to
1117 * 0 bytes if this happens. */
1118 p = p_save + total_length;
1119 if (remaining_size < total_length)
1122 remaining_size -= total_length;
1124 inode->ads_entries = ads_entries;
1126 inode->next_stream_id = inode->num_ads + 1;
1129 out_free_ads_entries:
1130 for (u16 i = 0; i < num_ads; i++)
1131 destroy_ads_entry(&ads_entries[i]);
1137 * Reads a directory entry, including all alternate data stream entries that
1138 * follow it, from the WIM image's metadata resource.
1140 * @metadata_resource: Buffer containing the uncompressed metadata resource.
1141 * @metadata_resource_len: Length of the metadata resource.
1142 * @offset: Offset of this directory entry in the metadata resource.
1143 * @dentry: A `struct dentry' that will be filled in by this function.
1145 * Return 0 on success or nonzero on failure. On failure, @dentry have been
1146 * modified, bu it will be left with no pointers to any allocated buffers.
1147 * On success, the dentry->length field must be examined. If zero, this was a
1148 * special "end of directory" dentry and not a real dentry. If nonzero, this
1149 * was a real dentry.
1151 int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
1152 u64 offset, struct dentry *dentry)
1155 u64 calculated_size;
1156 char *file_name = NULL;
1157 char *file_name_utf8 = NULL;
1158 char *short_name = NULL;
1161 size_t file_name_utf8_len = 0;
1163 struct inode *inode = NULL;
1165 dentry_common_init(dentry);
1167 /*Make sure the dentry really fits into the metadata resource.*/
1168 if (offset + 8 > metadata_resource_len || offset + 8 < offset) {
1169 ERROR("Directory entry starting at %"PRIu64" ends past the "
1170 "end of the metadata resource (size %"PRIu64")",
1171 offset, metadata_resource_len);
1172 return WIMLIB_ERR_INVALID_DENTRY;
1175 /* Before reading the whole dentry, we need to read just the length.
1176 * This is because a dentry of length 8 (that is, just the length field)
1177 * terminates the list of sibling directory entries. */
1179 p = get_u64(&metadata_resource[offset], &dentry->length);
1181 /* A zero length field (really a length of 8, since that's how big the
1182 * directory entry is...) indicates that this is the end of directory
1183 * dentry. We do not read it into memory as an actual dentry, so just
1184 * return successfully in that case. */
1185 if (dentry->length == 0)
1188 /* If the dentry does not overflow the metadata resource buffer and is
1189 * not too short, read the rest of it (excluding the alternate data
1190 * streams, but including the file name and short name variable-length
1191 * fields) into memory. */
1192 if (offset + dentry->length >= metadata_resource_len
1193 || offset + dentry->length < offset)
1195 ERROR("Directory entry at offset %"PRIu64" and with size "
1196 "%"PRIu64" ends past the end of the metadata resource "
1198 offset, dentry->length, metadata_resource_len);
1199 return WIMLIB_ERR_INVALID_DENTRY;
1202 if (dentry->length < WIM_DENTRY_DISK_SIZE) {
1203 ERROR("Directory entry has invalid length of %"PRIu64" bytes",
1205 return WIMLIB_ERR_INVALID_DENTRY;
1208 inode = new_timeless_inode();
1210 return WIMLIB_ERR_NOMEM;
1212 p = get_u32(p, &inode->attributes);
1213 p = get_u32(p, (u32*)&inode->security_id);
1214 p = get_u64(p, &dentry->subdir_offset);
1216 /* 2 unused fields */
1217 p += 2 * sizeof(u64);
1218 /*p = get_u64(p, &dentry->unused1);*/
1219 /*p = get_u64(p, &dentry->unused2);*/
1221 p = get_u64(p, &inode->creation_time);
1222 p = get_u64(p, &inode->last_access_time);
1223 p = get_u64(p, &inode->last_write_time);
1225 p = get_bytes(p, SHA1_HASH_SIZE, inode->hash);
1228 * I don't know what's going on here. It seems like M$ screwed up the
1229 * reparse points, then put the fields in the same place and didn't
1230 * document it. The WIM_HDR_FLAG_RP_FIX flag in the WIM header might
1231 * have something to do with this, but it's not documented.
1233 if (inode->attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1236 p = get_u32(p, &inode->reparse_tag);
1239 p = get_u32(p, &inode->reparse_tag);
1240 p = get_u64(p, &inode->ino);
1243 /* By the way, the reparse_reserved field does not actually exist (at
1244 * least when the file is not a reparse point) */
1246 p = get_u16(p, &inode->num_ads);
1248 p = get_u16(p, &short_name_len);
1249 p = get_u16(p, &file_name_len);
1251 /* We now know the length of the file name and short name. Make sure
1252 * the length of the dentry is large enough to actually hold them.
1254 * The calculated length here is unaligned to allow for the possibility
1255 * that the dentry->length names an unaligned length, although this
1256 * would be unexpected. */
1257 calculated_size = __dentry_correct_length_unaligned(file_name_len,
1260 if (dentry->length < calculated_size) {
1261 ERROR("Unexpected end of directory entry! (Expected "
1262 "at least %"PRIu64" bytes, got %"PRIu64" bytes. "
1263 "short_name_len = %hu, file_name_len = %hu)",
1264 calculated_size, dentry->length,
1265 short_name_len, file_name_len);
1266 return WIMLIB_ERR_INVALID_DENTRY;
1269 /* Read the filename if present. Note: if the filename is empty, there
1270 * is no null terminator following it. */
1271 if (file_name_len) {
1272 file_name = MALLOC(file_name_len);
1274 ERROR("Failed to allocate %hu bytes for dentry file name",
1276 return WIMLIB_ERR_NOMEM;
1278 p = get_bytes(p, file_name_len, file_name);
1280 /* Convert filename to UTF-8. */
1281 file_name_utf8 = utf16_to_utf8(file_name, file_name_len,
1282 &file_name_utf8_len);
1284 if (!file_name_utf8) {
1285 ERROR("Failed to allocate memory to convert UTF-16 "
1286 "filename (%hu bytes) to UTF-8", file_name_len);
1287 ret = WIMLIB_ERR_NOMEM;
1288 goto out_free_file_name;
1291 WARNING("Expected two zero bytes following the file name "
1292 "`%s', but found non-zero bytes", file_name_utf8);
1296 /* Align the calculated size */
1297 calculated_size = (calculated_size + 7) & ~7;
1299 if (dentry->length > calculated_size) {
1300 /* Weird; the dentry says it's longer than it should be. Note
1301 * that the length field does NOT include the size of the
1302 * alternate stream entries. */
1304 /* Strangely, some directory entries inexplicably have a little
1305 * over 70 bytes of extra data. The exact amount of data seems
1306 * to be 72 bytes, but it is aligned on the next 8-byte
1307 * boundary. It does NOT seem to be alternate data stream
1308 * entries. Here's an example of the aligned data:
1310 * 01000000 40000000 6c786bba c58ede11 b0bb0026 1870892a b6adb76f
1311 * e63a3e46 8fca8653 0d2effa1 6c786bba c58ede11 b0bb0026 1870892a
1312 * 00000000 00000000 00000000 00000000
1314 * Here's one interpretation of how the data is laid out.
1317 * u32 field1; (always 0x00000001)
1318 * u32 field2; (always 0x40000000)
1319 * u8 data[48]; (???)
1320 * u64 reserved1; (always 0)
1321 * u64 reserved2; (always 0)
1323 DEBUG("Dentry for file or directory `%s' has %zu extra "
1325 file_name_utf8, dentry->length - calculated_size);
1328 /* Read the short filename if present. Note: if there is no short
1329 * filename, there is no null terminator following it. */
1330 if (short_name_len) {
1331 short_name = MALLOC(short_name_len);
1333 ERROR("Failed to allocate %hu bytes for short filename",
1335 ret = WIMLIB_ERR_NOMEM;
1336 goto out_free_file_name_utf8;
1339 p = get_bytes(p, short_name_len, short_name);
1341 WARNING("Expected two zero bytes following the file name "
1342 "`%s', but found non-zero bytes", file_name_utf8);
1347 * Read the alternate data streams, if present. dentry->num_ads tells
1348 * us how many they are, and they will directly follow the dentry
1351 * Note that each alternate data stream entry begins on an 8-byte
1352 * aligned boundary, and the alternate data stream entries are NOT
1353 * included in the dentry->length field for some reason.
1355 if (inode->num_ads != 0) {
1356 if (calculated_size > metadata_resource_len - offset) {
1357 ERROR("Not enough space in metadata resource for "
1358 "alternate stream entries");
1359 ret = WIMLIB_ERR_INVALID_DENTRY;
1360 goto out_free_short_name;
1362 ret = read_ads_entries(&metadata_resource[offset + calculated_size],
1364 metadata_resource_len - offset - calculated_size);
1366 goto out_free_short_name;
1369 /* We've read all the data for this dentry. Set the names and their
1370 * lengths, and we've done. */
1371 dentry->inode = inode;
1372 dentry->file_name = file_name;
1373 dentry->file_name_utf8 = file_name_utf8;
1374 dentry->short_name = short_name;
1375 dentry->file_name_len = file_name_len;
1376 dentry->file_name_utf8_len = file_name_utf8_len;
1377 dentry->short_name_len = short_name_len;
1379 out_free_short_name:
1381 out_free_file_name_utf8:
1382 FREE(file_name_utf8);
1390 int verify_inode(struct inode *inode, const WIMStruct *w)
1392 const struct lookup_table *table = w->lookup_table;
1393 const struct wim_security_data *sd = wim_const_security_data(w);
1394 const struct dentry *first_dentry = inode_first_dentry(inode);
1395 int ret = WIMLIB_ERR_INVALID_DENTRY;
1397 /* Check the security ID */
1398 if (inode->security_id < -1) {
1399 ERROR("Dentry `%s' has an invalid security ID (%d)",
1400 first_dentry->full_path_utf8, inode->security_id);
1403 if (inode->security_id >= sd->num_entries) {
1404 ERROR("Dentry `%s' has an invalid security ID (%d) "
1405 "(there are only %u entries in the security table)",
1406 first_dentry->full_path_utf8, inode->security_id,
1411 /* Check that lookup table entries for all the resources exist, except
1412 * if the SHA1 message digest is all 0's, which indicates there is
1413 * intentionally no resource there. */
1414 if (w->hdr.total_parts == 1) {
1415 for (unsigned i = 0; i <= inode->num_ads; i++) {
1416 struct lookup_table_entry *lte;
1418 hash = inode_stream_hash_unresolved(inode, i);
1419 lte = __lookup_resource(table, hash);
1420 if (!lte && !is_zero_hash(hash)) {
1421 ERROR("Could not find lookup table entry for stream "
1422 "%u of dentry `%s'", i, first_dentry->full_path_utf8);
1425 if (lte && (lte->real_refcnt += inode->link_count) > lte->refcnt)
1427 #ifdef ENABLE_ERROR_MESSAGES
1428 WARNING("The following lookup table entry "
1429 "has a reference count of %u, but",
1431 WARNING("We found %zu references to it",
1433 WARNING("(One dentry referencing it is at `%s')",
1434 first_dentry->full_path_utf8);
1436 print_lookup_table_entry(lte);
1438 /* Guess what! install.wim for Windows 8
1439 * contains a stream with 2 dentries referencing
1440 * it, but the lookup table entry has reference
1441 * count of 1. So we will need to handle this
1442 * case and not just make it be an error... I'm
1443 * just setting the reference count to the
1444 * number of references we found.
1445 * (Unfortunately, even after doing this, the
1446 * reference count could be too low if it's also
1447 * referenced in other WIM images) */
1450 lte->refcnt = lte->real_refcnt;
1451 WARNING("Fixing reference count");
1459 /* Make sure there is only one un-named stream. */
1460 unsigned num_unnamed_streams = 0;
1461 for (unsigned i = 0; i <= inode->num_ads; i++) {
1463 hash = inode_stream_hash_unresolved(inode, i);
1464 if (!inode_stream_name_len(inode, i) && !is_zero_hash(hash))
1465 num_unnamed_streams++;
1467 if (num_unnamed_streams > 1) {
1468 ERROR("Dentry `%s' has multiple (%u) un-named streams",
1469 first_dentry->full_path_utf8, num_unnamed_streams);
1472 inode->verified = true;
1479 /* Run some miscellaneous verifications on a WIM dentry */
1480 int verify_dentry(struct dentry *dentry, void *wim)
1482 const WIMStruct *w = wim;
1483 const struct inode *inode = dentry->inode;
1484 int ret = WIMLIB_ERR_INVALID_DENTRY;
1486 if (!dentry->inode->verified) {
1487 ret = verify_inode(dentry->inode, w);
1492 /* Cannot have a short name but no long name */
1493 if (dentry->short_name_len && !dentry->file_name_len) {
1494 ERROR("Dentry `%s' has a short name but no long name",
1495 dentry->full_path_utf8);
1499 /* Make sure root dentry is unnamed */
1500 if (dentry_is_root(dentry)) {
1501 if (dentry->file_name_len) {
1502 ERROR("The root dentry is named `%s', but it must "
1503 "be unnamed", dentry->file_name_utf8);
1509 /* Check timestamps */
1510 if (inode->last_access_time < inode->creation_time ||
1511 inode->last_write_time < inode->creation_time) {
1512 WARNING("Dentry `%s' was created after it was last accessed or "
1513 "written to", dentry->full_path_utf8);
1523 * Writes a WIM dentry to an output buffer.
1525 * @dentry: The dentry structure.
1526 * @p: The memory location to write the data to.
1527 * @return: Pointer to the byte after the last byte we wrote as part of the
1530 static u8 *write_dentry(const struct dentry *dentry, u8 *p)
1534 const struct inode *inode = dentry->inode;
1536 /* We calculate the correct length of the dentry ourselves because the
1537 * dentry->length field may been set to an unexpected value from when we
1538 * read the dentry in (for example, there may have been unknown data
1539 * appended to the end of the dentry...) */
1540 u64 length = dentry_correct_length(dentry);
1542 p = put_u64(p, length);
1543 p = put_u32(p, inode->attributes);
1544 p = put_u32(p, inode->security_id);
1545 p = put_u64(p, dentry->subdir_offset);
1546 p = put_u64(p, 0); /* unused1 */
1547 p = put_u64(p, 0); /* unused2 */
1548 p = put_u64(p, inode->creation_time);
1549 p = put_u64(p, inode->last_access_time);
1550 p = put_u64(p, inode->last_write_time);
1551 hash = inode_stream_hash(inode, 0);
1552 p = put_bytes(p, SHA1_HASH_SIZE, hash);
1553 if (inode->attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1554 p = put_zeroes(p, 4);
1555 p = put_u32(p, inode->reparse_tag);
1556 p = put_zeroes(p, 4);
1560 if (inode->link_count == 1)
1563 link_group_id = inode->ino;
1564 p = put_u64(p, link_group_id);
1566 p = put_u16(p, inode->num_ads);
1567 p = put_u16(p, dentry->short_name_len);
1568 p = put_u16(p, dentry->file_name_len);
1569 if (dentry->file_name_len) {
1570 p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name);
1571 p = put_u16(p, 0); /* filename padding, 2 bytes. */
1573 if (dentry->short_name) {
1574 p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name);
1575 p = put_u16(p, 0); /* short name padding, 2 bytes */
1578 /* Align to 8-byte boundary */
1579 wimlib_assert(length >= (p - orig_p)
1580 && length - (p - orig_p) <= 7);
1581 p = put_zeroes(p, length - (p - orig_p));
1583 /* Write the alternate data streams, if there are any. Please see
1584 * read_ads_entries() for comments about the format of the on-disk
1585 * alternate data stream entries. */
1586 for (u16 i = 0; i < inode->num_ads; i++) {
1587 p = put_u64(p, ads_entry_total_length(&inode->ads_entries[i]));
1588 p = put_u64(p, 0); /* Unused */
1589 hash = inode_stream_hash(inode, i + 1);
1590 p = put_bytes(p, SHA1_HASH_SIZE, hash);
1591 p = put_u16(p, inode->ads_entries[i].stream_name_len);
1592 if (inode->ads_entries[i].stream_name_len) {
1593 p = put_bytes(p, inode->ads_entries[i].stream_name_len,
1594 (u8*)inode->ads_entries[i].stream_name);
1597 p = put_zeroes(p, (8 - (p - orig_p) % 8) % 8);
1599 #ifdef ENABLE_ASSERTIONS
1600 wimlib_assert(p - orig_p == __dentry_total_length(dentry, length));
1605 /* Recursive function that writes a dentry tree rooted at @parent, not including
1606 * @parent itself, which has already been written. */
1607 static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p)
1609 const struct dentry *child;
1611 /* Nothing to do if this dentry has no children. */
1612 if (parent->subdir_offset == 0)
1615 /* Write child dentries and end-of-directory entry.
1617 * Note: we need to write all of this dentry's children before
1618 * recursively writing the directory trees rooted at each of the child
1619 * dentries, since the on-disk dentries for a dentry's children are
1620 * always located at consecutive positions in the metadata resource! */
1621 child = parent->inode->children;
1624 p = write_dentry(child, p);
1625 child = child->next;
1626 } while (child != parent->inode->children);
1629 /* write end of directory entry */
1632 /* Recurse on children. */
1635 p = write_dentry_tree_recursive(child, p);
1636 child = child->next;
1637 } while (child != parent->inode->children);
1642 /* Writes a directory tree to the metadata resource.
1644 * @root: Root of the dentry tree.
1645 * @p: Pointer to a buffer with enough space for the dentry tree.
1647 * Returns pointer to the byte after the last byte we wrote.
1649 u8 *write_dentry_tree(const struct dentry *root, u8 *p)
1651 wimlib_assert(dentry_is_root(root));
1653 /* If we're the root dentry, we have no parent that already
1654 * wrote us, so we need to write ourselves. */
1655 p = write_dentry(root, p);
1657 /* Write end of directory entry after the root dentry just to be safe;
1658 * however the root dentry obviously cannot have any siblings. */
1661 /* Recursively write the rest of the dentry tree. */
1662 return write_dentry_tree_recursive(root, p);
1665 /* Reads the children of a dentry, and all their children, ..., etc. from the
1666 * metadata resource and into the dentry tree.
1668 * @metadata_resource: An array that contains the uncompressed metadata
1669 * resource for the WIM file.
1671 * @metadata_resource_len: The length of the uncompressed metadata resource, in
1674 * @dentry: A pointer to a `struct dentry' that is the root of the directory
1675 * tree and has already been read from the metadata resource. It
1676 * does not need to be the real root because this procedure is
1677 * called recursively.
1679 * @return: Zero on success, nonzero on failure.
1681 int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
1682 struct dentry *dentry)
1684 u64 cur_offset = dentry->subdir_offset;
1685 struct dentry *prev_child = NULL;
1686 struct dentry *first_child = NULL;
1687 struct dentry *child;
1688 struct dentry cur_child;
1692 * If @dentry has no child dentries, nothing more needs to be done for
1693 * this branch. This is the case for regular files, symbolic links, and
1694 * *possibly* empty directories (although an empty directory may also
1695 * have one child dentry that is the special end-of-directory dentry)
1697 if (cur_offset == 0)
1700 /* Find and read all the children of @dentry. */
1703 /* Read next child of @dentry into @cur_child. */
1704 ret = read_dentry(metadata_resource, metadata_resource_len,
1705 cur_offset, &cur_child);
1709 /* Check for end of directory. */
1710 if (cur_child.length == 0)
1713 /* Not end of directory. Allocate this child permanently and
1714 * link it to the parent and previous child. */
1715 child = MALLOC(sizeof(struct dentry));
1717 ERROR("Failed to allocate %zu bytes for new dentry",
1718 sizeof(struct dentry));
1719 ret = WIMLIB_ERR_NOMEM;
1722 memcpy(child, &cur_child, sizeof(struct dentry));
1725 prev_child->next = child;
1726 child->prev = prev_child;
1728 first_child = child;
1731 child->parent = dentry;
1733 inode_add_dentry(child, child->inode);
1735 /* If there are children of this child, call this procedure
1737 if (child->subdir_offset != 0) {
1738 ret = read_dentry_tree(metadata_resource,
1739 metadata_resource_len, child);
1744 /* Advance to the offset of the next child. Note: We need to
1745 * advance by the TOTAL length of the dentry, not by the length
1746 * child->length, which although it does take into account the
1747 * padding, it DOES NOT take into account alternate stream
1749 cur_offset += dentry_total_length(child);
1752 /* Link last child to first one, and set parent's children pointer to
1753 * the first child. */
1755 prev_child->next = first_child;
1756 first_child->prev = prev_child;
1758 dentry->inode->children = first_child;