]> wimlib.net Git - wimlib/blob - src/lookup_table.c
Char encoding updates and misc. fixes
[wimlib] / src / lookup_table.c
1 /*
2  * lookup_table.c
3  *
4  * Lookup table, implemented as a hash table, that maps SHA1 message digests to
5  * data streams.
6  */
7
8 /*
9  * Copyright (C) 2012, 2013 Eric Biggers
10  *
11  * This file is part of wimlib, a library for working with WIM files.
12  *
13  * wimlib is free software; you can redistribute it and/or modify it under the
14  * terms of the GNU General Public License as published by the Free
15  * Software Foundation; either version 3 of the License, or (at your option)
16  * any later version.
17  *
18  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
19  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20  * A PARTICULAR PURPOSE. See the GNU General Public License for more
21  * details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with wimlib; if not, see http://www.gnu.org/licenses/.
25  */
26
27 #include "wimlib_internal.h"
28 #include "lookup_table.h"
29 #include "buffer_io.h"
30 #include <errno.h>
31
32 #ifdef WITH_FUSE
33 #include <unistd.h>
34 #endif
35
36 struct wim_lookup_table *
37 new_lookup_table(size_t capacity)
38 {
39         struct wim_lookup_table *table;
40         struct hlist_head *array;
41
42         table = MALLOC(sizeof(struct wim_lookup_table));
43         if (table) {
44                 array = CALLOC(capacity, sizeof(array[0]));
45                 if (array) {
46                         table->num_entries = 0;
47                         table->capacity = capacity;
48                         table->array = array;
49                 } else {
50                         FREE(table);
51                         table = NULL;
52                         ERROR("Failed to allocate memory for lookup table with capacity %zu",
53                               capacity);
54                 }
55         }
56         return table;
57 }
58
59 struct wim_lookup_table_entry *
60 new_lookup_table_entry()
61 {
62         struct wim_lookup_table_entry *lte;
63
64         lte = CALLOC(1, sizeof(struct wim_lookup_table_entry));
65         if (lte) {
66                 lte->part_number  = 1;
67                 lte->refcnt       = 1;
68         } else {
69                 ERROR("Out of memory (tried to allocate %zu bytes for "
70                       "lookup table entry)",
71                       sizeof(struct wim_lookup_table_entry));
72         }
73         return lte;
74 }
75
76 struct wim_lookup_table_entry *
77 clone_lookup_table_entry(const struct wim_lookup_table_entry *old)
78 {
79         struct wim_lookup_table_entry *new;
80
81         new = MALLOC(sizeof(*new));
82         if (!new)
83                 return NULL;
84
85         memcpy(new, old, sizeof(*old));
86         new->extracted_file = NULL;
87         switch (new->resource_location) {
88 #ifdef __WIN32__
89         case RESOURCE_WIN32:
90 #endif
91         case RESOURCE_IN_STAGING_FILE:
92         case RESOURCE_IN_FILE_ON_DISK:
93                 BUILD_BUG_ON((void*)&old->file_on_disk !=
94                              (void*)&old->staging_file_name);
95                 new->staging_file_name = TSTRDUP(old->staging_file_name);
96                 if (!new->staging_file_name)
97                         goto out_free;
98                 break;
99         case RESOURCE_IN_ATTACHED_BUFFER:
100                 new->attached_buffer = MALLOC(wim_resource_size(old));
101                 if (!new->attached_buffer)
102                         goto out_free;
103                 memcpy(new->attached_buffer, old->attached_buffer,
104                        wim_resource_size(old));
105                 break;
106 #ifdef WITH_NTFS_3G
107         case RESOURCE_IN_NTFS_VOLUME:
108                 if (old->ntfs_loc) {
109                         struct ntfs_location *loc;
110                         loc = MALLOC(sizeof(*loc));
111                         if (!loc)
112                                 goto out_free;
113                         memcpy(loc, old->ntfs_loc, sizeof(*loc));
114                         loc->path = NULL;
115                         loc->stream_name = NULL;
116                         new->ntfs_loc = loc;
117                         loc->path = STRDUP(old->ntfs_loc->path);
118                         if (!loc->path)
119                                 goto out_free;
120                         loc->stream_name = MALLOC((loc->stream_name_nchars + 1) * 2);
121                         if (!loc->stream_name)
122                                 goto out_free;
123                         memcpy(loc->stream_name,
124                                old->ntfs_loc->stream_name,
125                                (loc->stream_name_nchars + 1) * 2);
126                 }
127                 break;
128 #endif
129         default:
130                 break;
131         }
132         return new;
133 out_free:
134         free_lookup_table_entry(new);
135         return NULL;
136 }
137
138 void
139 free_lookup_table_entry(struct wim_lookup_table_entry *lte)
140 {
141         if (lte) {
142                 switch (lte->resource_location) {
143                 case RESOURCE_IN_STAGING_FILE:
144                 case RESOURCE_IN_ATTACHED_BUFFER:
145                 case RESOURCE_IN_FILE_ON_DISK:
146 #ifdef __WIN32__
147                 case RESOURCE_WIN32:
148 #endif
149                         BUILD_BUG_ON((void*)&lte->file_on_disk !=
150                                      (void*)&lte->staging_file_name);
151                         BUILD_BUG_ON((void*)&lte->file_on_disk !=
152                                      (void*)&lte->attached_buffer);
153                         FREE(lte->file_on_disk);
154                         break;
155 #ifdef WITH_NTFS_3G
156                 case RESOURCE_IN_NTFS_VOLUME:
157                         if (lte->ntfs_loc) {
158                                 FREE(lte->ntfs_loc->path);
159                                 FREE(lte->ntfs_loc->stream_name);
160                                 FREE(lte->ntfs_loc);
161                         }
162                         break;
163 #endif
164                 default:
165                         break;
166                 }
167                 FREE(lte);
168         }
169 }
170
171 static int
172 do_free_lookup_table_entry(struct wim_lookup_table_entry *entry, void *ignore)
173 {
174         free_lookup_table_entry(entry);
175         return 0;
176 }
177
178
179 void
180 free_lookup_table(struct wim_lookup_table *table)
181 {
182         DEBUG2("Freeing lookup table");
183         if (table) {
184                 if (table->array) {
185                         for_lookup_table_entry(table,
186                                                do_free_lookup_table_entry,
187                                                NULL);
188                         FREE(table->array);
189                 }
190                 FREE(table);
191         }
192 }
193
194 /*
195  * Inserts an entry into the lookup table.
196  *
197  * @table:      A pointer to the lookup table.
198  * @lte:        A pointer to the entry to insert.
199  */
200 void
201 lookup_table_insert(struct wim_lookup_table *table,
202                     struct wim_lookup_table_entry *lte)
203 {
204         size_t i = lte->hash_short % table->capacity;
205         hlist_add_head(&lte->hash_list, &table->array[i]);
206
207         /* XXX Make the table grow when too many entries have been inserted. */
208         table->num_entries++;
209 }
210
211 static void
212 finalize_lte(struct wim_lookup_table_entry *lte)
213 {
214         #ifdef WITH_FUSE
215         if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
216                 unlink(lte->staging_file_name);
217                 list_del(&lte->staging_list);
218         }
219         #endif
220         free_lookup_table_entry(lte);
221 }
222
223 /* Decrements the reference count for the lookup table entry @lte.  If its
224  * reference count reaches 0, it is unlinked from the lookup table.  If,
225  * furthermore, the entry has no opened file descriptors associated with it, the
226  * entry is freed.  */
227 void
228 lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
229                      struct wim_lookup_table *table)
230 {
231         wimlib_assert(lte != NULL);
232         wimlib_assert(lte->refcnt != 0);
233         if (--lte->refcnt == 0) {
234                 lookup_table_unlink(table, lte);
235         #ifdef WITH_FUSE
236                 if (lte->num_opened_fds == 0)
237         #endif
238                         finalize_lte(lte);
239         }
240 }
241
242 #ifdef WITH_FUSE
243 void
244 lte_decrement_num_opened_fds(struct wim_lookup_table_entry *lte)
245 {
246         if (lte->num_opened_fds != 0)
247                 if (--lte->num_opened_fds == 0 && lte->refcnt == 0)
248                         finalize_lte(lte);
249 }
250 #endif
251
252 /* Calls a function on all the entries in the WIM lookup table.  Stop early and
253  * return nonzero if any call to the function returns nonzero. */
254 int
255 for_lookup_table_entry(struct wim_lookup_table *table,
256                        int (*visitor)(struct wim_lookup_table_entry *, void *),
257                        void *arg)
258 {
259         struct wim_lookup_table_entry *lte;
260         struct hlist_node *pos, *tmp;
261         int ret;
262
263         for (size_t i = 0; i < table->capacity; i++) {
264                 hlist_for_each_entry_safe(lte, pos, tmp, &table->array[i],
265                                           hash_list)
266                 {
267                         ret = visitor(lte, arg);
268                         if (ret != 0)
269                                 return ret;
270                 }
271         }
272         return 0;
273 }
274
275
276 /*
277  * Reads the lookup table from a WIM file.
278  */
279 int
280 read_lookup_table(WIMStruct *w)
281 {
282         u64 num_entries;
283         u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
284         int ret;
285         struct wim_lookup_table *table;
286         struct wim_lookup_table_entry *cur_entry = NULL, *duplicate_entry;
287
288         if (resource_is_compressed(&w->hdr.lookup_table_res_entry)) {
289                 ERROR("Didn't expect a compressed lookup table!");
290                 ERROR("Ask the author to implement support for this.");
291                 return WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE;
292         }
293
294         DEBUG("Reading lookup table: offset %"PRIu64", size %"PRIu64"",
295               w->hdr.lookup_table_res_entry.offset,
296               w->hdr.lookup_table_res_entry.original_size);
297
298         if (fseeko(w->fp, w->hdr.lookup_table_res_entry.offset, SEEK_SET) != 0)
299         {
300                 ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" to read "
301                                  "lookup table",
302                                  w->hdr.lookup_table_res_entry.offset);
303                 return WIMLIB_ERR_READ;
304         }
305
306         num_entries = w->hdr.lookup_table_res_entry.original_size /
307                       WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE;
308         table = new_lookup_table(num_entries * 2 + 1);
309         if (!table)
310                 return WIMLIB_ERR_NOMEM;
311
312         while (num_entries--) {
313                 const u8 *p;
314
315                 if (fread(buf, 1, sizeof(buf), w->fp) != sizeof(buf)) {
316                         if (feof(w->fp)) {
317                                 ERROR("Unexpected EOF in WIM lookup table!");
318                         } else {
319                                 ERROR_WITH_ERRNO("Error reading WIM lookup "
320                                                  "table");
321                         }
322                         ret = WIMLIB_ERR_READ;
323                         goto out;
324                 }
325                 cur_entry = new_lookup_table_entry();
326                 if (!cur_entry) {
327                         ret = WIMLIB_ERR_NOMEM;
328                         goto out;
329                 }
330                 cur_entry->wim = w;
331                 cur_entry->resource_location = RESOURCE_IN_WIM;
332
333                 p = get_resource_entry(buf, &cur_entry->resource_entry);
334                 p = get_u16(p, &cur_entry->part_number);
335                 p = get_u32(p, &cur_entry->refcnt);
336                 p = get_bytes(p, SHA1_HASH_SIZE, cur_entry->hash);
337
338                 if (cur_entry->part_number != w->hdr.part_number) {
339                         ERROR("A lookup table entry in part %hu of the WIM "
340                               "points to part %hu",
341                               w->hdr.part_number, cur_entry->part_number);
342                         ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
343                         goto out_free_cur_entry;
344                 }
345
346                 if (is_zero_hash(cur_entry->hash)) {
347                         ERROR("The WIM lookup table contains an entry with a "
348                               "SHA1 message digest of all 0's");
349                         ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
350                         goto out_free_cur_entry;
351                 }
352
353                 /* Ordinarily, no two streams should share the same SHA1 message
354                  * digest.  However, this constraint can be broken for metadata
355                  * resources--- two identical images will have the same metadata
356                  * resource, but their lookup table entries are not shared. */
357                 duplicate_entry = __lookup_resource(table, cur_entry->hash);
358                 if (duplicate_entry
359                     && !((duplicate_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
360                           && cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA))
361                 {
362                 #ifdef ENABLE_ERROR_MESSAGES
363                         ERROR("The WIM lookup table contains two entries with the "
364                               "same SHA1 message digest!");
365                         ERROR("The first entry is:");
366                         print_lookup_table_entry(duplicate_entry, stderr);
367                         ERROR("The second entry is:");
368                         print_lookup_table_entry(cur_entry, stderr);
369                 #endif
370                         ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
371                         goto out_free_cur_entry;
372                 }
373
374                 if (!(cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED)
375                     && (cur_entry->resource_entry.size !=
376                         cur_entry->resource_entry.original_size))
377                 {
378                 #ifdef ENABLE_ERROR_MESSAGES
379                         ERROR("Found uncompressed resource with original size "
380                               "not the same as compressed size");
381                         ERROR("The lookup table entry for the resource is as follows:");
382                         print_lookup_table_entry(cur_entry, stderr);
383                 #endif
384                         ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
385                         goto out_free_cur_entry;
386                 }
387                 if ((cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
388                     && cur_entry->refcnt != 1)
389                 {
390                 #ifdef ENABLE_ERROR_MESSAGES
391                         ERROR("Found metadata resource with refcnt != 1:");
392                         print_lookup_table_entry(cur_entry, stderr);
393                 #endif
394                         ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
395                         goto out_free_cur_entry;
396                 }
397                 lookup_table_insert(table, cur_entry);
398
399         }
400         DEBUG("Done reading lookup table.");
401         w->lookup_table = table;
402         return 0;
403 out_free_cur_entry:
404         FREE(cur_entry);
405 out:
406         free_lookup_table(table);
407         return ret;
408 }
409
410
411 /*
412  * Writes a lookup table entry to the output file.
413  */
414 int
415 write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
416 {
417         FILE *out;
418         u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
419         u8 *p;
420
421         out = __out;
422
423         /* Don't write entries that have not had file resources or metadata
424          * resources written for them. */
425         if (lte->out_refcnt == 0)
426                 return 0;
427
428         if (lte->output_resource_entry.flags & WIM_RESHDR_FLAG_METADATA) {
429                 DEBUG("Writing metadata entry at %"PRIu64" "
430                       "(orig size = %"PRIu64")",
431                       ftello(out), lte->output_resource_entry.original_size);
432         }
433
434         p = put_resource_entry(buf, &lte->output_resource_entry);
435         p = put_u16(p, lte->part_number);
436         p = put_u32(p, lte->out_refcnt);
437         p = put_bytes(p, SHA1_HASH_SIZE, lte->hash);
438         if (fwrite(buf, 1, sizeof(buf), out) != sizeof(buf)) {
439                 ERROR_WITH_ERRNO("Failed to write lookup table entry");
440                 return WIMLIB_ERR_WRITE;
441         }
442         return 0;
443 }
444
445 /* Writes the lookup table to the output file. */
446 int
447 write_lookup_table(struct wim_lookup_table *table, FILE *out,
448                    struct resource_entry *out_res_entry)
449 {
450         off_t start_offset, end_offset;
451         int ret;
452
453         start_offset = ftello(out);
454         if (start_offset == -1)
455                 return WIMLIB_ERR_WRITE;
456
457         ret = for_lookup_table_entry(table, write_lookup_table_entry, out);
458         if (ret != 0)
459                 return ret;
460
461         end_offset = ftello(out);
462         if (end_offset == -1)
463                 return WIMLIB_ERR_WRITE;
464
465         out_res_entry->offset        = start_offset;
466         out_res_entry->size          = end_offset - start_offset;
467         out_res_entry->original_size = end_offset - start_offset;
468         out_res_entry->flags         = WIM_RESHDR_FLAG_METADATA;
469
470         return 0;
471 }
472
473
474 int
475 lte_zero_real_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
476 {
477         lte->real_refcnt = 0;
478         return 0;
479 }
480
481 int
482 lte_zero_out_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
483 {
484         lte->out_refcnt = 0;
485         return 0;
486 }
487
488 int
489 lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore)
490 {
491         if (lte->extracted_file != NULL) {
492                 FREE(lte->extracted_file);
493                 lte->extracted_file = NULL;
494         }
495         return 0;
496 }
497
498 void
499 print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out)
500 {
501         if (!lte) {
502                 tputc(T('\n'), out);
503                 return;
504         }
505         tfprintf(out, T("Offset            = %"PRIu64" bytes\n"),
506                  lte->resource_entry.offset);
507
508         tfprintf(out, T("Size              = %"PRIu64" bytes\n"),
509                  (u64)lte->resource_entry.size);
510
511         tfprintf(out, T("Original size     = %"PRIu64" bytes\n"),
512                  lte->resource_entry.original_size);
513
514         tfprintf(out, T("Part Number       = %hu\n"), lte->part_number);
515         tfprintf(out, T("Reference Count   = %u\n"), lte->refcnt);
516
517         tfprintf(out, T("Hash              = 0x"));
518         print_hash(lte->hash);
519         tputc(T('\n'), out);
520
521         tfprintf(out, T("Flags             = "));
522         u8 flags = lte->resource_entry.flags;
523         if (flags & WIM_RESHDR_FLAG_COMPRESSED)
524                 tfputs(T("WIM_RESHDR_FLAG_COMPRESSED, "), out);
525         if (flags & WIM_RESHDR_FLAG_FREE)
526                 tfputs(T("WIM_RESHDR_FLAG_FREE, "), out);
527         if (flags & WIM_RESHDR_FLAG_METADATA)
528                 tfputs(T("WIM_RESHDR_FLAG_METADATA, "), out);
529         if (flags & WIM_RESHDR_FLAG_SPANNED)
530                 tfputs(T("WIM_RESHDR_FLAG_SPANNED, "), out);
531         tputc(T('\n'), out);
532         switch (lte->resource_location) {
533         case RESOURCE_IN_WIM:
534                 if (lte->wim->filename) {
535                         tfprintf(out, T("WIM file          = `%"TS"'\n"),
536                                  lte->wim->filename);
537                 }
538                 break;
539 #ifdef __WIN32__
540         case RESOURCE_WIN32:
541 #endif
542         case RESOURCE_IN_FILE_ON_DISK:
543                 tfprintf(out, T("File on Disk      = `%"TS"'\n"),
544                          lte->file_on_disk);
545                 break;
546         case RESOURCE_IN_STAGING_FILE:
547                 tfprintf(out, T("Staging File      = `%"TS"'\n"),
548                                 lte->staging_file_name);
549                 break;
550         default:
551                 break;
552         }
553         tputc(T('\n'), out);
554 }
555
556 static int
557 do_print_lookup_table_entry(struct wim_lookup_table_entry *lte, void *fp)
558 {
559         print_lookup_table_entry(lte, (FILE*)fp);
560         return 0;
561 }
562
563 /*
564  * Prints the lookup table of a WIM file.
565  */
566 WIMLIBAPI void
567 wimlib_print_lookup_table(WIMStruct *w)
568 {
569         for_lookup_table_entry(w->lookup_table,
570                                do_print_lookup_table_entry,
571                                stdout);
572 }
573
574 /* Given a SHA1 message digest, return the corresponding entry in the WIM's
575  * lookup table, or NULL if there is none.  */
576 struct wim_lookup_table_entry *
577 __lookup_resource(const struct wim_lookup_table *table, const u8 hash[])
578 {
579         size_t i;
580         struct wim_lookup_table_entry *lte;
581         struct hlist_node *pos;
582
583         wimlib_assert(table != NULL);
584         wimlib_assert(hash != NULL);
585
586         i = *(size_t*)hash % table->capacity;
587         hlist_for_each_entry(lte, pos, &table->array[i], hash_list)
588                 if (hashes_equal(hash, lte->hash))
589                         return lte;
590         return NULL;
591 }
592
593 #ifdef WITH_FUSE
594 /*
595  * Finds the dentry, lookup table entry, and stream index for a WIM file stream,
596  * given a path name.
597  *
598  * This is only for pre-resolved inodes.
599  */
600 int
601 lookup_resource(WIMStruct *w,
602                 const tchar *path,
603                 int lookup_flags,
604                 struct wim_dentry **dentry_ret,
605                 struct wim_lookup_table_entry **lte_ret,
606                 u16 *stream_idx_ret)
607 {
608         struct wim_dentry *dentry;
609         struct wim_lookup_table_entry *lte;
610         u16 stream_idx;
611         const tchar *stream_name = NULL;
612         struct wim_inode *inode;
613         tchar *p = NULL;
614
615         if (lookup_flags & LOOKUP_FLAG_ADS_OK) {
616                 stream_name = path_stream_name(path);
617                 if (stream_name) {
618                         p = (tchar*)stream_name - 1;
619                         *p = T('\0');
620                 }
621         }
622
623         dentry = get_dentry(w, path);
624         if (p)
625                 *p = T(':');
626         if (!dentry)
627                 return -errno;
628
629         inode = dentry->d_inode;
630
631         wimlib_assert(inode->i_resolved);
632
633         if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK)
634               && inode_is_directory(inode))
635                 return -EISDIR;
636
637         if (stream_name) {
638                 struct wim_ads_entry *ads_entry;
639                 u16 ads_idx;
640                 ads_entry = inode_get_ads_entry(inode, stream_name,
641                                                 &ads_idx);
642                 if (ads_entry) {
643                         stream_idx = ads_idx + 1;
644                         lte = ads_entry->lte;
645                         goto out;
646                 } else {
647                         return -ENOENT;
648                 }
649         } else {
650                 lte = inode->i_lte;
651                 stream_idx = 0;
652         }
653 out:
654         if (dentry_ret)
655                 *dentry_ret = dentry;
656         if (lte_ret)
657                 *lte_ret = lte;
658         if (stream_idx_ret)
659                 *stream_idx_ret = stream_idx;
660         return 0;
661 }
662 #endif
663
664 /* Resolve an inode's lookup table entries
665  *
666  * This replaces the SHA1 hash fields (which are used to lookup an entry in the
667  * lookup table) with pointers directly to the lookup table entries.  A circular
668  * linked list of streams sharing the same lookup table entry is created.
669  *
670  * This function always succeeds; unresolved lookup table entries are given a
671  * NULL pointer.
672  */
673 void
674 inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
675 {
676
677         if (!inode->i_resolved) {
678                 struct wim_lookup_table_entry *lte;
679                 /* Resolve the default file stream */
680                 lte = __lookup_resource(table, inode->i_hash);
681                 inode->i_lte = lte;
682                 inode->i_resolved = 1;
683
684                 /* Resolve the alternate data streams */
685                 for (u16 i = 0; i < inode->i_num_ads; i++) {
686                         struct wim_ads_entry *cur_entry = &inode->i_ads_entries[i];
687                         lte = __lookup_resource(table, cur_entry->hash);
688                         cur_entry->lte = lte;
689                 }
690         }
691 }
692
693 void
694 inode_unresolve_ltes(struct wim_inode *inode)
695 {
696         if (inode->i_resolved) {
697                 if (inode->i_lte)
698                         copy_hash(inode->i_hash, inode->i_lte->hash);
699                 else
700                         zero_out_hash(inode->i_hash);
701
702                 for (u16 i = 0; i < inode->i_num_ads; i++) {
703                         if (inode->i_ads_entries[i].lte)
704                                 copy_hash(inode->i_ads_entries[i].hash,
705                                           inode->i_ads_entries[i].lte->hash);
706                         else
707                                 zero_out_hash(inode->i_ads_entries[i].hash);
708                 }
709                 inode->i_resolved = 0;
710         }
711 }
712
713 /*
714  * Returns the lookup table entry for stream @stream_idx of the inode, where
715  * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
716  * corresponds to an alternate data stream.
717  *
718  * This works for both resolved and un-resolved inodes.
719  */
720 struct wim_lookup_table_entry *
721 inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
722                  const struct wim_lookup_table *table)
723 {
724         if (inode->i_resolved)
725                 return inode_stream_lte_resolved(inode, stream_idx);
726         else
727                 return inode_stream_lte_unresolved(inode, stream_idx, table);
728 }
729
730
731 /* Return the lookup table entry for the unnamed data stream of an inode, or
732  * NULL if there is none.
733  *
734  * You'd think this would be easier than it actually is, since the unnamed data
735  * stream should be the one referenced from the inode itself.  Alas, if there
736  * are named data streams, Microsoft's "imagex.exe" program will put the unnamed
737  * data stream in one of the alternate data streams instead of inside the WIM
738  * dentry itself.  So we need to check the alternate data streams too.
739  *
740  * Also, note that a dentry may appear to have more than one unnamed stream, but
741  * if the SHA1 message digest is all 0's then the corresponding stream does not
742  * really "count" (this is the case for the inode's own file stream when the
743  * file stream that should be there is actually in one of the alternate stream
744  * entries.).  This is despite the fact that we may need to extract such a
745  * missing entry as an empty file or empty named data stream.
746  */
747 struct wim_lookup_table_entry *
748 inode_unnamed_lte(const struct wim_inode *inode,
749                   const struct wim_lookup_table *table)
750 {
751         if (inode->i_resolved)
752                 return inode_unnamed_lte_resolved(inode);
753         else
754                 return inode_unnamed_lte_unresolved(inode, table);
755 }
756
757 static int
758 lte_add_stream_size(struct wim_lookup_table_entry *lte, void *total_bytes_p)
759 {
760         *(u64*)total_bytes_p += lte->resource_entry.size;
761         return 0;
762 }
763
764 u64
765 lookup_table_total_stream_size(struct wim_lookup_table *table)
766 {
767         u64 total_size = 0;
768         for_lookup_table_entry(table, lte_add_stream_size, &total_size);
769         return total_size;
770 }