]> wimlib.net Git - wimlib/blobdiff - src/wim.c
Windows native build
[wimlib] / src / wim.c
index 117361c140bf0ebc3a968ca2f9d100a9281b3b5f..1ffc3fef442dccb5e0760bcd28db5f3cbbd99a31 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -1,10 +1,9 @@
 /*
- * wim.c
+ * wim.c - Stuff that doesn't fit into any other file
  */
 
 /*
- * Copyright (C) 2010 Carl Thijssen
- * Copyright (C) 2012 Eric Biggers
+ * Copyright (C) 2012, 2013 Eric Biggers
  *
  * wimlib - Library for working with WIM files
  *
  */
 
 #include "config.h"
+
+#ifdef __WIN32__
+#      include <windows.h>
+#      ifdef ERROR
+#              undef ERROR
+#      endif
+#endif
+
 #include <limits.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <errno.h>
 
 #include "dentry.h"
 #include <unistd.h>
 #endif
 
 #include "wimlib_internal.h"
-#include "io.h"
+#include "buffer_io.h"
 #include "lookup_table.h"
 #include "xml.h"
 
-static int print_metadata(WIMStruct *w)
+#ifdef __WIN32__
+static char *realpath(const char *path, char *resolved_path)
+{
+       DWORD ret;
+       wimlib_assert(resolved_path == NULL);
+
+       ret = GetFullPathNameA(path, 0, NULL, NULL);
+       if (!ret)
+               goto fail_win32;
+
+       resolved_path = MALLOC(ret + 1);
+       if (!resolved_path)
+               goto fail;
+       ret = GetFullPathNameA(path, ret, resolved_path, NULL);
+       if (!ret) {
+               free(resolved_path);
+               goto fail_win32;
+       }
+       return resolved_path;
+fail_win32:
+       win32_error(GetLastError());
+fail:
+       return NULL;
+}
+#endif
+
+static int image_print_metadata(WIMStruct *w)
 {
        DEBUG("Printing metadata for image %d", w->current_image);
        print_security_data(wim_security_data(w));
@@ -52,13 +86,13 @@ static int print_metadata(WIMStruct *w)
 }
 
 
-static int print_files(WIMStruct *w)
+static int image_print_files(WIMStruct *w)
 {
        return for_dentry_in_tree(wim_root_dentry(w), print_dentry_full_path,
                                  NULL);
 }
 
