Add wimlib_global_{init,cleanup}()
authorEric Biggers <ebiggers3@gmail.com>
Sun, 3 Mar 2013 21:16:08 +0000 (15:16 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 3 Mar 2013 21:56:47 +0000 (15:56 -0600)
programs/imagex.c
src/encoding.c
src/util.h
src/wim.c
src/wimlib.h
src/xml.c
src/xml.h

index 5ab9aeb..358e2d1 100644 (file)
@@ -1779,22 +1779,28 @@ int main(int argc, const char **argv)
        argv++;
 
        wimlib_set_print_errors(true);
+       ret = wimlib_global_init();
+       if (ret)
+               goto out;
 
        for_imagex_command(cmd) {
                if (strcmp(cmd->name, *argv) == 0) {
                        ret = cmd->func(argc, argv);
-                       if (ret > 0) {
-                               imagex_error("Exiting with error code %d:\n"
-                                            "       %s.", ret,
-                                            wimlib_get_error_string(ret));
-                               if (ret == WIMLIB_ERR_NTFS_3G && errno != 0)
-                                       imagex_error_with_errno("errno");
-                       }
-                       return ret;
+                       goto out;
                }
        }
 
        imagex_error("Unrecognized command: `%s'", argv[0]);
        usage_all();
        return 1;
+out:
+       if (ret > 0) {
+               imagex_error("Exiting with error code %d:\n"
+                            "       %s.", ret,
+                            wimlib_get_error_string(ret));
+               if (ret == WIMLIB_ERR_NTFS_3G && errno != 0)
+                       imagex_error_with_errno("errno");
+       }
+       wimlib_global_cleanup();
+       return ret;
 }
index edb24c7..30a8889 100644 (file)
@@ -132,6 +132,47 @@ static int utf8_to_utf16_size(const char *s)
 }
 #endif /* !WITH_NTFS_3G */
 
+#ifndef WITH_NTFS_3G
+static iconv_t cd_utf8_to_utf16 = (iconv_t)(-1);
+static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1);
+
+int iconv_global_init()
+{
+       if (cd_utf16_to_utf8 == (iconv_t)(-1)) {
+               cd_utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE");
+               if (cd_utf16_to_utf8 == (iconv_t)-1) {
+                       ERROR_WITH_ERRNO("Failed to get conversion descriptor "
+                                        "for converting UTF-16LE to UTF-8");
+                       if (errno == ENOMEM)
+                               return WIMLIB_ERR_NOMEM;
+                       else
+                               return WIMLIB_ERR_ICONV_NOT_AVAILABLE;
+               }
+       }
+
+       if (cd_utf8_to_utf16 == (iconv_t)(-1)) {
+               cd_utf8_to_utf16 = iconv_open("UTF-16LE", "UTF-8");
+               if (cd_utf8_to_utf16 == (iconv_t)-1) {
+                       ERROR_WITH_ERRNO("Failed to get conversion descriptor "
+                                        "for converting UTF-8 to UTF-16LE");
+                       if (errno == ENOMEM)
+                               return WIMLIB_ERR_NOMEM;
+                       else
+                               return WIMLIB_ERR_ICONV_NOT_AVAILABLE;
+               }
+       }
+       return 0;
+}
+
+void iconv_global_cleanup()
+{
+       if (cd_utf8_to_utf16 != (iconv_t)(-1))
+               iconv_close(cd_utf8_to_utf16);
+       if (cd_utf16_to_utf8 != (iconv_t)(-1))
+               iconv_close(cd_utf16_to_utf8);
+}
+#endif
+
 /* Converts a string in the UTF-16LE encoding to a newly allocated string in the
  * UTF-8 encoding.
  *
@@ -167,19 +208,12 @@ int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes,
                else
                        ret = WIMLIB_ERR_INVALID_UTF16_STRING;
        }
-#else /* WITH_NTFS_3G */
-       static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1);
-       if (cd_utf16_to_utf8 == (iconv_t)(-1)) {
-               cd_utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE");
-               if (cd_utf16_to_utf8 == (iconv_t)-1) {
-                       ERROR_WITH_ERRNO("Failed to get conversion descriptor "
-                                        "for converting UTF-16LE to UTF-8");
-                       if (errno == ENOMEM)
-                               return WIMLIB_ERR_NOMEM;
-                       else
-                               return WIMLIB_ERR_ICONV_NOT_AVAILABLE;
-               }
-       }
+#else /* !WITH_NTFS_3G */
+
+       ret = iconv_global_init();
+       if (ret != 0)
+               return ret;
+
        ret = utf16_to_utf8_size((const u16*)utf16_str, utf16_nbytes / 2);
        if (ret >= 0) {
                size_t utf8_expected_nbytes;
@@ -262,20 +296,11 @@ int utf8_to_utf16(const char *utf8_str, size_t utf8_nbytes,
                else
                        ret = WIMLIB_ERR_INVALID_UTF8_STRING;
        }
-#else /* WITH_NTFS_3G */
-       static iconv_t cd_utf8_to_utf16 = (iconv_t)(-1);
-       if (cd_utf8_to_utf16 == (iconv_t)(-1)) {
-               cd_utf8_to_utf16 = iconv_open("UTF-16LE", "UTF-8");
-               if (cd_utf8_to_utf16 == (iconv_t)-1) {
-                       ERROR_WITH_ERRNO("Failed to get conversion descriptor "
-                                        "for converting UTF-8 to UTF-16LE");
-                       if (errno == ENOMEM)
-                               return WIMLIB_ERR_NOMEM;
-                       else
-                               return WIMLIB_ERR_ICONV_NOT_AVAILABLE;
-               }
-       }
+#else /* !WITH_NTFS_3G */
 
+       ret = iconv_global_init();
+       if (ret != 0)
+               return ret;
        ret = utf8_to_utf16_size(utf8_str);
        if (ret >= 0) {
                size_t utf16_expected_nbytes;
index 3db022a..0979d98 100644 (file)
@@ -162,6 +162,19 @@ extern char *wimlib_strdup(const char *str);
 
 
 /* encoding.c */
+
+#ifdef WITH_NTFS_3G
+static inline int iconv_global_init()
+{
+       return 0;
+}
+
+static inline void iconv_global_cleanup() { }
+#else
+extern int iconv_global_init();
+extern void iconv_global_cleanup();
+#endif
+
 extern int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes,
                         char **utf8_str_ret, size_t *utf8_nbytes_ret);
 
index 23858d6..b52a28d 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -634,3 +634,19 @@ WIMLIBAPI void wimlib_free(WIMStruct *w)
 #endif
        FREE(w);
 }
