Various fixes
authorEric Biggers <ebiggers3@gmail.com>
Mon, 20 Aug 2012 22:27:14 +0000 (17:27 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 20 Aug 2012 22:27:14 +0000 (17:27 -0500)
17 files changed:
src/dentry.c
src/dentry.h
src/extract.c
src/hardlink.c
src/integrity.c
src/lookup_table.c
src/lookup_table.h
src/modify.c
src/mount.c
src/resource.c
src/sha1.h
src/symlink.c
src/util.c
src/util.h
src/wim.c
src/wimlib.h
src/wimlib_internal.h

index 98d117b..2f0cabd 100644 (file)
@@ -412,13 +412,12 @@ struct file_attr_flag file_attr_flags[] = {
  * 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);
@@ -429,9 +428,12 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        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);
@@ -446,25 +448,20 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        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;
 }
@@ -830,7 +827,7 @@ static int read_ads_entries(const u8 *p, struct dentry *dentry,
                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);
@@ -946,7 +943,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_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
@@ -1111,7 +1108,7 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
                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);
@@ -1141,7 +1138,11 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
        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);
index f8f0523..db6481b 100644 (file)
@@ -4,6 +4,7 @@
 #include "util.h"
 #include "config.h"
 #include "list.h"
+#include "sha1.h"
 #include <string.h>
 
 
@@ -16,10 +17,6 @@ typedef struct WIMStruct WIMStruct;
 
 #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
@@ -58,7 +55,7 @@ struct lookup_table_entry;
 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) */
@@ -155,7 +152,7 @@ struct dentry {
         * 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;
        };
 
@@ -241,31 +238,6 @@ struct dentry {
        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)
index 1648ade..8c3aedb 100644 (file)
@@ -209,7 +209,7 @@ static int extract_regular_file(WIMStruct *w,
 {
        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) {
index ba4f2e1..b32309f 100644 (file)
@@ -220,9 +220,8 @@ static bool dentries_have_same_ads(const struct dentry *d1,
                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;
@@ -247,7 +246,7 @@ static int share_dentry_ads(struct dentry *owner, struct dentry *user)
                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;
        }
index 55d950a..e310716 100644 (file)
@@ -50,7 +50,7 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size,
                            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;
@@ -85,11 +85,11 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size,
                        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;
@@ -181,7 +181,7 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
              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" "
@@ -264,7 +264,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
        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);
 
@@ -321,7 +321,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset,
                        goto err2;
                }
                sha1_buffer(chunk_buf, bytes_read, p);
-               p += WIM_HASH_SIZE;
+               p += SHA1_HASH_SIZE;
                bytes_remaining -= bytes_read;
        }
        if (show_progress)
index 2ccb0ef..a409947 100644 (file)
@@ -219,7 +219,7 @@ int read_lookup_table(FILE *fp, u64 offset, u64 size,
                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.");
@@ -258,7 +258,7 @@ int write_lookup_table_entry(struct lookup_table_entry *lte, void *__out)
        p = put_resource_entry(buf, &lte->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;
@@ -274,8 +274,12 @@ int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore)
        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", 
@@ -301,6 +305,12 @@ int print_lookup_table_entry(struct lookup_table_entry *lte, void *ignore)
        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;
 }
 
@@ -310,7 +320,7 @@ int print_lookup_table_entry(struct lookup_table_entry *lte, void *ignore)
 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);
 }
 
@@ -326,7 +336,7 @@ __lookup_resource(const struct lookup_table *table, const u8 hash[])
 
        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;
 }
@@ -398,7 +408,8 @@ int dentry_resolve_ltes(struct dentry *dentry, void *__table)
        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);
@@ -427,3 +438,13 @@ int dentry_resolve_ltes(struct dentry *dentry, void *__table)
        }
        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);
+}
+
index 8719814..6facf65 100644 (file)
@@ -2,6 +2,7 @@
 #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. */
