4 * In the WIM file format, the dentries are stored in the "metadata resource"
5 * section right after the security data. Each image in the WIM file has its
6 * own metadata resource with its own security data and dentry tree. Dentries
7 * in different images may share file resources by referring to the same lookup
12 * Copyright (C) 2012, 2013 Eric Biggers
14 * This file is part of wimlib, a library for working with WIM files.
16 * wimlib is free software; you can redistribute it and/or modify it under the
17 * terms of the GNU General Public License as published by the Free Software
18 * Foundation; either version 3 of the License, or (at your option) any later
21 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
22 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
23 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along with
26 * wimlib; if not, see http://www.gnu.org/licenses/.
34 #include "wimlib/dentry.h"
35 #include "wimlib/encoding.h"
36 #include "wimlib/endianness.h"
37 #include "wimlib/error.h"
38 #include "wimlib/lookup_table.h"
39 #include "wimlib/metadata.h"
40 #include "wimlib/resource.h"
41 #include "wimlib/sha1.h"
42 #include "wimlib/timestamp.h"
46 /* WIM alternate data stream entry (on-disk format) */
47 struct wim_ads_entry_on_disk {
48 /* Length of the entry, in bytes. This apparently includes all
49 * fixed-length fields, plus the stream name and null terminator if
50 * present, and the padding up to an 8 byte boundary. wimlib is a
51 * little less strict when reading the entries, and only requires that
52 * the number of bytes from this field is at least as large as the size
53 * of the fixed length fields and stream name without null terminator.
59 /* SHA1 message digest of the uncompressed stream; or, alternatively,
60 * can be all zeroes if the stream has zero length. */
61 u8 hash[SHA1_HASH_SIZE];
63 /* Length of the stream name, in bytes. 0 if the stream is unnamed. */
64 le16 stream_name_nbytes;
66 /* Stream name in UTF-16LE. It is @stream_name_nbytes bytes long,
67 * excluding the the null terminator. There is a null terminator
68 * character if @stream_name_nbytes != 0; i.e., if this stream is named.
70 utf16lechar stream_name[];
73 #define WIM_ADS_ENTRY_DISK_SIZE 38
75 /* WIM directory entry (on-disk format) */
76 struct wim_dentry_on_disk {
84 le64 last_access_time;
86 u8 unnamed_stream_hash[SHA1_HASH_SIZE];
93 } _packed_attribute reparse;
96 le64 hard_link_group_id;
97 } _packed_attribute nonreparse;
99 le16 num_alternate_data_streams;
100 le16 short_name_nbytes;
101 le16 file_name_nbytes;
103 /* Follewed by variable length file name, if file_name_nbytes != 0 */
104 utf16lechar file_name[];
106 /* Followed by variable length short name, if short_name_nbytes != 0 */
107 /*utf16lechar short_name[];*/
110 #define WIM_DENTRY_DISK_SIZE 102
112 /* Calculates the unaligned length, in bytes, of an on-disk WIM dentry that has
113 * a file name and short name that take the specified numbers of bytes. This
114 * excludes any alternate data stream entries that may follow the dentry. */
116 _dentry_correct_length_unaligned(u16 file_name_nbytes, u16 short_name_nbytes)
118 u64 length = sizeof(struct wim_dentry_on_disk);
119 if (file_name_nbytes)
120 length += file_name_nbytes + 2;
121 if (short_name_nbytes)
122 length += short_name_nbytes + 2;
126 /* Calculates the unaligned length, in bytes, of an on-disk WIM dentry, based on
127 * the file name length and short name length. Note that dentry->length is
128 * ignored; also, this excludes any alternate data stream entries that may
129 * follow the dentry. */
131 dentry_correct_length_unaligned(const struct wim_dentry *dentry)
133 return _dentry_correct_length_unaligned(dentry->file_name_nbytes,
134 dentry->short_name_nbytes);
137 /* Return %true iff the alternate data stream entry @entry has the UTF-16LE
138 * stream name @name that has length @name_nbytes bytes. */
140 ads_entry_has_name(const struct wim_ads_entry *entry,
141 const utf16lechar *name, size_t name_nbytes)
143 return entry->stream_name_nbytes == name_nbytes &&
144 memcmp(entry->stream_name, name, name_nbytes) == 0;
147 /* Duplicates a string of system-dependent encoding into a UTF-16LE string and
148 * returns the string and its length, in bytes, in the pointer arguments. Frees
149 * any existing string at the return location before overwriting it. */
151 get_utf16le_name(const tchar *name, utf16lechar **name_utf16le_ret,
152 u16 *name_utf16le_nbytes_ret)
154 utf16lechar *name_utf16le;
155 size_t name_utf16le_nbytes;
158 name_utf16le_nbytes = tstrlen(name) * sizeof(utf16lechar);
159 name_utf16le = MALLOC(name_utf16le_nbytes + sizeof(utf16lechar));
161 return WIMLIB_ERR_NOMEM;
162 memcpy(name_utf16le, name, name_utf16le_nbytes + sizeof(utf16lechar));
166 ret = tstr_to_utf16le(name, tstrlen(name), &name_utf16le,
167 &name_utf16le_nbytes);
169 if (name_utf16le_nbytes > 0xffff) {
171 ERROR("Multibyte string \"%"TS"\" is too long!", name);
172 ret = WIMLIB_ERR_INVALID_UTF8_STRING;
177 FREE(*name_utf16le_ret);
178 *name_utf16le_ret = name_utf16le;
179 *name_utf16le_nbytes_ret = name_utf16le_nbytes;
184 /* Sets the name of a WIM dentry from a multibyte string. */
186 set_dentry_name(struct wim_dentry *dentry, const tchar *new_name)
189 ret = get_utf16le_name(new_name, &dentry->file_name,
190 &dentry->file_name_nbytes);
192 /* Clear the short name and recalculate the dentry length */
193 if (dentry_has_short_name(dentry)) {
194 FREE(dentry->short_name);
195 dentry->short_name = NULL;
196 dentry->short_name_nbytes = 0;
202 /* Returns the total length of a WIM alternate data stream entry on-disk,
203 * including the stream name, the null terminator, AND the padding after the
204 * entry to align the next ADS entry or dentry on an 8-byte boundary. */
206 ads_entry_total_length(const struct wim_ads_entry *entry)
208 u64 len = sizeof(struct wim_ads_entry_on_disk);
209 if (entry->stream_name_nbytes)
210 len += entry->stream_name_nbytes + 2;
211 return (len + 7) & ~7;
216 _dentry_total_length(const struct wim_dentry *dentry, u64 length)
218 const struct wim_inode *inode = dentry->d_inode;
219 for (u16 i = 0; i < inode->i_num_ads; i++)
220 length += ads_entry_total_length(&inode->i_ads_entries[i]);
221 return (length + 7) & ~7;
224 /* Calculate the aligned *total* length of an on-disk WIM dentry. This includes
225 * all alternate data streams. */
227 dentry_correct_total_length(const struct wim_dentry *dentry)
229 return _dentry_total_length(dentry,
230 dentry_correct_length_unaligned(dentry));
233 /* Like dentry_correct_total_length(), but use the existing dentry->length field
234 * instead of calculating its "correct" value. */
236 dentry_total_length(const struct wim_dentry *dentry)
238 return _dentry_total_length(dentry, dentry->length);
242 for_dentry_in_rbtree(struct rb_node *root,
243 int (*visitor)(struct wim_dentry *, void *),
247 struct rb_node *node = root;
251 list_add(&rbnode_dentry(node)->tmp_list, &stack);
252 node = node->rb_left;
254 struct list_head *next;
255 struct wim_dentry *dentry;
260 dentry = container_of(next, struct wim_dentry, tmp_list);
262 ret = visitor(dentry, arg);
265 node = dentry->rb_node.rb_right;
271 for_dentry_tree_in_rbtree_depth(struct rb_node *node,
272 int (*visitor)(struct wim_dentry*, void*),
277 ret = for_dentry_tree_in_rbtree_depth(node->rb_left,
281 ret = for_dentry_tree_in_rbtree_depth(node->rb_right,
285 ret = for_dentry_in_tree_depth(rbnode_dentry(node), visitor, arg);
293 for_dentry_tree_in_rbtree(struct rb_node *node,
294 int (*visitor)(struct wim_dentry*, void*),
299 ret = for_dentry_tree_in_rbtree(node->rb_left, visitor, arg);
302 ret = for_dentry_in_tree(rbnode_dentry(node), visitor, arg);
305 ret = for_dentry_tree_in_rbtree(node->rb_right, visitor, arg);
312 /* Calls a function on all directory entries in a WIM dentry tree. Logically,
313 * this is a pre-order traversal (the function is called on a parent dentry
314 * before its children), but sibling dentries will be visited in order as well.
317 for_dentry_in_tree(struct wim_dentry *root,
318 int (*visitor)(struct wim_dentry*, void*), void *arg)
324 ret = (*visitor)(root, arg);
327 return for_dentry_tree_in_rbtree(root->d_inode->i_children.rb_node,
332 /* Like for_dentry_in_tree(), but the visitor function is always called on a
333 * dentry's children before on itself. */
335 for_dentry_in_tree_depth(struct wim_dentry *root,
336 int (*visitor)(struct wim_dentry*, void*), void *arg)
342 ret = for_dentry_tree_in_rbtree_depth(root->d_inode->i_children.rb_node,
346 return (*visitor)(root, arg);
349 /* Calculate the full path of @dentry. The full path of its parent must have
350 * already been calculated, or it must be the root dentry. */
352 calculate_dentry_full_path(struct wim_dentry *dentry)
355 u32 full_path_nbytes;
358 if (dentry->_full_path)
361 if (dentry_is_root(dentry)) {
362 full_path = TSTRDUP(T("/"));
364 return WIMLIB_ERR_NOMEM;
365 full_path_nbytes = 1 * sizeof(tchar);
367 struct wim_dentry *parent;
368 tchar *parent_full_path;
369 u32 parent_full_path_nbytes;
370 size_t filename_nbytes;
372 parent = dentry->parent;
373 if (dentry_is_root(parent)) {
374 parent_full_path = T("");
375 parent_full_path_nbytes = 0;
377 if (!parent->_full_path) {
378 ret = calculate_dentry_full_path(parent);
382 parent_full_path = parent->_full_path;
383 parent_full_path_nbytes = parent->full_path_nbytes;
386 /* Append this dentry's name as a tchar string to the full path
387 * of the parent followed by the path separator */
389 filename_nbytes = dentry->file_name_nbytes;
392 int ret = utf16le_to_tstr_nbytes(dentry->file_name,
393 dentry->file_name_nbytes,
400 full_path_nbytes = parent_full_path_nbytes + sizeof(tchar) +
402 full_path = MALLOC(full_path_nbytes + sizeof(tchar));
404 return WIMLIB_ERR_NOMEM;
405 memcpy(full_path, parent_full_path, parent_full_path_nbytes);
406 full_path[parent_full_path_nbytes / sizeof(tchar)] = T('/');
408 memcpy(&full_path[parent_full_path_nbytes / sizeof(tchar) + 1],
410 filename_nbytes + sizeof(tchar));
412 utf16le_to_tstr_buf(dentry->file_name,
413 dentry->file_name_nbytes,
414 &full_path[parent_full_path_nbytes /
418 dentry->_full_path = full_path;
419 dentry->full_path_nbytes= full_path_nbytes;
424 do_calculate_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
426 return calculate_dentry_full_path(dentry);
430 calculate_dentry_tree_full_paths(struct wim_dentry *root)
432 return for_dentry_in_tree(root, do_calculate_dentry_full_path, NULL);
436 dentry_full_path(struct wim_dentry *dentry)
438 calculate_dentry_full_path(dentry);
439 return dentry->_full_path;
443 increment_subdir_offset(struct wim_dentry *dentry, void *subdir_offset_p)
445 *(u64*)subdir_offset_p += dentry_correct_total_length(dentry);
450 call_calculate_subdir_offsets(struct wim_dentry *dentry, void *subdir_offset_p)
452 calculate_subdir_offsets(dentry, subdir_offset_p);
457 * Recursively calculates the subdir offsets for a directory tree.
459 * @dentry: The root of the directory tree.
460 * @subdir_offset_p: The current subdirectory offset; i.e., the subdirectory
461 * offset for @dentry.
464 calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p)
466 struct rb_node *node;
468 dentry->subdir_offset = *subdir_offset_p;
469 node = dentry->d_inode->i_children.rb_node;
471 /* Advance the subdir offset by the amount of space the children
472 * of this dentry take up. */
473 for_dentry_in_rbtree(node, increment_subdir_offset, subdir_offset_p);
475 /* End-of-directory dentry on disk. */
476 *subdir_offset_p += 8;
478 /* Recursively call calculate_subdir_offsets() on all the
480 for_dentry_in_rbtree(node, call_calculate_subdir_offsets, subdir_offset_p);
482 /* On disk, childless directories have a valid subdir_offset
483 * that points to an 8-byte end-of-directory dentry. Regular
484 * files or reparse points have a subdir_offset of 0. */
485 if (dentry_is_directory(dentry))
486 *subdir_offset_p += 8;
488 dentry->subdir_offset = 0;
493 compare_utf16le_names(const utf16lechar *name1, size_t nbytes1,
494 const utf16lechar *name2, size_t nbytes2)
496 int result = memcmp(name1, name2, min(nbytes1, nbytes2));
500 return (int)nbytes1 - (int)nbytes2;
504 dentry_compare_names(const struct wim_dentry *d1, const struct wim_dentry *d2)
506 return compare_utf16le_names(d1->file_name, d1->file_name_nbytes,
507 d2->file_name, d2->file_name_nbytes);
512 get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry,
513 const utf16lechar *name,
516 struct rb_node *node = dentry->d_inode->i_children.rb_node;
517 struct wim_dentry *child;
519 child = rbnode_dentry(node);
520 int result = compare_utf16le_names(name, name_nbytes,
522 child->file_name_nbytes);
524 node = node->rb_left;
526 node = node->rb_right;
533 /* Returns the child of @dentry that has the file name @name. Returns NULL if
534 * no child has the name. */
536 get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name)
539 return get_dentry_child_with_utf16le_name(dentry, name,
540 tstrlen(name) * sizeof(tchar));
542 utf16lechar *utf16le_name;
543 size_t utf16le_name_nbytes;
545 struct wim_dentry *child;
547 ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar),
548 &utf16le_name, &utf16le_name_nbytes);
552 child = get_dentry_child_with_utf16le_name(dentry,
554 utf16le_name_nbytes);
561 static struct wim_dentry *
562 get_dentry_utf16le(WIMStruct *wim, const utf16lechar *path)
564 struct wim_dentry *cur_dentry, *parent_dentry;
565 const utf16lechar *p, *pp;
567 cur_dentry = parent_dentry = wim_root_dentry(wim);
574 while (*p == cpu_to_le16('/'))
576 if (*p == cpu_to_le16('\0'))
579 while (*pp != cpu_to_le16('/') && *pp != cpu_to_le16('\0'))
582 cur_dentry = get_dentry_child_with_utf16le_name(parent_dentry, p,
583 (void*)pp - (void*)p);
584 if (cur_dentry == NULL)
587 parent_dentry = cur_dentry;
589 if (cur_dentry == NULL) {
590 if (dentry_is_directory(parent_dentry))
598 /* Returns the dentry corresponding to the @path, or NULL if there is no such
601 get_dentry(WIMStruct *wim, const tchar *path)
604 return get_dentry_utf16le(wim, path);
606 utf16lechar *path_utf16le;
607 size_t path_utf16le_nbytes;
609 struct wim_dentry *dentry;
611 ret = tstr_to_utf16le(path, tstrlen(path) * sizeof(tchar),
612 &path_utf16le, &path_utf16le_nbytes);
615 dentry = get_dentry_utf16le(wim, path_utf16le);
622 wim_pathname_to_inode(WIMStruct *wim, const tchar *path)
624 struct wim_dentry *dentry;
625 dentry = get_dentry(wim, path);
627 return dentry->d_inode;
632 /* Takes in a path of length @len in @buf, and transforms it into a string for
633 * the path of its parent directory. */
635 to_parent_name(tchar *buf, size_t len)
637 ssize_t i = (ssize_t)len - 1;
638 while (i >= 0 && buf[i] == T('/'))
640 while (i >= 0 && buf[i] != T('/'))
642 while (i >= 0 && buf[i] == T('/'))
644 buf[i + 1] = T('\0');
647 /* Returns the dentry that corresponds to the parent directory of @path, or NULL
648 * if the dentry is not found. */
650 get_parent_dentry(WIMStruct *wim, const tchar *path)
652 size_t path_len = tstrlen(path);
653 tchar buf[path_len + 1];
655 tmemcpy(buf, path, path_len + 1);
656 to_parent_name(buf, path_len);
657 return get_dentry(wim, buf);
660 /* Prints the full path of a dentry. */
662 print_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
664 int ret = calculate_dentry_full_path(dentry);
667 tprintf(T("%"TS"\n"), dentry->_full_path);
671 /* We want to be able to show the names of the file attribute flags that are
673 struct file_attr_flag {
677 struct file_attr_flag file_attr_flags[] = {
678 {FILE_ATTRIBUTE_READONLY, T("READONLY")},
679 {FILE_ATTRIBUTE_HIDDEN, T("HIDDEN")},
680 {FILE_ATTRIBUTE_SYSTEM, T("SYSTEM")},
681 {FILE_ATTRIBUTE_DIRECTORY, T("DIRECTORY")},
682 {FILE_ATTRIBUTE_ARCHIVE, T("ARCHIVE")},
683 {FILE_ATTRIBUTE_DEVICE, T("DEVICE")},
684 {FILE_ATTRIBUTE_NORMAL, T("NORMAL")},
685 {FILE_ATTRIBUTE_TEMPORARY, T("TEMPORARY")},
686 {FILE_ATTRIBUTE_SPARSE_FILE, T("SPARSE_FILE")},
687 {FILE_ATTRIBUTE_REPARSE_POINT, T("REPARSE_POINT")},
688 {FILE_ATTRIBUTE_COMPRESSED, T("COMPRESSED")},
689 {FILE_ATTRIBUTE_OFFLINE, T("OFFLINE")},
690 {FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,T("NOT_CONTENT_INDEXED")},
691 {FILE_ATTRIBUTE_ENCRYPTED, T("ENCRYPTED")},
692 {FILE_ATTRIBUTE_VIRTUAL, T("VIRTUAL")},
695 /* Prints a directory entry. @lookup_table is a pointer to the lookup table, if
696 * available. If the dentry is unresolved and the lookup table is NULL, the
697 * lookup table entries will not be printed. Otherwise, they will be. */
699 print_dentry(struct wim_dentry *dentry, void *lookup_table)
702 struct wim_lookup_table_entry *lte;
703 const struct wim_inode *inode = dentry->d_inode;
706 tprintf(T("[DENTRY]\n"));
707 tprintf(T("Length = %"PRIu64"\n"), dentry->length);
708 tprintf(T("Attributes = 0x%x\n"), inode->i_attributes);
709 for (size_t i = 0; i < ARRAY_LEN(file_attr_flags); i++)
710 if (file_attr_flags[i].flag & inode->i_attributes)
711 tprintf(T(" FILE_ATTRIBUTE_%"TS" is set\n"),
712 file_attr_flags[i].name);
713 tprintf(T("Security ID = %d\n"), inode->i_security_id);
714 tprintf(T("Subdir offset = %"PRIu64"\n"), dentry->subdir_offset);
716 wim_timestamp_to_str(inode->i_creation_time, buf, sizeof(buf));
717 tprintf(T("Creation Time = %"TS"\n"), buf);
719 wim_timestamp_to_str(inode->i_last_access_time, buf, sizeof(buf));
720 tprintf(T("Last Access Time = %"TS"\n"), buf);
722 wim_timestamp_to_str(inode->i_last_write_time, buf, sizeof(buf));
723 tprintf(T("Last Write Time = %"TS"\n"), buf);
725 if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
726 tprintf(T("Reparse Tag = 0x%"PRIx32"\n"), inode->i_reparse_tag);
727 tprintf(T("Reparse Point Flags = 0x%"PRIx16"\n"),
728 inode->i_not_rpfixed);
729 tprintf(T("Reparse Point Unknown 2 = 0x%"PRIx32"\n"),
730 inode->i_rp_unknown_2);
732 tprintf(T("Reparse Point Unknown 1 = 0x%"PRIx32"\n"),
733 inode->i_rp_unknown_1);
734 tprintf(T("Hard Link Group = 0x%"PRIx64"\n"), inode->i_ino);
735 tprintf(T("Hard Link Group Size = %"PRIu32"\n"), inode->i_nlink);
736 tprintf(T("Number of Alternate Data Streams = %hu\n"), inode->i_num_ads);
737 if (dentry_has_long_name(dentry))
738 wimlib_printf(T("Filename = \"%"WS"\"\n"), dentry->file_name);
739 if (dentry_has_short_name(dentry))
740 wimlib_printf(T("Short Name \"%"WS"\"\n"), dentry->short_name);
741 if (dentry->_full_path)
742 tprintf(T("Full Path = \"%"TS"\"\n"), dentry->_full_path);
744 lte = inode_stream_lte(dentry->d_inode, 0, lookup_table);
746 print_lookup_table_entry(lte, stdout);
748 hash = inode_stream_hash(inode, 0);
750 tprintf(T("Hash = 0x"));
751 print_hash(hash, stdout);
756 for (u16 i = 0; i < inode->i_num_ads; i++) {
757 tprintf(T("[Alternate Stream Entry %u]\n"), i);
758 wimlib_printf(T("Name = \"%"WS"\"\n"),
759 inode->i_ads_entries[i].stream_name);
760 tprintf(T("Name Length (UTF16 bytes) = %hu\n"),
761 inode->i_ads_entries[i].stream_name_nbytes);
762 hash = inode_stream_hash(inode, i + 1);
764 tprintf(T("Hash = 0x"));
765 print_hash(hash, stdout);
768 print_lookup_table_entry(inode_stream_lte(inode, i + 1, lookup_table),
774 /* Initializations done on every `struct wim_dentry'. */
776 dentry_common_init(struct wim_dentry *dentry)
778 memset(dentry, 0, sizeof(struct wim_dentry));
782 new_timeless_inode(void)
784 struct wim_inode *inode = CALLOC(1, sizeof(struct wim_inode));
786 inode->i_security_id = -1;
788 inode->i_next_stream_id = 1;
789 inode->i_not_rpfixed = 1;
790 INIT_LIST_HEAD(&inode->i_list);
792 if (pthread_mutex_init(&inode->i_mutex, NULL) != 0) {
793 ERROR_WITH_ERRNO("Error initializing mutex");
798 INIT_LIST_HEAD(&inode->i_dentry);
803 static struct wim_inode *
806 struct wim_inode *inode = new_timeless_inode();
808 u64 now = get_wim_timestamp();
809 inode->i_creation_time = now;
810 inode->i_last_access_time = now;
811 inode->i_last_write_time = now;
816 /* Creates an unlinked directory entry. */
818 new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
820 struct wim_dentry *dentry;
823 dentry = MALLOC(sizeof(struct wim_dentry));
825 return WIMLIB_ERR_NOMEM;
827 dentry_common_init(dentry);
828 ret = set_dentry_name(dentry, name);
830 dentry->parent = dentry;
831 *dentry_ret = dentry;
834 ERROR("Failed to set name on new dentry with name \"%"TS"\"",
842 _new_dentry_with_inode(const tchar *name, struct wim_dentry **dentry_ret,
845 struct wim_dentry *dentry;
848 ret = new_dentry(name, &dentry);
853 dentry->d_inode = new_timeless_inode();
855 dentry->d_inode = new_inode();
856 if (!dentry->d_inode) {
858 return WIMLIB_ERR_NOMEM;
861 inode_add_dentry(dentry, dentry->d_inode);
862 *dentry_ret = dentry;
867 new_dentry_with_timeless_inode(const tchar *name, struct wim_dentry **dentry_ret)
869 return _new_dentry_with_inode(name, dentry_ret, true);
873 new_dentry_with_inode(const tchar *name, struct wim_dentry **dentry_ret)
875 return _new_dentry_with_inode(name, dentry_ret, false);
879 new_filler_directory(const tchar *name, struct wim_dentry **dentry_ret)
882 struct wim_dentry *dentry;
884 DEBUG("Creating filler directory \"%"TS"\"", name);
885 ret = new_dentry_with_inode(name, &dentry);
888 /* Leave the inode number as 0; this is allowed for non
889 * hard-linked files. */
890 dentry->d_inode->i_resolved = 1;
891 dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
892 *dentry_ret = dentry;
897 init_ads_entry(struct wim_ads_entry *ads_entry, const void *name,
898 size_t name_nbytes, bool is_utf16le)
901 memset(ads_entry, 0, sizeof(*ads_entry));
904 utf16lechar *p = MALLOC(name_nbytes + sizeof(utf16lechar));
906 return WIMLIB_ERR_NOMEM;
907 memcpy(p, name, name_nbytes);
908 p[name_nbytes / 2] = cpu_to_le16(0);
909 ads_entry->stream_name = p;
910 ads_entry->stream_name_nbytes = name_nbytes;
912 if (name && *(const tchar*)name != T('\0')) {
913 ret = get_utf16le_name(name, &ads_entry->stream_name,
914 &ads_entry->stream_name_nbytes);
921 destroy_ads_entry(struct wim_ads_entry *ads_entry)
923 FREE(ads_entry->stream_name);
926 /* Frees an inode. */
928 free_inode(struct wim_inode *inode)
931 if (inode->i_ads_entries) {
932 for (u16 i = 0; i < inode->i_num_ads; i++)
933 destroy_ads_entry(&inode->i_ads_entries[i]);
934 FREE(inode->i_ads_entries);
937 wimlib_assert(inode->i_num_opened_fds == 0);
939 pthread_mutex_destroy(&inode->i_mutex);
941 /* HACK: This may instead delete the inode from i_list, but the
942 * hlist_del() behaves the same as list_del(). */
943 hlist_del(&inode->i_hlist);
944 FREE(inode->i_extracted_file);
949 /* Decrements link count on an inode and frees it if the link count reaches 0.
952 put_inode(struct wim_inode *inode)
954 wimlib_assert(inode->i_nlink != 0);
955 if (--inode->i_nlink == 0) {
957 if (inode->i_num_opened_fds == 0)
965 /* Frees a WIM dentry.
967 * The corresponding inode (if any) is freed only if its link count is
971 free_dentry(struct wim_dentry *dentry)
974 FREE(dentry->file_name);
975 FREE(dentry->short_name);
976 FREE(dentry->_full_path);
978 put_inode(dentry->d_inode);
983 /* This function is passed as an argument to for_dentry_in_tree_depth() in order
984 * to free a directory tree. */
986 do_free_dentry(struct wim_dentry *dentry, void *_lookup_table)
988 struct wim_lookup_table *lookup_table = _lookup_table;
991 struct wim_inode *inode = dentry->d_inode;
992 for (unsigned i = 0; i <= inode->i_num_ads; i++) {
993 struct wim_lookup_table_entry *lte;
995 lte = inode_stream_lte(inode, i, lookup_table);
997 lte_decrement_refcnt(lte, lookup_table);
1000 free_dentry(dentry);
1005 * Unlinks and frees a dentry tree.
1007 * @root: The root of the tree.
1008 * @lookup_table: The lookup table for dentries. If non-NULL, the
1009 * reference counts in the lookup table for the lookup
1010 * table entries corresponding to the dentries will be
1014 free_dentry_tree(struct wim_dentry *root, struct wim_lookup_table *lookup_table)
1016 for_dentry_in_tree_depth(root, do_free_dentry, lookup_table);
1020 * Links a dentry into the directory tree.
1022 * @parent: The dentry that will be the parent of @child.
1023 * @child: The dentry to link.
1025 * Returns non-NULL if a duplicate dentry was detected.
1028 dentry_add_child(struct wim_dentry * restrict parent,
1029 struct wim_dentry * restrict child)
1031 wimlib_assert(dentry_is_directory(parent));
1032 wimlib_assert(parent != child);
1034 struct rb_root *root = &parent->d_inode->i_children;
1035 struct rb_node **new = &(root->rb_node);
1036 struct rb_node *rb_parent = NULL;
1039 struct wim_dentry *this = rbnode_dentry(*new);
1040 int result = dentry_compare_names(child, this);
1045 new = &((*new)->rb_left);
1046 else if (result > 0)
1047 new = &((*new)->rb_right);
1051 child->parent = parent;
1052 rb_link_node(&child->rb_node, rb_parent, new);
1053 rb_insert_color(&child->rb_node, root);
1057 /* Unlink a WIM dentry from the directory entry tree. */
1059 unlink_dentry(struct wim_dentry *dentry)
1061 if (!dentry_is_root(dentry))
1062 rb_erase(&dentry->rb_node, &dentry->parent->d_inode->i_children);
1066 * Returns the alternate data stream entry belonging to @inode that has the
1067 * stream name @stream_name.
1069 struct wim_ads_entry *
1070 inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name,
1073 if (inode->i_num_ads == 0) {
1076 size_t stream_name_utf16le_nbytes;
1078 struct wim_ads_entry *result;
1080 #if TCHAR_IS_UTF16LE
1081 const utf16lechar *stream_name_utf16le;
1083 stream_name_utf16le = stream_name;
1084 stream_name_utf16le_nbytes = tstrlen(stream_name) * sizeof(tchar);
1086 utf16lechar *stream_name_utf16le;
1089 int ret = tstr_to_utf16le(stream_name,
1090 tstrlen(stream_name) *
1092 &stream_name_utf16le,
1093 &stream_name_utf16le_nbytes);
1101 if (ads_entry_has_name(&inode->i_ads_entries[i],
1102 stream_name_utf16le,
1103 stream_name_utf16le_nbytes))
1107 result = &inode->i_ads_entries[i];
1110 } while (++i != inode->i_num_ads);
1111 #if !TCHAR_IS_UTF16LE
1112 FREE(stream_name_utf16le);
1118 static struct wim_ads_entry *
1119 do_inode_add_ads(struct wim_inode *inode, const void *stream_name,
1120 size_t stream_name_nbytes, bool is_utf16le)
1123 struct wim_ads_entry *ads_entries;
1124 struct wim_ads_entry *new_entry;
1126 if (inode->i_num_ads >= 0xfffe) {
1127 ERROR("Too many alternate data streams in one inode!");
1130 num_ads = inode->i_num_ads + 1;
1131 ads_entries = REALLOC(inode->i_ads_entries,
1132 num_ads * sizeof(inode->i_ads_entries[0]));
1134 ERROR("Failed to allocate memory for new alternate data stream");
1137 inode->i_ads_entries = ads_entries;
1139 new_entry = &inode->i_ads_entries[num_ads - 1];
1140 if (init_ads_entry(new_entry, stream_name, stream_name_nbytes, is_utf16le))
1142 new_entry->stream_id = inode->i_next_stream_id++;
1143 inode->i_num_ads = num_ads;
1147 struct wim_ads_entry *
1148 inode_add_ads_utf16le(struct wim_inode *inode,
1149 const utf16lechar *stream_name,
1150 size_t stream_name_nbytes)
1152 DEBUG("Add alternate data stream \"%"WS"\"", stream_name);
1153 return do_inode_add_ads(inode, stream_name, stream_name_nbytes, true);
1157 * Add an alternate stream entry to a WIM inode and return a pointer to it, or
1158 * NULL if memory could not be allocated.
1160 struct wim_ads_entry *
1161 inode_add_ads(struct wim_inode *inode, const tchar *stream_name)
1163 DEBUG("Add alternate data stream \"%"TS"\"", stream_name);
1164 return do_inode_add_ads(inode, stream_name,
1165 tstrlen(stream_name) * sizeof(tchar),
1169 static struct wim_lookup_table_entry *
1170 add_stream_from_data_buffer(const void *buffer, size_t size,
1171 struct wim_lookup_table *lookup_table)
1173 u8 hash[SHA1_HASH_SIZE];
1174 struct wim_lookup_table_entry *lte, *existing_lte;
1176 sha1_buffer(buffer, size, hash);
1177 existing_lte = __lookup_resource(lookup_table, hash);
1179 wimlib_assert(wim_resource_size(existing_lte) == size);
1184 lte = new_lookup_table_entry();
1187 buffer_copy = memdup(buffer, size);
1189 free_lookup_table_entry(lte);
1192 lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
1193 lte->attached_buffer = buffer_copy;
1194 lte->resource_entry.original_size = size;
1195 copy_hash(lte->hash, hash);
1196 lookup_table_insert(lookup_table, lte);
1202 inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
1203 const void *value, size_t size,
1204 struct wim_lookup_table *lookup_table)
1206 struct wim_ads_entry *new_ads_entry;
1208 wimlib_assert(inode->i_resolved);
1210 new_ads_entry = inode_add_ads(inode, name);
1212 return WIMLIB_ERR_NOMEM;
1214 new_ads_entry->lte = add_stream_from_data_buffer(value, size,
1216 if (!new_ads_entry->lte) {
1217 inode_remove_ads(inode, new_ads_entry - inode->i_ads_entries,
1219 return WIMLIB_ERR_NOMEM;
1224 /* Set the unnamed stream of a WIM inode, given a data buffer containing the
1225 * stream contents. */
1227 inode_set_unnamed_stream(struct wim_inode *inode, const void *data, size_t len,
1228 struct wim_lookup_table *lookup_table)
1230 inode->i_lte = add_stream_from_data_buffer(data, len, lookup_table);
1232 return WIMLIB_ERR_NOMEM;
1233 inode->i_resolved = 1;
1237 /* Remove an alternate data stream from a WIM inode */
1239 inode_remove_ads(struct wim_inode *inode, u16 idx,
1240 struct wim_lookup_table *lookup_table)
1242 struct wim_ads_entry *ads_entry;
1243 struct wim_lookup_table_entry *lte;
1245 wimlib_assert(idx < inode->i_num_ads);
1246 wimlib_assert(inode->i_resolved);
1248 ads_entry = &inode->i_ads_entries[idx];
1250 DEBUG("Remove alternate data stream \"%"WS"\"", ads_entry->stream_name);
1252 lte = ads_entry->lte;
1254 lte_decrement_refcnt(lte, lookup_table);
1256 destroy_ads_entry(ads_entry);
1258 memmove(&inode->i_ads_entries[idx],
1259 &inode->i_ads_entries[idx + 1],
1260 (inode->i_num_ads - idx - 1) * sizeof(inode->i_ads_entries[0]));
1266 inode_get_unix_data(const struct wim_inode *inode,
1267 struct wimlib_unix_data *unix_data,
1268 u16 *stream_idx_ret)
1270 const struct wim_ads_entry *ads_entry;
1271 const struct wim_lookup_table_entry *lte;
1275 wimlib_assert(inode->i_resolved);
1277 ads_entry = inode_get_ads_entry((struct wim_inode*)inode,
1278 WIMLIB_UNIX_DATA_TAG, NULL);
1280 return NO_UNIX_DATA;
1283 *stream_idx_ret = ads_entry - inode->i_ads_entries;
1285 lte = ads_entry->lte;
1287 return NO_UNIX_DATA;
1289 size = wim_resource_size(lte);
1290 if (size != sizeof(struct wimlib_unix_data))
1291 return BAD_UNIX_DATA;
1293 ret = read_full_resource_into_buf(lte, unix_data);
1297 if (unix_data->version != 0)
1298 return BAD_UNIX_DATA;
1303 inode_set_unix_data(struct wim_inode *inode, uid_t uid, gid_t gid, mode_t mode,
1304 struct wim_lookup_table *lookup_table, int which)
1306 struct wimlib_unix_data unix_data;
1308 bool have_good_unix_data = false;
1309 bool have_unix_data = false;
1312 if (!(which & UNIX_DATA_CREATE)) {
1313 ret = inode_get_unix_data(inode, &unix_data, &stream_idx);
1314 if (ret == 0 || ret == BAD_UNIX_DATA || ret > 0)
1315 have_unix_data = true;
1317 have_good_unix_data = true;
1319 unix_data.version = 0;
1320 if (which & UNIX_DATA_UID || !have_good_unix_data)
1321 unix_data.uid = uid;
1322 if (which & UNIX_DATA_GID || !have_good_unix_data)
1323 unix_data.gid = gid;
1324 if (which & UNIX_DATA_MODE || !have_good_unix_data)
1325 unix_data.mode = mode;
1326 ret = inode_add_ads_with_data(inode, WIMLIB_UNIX_DATA_TAG,
1328 sizeof(struct wimlib_unix_data),
1330 if (ret == 0 && have_unix_data)
1331 inode_remove_ads(inode, stream_idx, lookup_table);
1334 #endif /* !__WIN32__ */
1336 /* Replace weird characters in filenames and alternate data stream names.
1338 * In particular we do not want the path separator to appear in any names, as
1339 * that would make it possible for a "malicious" WIM to extract itself to any
1340 * location it wanted to. */
1342 replace_forbidden_characters(utf16lechar *name)
1346 for (p = name; *p; p++) {
1348 if (wcschr(L"<>:\"/\\|?*", (wchar_t)*p))
1350 if (*p == cpu_to_le16('/'))
1354 WARNING("File, directory, or stream name \"%"WS"\"\n"
1355 " contains forbidden characters; "
1356 "substituting replacement characters.",
1361 *p = cpu_to_le16(0xfffd);
1363 *p = cpu_to_le16('?');
1370 * Reads the alternate data stream entries of a WIM dentry.
1372 * @p: Pointer to buffer that starts with the first alternate stream entry.
1374 * @inode: Inode to load the alternate data streams into.
1375 * @inode->i_num_ads must have been set to the number of
1376 * alternate data streams that are expected.
1378 * @remaining_size: Number of bytes of data remaining in the buffer pointed
1382 * Return 0 on success or nonzero on failure. On success, inode->i_ads_entries
1383 * is set to an array of `struct wim_ads_entry's of length inode->i_num_ads. On
1384 * failure, @inode is not modified.
1387 read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
1388 size_t nbytes_remaining)
1391 struct wim_ads_entry *ads_entries;
1394 BUILD_BUG_ON(sizeof(struct wim_ads_entry_on_disk) != WIM_ADS_ENTRY_DISK_SIZE);
1396 /* Allocate an array for our in-memory representation of the alternate
1397 * data stream entries. */
1398 num_ads = inode->i_num_ads;
1399 ads_entries = CALLOC(num_ads, sizeof(inode->i_ads_entries[0]));
1403 /* Read the entries into our newly allocated buffer. */
1404 for (u16 i = 0; i < num_ads; i++) {
1406 struct wim_ads_entry *cur_entry;
1407 const struct wim_ads_entry_on_disk *disk_entry =
1408 (const struct wim_ads_entry_on_disk*)p;
1410 cur_entry = &ads_entries[i];
1411 ads_entries[i].stream_id = i + 1;
1413 /* Do we have at least the size of the fixed-length data we know
1415 if (nbytes_remaining < sizeof(struct wim_ads_entry_on_disk))
1418 /* Read the length field */
1419 length = le64_to_cpu(disk_entry->length);
1421 /* Make sure the length field is neither so small it doesn't
1422 * include all the fixed-length data nor so large it overflows
1423 * the metadata resource buffer. */
1424 if (length < sizeof(struct wim_ads_entry_on_disk) ||
1425 length > nbytes_remaining)
1428 /* Read the rest of the fixed-length data. */
1430 cur_entry->reserved = le64_to_cpu(disk_entry->reserved);
1431 copy_hash(cur_entry->hash, disk_entry->hash);
1432 cur_entry->stream_name_nbytes = le16_to_cpu(disk_entry->stream_name_nbytes);
1434 /* If stream_name_nbytes != 0, this is a named stream.
1435 * Otherwise this is an unnamed stream, or in some cases (bugs
1436 * in Microsoft's software I guess) a meaningless entry
1437 * distinguished from the real unnamed stream entry, if any, by
1438 * the fact that the real unnamed stream entry has a nonzero
1440 if (cur_entry->stream_name_nbytes) {
1441 /* The name is encoded in UTF16-LE, which uses 2-byte
1442 * coding units, so the length of the name had better be
1443 * an even number of bytes... */
1444 if (cur_entry->stream_name_nbytes & 1)
1447 /* Add the length of the stream name to get the length
1448 * we actually need to read. Make sure this isn't more
1449 * than the specified length of the entry. */
1450 if (sizeof(struct wim_ads_entry_on_disk) +
1451 cur_entry->stream_name_nbytes > length)
1454 cur_entry->stream_name = MALLOC(cur_entry->stream_name_nbytes + 2);
1455 if (!cur_entry->stream_name)
1458 memcpy(cur_entry->stream_name,
1459 disk_entry->stream_name,
1460 cur_entry->stream_name_nbytes);
1461 cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = cpu_to_le16(0);
1462 replace_forbidden_characters(cur_entry->stream_name);
1465 /* It's expected that the size of every ADS entry is a multiple
1466 * of 8. However, to be safe, I'm allowing the possibility of
1467 * an ADS entry at the very end of the metadata resource ending
1468 * un-aligned. So although we still need to increment the input
1469 * pointer by @length to reach the next ADS entry, it's possible
1470 * that less than @length is actually remaining in the metadata
1471 * resource. We should set the remaining bytes to 0 if this
1473 length = (length + 7) & ~(u64)7;
1475 if (nbytes_remaining < length)
1476 nbytes_remaining = 0;
1478 nbytes_remaining -= length;
1480 inode->i_ads_entries = ads_entries;
1481 inode->i_next_stream_id = inode->i_num_ads + 1;
1485 ret = WIMLIB_ERR_NOMEM;
1486 goto out_free_ads_entries;
1488 ERROR("An alternate data stream entry is invalid");
1489 ret = WIMLIB_ERR_INVALID_DENTRY;
1490 out_free_ads_entries:
1492 for (u16 i = 0; i < num_ads; i++)
1493 destroy_ads_entry(&ads_entries[i]);
1501 * Reads a WIM directory entry, including all alternate data stream entries that
1502 * follow it, from the WIM image's metadata resource.
1504 * @metadata_resource:
1505 * Pointer to the metadata resource buffer.
1507 * @metadata_resource_len:
1508 * Length of the metadata resource buffer, in bytes.
1510 * @offset: Offset of the dentry within the metadata resource.
1512 * @dentry: A `struct wim_dentry' that will be filled in by this function.
1514 * Return 0 on success or nonzero on failure. On failure, @dentry will have
1515 * been modified, but it will not be left with pointers to any allocated
1516 * buffers. On success, the dentry->length field must be examined. If zero,
1517 * this was a special "end of directory" dentry and not a real dentry. If
1518 * nonzero, this was a real dentry.
1520 * Possible errors include:
1522 * WIMLIB_ERR_INVALID_DENTRY
1525 read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len,
1526 u64 offset, struct wim_dentry * restrict dentry)
1529 u64 calculated_size;
1530 utf16lechar *file_name;
1531 utf16lechar *short_name;
1532 u16 short_name_nbytes;
1533 u16 file_name_nbytes;
1535 struct wim_inode *inode;
1536 const u8 *p = &metadata_resource[offset];
1537 const struct wim_dentry_on_disk *disk_dentry =
1538 (const struct wim_dentry_on_disk*)p;
1540 BUILD_BUG_ON(sizeof(struct wim_dentry_on_disk) != WIM_DENTRY_DISK_SIZE);
1542 if ((uintptr_t)p & 7)
1543 WARNING("WIM dentry is not 8-byte aligned");
1545 dentry_common_init(dentry);
1547 /* Before reading the whole dentry, we need to read just the length.
1548 * This is because a dentry of length 8 (that is, just the length field)
1549 * terminates the list of sibling directory entries. */
1550 if (offset + sizeof(u64) > metadata_resource_len ||
1551 offset + sizeof(u64) < offset)
1553 ERROR("Directory entry starting at %"PRIu64" ends past the "
1554 "end of the metadata resource (size %"PRIu64")",
1555 offset, metadata_resource_len);
1556 return WIMLIB_ERR_INVALID_DENTRY;
1558 dentry->length = le64_to_cpu(disk_dentry->length);
1560 /* A zero length field (really a length of 8, since that's how big the
1561 * directory entry is...) indicates that this is the end of directory
1562 * dentry. We do not read it into memory as an actual dentry, so just
1563 * return successfully in this case. */
1564 if (dentry->length == 8)
1566 if (dentry->length == 0)
1569 /* Now that we have the actual length provided in the on-disk structure,
1570 * again make sure it doesn't overflow the metadata resource buffer. */
1571 if (offset + dentry->length > metadata_resource_len ||
1572 offset + dentry->length < offset)
1574 ERROR("Directory entry at offset %"PRIu64" and with size "
1575 "%"PRIu64" ends past the end of the metadata resource "
1577 offset, dentry->length, metadata_resource_len);
1578 return WIMLIB_ERR_INVALID_DENTRY;
1581 /* Make sure the dentry length is at least as large as the number of
1582 * fixed-length fields */
1583 if (dentry->length < sizeof(struct wim_dentry_on_disk)) {
1584 ERROR("Directory entry has invalid length of %"PRIu64" bytes",
1586 return WIMLIB_ERR_INVALID_DENTRY;
1589 /* Allocate a `struct wim_inode' for this `struct wim_dentry'. */
1590 inode = new_timeless_inode();
1592 return WIMLIB_ERR_NOMEM;
1594 /* Read more fields; some into the dentry, and some into the inode. */
1596 inode->i_attributes = le32_to_cpu(disk_dentry->attributes);
1597 inode->i_security_id = le32_to_cpu(disk_dentry->security_id);
1598 dentry->subdir_offset = le64_to_cpu(disk_dentry->subdir_offset);
1599 dentry->d_unused_1 = le64_to_cpu(disk_dentry->unused_1);
1600 dentry->d_unused_2 = le64_to_cpu(disk_dentry->unused_2);
1601 inode->i_creation_time = le64_to_cpu(disk_dentry->creation_time);
1602 inode->i_last_access_time = le64_to_cpu(disk_dentry->last_access_time);
1603 inode->i_last_write_time = le64_to_cpu(disk_dentry->last_write_time);
1604 copy_hash(inode->i_hash, disk_dentry->unnamed_stream_hash);
1606 /* I don't know what's going on here. It seems like M$ screwed up the
1607 * reparse points, then put the fields in the same place and didn't
1608 * document it. So we have some fields we read for reparse points, and
1609 * some fields in the same place for non-reparse-point.s */
1610 if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1611 inode->i_rp_unknown_1 = le32_to_cpu(disk_dentry->reparse.rp_unknown_1);
1612 inode->i_reparse_tag = le32_to_cpu(disk_dentry->reparse.reparse_tag);
1613 inode->i_rp_unknown_2 = le16_to_cpu(disk_dentry->reparse.rp_unknown_2);
1614 inode->i_not_rpfixed = le16_to_cpu(disk_dentry->reparse.not_rpfixed);
1615 /* Leave inode->i_ino at 0. Note that this means the WIM file
1616 * cannot archive hard-linked reparse points. Such a thing
1617 * doesn't really make sense anyway, although I believe it's
1618 * theoretically possible to have them on NTFS. */
1620 inode->i_rp_unknown_1 = le32_to_cpu(disk_dentry->nonreparse.rp_unknown_1);
1621 inode->i_ino = le64_to_cpu(disk_dentry->nonreparse.hard_link_group_id);
1624 inode->i_num_ads = le16_to_cpu(disk_dentry->num_alternate_data_streams);
1626 short_name_nbytes = le16_to_cpu(disk_dentry->short_name_nbytes);
1627 file_name_nbytes = le16_to_cpu(disk_dentry->file_name_nbytes);
1629 if ((short_name_nbytes & 1) | (file_name_nbytes & 1))
1631 ERROR("Dentry name is not valid UTF-16LE (odd number of bytes)!");
1632 ret = WIMLIB_ERR_INVALID_DENTRY;
1633 goto out_free_inode;
1636 /* We now know the length of the file name and short name. Make sure
1637 * the length of the dentry is large enough to actually hold them.
1639 * The calculated length here is unaligned to allow for the possibility
1640 * that the dentry->length names an unaligned length, although this
1641 * would be unexpected. */
1642 calculated_size = _dentry_correct_length_unaligned(file_name_nbytes,
1645 if (dentry->length < calculated_size) {
1646 ERROR("Unexpected end of directory entry! (Expected "
1647 "at least %"PRIu64" bytes, got %"PRIu64" bytes.)",
1648 calculated_size, dentry->length);
1649 ret = WIMLIB_ERR_INVALID_DENTRY;
1650 goto out_free_inode;
1653 p += sizeof(struct wim_dentry_on_disk);
1655 /* Read the filename if present. Note: if the filename is empty, there
1656 * is no null terminator following it. */
1657 if (file_name_nbytes) {
1658 file_name = MALLOC(file_name_nbytes + 2);
1660 ERROR("Failed to allocate %d bytes for dentry file name",
1661 file_name_nbytes + 2);
1662 ret = WIMLIB_ERR_NOMEM;
1663 goto out_free_inode;
1665 memcpy(file_name, p, file_name_nbytes);
1666 p += file_name_nbytes + 2;
1667 file_name[file_name_nbytes / 2] = cpu_to_le16(0);
1668 replace_forbidden_characters(file_name);
1674 /* Read the short filename if present. Note: if there is no short
1675 * filename, there is no null terminator following it. */
1676 if (short_name_nbytes) {
1677 short_name = MALLOC(short_name_nbytes + 2);
1679 ERROR("Failed to allocate %d bytes for dentry short name",
1680 short_name_nbytes + 2);
1681 ret = WIMLIB_ERR_NOMEM;
1682 goto out_free_file_name;
1684 memcpy(short_name, p, short_name_nbytes);
1685 p += short_name_nbytes + 2;
1686 short_name[short_name_nbytes / 2] = cpu_to_le16(0);
1687 replace_forbidden_characters(short_name);
1692 /* Align the dentry length */
1693 dentry->length = (dentry->length + 7) & ~7;
1696 * Read the alternate data streams, if present. dentry->num_ads tells
1697 * us how many they are, and they will directly follow the dentry
1700 * Note that each alternate data stream entry begins on an 8-byte
1701 * aligned boundary, and the alternate data stream entries seem to NOT
1702 * be included in the dentry->length field for some reason.
1704 if (inode->i_num_ads != 0) {
1705 ret = WIMLIB_ERR_INVALID_DENTRY;
1706 if (offset + dentry->length > metadata_resource_len ||
1707 (ret = read_ads_entries(&metadata_resource[offset + dentry->length],
1709 metadata_resource_len - offset - dentry->length)))
1711 ERROR("Failed to read alternate data stream "
1712 "entries of WIM dentry \"%"WS"\"", file_name);
1713 goto out_free_short_name;
1716 /* We've read all the data for this dentry. Set the names and their
1717 * lengths, and we've done. */
1718 dentry->d_inode = inode;
1719 dentry->file_name = file_name;
1720 dentry->short_name = short_name;
1721 dentry->file_name_nbytes = file_name_nbytes;
1722 dentry->short_name_nbytes = short_name_nbytes;
1725 out_free_short_name:
1735 /* Reads the children of a dentry, and all their children, ..., etc. from the
1736 * metadata resource and into the dentry tree.
1738 * @metadata_resource: An array that contains the uncompressed metadata
1739 * resource for the WIM file.
1741 * @metadata_resource_len: The length of the uncompressed metadata resource, in
1744 * @dentry: A pointer to a `struct wim_dentry' that is the root of the directory
1745 * tree and has already been read from the metadata resource. It
1746 * does not need to be the real root because this procedure is
1747 * called recursively.
1749 * Returns zero on success; nonzero on failure.
1752 read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
1753 struct wim_dentry *dentry)
1755 u64 cur_offset = dentry->subdir_offset;
1756 struct wim_dentry *child;
1757 struct wim_dentry cur_child;
1761 * If @dentry has no child dentries, nothing more needs to be done for
1762 * this branch. This is the case for regular files, symbolic links, and
1763 * *possibly* empty directories (although an empty directory may also
1764 * have one child dentry that is the special end-of-directory dentry)
1766 if (cur_offset == 0)
1769 /* Find and read all the children of @dentry. */
1772 /* Read next child of @dentry into @cur_child. */
1773 ret = read_dentry(metadata_resource, metadata_resource_len,
1774 cur_offset, &cur_child);
1778 /* Check for end of directory. */
1779 if (cur_child.length == 0)
1782 /* Not end of directory. Allocate this child permanently and
1783 * link it to the parent and previous child. */
1784 child = memdup(&cur_child, sizeof(struct wim_dentry));
1786 ERROR("Failed to allocate new dentry!");
1787 ret = WIMLIB_ERR_NOMEM;
1791 /* Advance to the offset of the next child. Note: We need to
1792 * advance by the TOTAL length of the dentry, not by the length
1793 * cur_child.length, which although it does take into account
1794 * the padding, it DOES NOT take into account alternate stream
1796 cur_offset += dentry_total_length(child);
1798 if (dentry_add_child(dentry, child)) {
1799 WARNING("Ignoring duplicate dentry \"%"WS"\"",
1801 WARNING("(In directory \"%"TS"\")", dentry_full_path(dentry));
1804 inode_add_dentry(child, child->d_inode);
1805 /* If there are children of this child, call this
1806 * procedure recursively. */
1807 if (child->subdir_offset != 0) {
1808 if (dentry_is_directory(child)) {
1809 ret = read_dentry_tree(metadata_resource,
1810 metadata_resource_len,
1815 WARNING("Ignoring children of non-directory \"%"TS"\"",
1816 dentry_full_path(child));
1826 * Writes a WIM dentry to an output buffer.
1828 * @dentry: The dentry structure.
1829 * @p: The memory location to write the data to.
1831 * Returns the pointer to the byte after the last byte we wrote as part of the
1832 * dentry, including any alternate data stream entries.
1835 write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
1837 const struct wim_inode *inode;
1838 struct wim_dentry_on_disk *disk_dentry;
1842 wimlib_assert(((uintptr_t)p & 7) == 0); /* 8 byte aligned */
1845 inode = dentry->d_inode;
1846 disk_dentry = (struct wim_dentry_on_disk*)p;
1848 disk_dentry->attributes = cpu_to_le32(inode->i_attributes);
1849 disk_dentry->security_id = cpu_to_le32(inode->i_security_id);
1850 disk_dentry->subdir_offset = cpu_to_le64(dentry->subdir_offset);
1851 disk_dentry->unused_1 = cpu_to_le64(dentry->d_unused_1);
1852 disk_dentry->unused_2 = cpu_to_le64(dentry->d_unused_2);
1853 disk_dentry->creation_time = cpu_to_le64(inode->i_creation_time);
1854 disk_dentry->last_access_time = cpu_to_le64(inode->i_last_access_time);
1855 disk_dentry->last_write_time = cpu_to_le64(inode->i_last_write_time);
1856 hash = inode_stream_hash(inode, 0);
1857 copy_hash(disk_dentry->unnamed_stream_hash, hash);
1858 if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1859 disk_dentry->reparse.rp_unknown_1 = cpu_to_le32(inode->i_rp_unknown_1);
1860 disk_dentry->reparse.reparse_tag = cpu_to_le32(inode->i_reparse_tag);
1861 disk_dentry->reparse.rp_unknown_2 = cpu_to_le16(inode->i_rp_unknown_2);
1862 disk_dentry->reparse.not_rpfixed = cpu_to_le16(inode->i_not_rpfixed);
1864 disk_dentry->nonreparse.rp_unknown_1 = cpu_to_le32(inode->i_rp_unknown_1);
1865 disk_dentry->nonreparse.hard_link_group_id =
1866 cpu_to_le64((inode->i_nlink == 1) ? 0 : inode->i_ino);
1868 disk_dentry->num_alternate_data_streams = cpu_to_le16(inode->i_num_ads);
1869 disk_dentry->short_name_nbytes = cpu_to_le16(dentry->short_name_nbytes);
1870 disk_dentry->file_name_nbytes = cpu_to_le16(dentry->file_name_nbytes);
1871 p += sizeof(struct wim_dentry_on_disk);
1873 if (dentry_has_long_name(dentry))
1874 p = mempcpy(p, dentry->file_name, dentry->file_name_nbytes + 2);
1876 if (dentry_has_short_name(dentry))
1877 p = mempcpy(p, dentry->short_name, dentry->short_name_nbytes + 2);
1879 /* Align to 8-byte boundary */
1880 while ((uintptr_t)p & 7)
1883 /* We calculate the correct length of the dentry ourselves because the
1884 * dentry->length field may been set to an unexpected value from when we
1885 * read the dentry in (for example, there may have been unknown data
1886 * appended to the end of the dentry...). Furthermore, the dentry may
1887 * have been renamed, thus changing its needed length. */
1888 disk_dentry->length = cpu_to_le64(p - orig_p);
1890 /* Write the alternate data streams entries, if any. */
1891 for (u16 i = 0; i < inode->i_num_ads; i++) {
1892 const struct wim_ads_entry *ads_entry =
1893 &inode->i_ads_entries[i];
1894 struct wim_ads_entry_on_disk *disk_ads_entry =
1895 (struct wim_ads_entry_on_disk*)p;
1898 disk_ads_entry->reserved = cpu_to_le64(ads_entry->reserved);
1900 hash = inode_stream_hash(inode, i + 1);
1901 copy_hash(disk_ads_entry->hash, hash);
1902 disk_ads_entry->stream_name_nbytes = cpu_to_le16(ads_entry->stream_name_nbytes);
1903 p += sizeof(struct wim_ads_entry_on_disk);
1904 if (ads_entry->stream_name_nbytes) {
1905 p = mempcpy(p, ads_entry->stream_name,
1906 ads_entry->stream_name_nbytes + 2);
1908 /* Align to 8-byte boundary */
1909 while ((uintptr_t)p & 7)
1911 disk_ads_entry->length = cpu_to_le64(p - orig_p);
1917 write_dentry_cb(struct wim_dentry *dentry, void *_p)
1920 *p = write_dentry(dentry, *p);
1925 write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p);
1928 write_dentry_tree_recursive_cb(struct wim_dentry *dentry, void *_p)
1931 *p = write_dentry_tree_recursive(dentry, *p);
1935 /* Recursive function that writes a dentry tree rooted at @parent, not including
1936 * @parent itself, which has already been written. */
1938 write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p)
1940 /* Nothing to do if this dentry has no children. */
1941 if (parent->subdir_offset == 0)
1944 /* Write child dentries and end-of-directory entry.
1946 * Note: we need to write all of this dentry's children before
1947 * recursively writing the directory trees rooted at each of the child
1948 * dentries, since the on-disk dentries for a dentry's children are
1949 * always located at consecutive positions in the metadata resource! */
1950 for_dentry_child(parent, write_dentry_cb, &p);
1952 /* write end of directory entry */
1953 *(le64*)p = cpu_to_le64(0);
1956 /* Recurse on children. */
1957 for_dentry_child(parent, write_dentry_tree_recursive_cb, &p);
1961 /* Writes a directory tree to the metadata resource.
1963 * @root: Root of the dentry tree.
1964 * @p: Pointer to a buffer with enough space for the dentry tree.
1966 * Returns pointer to the byte after the last byte we wrote.
1969 write_dentry_tree(const struct wim_dentry *root, u8 *p)
1971 DEBUG("Writing dentry tree.");
1972 wimlib_assert(dentry_is_root(root));
1974 /* If we're the root dentry, we have no parent that already
1975 * wrote us, so we need to write ourselves. */
1976 p = write_dentry(root, p);
1978 /* Write end of directory entry after the root dentry just to be safe;
1979 * however the root dentry obviously cannot have any siblings. */
1980 *(le64*)p = cpu_to_le64(0);
1983 /* Recursively write the rest of the dentry tree. */
1984 return write_dentry_tree_recursive(root, p);