-WIMStruct *new_wim_struct()
+static WIMStruct *new_wim_struct()
 {
        WIMStruct *w = CALLOC(1, sizeof(WIMStruct));
 #ifdef WITH_FUSE
@@ -107,8 +141,8 @@ int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *))
 
 static int sort_image_metadata_by_position(const void *p1, const void *p2)
 {
-       const struct image_metadata *imd1 = p1;
-       const struct image_metadata *imd2 = p2;
+       const struct wim_image_metadata *imd1 = p1;
+       const struct wim_image_metadata *imd2 = p2;
        u64 offset1 = imd1->metadata_lte->resource_entry.offset;
        u64 offset2 = imd2->metadata_lte->resource_entry.offset;
        if (offset1 < offset2)
@@ -123,7 +157,7 @@ static int sort_image_metadata_by_position(const void *p1, const void *p2)
  * 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 wim_lookup_table_entry *lte,
                                          void *wim_p)
 {
        WIMStruct *w = wim_p;
@@ -148,7 +182,7 @@ static int append_metadata_resource_entry(struct lookup_table_entry *lte,
 }
 
 /* Returns the compression type given in the flags of a WIM header. */
-int wim_hdr_flags_compression_type(int wim_hdr_flags)
+static int wim_hdr_flags_compression_type(int wim_hdr_flags)
 {
        if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESSION) {
                if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESS_LZX)
@@ -168,7 +202,7 @@ int wim_hdr_flags_compression_type(int wim_hdr_flags)
 WIMLIBAPI int wimlib_create_new_wim(int ctype, WIMStruct **w_ret)
 {
        WIMStruct *w;
-       struct lookup_table *table;
+       struct wim_lookup_table *table;
        int ret;
 
        DEBUG("Creating new WIM with %s compression.",
@@ -203,7 +237,8 @@ WIMLIBAPI int wimlib_get_num_images(const WIMStruct *w)
 
 int select_wim_image(WIMStruct *w, int image)
 {
-       struct image_metadata *imd;
+       struct wim_image_metadata *imd;
+       int ret;
 
        DEBUG("Selecting image %d", image);
 
@@ -233,20 +268,21 @@ int select_wim_image(WIMStruct *w, int image)
                        INIT_HLIST_HEAD(&imd->inode_list);
                }
        }
-
        w->current_image = image;
-       imd = wim_get_current_image_metadata(w);
-
+       imd = &w->image_metadata[image - 1];
        if (imd->root_dentry) {
-               return 0;
+               ret = 0;
        } else {
                #ifdef ENABLE_DEBUG
                DEBUG("Reading metadata resource specified by the following "
                      "lookup table entry:");
-               print_lookup_table_entry(imd->metadata_lte);
+               print_lookup_table_entry(imd->metadata_lte, stdout);
                #endif
-               return read_metadata_resource(w, imd);
+               ret = read_metadata_resource(w, imd);
+               if (ret)
+                       w->current_image = WIMLIB_NO_IMAGE;
        }
+       return ret;
 }
 
 
@@ -322,7 +358,7 @@ WIMLIBAPI void wimlib_print_wim_information(const WIMStruct *w)
        printf("Boot Index:     %d\n", hdr->boot_idx);
        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");
+       printf("Integrity Info: %s\n", (w->hdr.integrity.offset != 0) ? "yes" : "no");
        putchar('\n');
 }
 
@@ -362,35 +398,29 @@ WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image)
  * not WIMLIB_NO_IMAGE. */
 WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image)
 {
-       if (!w)
-               return WIMLIB_ERR_INVALID_PARAM;
        if (w->hdr.part_number != 1) {
                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;
        }
-       return for_image(w, image, print_metadata);
+       return for_image(w, image, image_print_metadata);
 }
 
 WIMLIBAPI int wimlib_print_files(WIMStruct *w, int image)
 {
-       if (!w)
-               return WIMLIB_ERR_INVALID_PARAM;
        if (w->hdr.part_number != 1) {
                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;
        }
-       return for_image(w, image, print_files);
+       return for_image(w, image, image_print_files);
 }
 
 /* Sets the index of the bootable image. */
 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("Cannot modify the boot index of a split WIM!");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
