* NULL if the resource entry for the dentry is not to be printed. */
int print_dentry(struct dentry *dentry, void *lookup_table)
{
- struct lookup_table_entry *lte;
- unsigned i;
+ const u8 *hash;
printf("[DENTRY]\n");
printf("Length = %"PRIu64"\n", dentry->length);
printf("Attributes = 0x%x\n", dentry->attributes);
- for (i = 0; i < ARRAY_LEN(file_attr_flags); i++)
+ for (unsigned i = 0; i < ARRAY_LEN(file_attr_flags); i++)
if (file_attr_flags[i].flag & dentry->attributes)
printf(" FILE_ATTRIBUTE_%s is set\n",
file_attr_flags[i].name);
printf("Creation Time = 0x%"PRIx64"\n", dentry->creation_time);
printf("Last Access Time = 0x%"PRIx64"\n", dentry->last_access_time);
printf("Last Write Time = 0x%"PRIx64"\n", dentry->last_write_time);
- printf("Hash = 0x");
- print_hash(dentry->hash);
- putchar('\n');
+ hash = dentry_stream_hash(dentry, 0);
+ if (hash) {
+ printf("Hash = 0x");
+ print_hash(hash);
+ putchar('\n');
+ }
printf("Reparse Tag = 0x%"PRIx32"\n", dentry->reparse_tag);
printf("Hard Link Group = 0x%"PRIx64"\n", dentry->hard_link);
printf("Number of Alternate Data Streams = %hu\n", dentry->num_ads);
puts("\"");
printf("Short Name Length = %hu\n", dentry->short_name_len);
printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8);
- if (lookup_table && (lte = __lookup_resource(lookup_table, dentry->hash)))
- print_lookup_table_entry(lte, NULL);
- else
- putchar('\n');
+ print_lookup_table_entry(dentry_stream_lte(dentry, 0, lookup_table));
for (u16 i = 0; i < dentry->num_ads; i++) {
printf("[Alternate Stream Entry %u]\n", i);
printf("Name = \"%s\"\n", dentry->ads_entries[i].stream_name_utf8);
printf("Name Length (UTF-16) = %u\n",
dentry->ads_entries[i].stream_name_len);
- printf("Hash = 0x");
- print_hash(dentry->ads_entries[i].hash);
- if (lookup_table &&
- (lte = __lookup_resource(lookup_table,
- dentry->ads_entries[i].hash)))
- {
- print_lookup_table_entry(lte, NULL);
- } else {
+ hash = dentry_stream_hash(dentry, i + 1);
+ if (hash) {
+ printf("Hash = 0x");
+ print_hash(hash);
putchar('\n');
}
+ print_lookup_table_entry(dentry_stream_lte(dentry, i + 1,
+ lookup_table));
}
return 0;
}
DEBUG2("ADS length = %"PRIu64, length);
p += 8; /* Unused */
- p = get_bytes(p, WIM_HASH_SIZE, (u8*)cur_entry->hash);
+ p = get_bytes(p, SHA1_HASH_SIZE, (u8*)cur_entry->hash);
p = get_u16(p, &cur_entry->stream_name_len);
DEBUG2("Stream name length = %u", cur_entry->stream_name_len);
p = get_u64(p, &dentry->last_access_time);
p = get_u64(p, &dentry->last_write_time);
- p = get_bytes(p, WIM_HASH_SIZE, dentry->hash);
+ p = get_bytes(p, SHA1_HASH_SIZE, dentry->hash);
/*
* I don't know what's going on here. It seems like M$ screwed up the
hash = dentry->lte->hash;
else
hash = dentry->hash;
- p = put_bytes(p, WIM_HASH_SIZE, hash);
+ p = put_bytes(p, SHA1_HASH_SIZE, hash);
if (dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
p = put_zeroes(p, 4);
p = put_u32(p, dentry->reparse_tag);
for (u16 i = 0; i < dentry->num_ads; i++) {
p = put_u64(p, ads_entry_length(&dentry->ads_entries[i]));
p = put_u64(p, 0); /* Unused */
- p = put_bytes(p, WIM_HASH_SIZE, dentry->ads_entries[i].hash);
+ if (dentry->resolved && dentry->ads_entries[i].lte)
+ hash = dentry->ads_entries[i].lte->hash;
+ else
+ hash = dentry->ads_entries[i].hash;
+ p = put_bytes(p, SHA1_HASH_SIZE, hash);
p = put_u16(p, dentry->ads_entries[i].stream_name_len);
p = put_bytes(p, dentry->ads_entries[i].stream_name_len,
(u8*)dentry->ads_entries[i].stream_name);
#include "util.h"
#include "config.h"
#include "list.h"
+#include "sha1.h"
#include <string.h>
#define WIM_ADS_ENTRY_DISK_SIZE 38
-#ifndef WIM_HASH_SIZE
-#define WIM_HASH_SIZE 20
-#endif
-
/*
* Reparse tags documented at
* http://msdn.microsoft.com/en-us/library/dd541667(v=prot.10).aspx
struct ads_entry {
union {
/* SHA-1 message digest of stream contents */
- u8 hash[WIM_HASH_SIZE];
+ u8 hash[SHA1_HASH_SIZE];
/* The corresponding lookup table entry (only for resolved
* streams) */
* opposed to the alternate file streams, which may have their own
* lookup table entries. */
union {
- u8 hash[WIM_HASH_SIZE];
+ u8 hash[SHA1_HASH_SIZE];
struct lookup_table_entry *lte;
};
char *extracted_file;
};
-/* Return hash of the "unnamed" (default) data stream. */
-static inline const u8 *dentry_hash(const struct dentry *dentry)
-{
- wimlib_assert(!dentry->resolved);
- /* If there are alternate data streams, the dentry hash field is zeroed
- * out, and we need to find the hash in the un-named data stream (should
- * be the first one, but check them in order just in case, and fall back
- * to the dentry hash field if we can't find an unnamed data stream). */
- for (u16 i = 0; i < dentry->num_ads; i++)
- if (dentry->ads_entries[i].stream_name_len == 0)
- return dentry->ads_entries[i].hash;
- return dentry->hash;
-}
-
-/* Return lte for the "unnamed" (default) data stream. Only for resolved
- * dentries */
-static inline struct lookup_table_entry *
-dentry_lte(const struct dentry *dentry)
-{
- wimlib_assert(dentry->resolved);
- for (u16 i = 0; i < dentry->num_ads; i++)
- if (dentry->ads_entries[i].stream_name_len == 0)
- return dentry->ads_entries[i].lte;
- return dentry->lte;
-}
/* Return the number of dentries in the hard link group */
static inline size_t dentry_link_group_size(const struct dentry *dentry)
{
struct lookup_table_entry *lte;
- lte = __lookup_resource(w->lookup_table, dentry_hash(dentry));
+ lte = dentry_first_lte(dentry, w->lookup_table);
if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) {
if (strcmp(d1->ads_entries[i].stream_name_utf8,
d2->ads_entries[i].stream_name_utf8) != 0)
return false;
- if (memcmp(d1->ads_entries[i].hash,
- d2->ads_entries[i].hash,
- WIM_HASH_SIZE) != 0)
+ if (!hashes_equal(d1->ads_entries[i].hash,
+ d2->ads_entries[i].hash))
return false;
}
return true;
mismatch_type = "security ID";
goto mismatch;
}
- if (memcmp(owner->hash, user->hash, WIM_HASH_SIZE) != 0) {
+ if (!hashes_equal(owner->hash, user->hash)) {
mismatch_type = "main file resource";
goto mismatch;
}
int *status)
{
char *chunk_buf;
- u8 resblock[WIM_HASH_SIZE];
+ u8 resblock[SHA1_HASH_SIZE];
u64 bytes_remaining;
size_t bytes_to_read;
uint percent_done;
goto verify_integrity_error;
}
sha1_buffer(chunk_buf, bytes_to_read, resblock);
- if (memcmp(resblock, sha1sums, WIM_HASH_SIZE) != 0) {
+ if (!hashes_equal(resblock, sha1sums)) {
*status = WIM_INTEGRITY_NOT_OK;
goto verify_integrity_done;
}
- sha1sums += WIM_HASH_SIZE;
+ sha1sums += SHA1_HASH_SIZE;
bytes_remaining -= bytes_to_read;
}
*status = WIM_INTEGRITY_OK;
integrity_table_size, num_entries, chunk_size);
- expected_size = num_entries * WIM_HASH_SIZE + 12;
+ expected_size = num_entries * SHA1_HASH_SIZE + 12;
if (integrity_table_size != expected_size) {
ERROR("Integrity table is %u bytes, but expected %"PRIu64" "
bytes_to_check = end_lookup_table_offset - end_header_offset;
num_entries = bytes_to_check / INTEGRITY_CHUNK_SIZE +
(bytes_to_check % INTEGRITY_CHUNK_SIZE != 0);
- integrity_table_size = num_entries * WIM_HASH_SIZE + 3 * sizeof(u32);
+ integrity_table_size = num_entries * SHA1_HASH_SIZE + 3 * sizeof(u32);
DEBUG("integrity table size = %u", integrity_table_size);
goto err2;
}
sha1_buffer(chunk_buf, bytes_read, p);
- p += WIM_HASH_SIZE;
+ p += SHA1_HASH_SIZE;
bytes_remaining -= bytes_read;
}
if (show_progress)
p = get_resource_entry(buf, &cur_entry->resource_entry);
p = get_u16(p, &cur_entry->part_number);
p = get_u32(p, &cur_entry->refcnt);
- p = get_bytes(p, WIM_HASH_SIZE, cur_entry->hash);
+ p = get_bytes(p, SHA1_HASH_SIZE, cur_entry->hash);
lookup_table_insert(table, cur_entry);
}
DEBUG("Done reading lookup table.");
p = put_resource_entry(buf, <e->output_resource_entry);
p = put_u16(p, lte->part_number);
p = put_u32(p, lte->out_refcnt);
- p = put_bytes(p, WIM_HASH_SIZE, lte->hash);
+ p = put_bytes(p, SHA1_HASH_SIZE, lte->hash);
if (fwrite(buf, 1, sizeof(buf), out) != sizeof(buf)) {
ERROR_WITH_ERRNO("Failed to write lookup table entry");
return WIMLIB_ERR_WRITE;
return 0;
}
-int print_lookup_table_entry(struct lookup_table_entry *lte, void *ignore)
+void print_lookup_table_entry(struct lookup_table_entry *lte)
{
+ if (!lte) {
+ putchar('\n');
+ return;
+ }
printf("Offset = %"PRIu64" bytes\n",
lte->resource_entry.offset);
printf("Size = %"PRIu64" bytes\n",
if (lte->file_on_disk && !lte->is_symlink)
printf("File on Disk = `%s'\n", lte->file_on_disk);
putchar('\n');
+}
+
+static int do_print_lookup_table_entry(struct lookup_table_entry *lte,
+ void *ignore)
+{
+ print_lookup_table_entry(lte);
return 0;
}
WIMLIBAPI void wimlib_print_lookup_table(WIMStruct *w)
{
for_lookup_table_entry(w->lookup_table,
- print_lookup_table_entry,
+ do_print_lookup_table_entry,
NULL);
}
i = *(size_t*)hash % table->capacity;
hlist_for_each_entry(lte, pos, &table->array[i], hash_list)
- if (memcmp(hash, lte->hash, WIM_HASH_SIZE) == 0)
+ if (hashes_equal(hash, lte->hash))
return lte;
return NULL;
}
struct lookup_table *table = __table;
struct lookup_table_entry *lte;
- wimlib_assert(!dentry->resolved);
+ if (dentry->resolved)
+ return 0;
/* Resolve the default file stream */
lte = __lookup_resource(table, dentry->hash);
}
return 0;
}
+
+struct lookup_table_entry *
+dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table)
+{
+ if (dentry->resolved)
+ return dentry_first_lte_resolved(dentry);
+ else
+ return dentry_first_lte_unresolved(dentry, table);
+}
+
#define _WIMLIB_LOOKUP_TABLE_H
#include "wimlib_internal.h"
#include "dentry.h"
+#include "sha1.h"
#include <sys/types.h>
/* Size of each lookup table entry in the WIM file. */
struct wimlib_fd;
-
/*
* An entry in the lookup table in the WIM file.
*
union {
/* SHA1 hash of the file resource pointed to by this lookup
* table entry */
- u8 hash[WIM_HASH_SIZE];
+ u8 hash[SHA1_HASH_SIZE];
/* First 4 or 8 bytes of the SHA1 hash, used for inserting the
* entry into the hash table. Since the SHA1 hashes can be
struct list_head staging_list;
};
+
extern struct lookup_table *new_lookup_table(size_t capacity);
extern void lookup_table_insert(struct lookup_table *table,
table->num_entries--;
}
+
extern struct lookup_table_entry *
lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[]);
extern int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore);
-extern int print_lookup_table_entry(struct lookup_table_entry *entry, void *ignore);
+extern void print_lookup_table_entry(struct lookup_table_entry *entry);
extern int read_lookup_table(FILE *fp, u64 offset, u64 size,
struct lookup_table **table_ret);
w->current_image - 1].metadata_lte->resource_entry;
}
+static inline struct lookup_table_entry *
+dentry_stream_lte_resolved(const struct dentry *dentry, unsigned stream_idx)
+{
+ wimlib_assert(dentry->resolved);
+ wimlib_assert(stream_idx <= dentry->num_ads);
+ if (stream_idx == 0)
+ return dentry->lte;
+ else
+ return dentry->ads_entries[stream_idx - 1].lte;
+}
+
+static inline struct lookup_table_entry *
+dentry_stream_lte_unresolved(const struct dentry *dentry, unsigned stream_idx,
+ const struct lookup_table *table)
+{
+ wimlib_assert(!dentry->resolved);
+ wimlib_assert(stream_idx <= dentry->num_ads);
+ if (!table)
+ return NULL;
+ if (stream_idx == 0)
+ return __lookup_resource(table, dentry->hash);
+ else
+ return __lookup_resource(table,
+ dentry->ads_entries[
+ stream_idx - 1].hash);
+}
+/*
+ * Returns the lookup table entry for stream @stream_idx of the dentry, where
+ * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
+ * corresponds to an alternate data stream.
+ *
+ * This works for both resolved and un-resolved dentries.
+ */
+static inline struct lookup_table_entry *
+dentry_stream_lte(const struct dentry *dentry, unsigned stream_idx,
+ const struct lookup_table *table)
+{
+ if (dentry->resolved)
+ return dentry_stream_lte_resolved(dentry, stream_idx);
+ else
+ return dentry_stream_lte_unresolved(dentry, stream_idx, table);
+}
+
+
+static inline const u8 *dentry_stream_hash_unresolved(const struct dentry *dentry,
+ unsigned stream_idx)
+{
+ wimlib_assert(!dentry->resolved);
+ wimlib_assert(stream_idx <= dentry->num_ads);
+ if (stream_idx == 0)
+ return dentry->hash;
+ else
+ return dentry->ads_entries[stream_idx - 1].hash;
+}
+
+static inline const u8 *dentry_stream_hash_resolved(const struct dentry *dentry,
+ unsigned stream_idx)
+{
+ struct lookup_table_entry *lte;
+ lte = dentry_stream_lte_resolved(dentry, stream_idx);
+ if (lte)
+ return lte->hash;
+ else
+ return NULL;
+}
+
+/*
+ * Returns the hash for stream @stream_idx of the dentry, where stream_idx = 0
+ * means the default un-named file stream, and stream_idx >= 1 corresponds to an
+ * alternate data stream.
+ *
+ * This works for both resolved and un-resolved dentries.
+ */
+static inline const u8 *dentry_stream_hash(const struct dentry *dentry,
+ unsigned stream_idx)
+{
+ if (dentry->resolved)
+ return dentry_stream_hash_resolved(dentry, stream_idx);
+ else
+ return dentry_stream_hash_unresolved(dentry, stream_idx);
+}
+
+static inline struct lookup_table_entry *
+dentry_first_lte_resolved(const struct dentry *dentry)
+{
+ struct lookup_table_entry *lte;
+ wimlib_assert(dentry->resolved);
+
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ lte = dentry_stream_lte_resolved(dentry, i);
+ if (lte)
+ return lte;
+ }
+ return NULL;
+}
+
+static inline struct lookup_table_entry *
+dentry_first_lte_unresolved(const struct dentry *dentry,
+ const struct lookup_table *table)
+{
+ struct lookup_table_entry *lte;
+ wimlib_assert(!dentry->resolved);
+
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ lte = dentry_stream_lte_unresolved(dentry, i, table);
+ if (lte)
+ return lte;
+ }
+ return NULL;
+}
+
+extern struct lookup_table_entry *
+dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table);
+
#endif
{
DEBUG("%s", root_disk_path);
struct stat root_stbuf;
- int ret;
+ int ret = 0;
int (*stat_fn)(const char *restrict, struct stat *restrict);
if (add_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)
ERROR("`%s' is not a directory", root_disk_path);
return WIMLIB_ERR_NOTDIR;
}
+ if (!S_ISREG(root_stbuf.st_mode) && !S_ISDIR(root_stbuf.st_mode)
+ && !S_ISLNK(root_stbuf.st_mode)) {
+ ERROR("`%s' is not a regular file, directory, or symbolic link.");
+ return WIMLIB_ERR_SPECIAL_FILE;
+ }
stbuf_to_dentry(&root_stbuf, root);
add_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT;
+ root->resolved = true;
if (dentry_is_directory(root)) {
/* Open the directory on disk */
/* Archiving a symbolic link */
size_t symlink_buf_len;
char deref_name_buf[4096];
- ssize_t ret = readlink(root_disk_path, deref_name_buf,
- sizeof(deref_name_buf) - 1);
- if (ret == -1) {
+ ssize_t deref_name_len;
+
+ deref_name_len = readlink(root_disk_path, deref_name_buf,
+ sizeof(deref_name_buf) - 1);
+ if (deref_name_len == -1) {
ERROR_WITH_ERRNO("Failed to read target of "
"symbolic link `%s'", root_disk_path);
- return WIMLIB_ERR_STAT;
+ return WIMLIB_ERR_READLINK;
}
- deref_name_buf[ret] = '\0';
+ deref_name_buf[deref_name_len] = '\0';
DEBUG("Read symlink `%s'", deref_name_buf);
ret = dentry_set_symlink(root, deref_name_buf,
lookup_table, NULL);
} else {
/* Regular file */
struct lookup_table_entry *lte;
+ u8 hash[SHA1_HASH_SIZE];
/* For each regular file, we must check to see if the file is in
* the lookup table already; if it is, we increment its refcnt;
* otherwise, we create a new lookup table entry and insert it.
* */
- ret = sha1sum(root_disk_path, root->hash);
+ ret = sha1sum(root_disk_path, hash);
if (ret != 0)
return ret;
- lte = __lookup_resource(lookup_table, root->hash);
+ lte = __lookup_resource(lookup_table, hash);
if (lte) {
lte->refcnt++;
+ DEBUG("Add lte reference %u for `%s'", lte->refcnt,
+ root_disk_path);
} else {
char *file_on_disk = STRDUP(root_disk_path);
if (!file_on_disk) {
lte->file_on_disk = file_on_disk;
lte->resource_entry.original_size = root_stbuf.st_size;
lte->resource_entry.size = root_stbuf.st_size;
- memcpy(lte->hash, root->hash, WIM_HASH_SIZE);
+ copy_hash(lte->hash, hash);
lookup_table_insert(lookup_table, lte);
}
+ root->lte = lte;
}
return ret;
}
* entry is created that references the location of the file resource in the
* source WIM file through the other_wim_fp field of the lookup table entry.
*/
-static int add_lookup_table_entry_to_dest_wim(struct dentry *dentry, void *arg)
+static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
{
WIMStruct *src_wim, *dest_wim;
- struct lookup_table_entry *src_table_entry;
- struct lookup_table_entry *dest_table_entry;
src_wim = ((struct wim_pair*)arg)->src_wim;
dest_wim = ((struct wim_pair*)arg)->dest_wim;
- if (dentry_is_directory(dentry))
- return 0;
-
- /* XXX ADS */
- src_table_entry = __lookup_resource(src_wim->lookup_table, dentry->hash);
- if (!src_table_entry)
- return 0;
-
- /* XXX ADS */
- dest_table_entry = __lookup_resource(dest_wim->lookup_table, dentry->hash);
- if (dest_table_entry) {
- dest_table_entry->refcnt++;
- } else {
- dest_table_entry = new_lookup_table_entry();
- if (!dest_table_entry)
- return WIMLIB_ERR_NOMEM;
- dest_table_entry->other_wim_fp = src_wim->fp;
- dest_table_entry->other_wim_ctype =
- wimlib_get_compression_type(src_wim);
- dest_table_entry->refcnt = 1;
- memcpy(&dest_table_entry->resource_entry,
- &src_table_entry->resource_entry,
- sizeof(struct resource_entry));
- memcpy(dest_table_entry->hash, dentry->hash, WIM_HASH_SIZE);
- lookup_table_insert(dest_wim->lookup_table, dest_table_entry);
+ wimlib_assert(!dentry->resolved);
+
+ for (unsigned i = 0; i < (unsigned)dentry->num_ads + 1; i++) {
+ struct lookup_table_entry *src_lte, *dest_lte;
+ src_lte = dentry_stream_lte_unresolved(dentry, i,
+ src_wim->lookup_table);
+ if (!src_lte)
+ continue;
+ dest_lte = dentry_stream_lte_unresolved(dentry, i,
+ dest_wim->lookup_table);
+ if (dest_lte) {
+ dest_lte->refcnt++;
+ } else {
+ dest_lte = new_lookup_table_entry();
+ if (!dest_lte)
+ return WIMLIB_ERR_NOMEM;
+ dest_lte->other_wim_fp = src_wim->fp;
+ dest_lte->other_wim_ctype =
+ wimlib_get_compression_type(src_wim);
+ memcpy(&dest_lte->resource_entry,
+ &src_lte->resource_entry,
+ sizeof(struct resource_entry));
+ copy_hash(dest_lte->hash,
+ dentry_stream_hash_unresolved(dentry, i));
+ lookup_table_insert(dest_wim->lookup_table, dest_lte);
+ }
}
return 0;
}
goto out_free_security_data;
metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA;
- randomize_byte_array(metadata_lte->hash, WIM_HASH_SIZE);
+ random_hash(metadata_lte->hash);
lookup_table_insert(w->lookup_table, metadata_lte);
new_imd = &imd[w->hdr.image_count];
/* Cleaning up here on failure would be hard. For example, we could
- * fail to allocate memory in add_lookup_table_entry_to_dest_wim(),
+ * fail to allocate memory in add_lte_to_dest_wim(),
* leaving the lookup table entries in the destination WIM in an
* inconsistent state. Until these issues can be resolved,
* wimlib_export_image() is documented as leaving dest_wim is an
for_dentry_in_tree(root, increment_dentry_refcnt, NULL);
wims.src_wim = src_wim;
wims.dest_wim = dest_wim;
- ret = for_dentry_in_tree(root, add_lookup_table_entry_to_dest_wim, &wims);
+ ret = for_dentry_in_tree(root, add_lte_to_dest_wim, &wims);
if (ret != 0)
return ret;
ret = add_new_dentry_tree(dest_wim, root);
root_dentry = new_dentry("");
if (!root_dentry)
return WIMLIB_ERR_NOMEM;
- ret = calculate_dentry_full_path(root_dentry, NULL);
-
- if (ret != 0)
- goto out_free_dentry_tree;
-
- root_dentry->attributes |= FILE_ATTRIBUTE_DIRECTORY;
DEBUG("Building dentry tree.");
ret = build_dentry_tree(root_dentry, dir, w->lookup_table,
goto out_free_dentry_tree;
}
- DEBUG("Recalculating full paths of dentries.");
+ DEBUG("Calculating full paths of dentries.");
ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL);
if (ret != 0)
goto out_free_dentry_tree;
stbuf->st_gid = getgid();
/* Use the size of the unnamed (default) file stream. */
- if ((lte = dentry_lte(dentry))) {
+ lte = dentry_first_lte_resolved(dentry);
+ if (lte) {
if (lte->staging_file_name) {
struct stat native_stat;
- if (stat(lte->staging_file_name, &native_stat) != 0)
+ if (stat(lte->staging_file_name, &native_stat) != 0) {
+ DEBUG("Failed to stat `%s': %m",
+ lte->staging_file_name);
return -errno;
+ }
stbuf->st_size = native_stat.st_size;
} else {
stbuf->st_size = lte->resource_entry.original_size;
int fd;
int errno_save;
- name_len = staging_dir_name_len + 1 + WIM_HASH_SIZE;
+ name_len = staging_dir_name_len + 1 + SHA1_HASH_SIZE;
name = MALLOC(name_len + 1);
if (!name) {
errno = ENOMEM;
memcpy(name, staging_dir_name, staging_dir_name_len);
name[staging_dir_name_len] = '/';
randomize_char_array_with_alnum(name + staging_dir_name_len + 1,
- WIM_HASH_SIZE);
+ SHA1_HASH_SIZE);
name[name_len] = '\0';
}
new_lte->resource_entry.original_size = size;
new_lte->refcnt = link_group_size;
- randomize_byte_array(new_lte->hash, WIM_HASH_SIZE);
+ random_hash(new_lte->hash);
new_lte->staging_file_name = staging_file_name;
lookup_table_insert(w->lookup_table, new_lte);
{
struct lookup_table_entry *duplicate_lte;
int ret;
- u8 hash[WIM_HASH_SIZE];
+ u8 hash[SHA1_HASH_SIZE];
ret = sha1sum(lte->staging_file_name, hash);
if (ret != 0)
return ret;
lookup_table_unlink(table, lte);
- memcpy(lte->hash, hash, WIM_HASH_SIZE);
+ copy_hash(lte->hash, hash);
duplicate_lte = __lookup_resource(table, hash);
dentry->ads_entries[1].lte_group_list.type = STREAM_TYPE_ADS;
list_add(&dentry->ads_entries[1].lte_group_list.list,
<e->lte_group_list);
- dentry->ads_entries[1].lte = lte;
- dentry->resolved = true;
+ wimlib_assert(dentry->resolved);
link_dentry(dentry, dentry_parent);
return 0;
ERROR("The following lookup table entry has a reference count "
"of %u, but", lte->refcnt);
ERROR("We found %u references to it", lte_group_size);
- print_lookup_table_entry(lte, NULL);
+ print_lookup_table_entry(lte);
#endif
return WIMLIB_ERR_INVALID_DENTRY;
}
u64 subdir_offset;
struct dentry *root;
struct lookup_table_entry *lte;
- struct resource_entry *res_entry;
off_t metadata_offset;
u64 metadata_original_size;
u64 metadata_compressed_size;
int metadata_ctype;
- u8 hash[WIM_HASH_SIZE];
+ u8 hash[SHA1_HASH_SIZE];
DEBUG("Writing metadata resource for image %d", w->current_image);
/* Update the lookup table entry, including the hash and output resource
* entry fields, for this image's metadata resource. */
lte = wim_metadata_lookup_table_entry(w);
- res_entry = <e->output_resource_entry;
lte->out_refcnt++;
- if (memcmp(hash, lte->hash, WIM_HASH_SIZE) != 0) {
+ if (!hashes_equal(hash, lte->hash)) {
lookup_table_unlink(w->lookup_table, lte);
- memcpy(lte->hash, hash, WIM_HASH_SIZE);
+ copy_hash(lte->hash, hash);
lookup_table_insert(w->lookup_table, lte);
}
- res_entry->original_size = metadata_original_size;
- res_entry->offset = metadata_offset;
- res_entry->size = metadata_compressed_size;
- res_entry->flags = WIM_RESHDR_FLAG_METADATA;
+ lte->output_resource_entry.original_size = metadata_original_size;
+ lte->output_resource_entry.offset = metadata_offset;
+ lte->output_resource_entry.size = metadata_compressed_size;
+ lte->output_resource_entry.flags = WIM_RESHDR_FLAG_METADATA;
if (metadata_ctype != WIM_COMPRESSION_TYPE_NONE)
- res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED;
+ lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_COMPRESSED;
return 0;
}
-static int write_file_resource(WIMStruct *w, const u8 hash[])
+static int write_file_resource(WIMStruct *w, struct lookup_table_entry *lte)
{
- /* Get the lookup entry for the file resource. */
- struct lookup_table_entry *lte;
-
- lte = __lookup_resource(w->lookup_table, hash);
if (!lte)
return 0;
}
/*
- * Writes a dentry's resources to the output file.
+ * Writes a dentry's resources, including the main file resource as well as all
+ * alternate data streams, to the output file.
*
- * @dentry: The dentry for the file resource.
+ * @dentry: The dentry for the file.
* @wim_p: A pointer to the WIMStruct. The fields of interest to this
* function are the input and output file streams and the lookup
- * table, and the alternate data streams.
+ * table.
*
* @return zero on success, nonzero on failure.
*/
{
WIMStruct *w = wim_p;
int ret;
+ struct lookup_table_entry *lte;
- /* Directories don't need file resources. */
- if (dentry_is_directory(dentry))
- return 0;
-
- ret = write_file_resource(w, dentry->hash);
- if (ret != 0)
- return ret;
- for (u16 i = 0; i < dentry->num_ads; i++) {
- ret = write_file_resource(w, dentry->ads_entries[i].hash);
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ lte = dentry_stream_lte(dentry, i, w->lookup_table);
+ ret = write_file_resource(w, lte);
if (ret != 0)
return ret;
}
#include <stdio.h>
#include <stddef.h>
#include "string.h"
+#include "util.h"
#define SHA1_HASH_SIZE 20
return memcmp(hash, empty_file_sha1sum, SHA1_HASH_SIZE) == 0;
}
+static inline void copy_hash(u8 dest[SHA1_HASH_SIZE],
+ const u8 src[SHA1_HASH_SIZE])
+{
+ memcpy(dest, src, SHA1_HASH_SIZE);
+}
+
+static inline void random_hash(u8 hash[SHA1_HASH_SIZE])
+{
+ randomize_byte_array(hash, SHA1_HASH_SIZE);
+}
+
+static inline bool hashes_equal(const u8 h1[SHA1_HASH_SIZE],
+ const u8 h2[SHA1_HASH_SIZE])
+{
+ return memcmp(h1, h2, SHA1_HASH_SIZE) == 0;
+}
+
+/* Prints a hash code field. */
+static inline void print_hash(const u8 hash[])
+{
+ print_byte_field(hash, SHA1_HASH_SIZE);
+}
extern int sha1sum(const char *filename, void *md);
return buf;
}
-static const struct lookup_table_entry *
-dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table)
-{
- const struct lookup_table_entry *lte;
- if (dentry->resolved) {
- if (dentry->lte)
- return dentry->lte;
- for (u16 i = 0; i < dentry->num_ads; i++)
- if (dentry->ads_entries[i].lte)
- return dentry->ads_entries[i].lte;
- } else {
- const u8 *hash = dentry->hash;
- u16 i = 0;
- while (1) {
- if ((lte = __lookup_resource(table, hash)))
- break;
- if (i == dentry->num_ads)
- return NULL;
- hash = dentry->ads_entries[i].hash;
- i++;
- }
- }
- return NULL;
-}
-
/* Get the symlink target from a dentry that's already checked to be either a
* "real" symlink or a junction point. */
ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len,
if (lte->is_symlink && lte->symlink_buf) {
res_buf = lte->symlink_buf;
} else {
- res_buf = __res_buf;
if (read_full_resource(w->fp, res_entry->size,
res_entry->original_size,
res_entry->offset,
}
static int dentry_set_symlink_buf(struct dentry *dentry,
- const u8 symlink_buf_hash[])
+ struct lookup_table_entry *lte)
{
struct ads_entry *ads_entries;
ads_entries = CALLOC(2, sizeof(struct ads_entry));
if (!ads_entries)
return WIMLIB_ERR_NOMEM;
- memcpy(ads_entries[1].hash, symlink_buf_hash, WIM_HASH_SIZE);
+
wimlib_assert(dentry->num_ads == 0);
- wimlib_assert(!dentry->ads_entries);
+ wimlib_assert(dentry->ads_entries == NULL);
+
+ ads_entries[1].lte = lte;
+
/*dentry_free_ads_entries(dentry);*/
dentry->num_ads = 2;
dentry->ads_entries = ads_entries;
return 0;
}
+/*
+ * Sets @dentry to be a symbolic link pointing to @target.
+ *
+ * A lookup table entry for the symbolic link data buffer is created and
+ * inserted into @lookup_table, unless there is an existing lookup table entry
+ * for the exact same data, in which its reference count is incremented.
+ *
+ * The lookup table entry is returned in @lte_ret.
+ *
+ * On failure @dentry and @lookup_table are not modified.
+ */
int dentry_set_symlink(struct dentry *dentry, const char *target,
struct lookup_table *lookup_table,
struct lookup_table_entry **lte_ret)
int ret;
size_t symlink_buf_len;
struct lookup_table_entry *lte = NULL, *existing_lte;
- u8 symlink_buf_hash[WIM_HASH_SIZE];
+ u8 symlink_buf_hash[SHA1_HASH_SIZE];
void *symlink_buf;
symlink_buf = make_symlink_reparse_data_buf(target, &symlink_buf_len);
return WIMLIB_ERR_NOMEM;
DEBUG("Made symlink reparse data buf (len = %zu, name len = %zu)",
- symlink_buf_len, ret);
+ symlink_buf_len, symlink_buf_len);
sha1_buffer(symlink_buf, symlink_buf_len, symlink_buf_hash);
existing_lte = __lookup_resource(lookup_table, symlink_buf_hash);
if (existing_lte) {
- existing_lte->refcnt++;
lte = existing_lte;
} else {
DEBUG("Creating new lookup table entry for symlink buf");
lte->symlink_buf = symlink_buf;
lte->resource_entry.original_size = symlink_buf_len;
lte->resource_entry.size = symlink_buf_len;
- memcpy(lte->hash, symlink_buf_hash, WIM_HASH_SIZE);
+ copy_hash(lte->hash, symlink_buf_hash);
}
- ret = dentry_set_symlink_buf(dentry, symlink_buf_hash);
+ ret = dentry_set_symlink_buf(dentry, lte);
if (ret != 0)
goto out_free_lte;
+ dentry->resolved = true;
+
DEBUG("Loaded symlink buf");
- if (!existing_lte)
+ if (existing_lte)
+ lte->refcnt++;
+ else
lookup_table_insert(lookup_table, lte);
if (lte_ret)
*lte_ret = lte;
= "Failed to open a directory",
[WIMLIB_ERR_READ]
= "Could not read data from a file",
+ [WIMLIB_ERR_READLINK]
+ = "Could not read the target of a symbolic link",
[WIMLIB_ERR_RENAME]
= "Could not rename a file",
+ [WIMLIB_ERR_SPECIAL_FILE]
+ = "Encountered a special file that cannot be archived",
[WIMLIB_ERR_SPLIT_INVALID]
= "The WIM is part of an invalid split WIM",
[WIMLIB_ERR_SPLIT_UNSUPPORTED]
}
/* Fills @n bytes pointer to by @p with random numbers. */
-void randomize_byte_array(void *__p, size_t n)
+void randomize_byte_array(u8 *p, size_t n)
{
- u8 *p = __p;
-
if (!seeded) {
srand(time(NULL));
seeded = true;
extern char *utf8_to_utf16(const char *utf8_str, size_t utf8_len,
size_t *utf16_len_ret);
-extern void randomize_byte_array(void *p, size_t n);
+extern void randomize_byte_array(u8 *p, size_t n);
extern void randomize_char_array_with_alnum(char p[], size_t n);
#ifdef ENABLE_DEBUG
DEBUG("Reading metadata resource specified by the following "
"lookup table entry:");
- print_lookup_table_entry(imd->metadata_lte, NULL);
+ print_lookup_table_entry(imd->metadata_lte);
#endif
return read_metadata_resource(w->fp,
wimlib_get_compression_type(w),
WIMLIB_ERR_NTFS_3G,
WIMLIB_ERR_OPEN,
WIMLIB_ERR_OPENDIR,
+ WIMLIB_ERR_READLINK,
WIMLIB_ERR_READ,
WIMLIB_ERR_RENAME,
+ WIMLIB_ERR_SPECIAL_FILE,
WIMLIB_ERR_SPLIT_INVALID,
WIMLIB_ERR_SPLIT_UNSUPPORTED,
WIMLIB_ERR_STAT,
struct stat;
-#ifndef WIM_HASH_SIZE
-#define WIM_HASH_SIZE 20
-#endif
-
#define WIM_MAGIC_LEN 8
#define WIM_GID_LEN 16
#define WIM_UNUSED_LEN 60
return &w->image_metadata[w->current_image - 1];
}
-/* Prints a hash code field. */
-static inline void print_hash(const u8 hash[])
-{
- print_byte_field(hash, WIM_HASH_SIZE);
-}
-
/* hardlink.c */
struct link_group_table *new_link_group_table(u64 capacity);