Various cleanups
authorEric Biggers <ebiggers3@gmail.com>
Fri, 26 Oct 2012 21:31:30 +0000 (16:31 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 26 Oct 2012 21:31:30 +0000 (16:31 -0500)
src/dentry.c
src/header.c
src/integrity.c
src/lookup_table.c
src/modify.c
src/resource.c
src/security.c
src/util.c
src/wim.c
src/wimlib.h
src/xml.c

index fa7ff56..bca9f35 100644 (file)
@@ -68,7 +68,7 @@ static u64 dentry_correct_length(const struct dentry *dentry)
  * Returns true if @dentry has the UTF-8 file name @name that has length
  * @name_len.
  */
-static bool dentry_has_name(const struct dentry *dentry, const char *name, 
+static bool dentry_has_name(const struct dentry *dentry, const char *name,
                            size_t name_len)
 {
        if (dentry->file_name_utf8_len != name_len)
@@ -199,7 +199,7 @@ void stbuf_to_inode(const struct stat *stbuf, struct inode *inode)
 }
 
 #ifdef WITH_FUSE
-/* Transfers file attributes from a struct inode to a `stat' buffer. 
+/* Transfers file attributes from a struct inode to a `stat' buffer.
  *
  * The lookup table entry tells us which stream in the inode we are statting.
  * For a named data stream, everything returned is the same as the unnamed data
@@ -244,11 +244,11 @@ int inode_to_stbuf(const struct inode *inode, struct lookup_table_entry *lte,
 }
 #endif
 
-/* 
+/*
  * Calls a function on all directory entries in a directory tree.  It is called
  * on a parent before its children.
  */
-int for_dentry_in_tree(struct dentry *root, 
+int for_dentry_in_tree(struct dentry *root,
                       int (*visitor)(struct dentry*, void*), void *arg)
 {
        int ret;
@@ -273,11 +273,11 @@ int for_dentry_in_tree(struct dentry *root,
        return 0;
 }
 
-/* 
+/*
  * Like for_dentry_in_tree(), but the visitor function is always called on a
  * dentry's children before on itself.
  */
-int for_dentry_in_tree_depth(struct dentry *root, 
+int for_dentry_in_tree_depth(struct dentry *root,
                             int (*visitor)(struct dentry*, void*), void *arg)
 {
        int ret;
@@ -297,9 +297,9 @@ int for_dentry_in_tree_depth(struct dentry *root,
        return visitor(root, arg);
 }
 
-/* 
+/*
  * Calculate the full path of @dentry, based on its parent's full path and on
- * its UTF-8 file name. 
+ * its UTF-8 file name.
  */
 int calculate_dentry_full_path(struct dentry *dentry, void *ignore)
 {
@@ -347,12 +347,12 @@ oom:
        return WIMLIB_ERR_NOMEM;
 }
 
-/* 
- * Recursively calculates the subdir offsets for a directory tree. 
+/*
+ * Recursively calculates the subdir offsets for a directory tree.
  *
  * @dentry:  The root of the directory tree.
  * @subdir_offset_p:  The current subdirectory offset; i.e., the subdirectory
- *     offset for @dentry. 
+ *     offset for @dentry.
  */
 void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p)
 {
@@ -389,14 +389,14 @@ void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p)
        }
 }
 
-/* Returns the child of @dentry that has the file name @name.  
+/* Returns the child of @dentry that has the file name @name.
  * Returns NULL if no child has the name. */
-struct dentry *get_dentry_child_with_name(const struct dentry *dentry, 
+struct dentry *get_dentry_child_with_name(const struct dentry *dentry,
                                          const char *name)
 {
        struct dentry *child;
        size_t name_len;
-       
+
        child = dentry->d_inode->children;
        if (child) {
                name_len = strlen(name);
@@ -557,7 +557,7 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        } else {
                hash = inode_stream_hash(inode, 0);
                if (hash) {
-                       printf("Hash              = 0x"); 
+                       printf("Hash              = 0x");
                        print_hash(hash);
                        putchar('\n');
                        putchar('\n');
@@ -570,7 +570,7 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
                        inode->ads_entries[i].stream_name_len);
                hash = inode_stream_hash(inode, i + 1);
                if (hash) {
-                       printf("Hash              = 0x"); 
+                       printf("Hash              = 0x");
                        print_hash(hash);
                        putchar('\n');
                }
@@ -613,7 +613,7 @@ static struct inode *new_inode()
        return inode;
 }
 
-/* 
+/*
  * Creates an unlinked directory entry.
  *
  * @name:  The UTF-8 filename of the new dentry.
@@ -623,7 +623,7 @@ static struct inode *new_inode()
 struct dentry *new_dentry(const char *name)
 {
        struct dentry *dentry;
-       
+
        dentry = MALLOC(sizeof(struct dentry));
        if (!dentry)
                goto err;
@@ -724,7 +724,7 @@ static void put_inode(struct inode *inode)
        }
 }
 
-/* Frees a WIM dentry. 
+/* Frees a WIM dentry.
  *
  * The inode is freed only if its link count is decremented to 0.
  */
@@ -751,7 +751,7 @@ void put_dentry(struct dentry *dentry)
                free_dentry(dentry);
 }
 
-/* 
+/*
  * This function is passed as an argument to for_dentry_in_tree_depth() in order
  * to free a directory tree.  __args is a pointer to a `struct free_dentry_args'.
  */
@@ -775,7 +775,7 @@ static int do_free_dentry(struct dentry *dentry, void *__lookup_table)
        return 0;
 }
 
-/* 
+/*
  * Unlinks and frees a dentry tree.
  *
  * @root:              The root of the tree.
@@ -797,7 +797,7 @@ int increment_dentry_refcnt(struct dentry *dentry, void *ignore)
        return 0;
 }
 
-/* 
+/*
  * Links a dentry into the directory tree.
  *
  * @dentry: The dentry to link.
@@ -823,8 +823,8 @@ void link_dentry(struct dentry *dentry, struct dentry *parent)
 
 
 #ifdef WITH_FUSE
-/* 
- * Unlink a dentry from the directory tree. 
+/*
+ * Unlink a dentry from the directory tree.
  *
  * Note: This merely removes it from the in-memory tree structure.
  */
@@ -928,7 +928,7 @@ static int verify_inode(struct inode *inode, const WIMStruct *w)
                        num_unnamed_streams++;
        }
        if (num_unnamed_streams > 1) {
-               ERROR("Dentry `%s' has multiple (%u) un-named streams", 
+               ERROR("Dentry `%s' has multiple (%u) un-named streams",
                      first_dentry->full_path_utf8, num_unnamed_streams);
                goto out;
        }
@@ -1010,7 +1010,7 @@ struct ads_entry *inode_get_ads_entry(struct inode *inode,
 #endif
 
 #if defined(WITH_FUSE) || defined(WITH_NTFS_3G)
-/* 
+/*
  * Add an alternate stream entry to an inode and return a pointer to it, or NULL
  * if memory could not be allocated.
  */
@@ -1076,7 +1076,7 @@ void inode_remove_ads(struct inode *inode, u16 idx,
 
 
 
-/* 
+/*
  * Reads the alternate data stream entries for a dentry.
  *
  * @p: Pointer to buffer that starts with the first alternate stream entry.
@@ -1092,7 +1092,7 @@ void inode_remove_ads(struct inode *inode, u16 idx,
  *
  * struct ads_entry_on_disk {
  *     u64  length;          // Length of the entry, in bytes.  This includes
- *                                 all fields (including the stream name and 
+ *                                 all fields (including the stream name and
  *                                 null terminator if present, AND the padding!).
  *     u64  reserved;        // Seems to be unused
  *     u8   hash[20];        // SHA1 message digest of the uncompressed stream
@@ -1240,7 +1240,7 @@ out_free_ads_entries:
        return ret;
 }
 
-/* 
+/*
  * Reads a directory entry, including all alternate data stream entries that
  * follow it, from the WIM image's metadata resource.
  *
@@ -1255,7 +1255,7 @@ out_free_ads_entries:
  * special "end of directory" dentry and not a real dentry.  If nonzero, this
  * was a real dentry.
  */
-int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, 
+int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                u64 offset, struct dentry *dentry)
 {
        const u8 *p;
@@ -1330,7 +1330,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        p = get_u64(p, &inode->last_write_time);
 
        p = get_bytes(p, SHA1_HASH_SIZE, inode->hash);
-       
+
        /*
         * I don't know what's going on here.  It seems like M$ screwed up the
         * reparse points, then put the fields in the same place and didn't
@@ -1349,14 +1349,14 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
 
        /* By the way, the reparse_reserved field does not actually exist (at
         * least when the file is not a reparse point) */
-       
+
        p = get_u16(p, &inode->num_ads);
 
        p = get_u16(p, &short_name_len);
        p = get_u16(p, &file_name_len);
 
        /* We now know the length of the file name and short name.  Make sure
-        * the length of the dentry is large enough to actually hold them. 
+        * the length of the dentry is large enough to actually hold them.
         *
         * The calculated length here is unaligned to allow for the possibility
         * that the dentry->length names an unaligned length, although this
@@ -1367,7 +1367,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        if (dentry->length < calculated_size) {
                ERROR("Unexpected end of directory entry! (Expected "
                      "at least %"PRIu64" bytes, got %"PRIu64" bytes. "
-                     "short_name_len = %hu, file_name_len = %hu)", 
+                     "short_name_len = %hu, file_name_len = %hu)",
                      calculated_size, dentry->length,
                      short_name_len, file_name_len);
                return WIMLIB_ERR_INVALID_DENTRY;
@@ -1385,7 +1385,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                p = get_bytes(p, file_name_len, file_name);
 
                /* Convert filename to UTF-8. */
-               file_name_utf8 = utf16_to_utf8(file_name, file_name_len, 
+               file_name_utf8 = utf16_to_utf8(file_name, file_name_len,
                                               &file_name_utf8_len);
 
                if (!file_name_utf8) {
@@ -1450,7 +1450,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                p += 2;
        }
 
-       /* 
+       /*
         * Read the alternate data streams, if present.  dentry->num_ads tells
         * us how many they are, and they will directly follow the dentry
         * on-disk.
@@ -1520,7 +1520,7 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        struct dentry cur_child;
        int ret;
 
-       /* 
+       /*
         * If @dentry has no child dentries, nothing more needs to be done for
         * this branch.  This is the case for regular files, symbolic links, and
         * *possibly* empty directories (although an empty directory may also
@@ -1533,7 +1533,7 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        while (1) {
 
                /* Read next child of @dentry into @cur_child. */
-               ret = read_dentry(metadata_resource, metadata_resource_len, 
+               ret = read_dentry(metadata_resource, metadata_resource_len,
                                  cur_offset, &cur_child);
                if (ret != 0)
                        break;
@@ -1567,7 +1567,7 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                /* If there are children of this child, call this procedure
                 * recursively. */
                if (child->subdir_offset != 0) {
-                       ret = read_dentry_tree(metadata_resource, 
+                       ret = read_dentry_tree(metadata_resource,
                                               metadata_resource_len, child);
                        if (ret != 0)
                                break;
@@ -1591,7 +1591,7 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        return ret;
 }
 
-/* 
+/*
  * Writes a WIM dentry to an output buffer.
  *
  * @dentry:  The dentry structure.
@@ -1681,7 +1681,7 @@ static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p)
        if (parent->subdir_offset == 0)
                return p;
 
-       /* Write child dentries and end-of-directory entry. 
+       /* Write child dentries and end-of-directory entry.
         *
         * Note: we need to write all of this dentry's children before
         * recursively writing the directory trees rooted at each of the child
index 68ea052..5563d70 100644 (file)
@@ -32,7 +32,7 @@ static const u8 wim_magic_chars[WIM_MAGIC_LEN] = {
                        'M', 'S', 'W', 'I', 'M', '\0', '\0', '\0' };
 
 /* Reads the header for a WIM file.  */
-int read_header(FILE *fp, struct wim_header *hdr, int split_ok)
+int read_header(FILE *fp, struct wim_header *hdr, int open_flags)
 {
        size_t bytes_read;
        u8 buf[WIM_HEADER_DISK_SIZE];
@@ -66,7 +66,7 @@ int read_header(FILE *fp, struct wim_header *hdr, int split_ok)
        /* Byte 12 */
 
        if (hdr_size != WIM_HEADER_DISK_SIZE) {
-               DEBUG("ERROR: Header is size %u (expected %u)",
+               ERROR("Header is %u bytes (expected %u bytes)",
                      hdr_size, WIM_HEADER_DISK_SIZE);
                return WIMLIB_ERR_INVALID_HEADER_SIZE;
        }
@@ -104,7 +104,9 @@ int read_header(FILE *fp, struct wim_header *hdr, int split_ok)
        p = get_u16(p, &hdr->part_number);
        p = get_u16(p, &hdr->total_parts);
 
-       if (!split_ok && (hdr->part_number != 1 || hdr->total_parts != 1)) {
+       if (!(open_flags & WIMLIB_OPEN_FLAG_SPLIT_OK)
+           && (hdr->part_number != 1 || hdr->total_parts != 1))
+       {
                ERROR("This WIM is part %u of a %u-part WIM",
                      hdr->part_number, hdr->total_parts);
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
index 70ff7ff..f94b743 100644 (file)
@@ -201,6 +201,12 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
        end_lookup_table_offset = w->hdr.lookup_table_res_entry.offset +
                                  w->hdr.lookup_table_res_entry.size;
 
+       if (end_lookup_table_offset < WIM_HEADER_DISK_SIZE) {
+               ERROR("WIM lookup table ends before WIM header ends???");
+               ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
+               goto out;
+       }
+
        bytes_to_check = end_lookup_table_offset - WIM_HEADER_DISK_SIZE;
 
        expected_num_entries = (bytes_to_check + chunk_size - 1) / chunk_size;
index 02125ae..1226488 100644 (file)
@@ -61,15 +61,14 @@ struct lookup_table_entry *new_lookup_table_entry()
        struct lookup_table_entry *lte;
        
        lte = CALLOC(1, sizeof(struct lookup_table_entry));
-       if (!lte) {
+       if (lte) {
+               lte->part_number  = 1;
+               lte->refcnt       = 1;
+       } else {
                ERROR("Out of memory (tried to allocate %zu bytes for "
                      "lookup table entry)",
                      sizeof(struct lookup_table_entry));
-               return NULL;
        }
-
-       lte->part_number  = 1;
-       lte->refcnt       = 1;
        return lte;
 }
 
@@ -278,7 +277,8 @@ int read_lookup_table(WIMStruct *w)
              w->hdr.lookup_table_res_entry.offset,
              w->hdr.lookup_table_res_entry.original_size);
 
-       if (fseeko(w->fp, w->hdr.lookup_table_res_entry.offset, SEEK_SET) != 0) {
+       if (fseeko(w->fp, w->hdr.lookup_table_res_entry.offset, SEEK_SET) != 0)
+       {
                ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" to read "
                                 "lookup table",
                                 w->hdr.lookup_table_res_entry.offset);
@@ -323,7 +323,6 @@ int read_lookup_table(WIMStruct *w)
                              w->hdr.part_number, cur_entry->part_number);
                        ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
                        goto out_free_cur_entry;
-                       
                }
 
                if (is_zero_hash(cur_entry->hash)) {
@@ -347,7 +346,7 @@ int read_lookup_table(WIMStruct *w)
 
                if (!(cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED)
                    && (cur_entry->resource_entry.size !=
-                     cur_entry->resource_entry.original_size))
+                       cur_entry->resource_entry.original_size))
                {
                        ERROR("Found uncompressed resource with original size "
                              "not the same as compressed size");
index b0da749..775312c 100644 (file)
@@ -55,7 +55,7 @@ void destroy_image_metadata(struct image_metadata *imd, struct lookup_table *lt)
                lookup_table_remove(lt, imd->metadata_lte);
 }
 
-/* 
+/*
  * Recursively builds a dentry tree from a directory tree on disk, outside the
  * WIM file.
  *
@@ -63,10 +63,10 @@ void destroy_image_metadata(struct image_metadata *imd, struct lookup_table *lt)
  *             modified if successful.  NULL if the file or directory was
  *             excluded from capture.
  *
- * @root_disk_path:  The path to the root of the directory tree on disk. 
+ * @root_disk_path:  The path to the root of the directory tree on disk.
  *
  * @lookup_table: The lookup table for the WIM file.  For each file added to the
- *             dentry tree being built, an entry is added to the lookup table, 
+ *             dentry tree being built, an entry is added to the lookup table,
  *             unless an identical stream is already in the lookup table.
  *             These lookup table entries that are added point to the path of
  *             the file on disk.
@@ -128,7 +128,7 @@ static int build_dentry_tree(struct dentry **root_ret,
                return WIMLIB_ERR_STAT;
        }
 
-       if ((add_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) && 
+       if ((add_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
              !S_ISDIR(root_stbuf.st_mode)) {
                ERROR("`%s' is not a directory", root_disk_path);
                return WIMLIB_ERR_NOTDIR;
@@ -202,7 +202,7 @@ static int build_dentry_tree(struct dentry **root_ret,
        } else if (dentry_is_symlink(root)) { /* Archiving a symbolic link */
                char deref_name_buf[4096];
                ssize_t deref_name_len;
-               
+       
                deref_name_len = readlink(root_disk_path, deref_name_buf,
                                          sizeof(deref_name_buf) - 1);
                if (deref_name_len >= 0) {
@@ -307,7 +307,7 @@ static int allocate_lte_if_needed(struct dentry *dentry, void *arg)
        return 0;
 }
 
-/* 
+/*
  * This function takes in a dentry that was previously located only in image(s)
  * in @src_wim, but now is being added to @dest_wim.  For each stream associated
  * with the dentry, if there is already a lookup table entry for that stream in
@@ -362,7 +362,7 @@ static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
 /*
  * Adds an image (given by its dentry tree) to the image metadata array of a WIM
  * file, adds an entry to the lookup table for the image metadata, updates the
- * image count in the header, and selects the new image. 
+ * image count in the header, and selects the new image.
  *
  * Does not update the XML data.
  *
@@ -392,9 +392,9 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry,
                return WIMLIB_ERR_NOMEM;
        }
 
-       memcpy(imd, w->image_metadata, 
+       memcpy(imd, w->image_metadata,
               w->hdr.image_count * sizeof(struct image_metadata));
-       
+
        metadata_lte = new_lookup_table_entry();
        if (!metadata_lte)
                goto out_free_imd;
@@ -431,11 +431,11 @@ out_free_imd:
 /*
  * Copies an image, or all the images, from a WIM file, into another WIM file.
  */
-WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, 
-                                 int src_image, 
-                                 WIMStruct *dest_wim, 
-                                 const char *dest_name, 
-                                 const char *dest_description, 
+WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
+                                 int src_image,
+                                 WIMStruct *dest_wim,
+                                 const char *dest_name,
+                                 const char *dest_description,
                                  int flags,
                                  WIMStruct **additional_swms,
                                  unsigned num_additional_swms)
@@ -461,7 +461,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
 
                        /* multi-image export. */
 
-                       if ((flags & WIMLIB_EXPORT_FLAG_BOOT) && 
+                       if ((flags & WIMLIB_EXPORT_FLAG_BOOT) &&
                              (src_wim->hdr.boot_idx == 0))
                        {
                                /* Specifying the boot flag on a multi-image
@@ -486,7 +486,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                if (i != src_wim->hdr.boot_idx)
                                        export_flags &= ~WIMLIB_EXPORT_FLAG_BOOT;
 
-                               ret = wimlib_export_image(src_wim, i, dest_wim, 
+                               ret = wimlib_export_image(src_wim, i, dest_wim,
                                                          NULL, NULL,
                                                          export_flags,
                                                          additional_swms,
@@ -495,8 +495,10 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                        return ret;
                        }
                        return 0;
+               } else if (src_wim->hdr.image_count == 1) {
+                       src_image = 1;
                } else {
-                       src_image = 1; 
+                       return 0;
                }
        }
 
@@ -600,8 +602,8 @@ out:
        return ret;
 }
 
-/* 
- * Deletes an image from the WIM. 
+/*
+ * Deletes an image from the WIM.
  */
 WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image)
 {
@@ -742,7 +744,7 @@ static int init_capture_config(const char *_config_str, size_t config_len,
                FREE(config_str);
                return WIMLIB_ERR_NOMEM;
        }
-       
+
        memcpy(config_str, _config_str, config_len);
        next_p = config_str;
        config->config_str = config_str;
@@ -758,7 +760,7 @@ static int init_capture_config(const char *_config_str, size_t config_len,
                        ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
                        goto out_destroy;
                }
-               
+       
                next_p = eol + 1;
                bytes_remaining -= (next_p - p);
                if (eol == p)
@@ -887,7 +889,7 @@ bool exclude_path(const char *path, const struct capture_config *config,
                     && path[config->prefix_len] == '/')
                        path += config->prefix_len;
        }
-       return match_pattern(path, basename, &config->exclusion_list) && 
+       return match_pattern(path, basename, &config->exclusion_list) &&
                !match_pattern(path, basename, &config->exclusion_exception);
 
 }
@@ -910,7 +912,7 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
                 const char *config_str, size_t config_len,
                 int flags,
                 int (*capture_tree)(struct dentry **, const char *,
-                                    struct lookup_table *, 
+                                    struct lookup_table *,
                                     struct wim_security_data *,
                                     const struct capture_config *,
                                     int, void *),
@@ -1027,7 +1029,7 @@ out_destroy_config:
 /*
  * Adds an image to a WIM file from a directory tree on disk.
  */
-WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, 
+WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir,
                               const char *name, const char *config_str,
                               size_t config_len, int flags)
 {
index d35d936..be9bd7c 100644 (file)
@@ -390,8 +390,21 @@ const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry)
        p = get_u8(p, &flags);
        entry->size = size;
        entry->flags = flags;
+
+       /* offset and original_size are truncated to 62 bits to avoid possible
+        * overflows, when converting to a signed 64-bit integer (off_t) or when
+        * adding size or original_size.  This is okay since no one would ever
+        * actually have a WIM bigger than 4611686018427387903 bytes... */
        p = get_u64(p, &entry->offset);
+       if (entry->offset & 0xc000000000000000ULL) {
+               WARNING("Truncating offset in resource entry");
+               entry->offset &= 0x3fffffffffffffffULL;
+       }
        p = get_u64(p, &entry->original_size);
+       if (entry->original_size & 0xc000000000000000ULL) {
+               WARNING("Truncating original_size in resource entry");
+               entry->original_size &= 0x3fffffffffffffffULL;
+       }
        return p;
 }
 
index 63ab5ba..c05dd06 100644 (file)
@@ -285,6 +285,8 @@ static void print_security_descriptor(const u8 *p, u64 size)
  */
 void print_security_data(const struct wim_security_data *sd)
 {
+       wimlib_assert(sd != NULL);
+
        puts("[SECURITY DATA]");
        printf("Length            = %"PRIu32" bytes\n", sd->total_length);
        printf("Number of Entries = %"PRIu32"\n", sd->num_entries);
index 1df757f..b68db91 100644 (file)
@@ -106,97 +106,97 @@ WIMLIBAPI int wimlib_set_print_errors(bool show_error_messages)
 }
 
 static const char *error_strings[] = {
-       [WIMLIB_ERR_SUCCESS] 
+       [WIMLIB_ERR_SUCCESS]
                = "Success",
-       [WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE] 
+       [WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE]
                = "Lookup table is compressed",
-       [WIMLIB_ERR_DECOMPRESSION] 
+       [WIMLIB_ERR_DECOMPRESSION]
                = "Failed to decompress compressed data",
-       [WIMLIB_ERR_DELETE_STAGING_DIR] 
+       [WIMLIB_ERR_DELETE_STAGING_DIR]
                = "Failed to delete staging directory",
-       [WIMLIB_ERR_FORK] 
+       [WIMLIB_ERR_FORK]
                = "Failed to fork another process",
-       [WIMLIB_ERR_FUSE] 
+       [WIMLIB_ERR_FUSE]
                = "An error was returned by fuse_main()",
-       [WIMLIB_ERR_FUSERMOUNT] 
+       [WIMLIB_ERR_FUSERMOUNT]
                = "Could not execute the `fusermount' program, or it exited "
                        "with a failure status",
-       [WIMLIB_ERR_IMAGE_COUNT] 
+       [WIMLIB_ERR_IMAGE_COUNT]
                = "Inconsistent image count among the metadata "
                        "resources, the WIM header, and/or the XML data",
-       [WIMLIB_ERR_IMAGE_NAME_COLLISION] 
+       [WIMLIB_ERR_IMAGE_NAME_COLLISION]
                = "Tried to add an image with a name that is already in use",
-       [WIMLIB_ERR_INTEGRITY] 
+       [WIMLIB_ERR_INTEGRITY]
                = "The WIM failed an integrity check",
        [WIMLIB_ERR_INVALID_CAPTURE_CONFIG]
                = "The capture configuration string was invalid",
-       [WIMLIB_ERR_INVALID_CHUNK_SIZE] 
+       [WIMLIB_ERR_INVALID_CHUNK_SIZE]
                = "The WIM is compressed but does not have a chunk "
                        "size of 32768",
-       [WIMLIB_ERR_INVALID_COMPRESSION_TYPE] 
+       [WIMLIB_ERR_INVALID_COMPRESSION_TYPE]
                = "The WIM is compressed, but is not marked as having LZX or "
                        "XPRESS compression",
-       [WIMLIB_ERR_INVALID_DENTRY] 
+       [WIMLIB_ERR_INVALID_DENTRY]
                = "A directory entry in the WIM was invalid",
-       [WIMLIB_ERR_INVALID_HEADER_SIZE] 
+       [WIMLIB_ERR_INVALID_HEADER_SIZE]
                = "The WIM header was not 208 bytes",
-       [WIMLIB_ERR_INVALID_IMAGE] 
+       [WIMLIB_ERR_INVALID_IMAGE]
                = "Tried to select an image that does not exist in the WIM",
-       [WIMLIB_ERR_INVALID_INTEGRITY_TABLE] 
+       [WIMLIB_ERR_INVALID_INTEGRITY_TABLE]
                = "The WIM's integrity table is invalid",
        [WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY]
                = "An entry in the WIM's lookup table is invalid",
-       [WIMLIB_ERR_INVALID_PARAM] 
+       [WIMLIB_ERR_INVALID_PARAM]
                = "An invalid parameter was given",
        [WIMLIB_ERR_INVALID_RESOURCE_HASH]
                = "The SHA1 message digest of a WIM resource did not match the expected value",
-       [WIMLIB_ERR_INVALID_RESOURCE_SIZE] 
-               = "A resource entry in the WIM is invalid",
-       [WIMLIB_ERR_LINK] 
+       [WIMLIB_ERR_INVALID_RESOURCE_SIZE]
+               = "A resource entry in the WIM has an invalid size",
+       [WIMLIB_ERR_LINK]
                = "Failed to create a hard or symbolic link when extracting "
                        "a file from the WIM",
-       [WIMLIB_ERR_MKDIR] 
+       [WIMLIB_ERR_MKDIR]
                = "Failed to create a directory",
-       [WIMLIB_ERR_MQUEUE] 
+       [WIMLIB_ERR_MQUEUE]
                = "Failed to create or use a POSIX message queue",
-       [WIMLIB_ERR_NOMEM] 
+       [WIMLIB_ERR_NOMEM]
                = "Ran out of memory",
-       [WIMLIB_ERR_NOTDIR] 
+       [WIMLIB_ERR_NOTDIR]
                = "Expected a directory",
-       [WIMLIB_ERR_NOT_A_WIM_FILE] 
+       [WIMLIB_ERR_NOT_A_WIM_FILE]
                = "The file did not begin with the magic characters that "
                        "identify a WIM file",
-       [WIMLIB_ERR_NO_FILENAME] 
+       [WIMLIB_ERR_NO_FILENAME]
                = "The WIM is not identified with a filename",
        [WIMLIB_ERR_NTFS_3G]
                = "NTFS-3g encountered an error (check errno)",
-       [WIMLIB_ERR_OPEN] 
+       [WIMLIB_ERR_OPEN]
                = "Failed to open a file",
-       [WIMLIB_ERR_OPENDIR] 
+       [WIMLIB_ERR_OPENDIR]
                = "Failed to open a directory",
-       [WIMLIB_ERR_READ] 
+       [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] 
+       [WIMLIB_ERR_RENAME]
                = "Could not rename a file",
        [WIMLIB_ERR_SPECIAL_FILE]
                = "Encountered a special file that cannot be archived",
-       [WIMLIB_ERR_SPLIT_INVALID] 
+       [WIMLIB_ERR_SPLIT_INVALID]
                = "The WIM is part of an invalid split WIM",
-       [WIMLIB_ERR_SPLIT_UNSUPPORTED] 
+       [WIMLIB_ERR_SPLIT_UNSUPPORTED]
                = "The WIM is part of a split WIM, which is not supported for this operation",
-       [WIMLIB_ERR_STAT] 
+       [WIMLIB_ERR_STAT]
                = "Could not read the metadata for a file or directory",
-       [WIMLIB_ERR_TIMEOUT] 
+       [WIMLIB_ERR_TIMEOUT]
                = "Timed out",
-       [WIMLIB_ERR_UNKNOWN_VERSION] 
+       [WIMLIB_ERR_UNKNOWN_VERSION]
                = "The WIM file is marked with an unknown version number",
-       [WIMLIB_ERR_UNSUPPORTED] 
+       [WIMLIB_ERR_UNSUPPORTED]
                = "The requested operation is unsupported",
-       [WIMLIB_ERR_WRITE] 
+       [WIMLIB_ERR_WRITE]
                = "Failed to write data to a file",
-       [WIMLIB_ERR_XML] 
+       [WIMLIB_ERR_XML]
                = "The XML data of the WIM is invalid",
 };
 
@@ -228,8 +228,8 @@ char *wimlib_strdup(const char *str)
 {
        size_t size;
        char *p;
-       
-       size = strlen(str); 
+
+       size = strlen(str);
        p = MALLOC(size + 1);
        if (p)
                memcpy(p, str, size + 1);
@@ -250,7 +250,7 @@ WIMLIBAPI int wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
        wimlib_free_func    = free_func    ? free_func    : free;
        wimlib_realloc_func = realloc_func ? realloc_func : realloc;
 
-       xml_set_memory_allocator(wimlib_malloc_func, wimlib_free_func, 
+       xml_set_memory_allocator(wimlib_malloc_func, wimlib_free_func,
                                 wimlib_realloc_func);
        return 0;
 #else
@@ -287,7 +287,7 @@ char *utf16_to_utf8(const char *utf16_str, size_t utf16_len,
 
        char *orig_utf8_str = utf8_str;
 
-       size_t num_chars_converted = iconv(cd_utf16_to_utf8, (char**)&utf16_str, 
+       size_t num_chars_converted = iconv(cd_utf16_to_utf8, (char**)&utf16_str,
                        &utf16_bytes_left, &utf8_str, &utf8_bytes_left);
 
        if (num_chars_converted == (size_t)(-1)) {
@@ -330,7 +330,7 @@ char *utf8_to_utf16(const char *utf8_str, size_t utf8_len,
 
        char *orig_utf16_str = utf16_str;
 
-       size_t num_chars_converted = iconv(cd_utf8_to_utf16, (char**)&utf8_str, 
+       size_t num_chars_converted = iconv(cd_utf8_to_utf16, (char**)&utf8_str,
                        &utf8_bytes_left, &utf16_str, &utf16_bytes_left);
 
        if (num_chars_converted == (size_t)(-1)) {
@@ -444,7 +444,7 @@ const char *path_basename(const char *path)
        return p + 1;
 }
 
-/* 
+/*
  * Returns a pointer to the part of @path following the first colon in the last
  * path component, or NULL if the last path component does not contain a colon.
  */
@@ -458,7 +458,7 @@ const char *path_stream_name(const char *path)
                return stream_name + 1;
 }
 
-/* 
+/*
  * Splits a file path into the part before the first '/', or the entire name if
  * there is no '/', and the part after the first sequence of '/' characters.
  *
@@ -466,7 +466,7 @@ const char *path_stream_name(const char *path)
  * @first_part_len_ret: A pointer to a `size_t' into which the length of the
  *                             first part of the path will be returned.
  * @return:            A pointer to the next part of the path, after the first
- *                             sequence of '/', or a pointer to the terminating 
+ *                             sequence of '/', or a pointer to the terminating
  *                             null byte in the case of a path without any '/'.
  */
 const char *path_next_part(const char *path, size_t *first_part_len_ret)
@@ -501,9 +501,9 @@ int get_num_path_components(const char *path)
 }
 
 
-/* 
+/*
  * Prints a string.  Printable characters are printed as-is, while unprintable
- * characters are printed as their octal escape codes. 
+ * characters are printed as their octal escape codes.
  */
 void print_string(const void *string, size_t len)
 {
index fe21649..2883b6a 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -6,7 +6,7 @@
  * Copyright (C) 2010 Carl Thijssen
  * Copyright (C) 2012 Eric Biggers
  *
- * wimlib - Library for working with WIM files 
+ * wimlib - Library for working with WIM files
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
 
 static int print_metadata(WIMStruct *w)
 {
+       DEBUG("Printing metadata for image %d", w->current_image);
        print_security_data(wim_security_data(w));
-       return for_dentry_in_tree(wim_root_dentry(w), print_dentry, 
+       return for_dentry_in_tree(wim_root_dentry(w), print_dentry,
                                  w->lookup_table);
 }
 
 
 static int print_files(WIMStruct *w)
 {
-       return for_dentry_in_tree(wim_root_dentry(w), print_dentry_full_path, 
+       return for_dentry_in_tree(wim_root_dentry(w), print_dentry_full_path,
                                  NULL);
 }
 
@@ -57,7 +58,7 @@ WIMStruct *new_wim_struct()
        return CALLOC(1, sizeof(WIMStruct));
 }
 
-/* 
+/*
  * Calls a function on images in the WIM.  If @image is WIM_ALL_IMAGES, @visitor
  * is called on the WIM once for each image, with each image selected as the
  * current image in turn.  If @image is a certain image, @visitor is called on
@@ -66,19 +67,20 @@ WIMStruct *new_wim_struct()
 int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *))
 {
        int ret;
-       int i;
+       int start;
        int end;
+       int i;
 
        if (image == WIM_ALL_IMAGES) {
-               i = 1;
+               start = 1;
                end = w->hdr.image_count;
-       } else {
-               if (image < 1 || image > w->hdr.image_count)
-                       return WIMLIB_ERR_INVALID_IMAGE;
-               i = image;
+       } else if (image >= 1 && image <= w->hdr.image_count) {
+               start = image;
                end = image;
+       } else {
+               return WIMLIB_ERR_INVALID_IMAGE;
        }
-       for (; i <= end; i++) {
+       for (i = start; i <= end; i++) {
                ret = select_wim_image(w, i);
                if (ret != 0)
                        return ret;
@@ -91,10 +93,10 @@ int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *))
 
 static int sort_image_metadata_by_position(const void *p1, const void *p2)
 {
-       struct image_metadata *bmd1 = (struct image_metadata*)p1;
-       struct image_metadata *bmd2 = (struct image_metadata*)p2;
-       u64 offset1 = bmd1->metadata_lte->resource_entry.offset;
-       u64 offset2 = bmd2->metadata_lte->resource_entry.offset;
+       const struct image_metadata *imd1 = p1;
+       const struct image_metadata *imd2 = p2;
+       u64 offset1 = imd1->metadata_lte->resource_entry.offset;
+       u64 offset2 = imd2->metadata_lte->resource_entry.offset;
        if (offset1 < offset2)
                return -1;
        else if (offset1 > offset2)
@@ -103,31 +105,31 @@ static int sort_image_metadata_by_position(const void *p1, const void *p2)
                return 0;
 }
 
-/* 
+/*
  * If @lte points to a metadata resource, append it to the list of metadata
  * resources in the WIMStruct.  Otherwise, do nothing.
  */
-static int append_metadata_resource_entry(struct lookup_table_entry *lte, 
+static int append_metadata_resource_entry(struct lookup_table_entry *lte,
                                          void *wim_p)
 {
        WIMStruct *w = wim_p;
+       int ret = 0;
 
        if (lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) {
-               /*fprintf(stderr, "found mlte at %u\n", lte->resource_entry.offset);*/
                if (w->current_image == w->hdr.image_count) {
                        ERROR("Expected only %u images, but found more",
                              w->hdr.image_count);
-                       return WIMLIB_ERR_IMAGE_COUNT;
+                       ret = WIMLIB_ERR_IMAGE_COUNT;
                } else {
                        DEBUG("Found metadata resource for image %u at "
                              "offset %"PRIu64".",
-                             w->current_image + 1, 
+                             w->current_image + 1,
                              lte->resource_entry.offset);
                        w->image_metadata[
                                w->current_image++].metadata_lte = lte;
                }
        }
-       return 0;
+       return ret;
 }
 
 /* Returns the compression type given in the flags of a WIM header. */
@@ -285,7 +287,7 @@ WIMLIBAPI int wimlib_resolve_image(WIMStruct *w, const char *image_name_or_num)
 WIMLIBAPI void wimlib_print_wim_information(const WIMStruct *w)
 {
        const struct wim_header *hdr;
-       
+
        hdr = &w->hdr;
        puts("WIM Information:");
        puts("----------------");
@@ -298,7 +300,7 @@ WIMLIBAPI void wimlib_print_wim_information(const WIMStruct *w)
                                                wimlib_get_compression_type(w)));
        printf("Part Number:    %d/%d\n", hdr->part_number, hdr->total_parts);
        printf("Boot Index:     %d\n", hdr->boot_idx);
-       printf("Size:           %"PRIu64" bytes\n", 
+       printf("Size:           %"PRIu64" bytes\n",
                                wim_info_get_total_bytes(w->wim_info));
        printf("Integrity Info: %s\n", (w->hdr.integrity.size != 0) ? "yes" : "no");
        putchar('\n');
@@ -311,20 +313,28 @@ WIMLIBAPI bool wimlib_has_integrity_table(const WIMStruct *w)
 
 WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image)
 {
+       int first;
+       int last;
+       int i;
+       int n;
        if (image == WIM_ALL_IMAGES) {
-               puts("Available Images:");
-               puts("-----------------");
-       } else {
-               int n;
-               int i;
-
+               n = printf("Available Images:\n");
+               first = 1;
+               last = w->hdr.image_count;
+       } else if (image >= 1 && image <= w->hdr.image_count) {
                n = printf("Information for Image %d\n", image);
-               for (i = 0; i < n - 1; i++)
-                       putchar('-');
-               putchar('\n');
-
+               first = image;
+               last = image;
+       } else {
+               printf("wimlib_print_available_images(): Invalid image %d",
+                      image);
+               return;
        }
-       print_image_info(w->wim_info, image);
+       for (i = 0; i < n - 1; i++)
+               putchar('-');
+       putchar('\n');
+       for (i = first; i <= last; i++)
+               print_image_info(w->wim_info, i);
 }
 
 
@@ -335,15 +345,11 @@ WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image)
        if (!w)
                return WIMLIB_ERR_INVALID_PARAM;
        if (w->hdr.part_number != 1) {
-               ERROR("We cannot show the metadata from part %hu of a %hu-part split WIM.",
+               ERROR("Cannot show the metadata from part %hu of a %hu-part split WIM!",
                       w->hdr.part_number, w->hdr.total_parts);
                ERROR("Select the first part of the split WIM to see the metadata.");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
-       if (image == WIM_ALL_IMAGES)
-               DEBUG("Printing metadata for all images");
-       else
-               DEBUG("Printing metadata for image %d", image);
        return for_image(w, image, print_metadata);
 }
 
@@ -352,7 +358,7 @@ WIMLIBAPI int wimlib_print_files(WIMStruct *w, int image)
        if (!w)
                return WIMLIB_ERR_INVALID_PARAM;
        if (w->hdr.part_number != 1) {
-               ERROR("We cannot list the files from part %hu of a %hu-part split WIM",
+               ERROR("Cannot list the files from part %hu of a %hu-part split WIM!",
                       w->hdr.part_number, w->hdr.total_parts);
                ERROR("Select the first part of the split WIM if you'd like to list the files.");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
@@ -366,21 +372,12 @@ WIMLIBAPI int wimlib_set_boot_idx(WIMStruct *w, int boot_idx)
        if (!w)
                return WIMLIB_ERR_INVALID_PARAM;
        if (w->hdr.total_parts != 1) {
-               ERROR("We cannot modify the boot index of a split WIM");
+               ERROR("Cannot modify the boot index of a split WIM!");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
        if (boot_idx < 0 || boot_idx > w->hdr.image_count)
                return WIMLIB_ERR_INVALID_IMAGE;
        w->hdr.boot_idx = boot_idx;
-       if (boot_idx == 0) {
-               memset(&w->hdr.boot_metadata_res_entry, 0, 
-                      sizeof(struct resource_entry));
-       } else {
-               memcpy(&w->hdr.boot_metadata_res_entry,
-                      &w->image_metadata[
-                               boot_idx - 1].metadata_lte->resource_entry, 
-                      sizeof(struct resource_entry));
-       }
        return 0;
 }
 
@@ -390,18 +387,18 @@ WIMLIBAPI int wimlib_get_part_number(const WIMStruct *w, int *total_parts_ret)
                *total_parts_ret = w->hdr.total_parts;
        return w->hdr.part_number;
 }
-                                   
+
 
 WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w)
 {
        return w->hdr.boot_idx;
 }
 
-/* 
+/*
  * Begins the reading of a WIM file; opens the file and reads its header and
  * lookup table, and optionally checks the integrity.
  */
-static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
+static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags)
 {
        int ret;
        uint xml_num_images;
@@ -422,7 +419,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
                return WIMLIB_ERR_OPEN;
        }
 
-       ret = read_header(w->fp, &w->hdr, flags & WIMLIB_OPEN_FLAG_SPLIT_OK);
+       ret = read_header(w->fp, &w->hdr, open_flags);
        if (ret != 0)
                return ret;
 
@@ -431,8 +428,8 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        /* If the boot index is invalid, print a warning and set it to 0 */
        if (w->hdr.boot_idx > w->hdr.image_count) {
                WARNING("In `%s', image %u is marked as bootable, "
-                       "but there are only %u images",
-                        in_wim_path, w->hdr.boot_idx, w->hdr.image_count);
+                       "but there are only %u images in the WIM",
+                       in_wim_path, w->hdr.boot_idx, w->hdr.image_count);
                w->hdr.boot_idx = 0;
        }
 
@@ -443,15 +440,13 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        }
 
 
-       if (flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY) {
+       if (open_flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY) {
                int integrity_status;
-               ret = check_wim_integrity(w, 
-                                         flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS, 
+               ret = check_wim_integrity(w,
+                                         open_flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS,
                                          &integrity_status);
-               if (ret != 0) {
-                       ERROR("Error in check_wim_integrity()");
+               if (ret != 0)
                        return ret;
-               }
                if (integrity_status == WIM_INTEGRITY_NONEXISTENT) {
                        WARNING("No integrity information for `%s'; skipping "
                                "integrity check.", w->filename);
@@ -471,7 +466,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        if (ret != 0)
                return ret;
 
-       w->image_metadata = CALLOC(w->hdr.image_count, 
+       w->image_metadata = CALLOC(w->hdr.image_count,
                                   sizeof(struct image_metadata));
 
        if (!w->image_metadata) {
@@ -484,7 +479,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        DEBUG("Looking for metadata resources in the lookup table.");
 
        /* Find the images in the WIM by searching the lookup table. */
-       ret = for_lookup_table_entry(w->lookup_table, 
+       ret = for_lookup_table_entry(w->lookup_table,
                                     append_metadata_resource_entry, w);
 
        if (ret != 0)
@@ -492,7 +487,9 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
 
        /* Make sure all the expected images were found.  (We already have
         * returned false if *extra* images were found) */
-       if (w->current_image != w->hdr.image_count && w->hdr.part_number == 1) {
+       if (w->current_image != w->hdr.image_count &&
+           w->hdr.part_number == 1)
+       {
                ERROR("Only found %u images in WIM, but expected %u",
                      w->current_image, w->hdr.image_count);
                return WIMLIB_ERR_IMAGE_COUNT;
@@ -509,7 +506,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        w->current_image = WIM_NO_IMAGE;
 
        /* Read the XML data. */
-       ret = read_xml_data(w->fp, &w->hdr.xml_res_entry, 
+       ret = read_xml_data(w->fp, &w->hdr.xml_res_entry,
                            &w->xml_data, &w->wim_info);
 
        if (ret != 0) {
@@ -534,27 +531,27 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
 /*
  * Opens a WIM file and creates a WIMStruct for it.
  */
-WIMLIBAPI int wimlib_open_wim(const char *wim_file, int flags, 
+WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags,
                              WIMStruct **w_ret)
 {
        WIMStruct *w;
        int ret;
 
-       DEBUG("wim_file = `%s', flags = %#x", wim_file, flags);
+       DEBUG("wim_file = `%s', open_flags = %#x", wim_file, open_flags);
        w = new_wim_struct();
        if (!w) {
                ERROR("Failed to allocate memory for WIMStruct");
                return WIMLIB_ERR_NOMEM;
        }
 
-       ret = begin_read(w, wim_file, flags);
-       if (ret != 0) {
+       ret = begin_read(w, wim_file, open_flags);
+       if (ret == 0) {
+               *w_ret = w;
+       } else {
                DEBUG("Could not begin reading the WIM file `%s'", wim_file);
                wimlib_free(w);
-               return ret;
        }
-       *w_ret = w;
-       return 0;
+       return ret;
 }
 
 /* Frees the memory for the WIMStruct, including all internal memory; also
index ad8db22..5ed6c68 100644 (file)
@@ -1129,7 +1129,9 @@ extern int wimlib_overwrite_xml_and_header(WIMStruct *wim, int flags);
  *     image, or ::WIM_ALL_IMAGES to print information about all images in the
  *     WIM.
  * 
- * @return This function has no return value.
+ * @return This function has no return value.  No error checking is done when
+ * printing the information.  If @a image is invalid, an error message is
+ * printed.
  */
 extern void wimlib_print_available_images(const WIMStruct *wim, int image);
 
index 4403989..89d08e0 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -246,7 +246,7 @@ void free_wim_info(struct wim_info *info)
 
 /* Reads the information from a <VERSION> element inside the <WINDOWS> element.
  * */
-static void xml_read_windows_version(const xmlNode *version_node, 
+static void xml_read_windows_version(const xmlNode *version_node,
                                     struct windows_version* windows_version)
 {
        xmlNode *child;
@@ -268,8 +268,8 @@ static void xml_read_windows_version(const xmlNode *version_node,
 
 /* Reads the information from a <LANGUAGE> element inside a <WINDOWS> element.
  * */
-static int xml_read_languages(const xmlNode *languages_node, 
-                             char ***languages_ret, 
+static int xml_read_languages(const xmlNode *languages_node,
+                             char ***languages_ret,
                              u64 *num_languages_ret,
                              char **default_language_ret)
 {
@@ -309,7 +309,7 @@ static int xml_read_languages(const xmlNode *languages_node,
 }
 
 /* Reads the information from a <WINDOWS> element inside an <IMAGE> element. */
-static int xml_read_windows_info(const xmlNode *windows_node, 
+static int xml_read_windows_info(const xmlNode *windows_node,
                                 struct windows_info *windows_info)
 {
        xmlNode *child;
@@ -321,27 +321,27 @@ static int xml_read_windows_info(const xmlNode *windows_node,
                if (node_name_is(child, "ARCH")) {
                        windows_info->arch = node_get_u64(child);
                } else if (node_name_is(child, "PRODUCTNAME")) {
-                       ret = node_get_string(child, 
+                       ret = node_get_string(child,
                                              &windows_info->product_name);
                } else if (node_name_is(child, "EDITIONID")) {
-                       ret = node_get_string(child, 
+                       ret = node_get_string(child,
                                              &windows_info->edition_id);
                } else if (node_name_is(child, "INSTALLATIONTYPE")) {
-                       ret = node_get_string(child, 
+                       ret = node_get_string(child,
                                              &windows_info->installation_type);
                } else if (node_name_is(child, "PRODUCTTYPE")) {
-                       ret = node_get_string(child, 
+                       ret = node_get_string(child,
                                              &windows_info->product_type);
                } else if (node_name_is(child, "PRODUCTSUITE")) {
-                       ret = node_get_string(child, 
+                       ret = node_get_string(child,
                                              &windows_info->product_suite);
                } else if (node_name_is(child, "LANGUAGES")) {
-                       ret = xml_read_languages(child, 
+                       ret = xml_read_languages(child,
                                                 &windows_info->languages,
                                                 &windows_info->num_languages,
                                                 &windows_info->default_language);
                } else if (node_name_is(child, "VERSION")) {
-                       xml_read_windows_version(child, 
+                       xml_read_windows_version(child,
                                                &windows_info->windows_version);
                        windows_info->windows_version_exists = true;
                } else if (node_name_is(child, "SYSTEMROOT")) {
@@ -357,13 +357,13 @@ static int xml_read_windows_info(const xmlNode *windows_node,
 }
 
 /* Reads the information from an <IMAGE> element. */
-static int xml_read_image_info(xmlNode *image_node, 
+static int xml_read_image_info(xmlNode *image_node,
                               struct image_info *image_info)
 {
        xmlNode *child;
        xmlChar *index_prop;
        int ret;
-       
+
        index_prop = xmlGetProp(image_node, "INDEX");
        if (index_prop) {
                char *tmp;
@@ -470,7 +470,7 @@ static int xml_read_wim_info(const xmlNode *wim_node,
        }
 
        /* Sort the array of struct image_infos by image index. */
-       qsort(wim_info->images, wim_info->num_images, 
+       qsort(wim_info->images, wim_info->num_images,
              sizeof(struct image_info), sort_by_index);
 done:
        *wim_info_ret = wim_info;
@@ -487,33 +487,52 @@ static void print_windows_info(const struct windows_info *windows_info)
        const struct windows_version *windows_version;
 
        printf("Architecture:           %s\n", get_arch(windows_info->arch));
-       printf("Product Name:           %s\n", windows_info->product_name);
-       printf("Edition ID:             %s\n", windows_info->edition_id);
-       printf("Installation Type:      %s\n", windows_info->installation_type);
+
+       if (windows_info->product_name)
+               printf("Product Name:           %s\n",
+                      windows_info->product_name);
+
+       if (windows_info->edition_id)
+               printf("Edition ID:             %s\n",
+                      windows_info->edition_id);
+
+       if (windows_info->installation_type)
+               printf("Installation Type:      %s\n",
+                      windows_info->installation_type);
+
        if (windows_info->hal)
                printf("HAL:                    %s\n", windows_info->hal);
-       printf("Product Type:           %s\n", windows_info->product_type);
+
+       if (windows_info->product_type)
+               printf("Product Type:           %s\n",
+                      windows_info->product_type);
+
        if (windows_info->product_suite)
-               printf("Product Suite:          %s\n", windows_info->product_suite);
+               printf("Product Suite:          %s\n",
+                      windows_info->product_suite);
        printf("Languages:              ");
        for (i = 0; i < windows_info->num_languages; i++) {
                fputs(windows_info->languages[i], stdout);
                putchar(' ');
        }
        putchar('\n');
-       printf("Default Language:       %s\n", windows_info->default_language);
-       printf("System Root:            %s\n", windows_info->system_root);
+       if (windows_info->default_language)
+               printf("Default Language:       %s\n",
+                      windows_info->default_language);
+       if (windows_info->system_root)
+               printf("System Root:            %s\n",
+                      windows_info->system_root);
        if (windows_info->windows_version_exists) {
                windows_version = &windows_info->windows_version;
-               printf("Major Version:          %"PRIu64"\n", 
+               printf("Major Version:          %"PRIu64"\n",
                                windows_version->major);
-               printf("Minor Version:          %"PRIu64"\n", 
+               printf("Minor Version:          %"PRIu64"\n",
                                windows_version->minor);
-               printf("Build:                  %"PRIu64"\n", 
+               printf("Build:                  %"PRIu64"\n",
                                windows_version->build);
-               printf("Service Pack Build:     %"PRIu64"\n", 
+               printf("Service Pack Build:     %"PRIu64"\n",
                                windows_version->sp_build);
-               printf("Service Pack Level:     %"PRIu64"\n", 
+               printf("Service Pack Level:     %"PRIu64"\n",
                                windows_version->sp_level);
        }
 }
@@ -522,35 +541,35 @@ static void print_windows_info(const struct windows_info *windows_info)
 /* Writes the information contained in a struct windows_version structure to the XML
  * document being constructed in memory.  This is the <VERSION> element inside
  * the <WINDOWS> element. */
-static int xml_write_windows_version(xmlTextWriter *writer, 
-                                       const struct windows_version *version)
+static int xml_write_windows_version(xmlTextWriter *writer,
+                                    const struct windows_version *version)
 {
        int rc;
        rc = xmlTextWriterStartElement(writer, "VERSION");
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "MAJOR", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "MAJOR", "%"PRIu64,
                                                                version->major);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "MINOR", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "MINOR", "%"PRIu64,
                                                                version->minor);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "BUILD", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "BUILD", "%"PRIu64,
                                                                version->build);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "SPBUILD", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "SPBUILD", "%"PRIu64,
                                                                version->sp_build);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "SPLEVEL", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "SPLEVEL", "%"PRIu64,
                                                                version->sp_level);
        if (rc < 0)
                return rc;
@@ -560,8 +579,8 @@ static int xml_write_windows_version(xmlTextWriter *writer,
 
 /* Writes the information contained in a struct windows_info structure to the XML
  * document being constructed in memory. This is the <WINDOWS> element. */
-static int xml_write_windows_info(xmlTextWriter *writer, 
-                                       const struct windows_info *windows_info)
+static int xml_write_windows_info(xmlTextWriter *writer,
+                                 const struct windows_info *windows_info)
 {
        int rc;
        rc = xmlTextWriterStartElement(writer, "WINDOWS");
@@ -569,55 +588,55 @@ static int xml_write_windows_info(xmlTextWriter *writer,
                return rc;
 
 
-       rc = xmlTextWriterWriteFormatElement(writer, "ARCH", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "ARCH", "%"PRIu64,
                                                        windows_info->arch);
        if (rc < 0)
                return rc;
-       
+
        if (windows_info->product_name) {
-               rc = xmlTextWriterWriteElement(writer, "PRODUCTNAME", 
+               rc = xmlTextWriterWriteElement(writer, "PRODUCTNAME",
                                                        windows_info->product_name);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->edition_id) {
-               rc = xmlTextWriterWriteElement(writer, "EDITIONID", 
+               rc = xmlTextWriterWriteElement(writer, "EDITIONID",
                                                        windows_info->edition_id);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->installation_type) {
-               rc = xmlTextWriterWriteElement(writer, "INSTALLATIONTYPE", 
+               rc = xmlTextWriterWriteElement(writer, "INSTALLATIONTYPE",
                                                        windows_info->installation_type);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->hal) {
-               rc = xmlTextWriterWriteElement(writer, "HAL", 
+               rc = xmlTextWriterWriteElement(writer, "HAL",
                                                        windows_info->hal);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->system_root) {
-               rc = xmlTextWriterWriteElement(writer, "SYSTEMROOT", 
+               rc = xmlTextWriterWriteElement(writer, "SYSTEMROOT",
                                                windows_info->system_root);
                        if (rc < 0)
                                return rc;
        }
 
        if (windows_info->product_type) {
-               rc = xmlTextWriterWriteElement(writer, "PRODUCTTYPE", 
+               rc = xmlTextWriterWriteElement(writer, "PRODUCTTYPE",
                                                windows_info->product_type);
                if (rc < 0)
                        return rc;
        }
 
        if (windows_info->product_suite) {
-               rc = xmlTextWriterWriteElement(writer, "PRODUCTSUITE", 
+               rc = xmlTextWriterWriteElement(writer, "PRODUCTSUITE",
                                                windows_info->product_suite);
                        if (rc < 0)
                                return rc;
@@ -629,12 +648,12 @@ static int xml_write_windows_info(xmlTextWriter *writer,
                        return rc;
 
                for (int i = 0; i < windows_info->num_languages; i++) {
-                       rc = xmlTextWriterWriteElement(writer, "LANGUAGE", 
+                       rc = xmlTextWriterWriteElement(writer, "LANGUAGE",
                                                        windows_info->languages[i]);
                        if (rc < 0)
                                return rc;
                }
-               rc = xmlTextWriterWriteElement(writer, "DEFAULT", 
+               rc = xmlTextWriterWriteElement(writer, "DEFAULT",
                                                windows_info->default_language);
                if (rc < 0)
                        return rc;
@@ -654,15 +673,15 @@ static int xml_write_windows_info(xmlTextWriter *writer,
 }
 
 /* Writes a time element to the XML document being constructed in memory. */
-static int xml_write_time(xmlTextWriter *writer, const char *element_name, 
-                                                               u64 time) 
+static int xml_write_time(xmlTextWriter *writer, const char *element_name,
+                         u64 time)
 {
        int rc;
        rc = xmlTextWriterStartElement(writer, element_name);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "HIGHPART", 
+       rc = xmlTextWriterWriteFormatElement(writer, "HIGHPART",
                                        "0x%"PRIX32, (u32)(time >> 32));
        if (rc < 0)
                return rc;
@@ -680,7 +699,7 @@ static int xml_write_time(xmlTextWriter *writer, const char *element_name,
 
 
 /* Writes an <IMAGE> element to the XML document. */
-static int xml_write_image_info(xmlTextWriter *writer, 
+static int xml_write_image_info(xmlTextWriter *writer,
                                const struct image_info *image_info)
 {
        int rc;
@@ -688,37 +707,37 @@ static int xml_write_image_info(xmlTextWriter *writer,
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatAttribute(writer, "INDEX", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatAttribute(writer, "INDEX", "%"PRIu64,
                                                image_info->index);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "DIRCOUNT", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "DIRCOUNT", "%"PRIu64,
                                                image_info->dir_count);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "FILECOUNT", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "FILECOUNT", "%"PRIu64,
                                                image_info->file_count);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "TOTALBYTES", "%"PRIu64,
                                                image_info->total_bytes);
        if (rc < 0)
                return rc;
 
-       rc = xmlTextWriterWriteFormatElement(writer, "HARDLINKBYTES", "%"PRIu64, 
+       rc = xmlTextWriterWriteFormatElement(writer, "HARDLINKBYTES", "%"PRIu64,
                                                image_info->hard_link_bytes);
        if (rc < 0)
                return rc;
 
-       rc = xml_write_time(writer, "CREATIONTIME", 
+       rc = xml_write_time(writer, "CREATIONTIME",
                                                image_info->creation_time);
        if (rc < 0)
                return rc;
 
-       rc = xml_write_time(writer, "LASTMODIFICATIONTIME", 
+       rc = xml_write_time(writer, "LASTMODIFICATIONTIME",
                                                image_info->last_modification_time);
        if (rc < 0)
                return rc;
@@ -737,19 +756,19 @@ static int xml_write_image_info(xmlTextWriter *writer,
                        return rc;
        }
        if (image_info->description) {
-               rc = xmlTextWriterWriteElement(writer, "DESCRIPTION", 
+               rc = xmlTextWriterWriteElement(writer, "DESCRIPTION",
                                                        image_info->description);
                if (rc < 0)
                        return rc;
        }
        if (image_info->display_name) {
-               rc = xmlTextWriterWriteElement(writer, "DISPLAYNAME", 
+               rc = xmlTextWriterWriteElement(writer, "DISPLAYNAME",
                                                image_info->display_name);
                if (rc < 0)
                        return rc;
        }
        if (image_info->display_description) {
-               rc = xmlTextWriterWriteElement(writer, "DISPLAYDESCRIPTION", 
+               rc = xmlTextWriterWriteElement(writer, "DISPLAYDESCRIPTION",
                                                image_info->display_description);
                if (rc < 0)
                        return rc;
@@ -784,7 +803,7 @@ static struct image_info *add_image_info_struct(struct wim_info *wim_info)
        return &images[wim_info->num_images - 1];
 }
 
-static int clone_windows_info(const struct windows_info *old, 
+static int clone_windows_info(const struct windows_info *old,
                              struct windows_info *new)
 {
        uint i;
@@ -793,7 +812,7 @@ static int clone_windows_info(const struct windows_info *old,
                return WIMLIB_ERR_NOMEM;
        if (old->edition_id && !(new->edition_id = STRDUP(old->edition_id)))
                return WIMLIB_ERR_NOMEM;
-       if (old->installation_type && !(new->installation_type = 
+       if (old->installation_type && !(new->installation_type =
                                        STRDUP(old->installation_type)))
                return WIMLIB_ERR_NOMEM;
        if (old->hal && !(new->hal = STRDUP(old->hal)))
@@ -816,7 +835,7 @@ static int clone_windows_info(const struct windows_info *old,
                                return WIMLIB_ERR_NOMEM;
                }
        }
-       if (old->default_language && 
+       if (old->default_language &&
                        !(new->default_language = STRDUP(old->default_language)))
                return WIMLIB_ERR_NOMEM;
        if (old->system_root && !(new->system_root = STRDUP(old->system_root)))
@@ -859,13 +878,13 @@ static int clone_image_info(const struct image_info *old, struct image_info *new
 
        if (old->windows_info_exists) {
                new->windows_info_exists = true;
-               return clone_windows_info(&old->windows_info, 
+               return clone_windows_info(&old->windows_info,
                                          &new->windows_info);
        }
        return 0;
 }
 
-/* Copies the XML information for an image between WIM files. 
+/* Copies the XML information for an image between WIM files.
  *
  * @dest_image_name and @dest_image_description are ignored if they are NULL;
  * otherwise, they are used to override the image name and/or image description
@@ -874,10 +893,10 @@ static int clone_image_info(const struct image_info *old, struct image_info *new
  * On failure, WIMLIB_ERR_NOMEM is returned and no changes are made.  Otherwise,
  * 0 is returned and the WIM information at *new_wim_info_p is modified.
  */
-int xml_export_image(const struct wim_info *old_wim_info, 
-                    int image, 
-                    struct wim_info **new_wim_info_p, 
-                    const char *dest_image_name, 
+int xml_export_image(const struct wim_info *old_wim_info,
+                    int image,
+                    struct wim_info **new_wim_info_p,
+                    const char *dest_image_name,
                     const char *dest_image_description)
 {
        struct wim_info *new_wim_info;
@@ -933,7 +952,7 @@ void xml_delete_image(struct wim_info **wim_info_p, int image)
        int i;
 
        DEBUG("Deleting image %d from the XML data.", image);
-       
+
        wim_info = *wim_info_p;
 
        wimlib_assert(wim_info);
@@ -974,7 +993,7 @@ void xml_set_memory_allocator(void *(*malloc_func)(size_t),
 
 static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
 {
-       struct image_info *info = arg; 
+       struct image_info *info = arg;
        struct lookup_table *lookup_table = info->lookup_table;
        const struct inode *inode = dentry->d_inode;
        struct lookup_table_entry *lte;
@@ -996,7 +1015,7 @@ static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
        else
                info->file_count++;
 
-       /* 
+       /*
         * Update total bytes and hard link bytes.
         *
         * Unfortunately there are some inconsistencies/bugs in the way this is
@@ -1046,7 +1065,7 @@ static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
 void xml_update_image_info(WIMStruct *w, int image)
 {
        struct image_info *image_info;
-       struct dentry *root; 
+       struct dentry *root;
        char *flags_save;
 
        DEBUG("Updating the image info for image %d", image);
@@ -1064,7 +1083,7 @@ void xml_update_image_info(WIMStruct *w, int image)
        for_dentry_in_tree(w->image_metadata[image - 1].root_dentry,
                           calculate_dentry_statistics,
                           image_info);
-                          
+                        
        image_info->lookup_table = NULL;
        image_info->flags = flags_save;
        image_info->last_modification_time = get_wim_timestamp();
@@ -1117,85 +1136,76 @@ out_free_wim_info:
        return WIMLIB_ERR_NOMEM;
 }
 
-/* Prints information about the specified image from struct wim_info structure. 
- * @image may be WIM_ALL_IMAGES. */
+/* Prints information about the specified image from struct wim_info structure.
+ * */
 void print_image_info(const struct wim_info *wim_info, int image)
 {
        uint i;
        const struct image_info *image_info;
        const char *desc;
+       int start;
+       int end;
+       time_t time;
+       char *p;
 
+       wimlib_assert(image >= 1 && image <= wim_info->num_images);
 
-       if (image == WIM_ALL_IMAGES) {
-               for (i = 1; i <= wim_info->num_images; i++)
-                       print_image_info(wim_info, i);
-       } else {
-               time_t time;
-               char *p;
+       image_info = &wim_info->images[image - 1];
 
-               image_info = &wim_info->images[image - 1];
+       printf("Index:                  %"PRIu64"\n", image_info->index);
+       printf("Name:                   %s\n", image_info->name);
 
-               printf("Index:                  %"PRIu64"\n", 
-                       image_info->index);
-               printf("Name:                   %s\n", 
-                       image_info->name);
-
-               /* Always print the Description: part even if there is no
-                * description. */
-               if (image_info->description)
-                       desc = image_info->description;
-               else
-                       desc = "";
-               printf("Description:            %s\n", desc);
-
-               if (image_info->display_name)
-                       printf("Display Name:           %s\n", 
-                               image_info->display_name);
-
-               if (image_info->display_description)
-                       printf("Display Description:    %s\n", 
-                               image_info->display_description);
-
-               printf("Directory Count:        %"PRIu64"\n", 
-                               image_info->dir_count);
-               printf("File Count:             %"PRIu64"\n", 
-                               image_info->file_count);
-               printf("Total Bytes:            %"PRIu64"\n", 
-                               image_info->total_bytes);
-               printf("Hard Link Bytes:        %"PRIu64"\n", 
-                               image_info->hard_link_bytes);
-
-               time = wim_timestamp_to_unix(image_info->creation_time);
-               p = asctime(gmtime(&time));
-               *(strrchr(p, '\n')) = '\0';
-
-               printf("Creation Time:          %s UTC\n", p);
-
-               time = wim_timestamp_to_unix(image_info->last_modification_time);
-               p = asctime(gmtime(&time));
-               *(strrchr(p, '\n')) = '\0';
-
-               printf("Last Modification Time: %s UTC\n", p);
-               if (image_info->windows_info_exists)
-                       print_windows_info(&image_info->windows_info);
-               if (image_info->flags)
-                       printf("Flags:                  %s\n", image_info->flags);
-               putchar('\n');
-       }
+       /* Always print the Description: part even if there is no
+        * description. */
+       if (image_info->description)
+               desc = image_info->description;
+       else
+               desc = "";
+       printf("Description:            %s\n", desc);
+
+       if (image_info->display_name)
+               printf("Display Name:           %s\n",
+                      image_info->display_name);
+
+       if (image_info->display_description)
+               printf("Display Description:    %s\n",
+                      image_info->display_description);
+
+       printf("Directory Count:        %"PRIu64"\n", image_info->dir_count);
+       printf("File Count:             %"PRIu64"\n", image_info->file_count);
+       printf("Total Bytes:            %"PRIu64"\n", image_info->total_bytes);
+       printf("Hard Link Bytes:        %"PRIu64"\n", image_info->hard_link_bytes);
+
+       time = wim_timestamp_to_unix(image_info->creation_time);
+       p = asctime(gmtime(&time));
+       *(strrchr(p, '\n')) = '\0';
+
+       printf("Creation Time:          %s UTC\n", p);
+
+       time = wim_timestamp_to_unix(image_info->last_modification_time);
+       p = asctime(gmtime(&time));
+       *(strrchr(p, '\n')) = '\0';
+
+       printf("Last Modification Time: %s UTC\n", p);
+       if (image_info->windows_info_exists)
+               print_windows_info(&image_info->windows_info);
+       if (image_info->flags)
+               printf("Flags:                  %s\n", image_info->flags);
+       putchar('\n');
 }
 
-/* 
+/*
  * Reads the XML data from a WIM file.
  */
-int read_xml_data(FILE *fp, const struct resource_entry *res, u8 **xml_data_ret,
-                 struct wim_info **info_ret)
+int read_xml_data(FILE *fp, const struct resource_entry *res,
+                 u8 **xml_data_ret, struct wim_info **info_ret)
 {
        u8 *xml_data;
        xmlDoc *doc;
        xmlNode *root;
        int ret;
 
-       DEBUG("XML data is %"PRIu64" bytes at offset %"PRIu64"", 
+       DEBUG("XML data is %"PRIu64" bytes at offset %"PRIu64"",
              (u64)res->size, res->offset);
 
        if (resource_is_compressed(res)) {
@@ -1273,14 +1283,14 @@ out_cleanup_parser:
                                goto err2; \
                        } })
 
-/* 
+/*
  * Writes XML data to a WIM file.
  *
  * If @total_bytes is non-zero, it specifies what to write to the TOTALBYTES
  * element in the XML data.  If zero, TOTALBYTES is given the default value of
  * the offset of the XML data.
  */
-int write_xml_data(const struct wim_info *wim_info, int image, FILE *out, 
+int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
                   u64 total_bytes)
 {
        xmlBuffer     *buf;
@@ -1294,8 +1304,8 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
        size_t utf16_len;
        size_t bytes_written;
 
-       wimlib_assert(image == WIM_ALL_IMAGES || 
-                       (wim_info != NULL && image >= 1 && 
+       wimlib_assert(image == WIM_ALL_IMAGES ||
+                       (wim_info != NULL && image >= 1 &&
                         image <= wim_info->num_images));
 
        /* The contents of the <TOTALBYTES> element in the XML data, under the
@@ -1373,7 +1383,7 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
                goto err2;
        }
 
-       if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF) || 
+       if ((putc(0xff, out)) == EOF || (putc(0xfe, out) == EOF) ||
                ((bytes_written = fwrite(utf16_str, 1, utf16_len, out))
                                != utf16_len)) {
                ERROR_WITH_ERRNO("Error writing XML data");
@@ -1405,7 +1415,7 @@ WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image)
 }
 
 /* Returns the description of the specified image. */
-WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w, 
+WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w,
                                                   int image)
 {
        DEBUG("Getting the description of image %d", image);
@@ -1433,7 +1443,7 @@ WIMLIBAPI bool wimlib_image_name_in_use(const WIMStruct *w, const char *name)
 WIMLIBAPI int wimlib_extract_xml_data(WIMStruct *w, FILE *fp)
 {
        DEBUG("Extracting the XML data.");
-       if (fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp) != 
+       if (fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp) !=
                        w->hdr.xml_res_entry.size) {
                ERROR_WITH_ERRNO("Failed to extract XML data");
                return WIMLIB_ERR_WRITE;
@@ -1482,7 +1492,7 @@ WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name)
 }
 
 /* Sets the description of an image in the WIM. */
-WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image, 
+WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image,
                                          const char *description)
 {
        char *p;