@@ -433,7 +463,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
                      wimlib_progress_func_t progress_func)
 {
        int ret;
-       uint xml_num_images;
+       int xml_num_images;
 
        DEBUG("Reading the WIM file `%s'", in_wim_path);
 
@@ -456,15 +486,17 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
        w->filename = realpath(in_wim_path, NULL);
        if (!w->filename) {
                ERROR_WITH_ERRNO("Failed to resolve WIM filename");
-               ret = WIMLIB_ERR_NOMEM;
-               goto out_close;
+               if (errno == ENOMEM)
+                       return WIMLIB_ERR_NOMEM;
+               else
+                       return WIMLIB_ERR_OPEN;
        }
 
        ret = read_header(w->fp, &w->hdr, open_flags);
        if (ret != 0)
-               goto out_close;
+               return ret;
 
-       DEBUG("Wim file contains %u images", w->hdr.image_count);
+       DEBUG("According to header, WIM contains %u images", w->hdr.image_count);
 
        /* If the boot index is invalid, print a warning and set it to 0 */
        if (w->hdr.boot_idx > w->hdr.image_count) {
@@ -475,45 +507,37 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
        }
 
        if (wimlib_get_compression_type(w) == WIMLIB_COMPRESSION_TYPE_INVALID) {
-               ERROR("Invalid compression type (WIM header flags = %x)",
+               ERROR("Invalid compression type (WIM header flags = 0x%x)",
                      w->hdr.flags);
-               ret = WIMLIB_ERR_INVALID_COMPRESSION_TYPE;
-               goto out_close;
+               return WIMLIB_ERR_INVALID_COMPRESSION_TYPE;
        }
 
        if (open_flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY) {
                ret = check_wim_integrity(w, progress_func);
                if (ret == WIM_INTEGRITY_NONEXISTENT) {
                        WARNING("No integrity information for `%s'; skipping "
-                               "integrity check.", w->filename);
+                               "integrity check.", in_wim_path);
                } else if (ret == WIM_INTEGRITY_NOT_OK) {
                        ERROR("WIM is not intact! (Failed integrity check)");
-                       ret = WIMLIB_ERR_INTEGRITY;
-                       goto out_close;
-               } else if (ret != 0) {
-                       goto out_close;
+                       return WIMLIB_ERR_INTEGRITY;
+               } else if (ret != WIM_INTEGRITY_OK) {
+                       return ret;
                }
        }
 
-       if (resource_is_compressed(&w->hdr.lookup_table_res_entry)) {
-               ERROR("Didn't expect a compressed lookup table!");
-               ERROR("Ask the author to implement support for this.");
-               ret = WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE;
-               goto out_close;
-       }
-
        ret = read_lookup_table(w);
        if (ret != 0)
-               goto out_close;
+               return ret;
 
-       w->image_metadata = CALLOC(w->hdr.image_count,
-                                  sizeof(struct image_metadata));
+       if (w->hdr.image_count != 0) {
+               w->image_metadata = CALLOC(w->hdr.image_count,
+                                          sizeof(struct wim_image_metadata));
 
-       if (!w->image_metadata) {
-               ERROR("Failed to allocate memory for %u metadata structures",
-                     w->hdr.image_count);
-               ret = WIMLIB_ERR_NOMEM;
-               goto out_free_lookup_table;
+               if (!w->image_metadata) {
+                       ERROR("Failed to allocate memory for %u image metadata structures",
+                             w->hdr.image_count);
+                       return WIMLIB_ERR_NOMEM;
+               }
        }
        w->current_image = 0;
 
@@ -524,17 +548,16 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
                                     append_metadata_resource_entry, w);
 
        if (ret != 0)
-               goto out_free_image_metadata;
+               return ret;
 
        /* Make sure all the expected images were found.  (We already have
-        * returned false if *extra* images were found) */
+        * returned WIMLIB_ERR_IMAGE_COUNT if *extra* images were found) */
        if (w->current_image != w->hdr.image_count &&
            w->hdr.part_number == 1)
        {
-               ERROR("Only found %u images in WIM, but expected %u",
+               ERROR("Only found %d images in WIM, but expected %u",
                      w->current_image, w->hdr.image_count);
-               ret = WIMLIB_ERR_IMAGE_COUNT;
-               goto out_free_image_metadata;
+               return WIMLIB_ERR_IMAGE_COUNT;
        }
 
        /* Sort images by the position of their metadata resources.  I'm
@@ -542,7 +565,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
         * file, rather than their order in the lookup table, which is random
         * because of hashing. */
        qsort(w->image_metadata, w->current_image,
-             sizeof(struct image_metadata), sort_image_metadata_by_position);
+             sizeof(struct wim_image_metadata), sort_image_metadata_by_position);
 
        w->current_image = WIMLIB_NO_IMAGE;
 
@@ -551,7 +574,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
                            &w->xml_data, &w->wim_info);
 
        if (ret != 0)
-               goto out_free_image_metadata;
+               return ret;
 
        xml_num_images = wim_info_get_num_images(w->wim_info);
        if (xml_num_images != w->hdr.image_count) {
@@ -559,34 +582,11 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
                      "in the XML data,", in_wim_path, xml_num_images);
                ERROR("but %u images in the WIM!  There must be exactly one "
                      "<IMAGE> element per image.", w->hdr.image_count);
