*/
/*
- * Copyright (C) 2012, 2013 Eric Biggers
+ * Copyright (C) 2012, 2013, 2014 Eric Biggers
*
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
*
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
*/
#ifdef HAVE_CONFIG_H
#include "wimlib/metadata.h"
#include "wimlib/ntfs_3g.h"
#include "wimlib/resource.h"
+#include "wimlib/unaligned.h"
#include "wimlib/util.h"
#include "wimlib/write.h"
void
free_lookup_table(struct wim_lookup_table *table)
{
- DEBUG("Freeing lookup table.");
- if (table == NULL)
- return;
-
- if (table->array) {
- for_lookup_table_entry(table,
- do_free_lookup_table_entry,
- NULL);
+ if (table) {
+ for_lookup_table_entry(table, do_free_lookup_table_entry, NULL);
FREE(table->array);
+ FREE(table);
}
- FREE(table);
}
struct wim_lookup_table_entry *
if (new == NULL)
return NULL;
- new->extracted_file = NULL;
switch (new->resource_location) {
case RESOURCE_IN_WIM:
list_add(&new->rspec_node, &new->rspec->stream_list);
case RESOURCE_IN_FILE_ON_DISK:
#ifdef __WIN32__
+ case RESOURCE_IN_WINNT_FILE_ON_DISK:
case RESOURCE_WIN32_ENCRYPTED:
#endif
#ifdef WITH_FUSE
break;
case RESOURCE_IN_FILE_ON_DISK:
#ifdef __WIN32__
+ case RESOURCE_IN_WINNT_FILE_ON_DISK:
case RESOURCE_WIN32_ENCRYPTED:
#endif
#ifdef WITH_FUSE
}
/*
- * Decrements the reference count for the lookup table entry @lte, which must be
- * inserted in the stream lookup table @table.
+ * Decrements the reference count of the single-instance stream @lte, which must
+ * be inserted in the stream lookup table @table.
+ *
+ * If the stream's reference count reaches 0, we may unlink it from @table and
+ * free it. However, we retain streams with 0 reference count that originated
+ * from WIM files (RESOURCE_IN_WIM). We do this for two reasons:
*
- * If the reference count reaches 0, this may cause @lte to be destroyed.
- * However, we may retain entries with 0 reference count. This does not affect
- * correctness, but it prevents the entries for valid streams in a WIM archive,
- * which will continue to be present after appending to the file, from being
- * lost merely because we dropped all references to them.
+ * 1. This prevents information about valid streams in a WIM file --- streams
+ * which will continue to be present after appending to the WIM file --- from
+ * being lost merely because we dropped all references to them.
+ *
+ * 2. Stream reference counts we read from WIM files can't be trusted. It's
+ * possible that a WIM has reference counts that are too low; WIMGAPI
+ * sometimes creates WIMs where this is the case. It's also possible that
+ * streams have been referenced from an external WIM; those streams can
+ * potentially have any reference count at all, either lower or higher than
+ * would be expected for this WIM ("this WIM" meaning the owner of @table) if
+ * it were a standalone WIM.
+ *
+ * So we can't take the reference counts too seriously. But at least, we do
+ * recalculate by default when writing a new WIM file.
*/
void
lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
struct wim_lookup_table *table)
{
- wimlib_assert(lte->refcnt != 0);
+ if (unlikely(lte->refcnt == 0)) /* See comment above */
+ return;
if (--lte->refcnt == 0) {
if (lte->unhashed) {
* that there still may be open file descriptors to it.)
* */
if (lte->resource_location == RESOURCE_IN_STAGING_FILE)
- unlink(lte->staging_file_name);
+ unlinkat(lte->staging_dir_fd,
+ lte->staging_file_name, 0);
#endif
} else {
if (!should_retain_lte(lte))
struct wim_lookup_table_entry *lte;
struct hlist_node *pos;
- i = *(size_t*)hash % table->capacity;
+ i = load_size_t_unaligned(hash) % table->capacity;
hlist_for_each_entry(lte, pos, &table->array[i], hash_list)
if (hashes_equal(hash, lte->hash))
return lte;
/* Different (possibly split) WIMs? */
if (wim1 != wim2) {
- v = memcmp(wim1->hdr.guid, wim2->hdr.guid, WIM_GID_LEN);
+ v = memcmp(wim1->hdr.guid, wim2->hdr.guid, WIM_GUID_LEN);
if (v)
return v;
}
case RESOURCE_IN_STAGING_FILE:
#endif
#ifdef __WIN32__
+ case RESOURCE_IN_WINNT_FILE_ON_DISK:
case RESOURCE_WIN32_ENCRYPTED:
#endif
/* Compare files by path: just a heuristic that will place files
/* Which part of the split WIM this stream is in; indexed from 1. */
le16 part_number;
- /* Reference count of this stream over all WIM images. */
+ /* Reference count of this stream over all WIM images. (But see comment
+ * above lte_decrement_refcnt().) */
le32 refcnt;
/* SHA1 message digest of the uncompressed data of this stream, or
/* cur_entry is now a stream bound to a resource. */
+ /* Ignore entries with all zeroes in the hash field. */
+ if (is_zero_hash(cur_entry->hash))
+ goto free_cur_entry_and_continue;
+
/* Verify that the part number matches that of the underlying
* WIM file. */
if (part_number != wim->hdr.part_number) {
goto free_cur_entry_and_continue;
}
- /* Ignore entries with all zeroes in the hash field. */
- if (is_zero_hash(cur_entry->hash))
- goto free_cur_entry_and_continue;
-
if (reshdr.flags & WIM_RESHDR_FLAG_METADATA) {
/* Lookup table entry for a metadata resource. */
copy_hash(disk_entry->hash, hash);
}
+/* Note: the list of stream entries must be sorted so that all entries for the
+ * same packed resource are consecutive. In addition, entries with
+ * WIM_RESHDR_FLAG_METADATA set must be in the same order as the indices of the
+ * underlying images. */
int
write_wim_lookup_table_from_stream_list(struct list_head *stream_list,
struct filedes *out_fd,
struct wim_lookup_table_entry_disk *table_buf_ptr;
int ret;
u64 prev_res_offset_in_wim = ~0ULL;
+ u64 prev_uncompressed_size;
+ u64 logical_offset;
table_size = 0;
list_for_each_entry(lte, stream_list, lookup_table_list) {
table_buf_ptr = table_buf;
prev_res_offset_in_wim = ~0ULL;
+ prev_uncompressed_size = 0;
+ logical_offset = 0;
list_for_each_entry(lte, stream_list, lookup_table_list) {
+ if (lte->out_reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) {
+ struct wim_reshdr tmp_reshdr;
- put_wim_lookup_table_entry(table_buf_ptr++,
- <e->out_reshdr,
- part_number,
- lte->out_refcnt,
- lte->hash);
- if (lte->out_reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS &&
- lte->out_res_offset_in_wim != prev_res_offset_in_wim)
- {
- /* Put the main resource entry for the pack. */
+ /* Eww. When WIMGAPI sees multiple resource packs, it
+ * expects the offsets to be adjusted as if there were
+ * really only one pack. */
- struct wim_reshdr reshdr;
+ if (lte->out_res_offset_in_wim != prev_res_offset_in_wim) {
+ /* Put the resource entry for pack */
+ tmp_reshdr.offset_in_wim = lte->out_res_offset_in_wim;
+ tmp_reshdr.size_in_wim = lte->out_res_size_in_wim;
+ tmp_reshdr.uncompressed_size = WIM_PACK_MAGIC_NUMBER;
+ tmp_reshdr.flags = WIM_RESHDR_FLAG_PACKED_STREAMS;
- reshdr.offset_in_wim = lte->out_res_offset_in_wim;
- reshdr.size_in_wim = lte->out_res_size_in_wim;
- reshdr.uncompressed_size = WIM_PACK_MAGIC_NUMBER;
- reshdr.flags = WIM_RESHDR_FLAG_PACKED_STREAMS;
+ put_wim_lookup_table_entry(table_buf_ptr++,
+ &tmp_reshdr,
+ part_number,
+ 1, zero_hash);
- DEBUG("Putting main entry for pack: "
- "size_in_wim=%"PRIu64", "
- "offset_in_wim=%"PRIu64", "
- "uncompressed_size=%"PRIu64,
- reshdr.size_in_wim,
- reshdr.offset_in_wim,
- reshdr.uncompressed_size);
+ logical_offset += prev_uncompressed_size;
+ prev_res_offset_in_wim = lte->out_res_offset_in_wim;
+ prev_uncompressed_size = lte->out_res_uncompressed_size;
+ }
+ tmp_reshdr = lte->out_reshdr;
+ tmp_reshdr.offset_in_wim += logical_offset;
put_wim_lookup_table_entry(table_buf_ptr++,
- &reshdr,
+ &tmp_reshdr,
part_number,
- 1, zero_hash);
- prev_res_offset_in_wim = lte->out_res_offset_in_wim;
+ lte->out_refcnt,
+ lte->hash);
+ } else {
+ put_wim_lookup_table_entry(table_buf_ptr++,
+ <e->out_reshdr,
+ part_number,
+ lte->out_refcnt,
+ lte->hash);
}
}
return ret;
}
-int
-lte_zero_real_refcnt(struct wim_lookup_table_entry *lte, void *_ignore)
-{
- lte->real_refcnt = 0;
- return 0;
-}
-
-int
-lte_zero_out_refcnt(struct wim_lookup_table_entry *lte, void *_ignore)
-{
- lte->out_refcnt = 0;
- return 0;
-}
-
-int
-lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *_ignore)
-{
- if (lte->extracted_file != NULL) {
- FREE(lte->extracted_file);
- lte->extracted_file = NULL;
- }
- return 0;
-}
-
/* Allocate a stream entry for the contents of the buffer, or re-use an existing
* entry in @lookup_table for the same stream. */
struct wim_lookup_table_entry *
.cb = cb,
.user_ctx = user_ctx,
};
- if (wim->hdr.part_number == 1) {
+ if (wim_has_metadata(wim)) {
int ret;
for (int i = 0; i < wim->hdr.image_count; i++) {
ret = do_iterate_lte(wim->image_metadata[i]->metadata_lte,