@@ -23,7 +24,6 @@ struct lookup_table {
 
 struct wimlib_fd;
 
-
 /* 
  * An entry in the lookup table in the WIM file. 
  *
@@ -56,7 +56,7 @@ struct lookup_table_entry {
        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
@@ -125,6 +125,7 @@ struct lookup_table_entry {
        struct list_head staging_list;
 };
 
+
 extern struct lookup_table *new_lookup_table(size_t capacity);
 
 extern void lookup_table_insert(struct lookup_table *table, 
@@ -138,6 +139,7 @@ static inline void lookup_table_unlink(struct lookup_table *table,
        table->num_entries--;
 }
 
+
 extern struct lookup_table_entry *
 lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[]);
 
@@ -162,7 +164,7 @@ extern int lookup_resource(WIMStruct *w, const char *path,
 
 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);
@@ -195,4 +197,118 @@ static inline struct resource_entry* wim_metadata_resource_entry(WIMStruct *w)
                        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
index 5250ff6..f4aadf9 100644 (file)
@@ -78,7 +78,7 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path,
 {
        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)
@@ -98,8 +98,14 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path,
                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 */
@@ -141,32 +147,37 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path,
                /* 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) {
@@ -181,9 +192,10 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path,
                        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;
 }
@@ -201,40 +213,39 @@ struct wim_pair {
  * 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;
 }
@@ -283,7 +294,7 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry)
                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];
@@ -391,7 +402,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
 
 
        /* 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
@@ -400,7 +411,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        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);
@@ -514,12 +525,6 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir,
        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,
@@ -530,7 +535,7 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir,
                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;
index 25b6bcd..adfb7d6 100644 (file)
@@ -203,11 +203,15 @@ int dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf)
        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;
@@ -239,7 +243,7 @@ static int create_staging_file(char **name_ret, int open_flags)
        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;
@@ -251,7 +255,7 @@ static int create_staging_file(char **name_ret, int open_flags)
                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';
 
 
@@ -482,7 +486,7 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
        }
        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);
@@ -773,14 +777,14 @@ static int calculate_sha1sum_of_staging_file(struct lookup_table_entry *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);
 
@@ -1432,8 +1436,7 @@ static int wimfs_symlink(const char *to, const char *from)
        dentry->ads_entries[1].lte_group_list.type = STREAM_TYPE_ADS;
        list_add(&dentry->ads_entries[1].lte_group_list.list,
                 &lte->lte_group_list);
-       dentry->ads_entries[1].lte = lte;
-       dentry->resolved = true;
+       wimlib_assert(dentry->resolved);
 
        link_dentry(dentry, dentry_parent);
        return 0;
@@ -1595,7 +1598,7 @@ static int check_lte_refcnt(struct lookup_table_entry *lte, void *ignore)
                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;
        }
index 6608529..3797f62 100644 (file)
@@ -1043,12 +1043,11 @@ int write_metadata_resource(WIMStruct *w)
        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);
 
@@ -1098,28 +1097,23 @@ int write_metadata_resource(WIMStruct *w)
        /* 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 = &lte->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;
 
@@ -1213,12 +1207,13 @@ static int write_file_resource(WIMStruct *w, const u8 hash[])
 }
 
 /* 
- * 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. 
  */
@@ -1226,16 +1221,11 @@ int write_dentry_resources(struct dentry *dentry, void *wim_p)
 {
        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;
        }
index 69398ce..f668116 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <stddef.h>
 #include "string.h"
+#include "util.h"
 
 #define SHA1_HASH_SIZE 20
 
@@ -15,6 +16,28 @@ static inline bool is_empty_file_hash(const u8 hash[SHA1_HASH_SIZE])
        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);
 
index f16d8c2..03f7837 100644 (file)
@@ -145,31 +145,6 @@ out:
        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,
@@ -193,7 +168,6 @@ 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,
@@ -207,22 +181,36 @@ ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len,
 }
 
 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)
@@ -231,7 +219,7 @@ int dentry_set_symlink(struct dentry *dentry, const char *target,
        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);
@@ -239,14 +227,13 @@ int dentry_set_symlink(struct dentry *dentry, const char *target,
                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");
@@ -259,17 +246,21 @@ int dentry_set_symlink(struct dentry *dentry, const char *target,
                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;
index c229b5a..8bcfa20 100644 (file)
@@ -167,8 +167,12 @@ static const char *error_strings[] = {
                = "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] 
@@ -383,10 +387,8 @@ void randomize_char_array_with_alnum(char p[], size_t n)
 }
 
 /* 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;
index 73f86ed..1fb1f09 100644 (file)
@@ -124,7 +124,7 @@ extern char *utf16_to_utf8(const char *utf16_str, size_t utf16_len,
 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);
 
index b2ed8d9..d105e8b 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -223,7 +223,7 @@ int wimlib_select_image(WIMStruct *w, int image)
                #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), 
index 8121863..d2b230b 100644 (file)
@@ -343,8 +343,10 @@ enum wimlib_error_code {
        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,
index bc7505d..b33f728 100644 (file)
 
 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
@@ -312,12 +308,6 @@ static inline struct image_metadata *wim_get_current_image_metadata(WIMStruct *w
        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);