]> wimlib.net Git - wimlib/blob - src/dentry.c
Initial commit (current version is wimlib 0.6.2)
[wimlib] / src / dentry.c
1 /*
2  * dentry.c
3  *
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
9  * entries.
10  *
11  * Copyright (C) 2010 Carl Thijssen
12  * Copyright (C) 2012 Eric Biggers
13  *
14  * wimlib - Library for working with WIM files 
15  *
16  * This library is free software; you can redistribute it and/or modify it under
17  * the terms of the GNU Lesser General Public License as published by the Free
18  * Software Foundation; either version 2.1 of the License, or (at your option) any
19  * later version.
20  *
21  * This library 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 A
23  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public License along
26  * with this library; if not, write to the Free Software Foundation, Inc., 59
27  * Temple Place, Suite 330, Boston, MA 02111-1307 USA 
28  */
29
30 #include "wimlib_internal.h"
31 #include "dentry.h"
32 #include "io.h"
33 #include "timestamp.h"
34 #include "lookup_table.h"
35 #include <unistd.h>
36 #include <sys/stat.h>
37
38
39 /* Transfers file attributes from a `stat' buffer to a struct dentry. */
40 void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry)
41 {
42         if (S_ISDIR(stbuf->st_mode))
43                 dentry->attributes = WIM_FILE_ATTRIBUTE_DIRECTORY;
44         else
45                 dentry->attributes = WIM_FILE_ATTRIBUTE_NORMAL;
46 }
47
48 /* Transfers file attributes from a struct dentry to a `stat' buffer. */
49 void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf, 
50                      const struct lookup_table *table)
51 {
52         struct lookup_table_entry *lte;
53
54         if (dentry_is_directory(dentry))
55                 stbuf->st_mode = S_IFDIR | 0755;
56         else
57                 stbuf->st_mode = S_IFREG | 0644;
58
59         if (table)
60                 lte = lookup_resource(table, dentry->hash);
61         else
62                 lte = NULL;
63
64         if (lte) {
65                 stbuf->st_nlink = lte->refcnt;
66                 stbuf->st_size = lte->resource_entry.original_size;
67         } else {
68                 stbuf->st_nlink = 1;
69                 stbuf->st_size = 0;
70         }
71         stbuf->st_uid     = getuid();
72         stbuf->st_gid     = getgid();
73         stbuf->st_atime   = ms_timestamp_to_unix(dentry->last_access_time);
74         stbuf->st_mtime   = ms_timestamp_to_unix(dentry->last_write_time);
75         stbuf->st_ctime   = ms_timestamp_to_unix(dentry->creation_time);
76         stbuf->st_blocks  = (stbuf->st_size + 511) / 512;
77 }
78
79 /* Makes all timestamp fields for the dentry be the current time. */
80 void dentry_update_all_timestamps(struct dentry *dentry)
81 {
82         u64 now = get_timestamp();
83         dentry->creation_time       = now;
84         dentry->last_access_time    = now;
85         dentry->last_write_time     = now;
86 }
87
88 /* 
89  * Calls a function on all directory entries in a directory tree.  It is called
90  * on a parent before its children.
91  */
92 int for_dentry_in_tree(struct dentry *root, 
93                        int (*visitor)(struct dentry*, void*), void *arg)
94 {
95         int ret;
96         struct dentry *child;
97
98         ret = visitor(root, arg);
99
100         if (ret != 0)
101                 return ret;
102
103         child = root->children;
104
105         if (!child)
106                 return 0;
107
108         do {
109                 ret = for_dentry_in_tree(child, visitor, arg);
110                 if (ret != 0)
111                         return ret;
112                 child = child->next;
113         } while (child != root->children);
114         return 0;
115 }
116
117 /* 
118  * Like for_dentry_in_tree(), but the visitor function is always called on a
119  * dentry's children before on itself.
120  */
121 int for_dentry_in_tree_depth(struct dentry *root, 
122                              int (*visitor)(struct dentry*, void*), void *arg)
123 {
124         int ret;
125         struct dentry *child;
126         struct dentry *next;
127
128         child = root->children;
129         if (child) {
130                 do {
131                         next = child->next;
132                         ret = for_dentry_in_tree_depth(child, visitor, arg);
133                         if (ret != 0)
134                                 return ret;
135                         child = next;
136                 } while (child != root->children);
137         }
138         return visitor(root, arg);
139 }
140
141 /* 
142  * Calculate the full path of @dentry, based on its parent's full path and on
143  * its UTF-8 file name. 
144  */
145 int calculate_dentry_full_path(struct dentry *dentry, void *ignore)
146 {
147         int parent_len;
148         int len;
149         char *parent_full_path;
150         char *full_path;
151
152         FREE(dentry->full_path_utf8);
153
154         if (dentry_is_root(dentry)) {
155                 dentry->full_path_utf8 = MALLOC(2);
156                 if (!dentry->full_path_utf8) {
157                         ERROR("Out of memory!\n");
158                         return WIMLIB_ERR_NOMEM;
159                 }
160
161                 dentry->full_path_utf8[0] = '/';
162                 dentry->full_path_utf8[1] = '\0';
163                 dentry->full_path_utf8_len = 1;
164                 return 0;
165         }
166
167         if (dentry_is_root(dentry->parent)) {
168                 parent_len = 0;
169                 parent_full_path = "";
170         } else {
171                 parent_len = dentry->parent->full_path_utf8_len;
172                 parent_full_path = dentry->parent->full_path_utf8;
173         }
174
175         len = parent_len + 1 + dentry->file_name_utf8_len;
176         full_path = MALLOC(len + 1);
177         if (!full_path) {
178                 ERROR("Out of memory!\n");
179                 return WIMLIB_ERR_NOMEM;
180         }
181
182         memcpy(full_path, parent_full_path, parent_len);
183         full_path[parent_len] = '/';
184         memcpy(full_path + parent_len + 1, dentry->file_name_utf8, 
185                                 dentry->file_name_utf8_len);
186         full_path[len] = '\0';
187         dentry->full_path_utf8 = full_path;
188         dentry->full_path_utf8_len = len;
189         return 0;
190 }
191
192 /* 
193  * Recursively calculates the subdir offsets for a directory tree. 
194  *
195  * @dentry:  The root of the directory tree.
196  * @subdir_offset_p:  The current subdirectory offset; i.e., the subdirectory
197  *      offset for @dentry. 
198  */
199 void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p)
200 {
201         struct dentry *child;
202
203         child = dentry->children;
204         dentry->subdir_offset = *subdir_offset_p;
205         if (child) {
206
207                 /* Advance the subdir offset by the amount of space the children
208                  * of this dentry take up. */
209                 do {
210                         *subdir_offset_p += child->length;
211                         child = child->next;
212                 } while (child != dentry->children);
213
214                 /* End-of-directory dentry on disk. */
215                 *subdir_offset_p += 8;
216
217                 /* Recursively call calculate_subdir_offsets() on all the
218                  * children. */
219                 do {
220                         calculate_subdir_offsets(child, subdir_offset_p);
221                         child = child->next;
222                 } while (child != dentry->children);
223         } else {
224                 /* On disk, childless directories have a valid subdir_offset
225                  * that points to an 8-byte end-of-directory dentry.  Regular
226                  * files have a subdir_offset of 0. */
227                 if (dentry_is_directory(dentry))
228                         *subdir_offset_p += 8;
229                 else
230                         dentry->subdir_offset = 0;
231         }
232 }
233
234
235 /* Returns the child of @dentry that has the file name @name.  
236  * Returns NULL if no child has the name. */
237 struct dentry *get_dentry_child_with_name(const struct dentry *dentry, 
238                                                         const char *name)
239 {
240         struct dentry *child;
241         size_t name_len;
242         
243         child = dentry->children;
244         if (child) {
245                 name_len = strlen(name);
246                 do {
247                         if (dentry_has_name(child, name, name_len))
248                                 return child;
249                         child = child->next;
250                 } while (child != dentry->children);
251         }
252         return NULL;
253 }
254
255 /* Retrieves the dentry that has the UTF-8 @path relative to the dentry
256  * @cur_dir.  Returns NULL if no dentry having the path is found. */
257 static struct dentry *get_dentry_relative_path(struct dentry *cur_dir, const char *path)
258 {
259         struct dentry *child;
260         size_t base_len;
261         const char *new_path;
262
263         if (*path == '\0')
264                 return cur_dir;
265
266         child = cur_dir->children;
267         if (child) {
268                 new_path = path_next_part(path, &base_len);
269                 do {
270                         if (dentry_has_name(child, path, base_len))
271                                 return get_dentry_relative_path(child, new_path);
272                         child = child->next;
273                 } while (child != cur_dir->children);
274         }
275         return NULL;
276 }
277
278 /* Returns the dentry corresponding to the UTF-8 @path, or NULL if there is no
279  * such dentry. */
280 struct dentry *get_dentry(WIMStruct *w, const char *path)
281 {
282         struct dentry *root = wim_root_dentry(w);
283         while (*path == '/')
284                 path++;
285         return get_dentry_relative_path(root, path);
286 }
287
288 /* Returns the parent directory for the @path. */
289 struct dentry *get_parent_dentry(WIMStruct *w, const char *path)
290 {
291         size_t path_len = strlen(path);
292         char buf[path_len + 1];
293
294         memcpy(buf, path, path_len + 1);
295
296         to_parent_name(buf, path_len);
297
298         return get_dentry(w, buf);
299 }
300
301 /* Prints the full path of a dentry. */
302 int print_dentry_full_path(struct dentry *dentry, void *ignore)
303 {
304         if (dentry->full_path_utf8)
305                 puts(dentry->full_path_utf8);
306         return 0;
307 }
308
309 /* Prints a directory entry.  @lookup_table is a pointer to the lookup table, or
310  * NULL if the resource entry for the dentry is not to be printed. */
311 int print_dentry(struct dentry *dentry, void *lookup_table)
312 {
313         struct lookup_table_entry *lte;
314
315         printf("Length            = %"PRIu64"\n", dentry->length);
316         printf("Attributes        = 0x%x\n", dentry->attributes);
317         /*printf("Security ID       = %d\n", dentry->security_id);*/
318         printf("Subdir offset     = %"PRIu64"\n", dentry->subdir_offset);
319         /*printf("Unused1           = %"PRIu64"\n", dentry->unused1);*/
320         /*printf("Unused2           = %"PRIu64"\n", dentry->unused2);*/
321         printf("Creation Time     = %"PRIu64"\n", dentry->creation_time);
322         printf("Last Access Time  = %"PRIu64"\n", dentry->last_access_time);
323         printf("Last Write Time   = %"PRIu64"\n", dentry->last_write_time);
324         printf("Creation Time     = 0x%"PRIx64"\n", dentry->creation_time);
325         printf("Hash              = "); 
326         print_hash(dentry->hash); 
327         putchar('\n');
328         /*printf("Reparse Tag       = %u\n", dentry->reparse_tag);*/
329         printf("Hard Link Group   = %"PRIu64"\n", dentry->hard_link);
330         /*printf("Number of Streams = %hu\n", dentry->streams);*/
331         printf("Filename          = \"");
332         print_string(dentry->file_name, dentry->file_name_len);
333         puts("\"");
334         printf("Filename Length   = %hu\n", dentry->file_name_len);
335         printf("Filename (UTF-8)  = \"%s\"\n", dentry->file_name_utf8);
336         printf("Filename (UTF-8) Length = %hu\n", dentry->file_name_utf8_len);
337         printf("Short Name        = \"");
338         print_string(dentry->short_name, dentry->short_name_len);
339         puts("\"");
340         printf("Short Name Length = %hu\n", dentry->short_name_len);
341         printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8);
342         if (lookup_table) {
343                 lte = lookup_resource(lookup_table, dentry->hash);
344                 if (lte)
345                         print_lookup_table_entry(lte, NULL);
346                 else
347                         putchar('\n');
348         } else {
349                 putchar('\n');
350         }
351         return 0;
352 }
353
354 static inline void dentry_common_init(struct dentry *dentry)
355 {
356         memset(dentry, 0, sizeof(struct dentry));
357         dentry->refcnt = 1;
358         /* We are currently ignoring the security data. */
359         /*dentry->security_id = -1;*/
360 }
361
362 /* 
363  * Creates an unlinked directory entry.
364  *
365  * @name:    The base name of the new dentry.
366  * @return:  A pointer to the new dentry, or NULL if out of memory.
367  */
368 struct dentry *new_dentry(const char *name)
369 {
370         struct dentry *dentry;
371         
372         dentry = MALLOC(sizeof(struct dentry));
373         if (!dentry)
374                 return NULL;
375
376         dentry_common_init(dentry);
377         if (change_dentry_name(dentry, name) != 0) {
378                 FREE(dentry);
379                 return NULL;
380         }
381
382         dentry_update_all_timestamps(dentry);
383         dentry->next   = dentry;
384         dentry->prev   = dentry;
385         dentry->parent = dentry;
386         return dentry;
387 }
388
389
390 void free_dentry(struct dentry *dentry)
391 {
392         FREE(dentry->file_name);
393         FREE(dentry->file_name_utf8);
394         FREE(dentry->short_name);
395         FREE(dentry->full_path_utf8);
396         FREE(dentry);
397 }
398
399 /* Arguments for do_free_dentry(). */
400 struct free_dentry_args {
401         struct lookup_table *lookup_table;
402         bool decrement_refcnt;
403 };
404
405 /* 
406  * This function is passed as an argument to for_dentry_in_tree_depth() in order
407  * to free a directory tree.  __args is a pointer to a `struct free_dentry_args'.
408  */
409 static int do_free_dentry(struct dentry *dentry, void *__args)
410 {
411         struct free_dentry_args *args = (struct free_dentry_args*)__args;
412
413         if (args->decrement_refcnt && !dentry_is_directory(dentry)) {
414                 lookup_table_decrement_refcnt(args->lookup_table, 
415                                               dentry->hash);
416         }
417
418         wimlib_assert(dentry->refcnt >= 1);
419         if (--dentry->refcnt == 0)
420                 free_dentry(dentry);
421         return 0;
422 }
423
424 /* 
425  * Unlinks and frees a dentry tree.
426  *
427  * @root:               The root of the tree.
428  * @lookup_table:       The lookup table for dentries.
429  * @decrement_refcnt:   True if the dentries in the tree are to have their 
430  *                      reference counts in the lookup table decremented.
431  */
432 void free_dentry_tree(struct dentry *root, struct lookup_table *lookup_table, 
433                       bool decrement_refcnt)
434 {
435         if (!root || !root->parent)
436                 return;
437
438         struct free_dentry_args args;
439         args.lookup_table        = lookup_table;
440         args.decrement_refcnt    = decrement_refcnt;
441         for_dentry_in_tree_depth(root, do_free_dentry, &args);
442 }
443
444 int increment_dentry_refcnt(struct dentry *dentry, void *ignore)
445 {
446         dentry->refcnt++;
447         return 0;
448 }
449
450 /* 
451  * Links a dentry into the directory tree.
452  *
453  * @dentry: The dentry to link.
454  * @parent: The dentry that will be the parent of @dentry.
455  */
456 void link_dentry(struct dentry *dentry, struct dentry *parent)
457 {
458         dentry->parent = parent;
459         if (parent->children) {
460                 /* Not an only child; link to siblings. */
461                 dentry->next = parent->children;
462                 dentry->prev = parent->children->prev;
463                 dentry->next->prev = dentry;
464                 dentry->prev->next = dentry;
465         } else {
466                 /* Only child; link to parent. */
467                 parent->children = dentry;
468                 dentry->next = dentry;
469                 dentry->prev = dentry;
470         }
471 }
472
473 /* Unlink a dentry from the directory tree. */
474 void unlink_dentry(struct dentry *dentry)
475 {
476         if (dentry_is_root(dentry))
477                 return;
478         if (dentry_is_only_child(dentry)) {
479                 dentry->parent->children = NULL;
480         } else {
481                 if (dentry_is_first_sibling(dentry))
482                         dentry->parent->children = dentry->next;
483                 dentry->next->prev = dentry->prev;
484                 dentry->prev->next = dentry->next;
485         }
486 }
487
488
489 /* Recalculates the length of @dentry based on its file name length and short
490  * name length.  */
491 static inline void recalculate_dentry_size(struct dentry *dentry)
492 {
493         dentry->length = WIM_DENTRY_DISK_SIZE + dentry->file_name_len + 
494                          2 + dentry->short_name_len;
495         /* Must be multiple of 8. */
496         dentry->length += (8 - dentry->length % 8) % 8;
497 }
498
499 /* Changes the name of a dentry to @new_name.  Only changes the file_name and
500  * file_name_utf8 fields; does not change the short_name, short_name_utf8, or
501  * full_path_utf8 fields.  Also recalculates its length. */
502 int change_dentry_name(struct dentry *dentry, const char *new_name)
503 {
504         size_t utf8_len;
505         size_t utf16_len;
506
507         FREE(dentry->file_name);
508
509         utf8_len = strlen(new_name);
510
511         dentry->file_name = utf8_to_utf16(new_name, utf8_len, &utf16_len);
512
513         if (!dentry->file_name)
514                 return WIMLIB_ERR_NOMEM;
515
516         FREE(dentry->file_name_utf8);
517         dentry->file_name_utf8 = MALLOC(utf8_len + 1);
518         if (!dentry->file_name_utf8) {
519                 FREE(dentry->file_name);
520                 dentry->file_name = NULL;
521                 return WIMLIB_ERR_NOMEM;
522         }
523
524         dentry->file_name_len = utf16_len;
525         dentry->file_name_utf8_len = utf8_len;
526         memcpy(dentry->file_name_utf8, new_name, utf8_len + 1);
527         recalculate_dentry_size(dentry);
528         return 0;
529 }
530
531 /* Parameters for calculate_dentry_statistics(). */
532 struct image_statistics {
533         struct lookup_table *lookup_table;
534         u64 *dir_count;
535         u64 *file_count;
536         u64 *total_bytes;
537         u64 *hard_link_bytes;
538 };
539
540 static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
541 {
542         struct image_statistics *stats;
543         struct lookup_table_entry *lte; 
544         
545         stats = arg;
546         lte = lookup_resource(stats->lookup_table, dentry->hash);
547
548         if (dentry_is_directory(dentry) && !dentry_is_root(dentry))
549                 ++*stats->dir_count;
550         else
551                 ++*stats->file_count;
552
553         if (lte) {
554                 u64 size = lte->resource_entry.original_size;
555                 *stats->total_bytes += size;
556                 if (++lte->out_refcnt == 1)
557                         *stats->hard_link_bytes += size;
558         }
559         return 0;
560 }
561
562 void calculate_dir_tree_statistics(struct dentry *root, struct lookup_table *table, 
563                                    u64 *dir_count_ret, u64 *file_count_ret, 
564                                    u64 *total_bytes_ret, 
565                                    u64 *hard_link_bytes_ret)
566 {
567         struct image_statistics stats;
568         *dir_count_ret         = 0;
569         *file_count_ret        = 0;
570         *total_bytes_ret       = 0;
571         *hard_link_bytes_ret   = 0;
572         stats.lookup_table     = table;
573         stats.dir_count       = dir_count_ret;
574         stats.file_count      = file_count_ret;
575         stats.total_bytes     = total_bytes_ret;
576         stats.hard_link_bytes = hard_link_bytes_ret;
577         for_lookup_table_entry(table, zero_out_refcnts, NULL);
578         for_dentry_in_tree(root, calculate_dentry_statistics, &stats);
579 }
580
581 /* 
582  * Reads a directory entry from the metadata resource.
583  */
584 int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, 
585                                         u64 offset, struct dentry *dentry)
586 {
587         const u8 *p;
588         u64 calculated_size;
589         char *file_name;
590         char *file_name_utf8;
591         char *short_name;
592         u16 short_name_len;
593         u16 file_name_len;
594         size_t file_name_utf8_len;
595
596         dentry_common_init(dentry);
597
598         /*Make sure the dentry really fits into the metadata resource.*/
599         if (offset + 8 > metadata_resource_len) {
600                 ERROR("Directory entry starting at %"PRIu64" ends past the "
601                         "end of the metadata resource (size %"PRIu64")!\n",
602                         offset, metadata_resource_len);
603                 return WIMLIB_ERR_INVALID_DENTRY;
604         }
605
606         /* Before reading the whole entry, we need to read just the length.
607          * This is because an entry of length 8 (that is, just the length field)
608          * terminates the list of sibling directory entries. */
609
610         p = get_u64(&metadata_resource[offset], &dentry->length);
611
612         /* A zero length field (really a length of 8, since that's how big the
613          * directory entry is...) indicates that this is the end of directory
614          * dentry.  We do not read it into memory as an actual dentry, so just
615          * return true in that case. */
616         if (dentry->length == 0)
617                 return 0;
618
619         if (offset + dentry->length >= metadata_resource_len) {
620                 ERROR("Directory entry at offset %"PRIu64" and with size "
621                                 "%"PRIu64" ends past the end of the metadata resource "
622                                 "(size %"PRIu64")!\n", offset, dentry->length,
623                                 metadata_resource_len);
624                 return WIMLIB_ERR_INVALID_DENTRY;
625         }
626
627         /* If it is a recognized length, read the rest of the directory entry.
628          * Note: The root directory entry has no name, and its length does not
629          * include the short name length field.  */
630         if (dentry->length < WIM_DENTRY_DISK_SIZE) {
631                 ERROR("Directory entry has invalid length of "
632                                 "%"PRIu64" bytes\n", dentry->length);
633                 return WIMLIB_ERR_INVALID_DENTRY;
634         }
635
636         p = get_u32(p, &dentry->attributes);
637         /* Currently ignoring security ID. */
638         p += sizeof(u32);
639         p = get_u64(p, &dentry->subdir_offset);
640
641         /* 2 unused fields */
642         p += 2 * sizeof(u64);
643
644         p = get_u64(p, &dentry->creation_time);
645         p = get_u64(p, &dentry->last_access_time);
646         p = get_u64(p, &dentry->last_write_time);
647
648         p = get_bytes(p, WIM_HASH_SIZE, dentry->hash);
649         
650         /* Currently ignoring reparse_tag. */
651         p += sizeof(u32);
652
653         /* The reparse_reserved field does not actually exist. */
654
655         p = get_u64(p, &dentry->hard_link);
656         
657         /* Currently ignoring streams. */
658         p += sizeof(u16);
659
660         p = get_u16(p, &short_name_len);
661         p = get_u16(p, &file_name_len);
662
663         calculated_size = WIM_DENTRY_DISK_SIZE + file_name_len + 2 +
664                           short_name_len;
665
666         if (dentry->length < calculated_size) {
667                 ERROR("Unexpected end of directory entry! (Expected "
668                                 "%"PRIu64" bytes, got %"PRIu64" bytes. "
669                                 "short_name_len = %hu, file_name_len = %hu)\n", 
670                                 calculated_size, dentry->length,
671                                 short_name_len, file_name_len);
672                 return WIMLIB_ERR_INVALID_DENTRY;
673         }
674
675         /* Read the filename. */
676         file_name = MALLOC(file_name_len);
677         if (!file_name) {
678                 ERROR("Failed to allocate %hu bytes for dentry file name!\n",
679                                 file_name_len);
680                 return WIMLIB_ERR_NOMEM;
681         }
682         p = get_bytes(p, file_name_len, file_name);
683
684         /* Convert filename to UTF-8. */
685         file_name_utf8 = utf16_to_utf8(file_name, file_name_len, 
686                                        &file_name_utf8_len);
687
688         if (!file_name_utf8) {
689                 ERROR("Failed to allocate memory to convert UTF16 "
690                                 "filename (%hu bytes) to UTF8\n",
691                                 file_name_len);
692                 goto err_nomem2;
693         }
694
695         /* Undocumented padding between file name and short name.  This probably
696          * is supposed to be a terminating NULL character. */
697         p += 2;
698
699         /* Read the short filename. */
700         short_name = MALLOC(short_name_len);
701         if (!short_name) {
702                 ERROR("Failed to allocate %hu bytes for short filename\n",
703                                 short_name_len);
704                 goto err_nomem1;
705         }
706
707         get_bytes(p, short_name_len, short_name);
708
709         dentry->file_name          = file_name;
710         dentry->file_name_utf8     = file_name_utf8;
711         dentry->short_name         = short_name;
712         dentry->file_name_len      = file_name_len;
713         dentry->file_name_utf8_len = file_name_utf8_len;
714         dentry->short_name_len     = short_name_len;
715         return 0;
716 err_nomem1:
717         FREE(dentry->file_name_utf8);
718 err_nomem2:
719         FREE(dentry->file_name);
720         return WIMLIB_ERR_NOMEM;
721 }
722
723 /* 
724  * Writes a dentry to an output buffer.
725  *
726  * @dentry:  The dentry structure.
727  * @p:       The memory location to write the data to.
728  * @return:  True on success, false on failure.
729  */
730 static u8 *write_dentry(const struct dentry *dentry, u8 *p)
731 {
732         u8 *orig_p = p;
733         memset(p, 0, dentry->length);
734         p = put_u64(p, dentry->length);
735         p = put_u32(p, dentry->attributes);
736         p = put_u32(p, (u32)(-1)); /* security id */
737         p = put_u64(p, dentry->subdir_offset);
738         p = put_u64(p, 0); /* unused1 */
739         p = put_u64(p, 0); /* unused2 */
740         p = put_u64(p, dentry->creation_time);
741         p = put_u64(p, dentry->last_access_time);
742         p = put_u64(p, dentry->last_write_time);
743         p = put_bytes(p, WIM_HASH_SIZE, dentry->hash);
744         p = put_u32(p, 0); /* reparse_tag */
745         p = put_u64(p, dentry->hard_link);
746         p = put_u16(p, 0); /*streams */
747         p = put_u16(p, dentry->short_name_len);
748         p = put_u16(p, dentry->file_name_len);
749         p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name);
750         p = put_u16(p, 0); /* filename padding, 2 bytes. */
751         p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name);
752         return orig_p + dentry->length;
753 }
754
755 /* Recursive function that writes a dentry tree rooted at @tree, not including
756  * @tree itself, which has already been written, except in the case of the root
757  * dentry, which is written right away, along with an end-of-directory entry. */
758 u8 *write_dentry_tree(const struct dentry *tree, u8 *p)
759 {
760         const struct dentry *child;
761
762         if (dentry_is_root(tree)) {
763                 p = write_dentry(tree, p);
764
765                 /* write end of directory entry */
766                 p = put_u64(p, 0);
767         } else {
768                 /* Nothing to do for a regular file. */
769                 if (dentry_is_regular_file(tree))
770                         return p;
771         }
772
773         /* Write child dentries and end-of-directory entry. */
774         child = tree->children;
775         if (child) {
776                 do {
777                         p = write_dentry(child, p);
778                         child = child->next;
779                 } while (child != tree->children);
780         }
781
782         /* write end of directory entry */
783         p = put_u64(p, 0);
784
785         /* Recurse on children. */
786         if (child) {
787                 do {
788                         p = write_dentry_tree(child, p);
789                         child = child->next;
790                 } while (child != tree->children);
791         }
792         return p;
793 }
794
795 /* Reads the children of a dentry, and all their children, ..., etc. from the
796  * metadata resource and into the dentry tree.
797  *
798  * @metadata_resource:  An array that contains the uncompressed metadata
799  *                              resource for the WIM file.
800  * @metadata_resource_len:      The length of @metadata_resource.
801  * @dentry:     A pointer to a struct dentry that is the root of the directory tree
802  *              and has already been read from the metadata resource.  It does not 
803  *              need to be the real root, because this procedure is called 
804  *              recursively.
805  * @return:     True on success, false on failure. 
806  */
807 int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
808                      struct dentry *dentry)
809 {
810         u64 cur_offset = dentry->subdir_offset;
811         struct dentry *prev_child = NULL;
812         struct dentry *first_child = NULL;
813         struct dentry *child;
814         struct dentry cur_child;
815         int ret;
816
817         /* If @dentry is a regular file, nothing more needs to be done for this
818          * branch. */
819         if (cur_offset == 0)
820                 return 0;
821
822         /* Find and read all the children of @dentry. */
823         while (1) {
824
825                 /* Read next child of @dentry into @cur_child. */
826                 ret = read_dentry(metadata_resource, metadata_resource_len, 
827                                   cur_offset, &cur_child);
828                 if (ret != 0)
829                         break;
830
831                 /* Check for end of directory. */
832                 if (cur_child.length == 0) {
833                         ret = 0;
834                         break;
835                 }
836
837                 /* Not end of directory.  Allocate this child permanently and
838                  * link it to the parent and previous child. */
839                 child = MALLOC(sizeof(struct dentry));
840                 if (!child) {
841                         ERROR("Failed to allocate %zu bytes for new dentry!\n",
842                                         sizeof(struct dentry));
843                         ret = WIMLIB_ERR_NOMEM;
844                         break;
845                 }
846                 memcpy(child, &cur_child, sizeof(struct dentry));
847
848                 if (prev_child) {
849                         prev_child->next = child;
850                         child->prev = prev_child;
851                 } else {
852                         first_child = child;
853                 }
854
855                 child->parent = dentry;
856                 prev_child = child;
857
858                 /* If there are children of this child, call this procedure
859                  * recursively. */
860                 if (child->subdir_offset != 0) {
861                         ret = read_dentry_tree(metadata_resource, 
862                                                metadata_resource_len, child);
863                         if (ret != 0)
864                                 break;
865                 }
866
867                 /* Advance to the offset of the next child. */
868                 cur_offset += child->length;
869         }
870
871         /* Link last child to first one, and set parent's
872          * children pointer to the first child.  */
873         if (prev_child) {
874                 prev_child->next = first_child;
875                 first_child->prev = prev_child;
876         }
877         dentry->children = first_child;
878         return ret;
879 }