+
+/* 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();
+}
index a249b89..1de5d04 100644 (file)
@@ -1282,6 +1282,34 @@ extern int wimlib_get_num_images(const WIMStruct *wim);
  */
 extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret);
 
+/**
+ * Since wimlib 1.2.6:  Initialization function for wimlib.  This is not
+ * re-entrant.  If you are calling wimlib functions concurrently in different
+ * threads, then you must call this function serially first.  Otherwise, calling
+ * this function is not required.
+ *
+ * @return 0 on success; nonzero on error.
+ * @retval ::WIMLIB_ERR_NOMEM
+ *     Could not allocate memory.
+ * @retval ::WIMLIB_ERR_ICONV_NOT_AVAILABLE
+ *     wimlib was configured --without-libntfs-3g at compilation time, and at
+ *     runtime the iconv() set of functions did not seem to be available,
+ *     perhaps due to missing files in the C library installation.
+ *
+ * If this function is not called or returns nonzero, then it will not be safe
+ * to use wimlib in multiple threads.  Furthermore, a nonzero return value here
+ * indicates that further calls into wimlib will probably fail when they try to
+ * repeat the same initializations.
+ */
+extern int wimlib_global_init();
+
+/**
+ * Since wimlib 1.2.6:  Cleanup function for wimlib.  This is not re-entrant.
+ * You are not required to call this function, but it will release any global
+ * memory allocated by the library.
+ */
+extern void wimlib_global_cleanup();
+
 /**
  * Returns true if the WIM has an integrity table.
  *
index 9b161c2..c840da9 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -1177,6 +1177,16 @@ void print_image_info(const struct wim_info *wim_info, int image)
        putchar('\n');
 }
 
+void libxml_global_init()
+{
+       xmlInitParser();
+}
+
+void libxml_global_cleanup()
+{
+       xmlCleanupParser();
+}
+
 /*
  * Reads the XML data from a WIM file.
  */
@@ -1194,19 +1204,19 @@ int read_xml_data(FILE *fp, const struct resource_entry *res_entry,
        if (resource_is_compressed(res_entry)) {
                ERROR("XML data is supposed to be uncompressed");
                ret = WIMLIB_ERR_XML;
-               goto out_cleanup_parser;
+               goto out;
        }
 
        if (res_entry->size < 2) {
                ERROR("XML data must be at least 2 bytes long");
                ret = WIMLIB_ERR_XML;
-               goto out_cleanup_parser;
+               goto out;
        }
 
        xml_data = MALLOC(res_entry->size + 2);
        if (!xml_data) {
                ret = WIMLIB_ERR_NOMEM;
-               goto out_cleanup_parser;
+               goto out;
        }
 
        ret = read_uncompressed_resource(fp, res_entry->offset,
@@ -1249,16 +1259,14 @@ int read_xml_data(FILE *fp, const struct resource_entry *res_entry,
        if (ret != 0)
                goto out_free_doc;
 
-       DEBUG("Freeing XML tree.");
-
        *xml_data_ret = xml_data;
        xml_data = NULL;
 out_free_doc:
+       DEBUG("Freeing XML tree.");
        xmlFreeDoc(doc);
 out_free_xml_data:
        FREE(xml_data);
-out_cleanup_parser:
-       xmlCleanupParser();
+out:
        return ret;
 }
 
index 5eb24c9..54993cb 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -36,6 +36,9 @@ extern int read_xml_data(FILE *fp, const struct resource_entry *res,
 extern int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
                          u64 total_bytes, struct resource_entry *out_res_entry);
 
+extern void libxml_global_init();
+extern void libxml_global_cleanup();
+
 static inline u64 wim_info_get_total_bytes(const struct wim_info *info)
 {
        return info->total_bytes;