-               ret = WIMLIB_ERR_IMAGE_COUNT;
-               goto out_free_xml_data;
+               return WIMLIB_ERR_IMAGE_COUNT;
        }
 
        DEBUG("Done beginning read of WIM file `%s'.", in_wim_path);
        return 0;
-
-       //
-       // Everything is freed in wimlib_free() anyway, so no need to roll back
-       // changes here.
-       //
-out_free_xml_data:
-       /*FREE(w->xml_data);*/
-       /*w->xml_data = NULL;*/
-       /*free_wim_info(w->wim_info);*/
-       /*w->wim_info = NULL;*/
-out_free_image_metadata:
-       /*FREE(w->image_metadata);*/
-       /*w->image_metadata = NULL;*/
-       /*w->current_image = WIMLIB_NO_IMAGE;*/
-out_free_lookup_table:
-       /*free_lookup_table(w->lookup_table);*/
-       /*w->lookup_table = NULL;*/
-out_close:
-       /*fclose(w->fp);*/
-       /*w->fp = NULL;*/
-out:
-       return ret;
 }
 
 
@@ -602,27 +602,38 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags,
 
        if (!wim_file || !w_ret)
                return WIMLIB_ERR_INVALID_PARAM;
+
        w = new_wim_struct();
-       if (!w) {
-               ERROR("Failed to allocate memory for WIMStruct");
+       if (!w)
                return WIMLIB_ERR_NOMEM;
-       }
 
        ret = begin_read(w, wim_file, open_flags, progress_func);
-       if (ret == 0) {
+       if (ret == 0)
                *w_ret = w;
-       } else {
-               DEBUG("Could not begin reading the WIM file `%s'", wim_file);
+       else
                wimlib_free(w);
-       }
        return ret;
 }
 
+void destroy_image_metadata(struct wim_image_metadata *imd,
+                           struct wim_lookup_table *table)
+{
+       free_dentry_tree(imd->root_dentry, table);
+       free_security_data(imd->security_data);
+
+       /* Get rid of the lookup table entry for this image's metadata resource
+        * */
+       if (table) {
+               lookup_table_unlink(table, imd->metadata_lte);
+               free_lookup_table_entry(imd->metadata_lte);
+       }
+}
+
 /* Frees the memory for the WIMStruct, including all internal memory; also
  * closes all files associated with the WIMStruct.  */
 WIMLIBAPI void wimlib_free(WIMStruct *w)
 {
-       DEBUG2("Freeing WIMStruct");
+       DEBUG("Freeing WIMStruct");
 
        if (!w)
                return;
@@ -647,7 +658,7 @@ WIMLIBAPI void wimlib_free(WIMStruct *w)
        FREE(w->xml_data);
        free_wim_info(w->wim_info);
        if (w->image_metadata) {
-               for (uint i = 0; i < w->hdr.image_count; i++)
+               for (unsigned i = 0; i < w->hdr.image_count; i++)
                        destroy_image_metadata(&w->image_metadata[i], NULL);
                FREE(w->image_metadata);
        }
@@ -658,4 +669,21 @@ WIMLIBAPI void wimlib_free(WIMStruct *w)
        }
 #endif
        FREE(w);
+       DEBUG("Freed WIMStruct");
+}
+
+/* Get global memory allocations out of the way.  Not strictly necessary in
+ * single-threaded programs like 'imagex'. */
+WIMLIBAPI int wimlib_global_init()
+{
+       libxml_global_init();
+       return iconv_global_init();
+}
+
+/* Free global memory allocations.  Not strictly necessary if the process using
+ * wimlib is just about to exit (as is the case for 'imagex'). */
+WIMLIBAPI void wimlib_global_cleanup()
+{
+       libxml_global_cleanup();
+       iconv_global_cleanup();
 }