]> wimlib.net Git - wimlib/blobdiff - src/util.c
Refactor error functions; make re-entrant
[wimlib] / src / util.c
index b68db910ad1abab7ad3576f72cfc955bb71e4419..9aad4b2cc2c962fbf1ba133d29aa098b629a2529 100644 (file)
  * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
+#undef _GNU_SOURCE
+/* Make sure the POSIX-compatible strerror_r() is declared, rather than the GNU
+ * version, which has a different return type. */
+#define _POSIX_C_SOURCE 200112
+#include <string.h>
+#define _GNU_SOURCE
+
 #include "wimlib_internal.h"
 #include "endianness.h"
-#include "sha1.h"
 #include "timestamp.h"
-#include <sys/time.h>
-
 
-#include <iconv.h>
-#include <string.h>
 #include <ctype.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
 #include <errno.h>
+#include <stdlib.h>
+
+#include <unistd.h> /* for getpid() */
 
 /* True if wimlib is to print an informational message when an error occurs.
  * This can be turned off by calling wimlib_set_print_errors(false). */
 #ifdef ENABLE_ERROR_MESSAGES
 #include <stdarg.h>
-bool __wimlib_print_errors = false;
+static bool wimlib_print_errors = false;
 
-void wimlib_error(const char *format, ...)
+static void wimlib_vmsg(const char *tag, const char *format,
+                       va_list va, bool perror)
 {
-       if (__wimlib_print_errors) {
-               va_list va;
-               int errno_save;
-
-               va_start(va, format);
-               errno_save = errno;
-               fputs("[ERROR] ", stderr);
+       if (wimlib_print_errors) {
+               int errno_save = errno;
+               fflush(stdout);
+               fputs(tag, stderr);
                vfprintf(stderr, format, va);
+               if (perror && errno_save != 0) {
+                       char buf[50];
+                       int res = strerror_r(errno_save, buf, sizeof(buf));
+                       if (res) {
+                               snprintf(buf, sizeof(buf),
+                                        "unknown error (errno=%d)", errno_save);
+                       }
+                       fputs(buf, stderr);
+               }
                putc('\n', stderr);
                errno = errno_save;
-               va_end(va);
        }
 }
 
+void wimlib_error(const char *format, ...)
+{
+       va_list va;
+
+       va_start(va, format);
+       wimlib_vmsg("[ERROR] ", format, va, false);
+       va_end(va);
+}
+
 void wimlib_error_with_errno(const char *format, ...)
 {
-       if (__wimlib_print_errors) {
-               va_list va;
-               int errno_save;
+       va_list va;
 
-               va_start(va, format);
-               errno_save = errno;
-               fflush(stdout);
-               fputs("[ERROR] ", stderr);
-               vfprintf(stderr, format, va);
-               fprintf(stderr, ": %s\n", strerror(errno_save));
-               errno = errno_save;
-               va_end(va);
-       }
+       va_start(va, format);
+       wimlib_vmsg("[ERROR] ", format, va, true);
+       va_end(va);
 }
 
 void wimlib_warning(const char *format, ...)
 {
-       if (__wimlib_print_errors) {
-               va_list va;
-               int errno_save;
+       va_list va;
 
-               va_start(va, format);
-               errno_save = errno;
-               fflush(stdout);
-               fputs("[WARNING] ", stderr);
-               vfprintf(stderr, format, va);
-               putc('\n', stderr);
-               errno = errno_save;
-               va_end(va);
-       }
+       va_start(va, format);
+       wimlib_vmsg("[WARNING] ", format, va, false);
+       va_end(va);
+}
+
+void wimlib_warning_with_errno(const char *format, ...)
+{
+       va_list va;
+
+       va_start(va, format);
+       wimlib_vmsg("[WARNING] ", format, va, true);
+       va_end(va);
 }
 
 #endif
@@ -97,23 +107,29 @@ void wimlib_warning(const char *format, ...)
 WIMLIBAPI int wimlib_set_print_errors(bool show_error_messages)
 {
 #ifdef ENABLE_ERROR_MESSAGES
-       __wimlib_print_errors = show_error_messages;
+       wimlib_print_errors = show_error_messages;
        return 0;
 #else
        if (show_error_messages)
                return WIMLIB_ERR_UNSUPPORTED;
+       else
+               return 0;
 #endif
 }
 
 static const char *error_strings[] = {
        [WIMLIB_ERR_SUCCESS]
                = "Success",
+       [WIMLIB_ERR_ALREADY_LOCKED]
+               = "The WIM is already locked for writing",
        [WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE]
                = "Lookup table is compressed",
        [WIMLIB_ERR_DECOMPRESSION]
                = "Failed to decompress compressed data",
        [WIMLIB_ERR_DELETE_STAGING_DIR]
                = "Failed to delete staging directory",
+       [WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED]
+               = "The process servicing the mounted WIM has crashed",
        [WIMLIB_ERR_FORK]
                = "Failed to fork another process",
        [WIMLIB_ERR_FUSE]
@@ -148,10 +164,25 @@ static const char *error_strings[] = {
                = "An entry in the WIM's lookup table is invalid",
        [WIMLIB_ERR_INVALID_PARAM]
                = "An invalid parameter was given",
+       [WIMLIB_ERR_INVALID_PART_NUMBER]
+               = "The part number or total parts of the WIM is invalid",
        [WIMLIB_ERR_INVALID_RESOURCE_HASH]
                = "The SHA1 message digest of a WIM resource did not match the expected value",
+       [WIMLIB_ERR_ICONV_NOT_AVAILABLE]
+               = "The iconv() function does not seem to work. "
+                 "Maybe check to make sure the directory /usr/lib/gconv exists",
        [WIMLIB_ERR_INVALID_RESOURCE_SIZE]
                = "A resource entry in the WIM has an invalid size",
+       [WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE]
+               = "The version of wimlib that has mounted a WIM image is incompatible with the "
+                 "version being used to unmount it",
+       [WIMLIB_ERR_INVALID_UTF8_STRING]
+               = "A string provided as input by the user was not a valid UTF-8 string",
+       [WIMLIB_ERR_INVALID_UTF16_STRING]
+               = "A string in a WIM dentry is not a valid UTF-16LE string",
+       [WIMLIB_ERR_LIBXML_UTF16_HANDLER_NOT_AVAILABLE]
+               = "libxml2 was unable to find a character encoding conversion handler "
+                 "for UTF-16LE",
        [WIMLIB_ERR_LINK]
                = "Failed to create a hard or symbolic link when extracting "
                        "a file from the WIM",
@@ -180,6 +211,10 @@ static const char *error_strings[] = {
                = "Could not read the target of a symbolic link",
        [WIMLIB_ERR_RENAME]
                = "Could not rename a file",
+       [WIMLIB_ERR_REOPEN]
+               = "Could not re-open the WIM after overwriting it",
+       [WIMLIB_ERR_RESOURCE_ORDER]
+               = "The components of the WIM were arranged in an unexpected order",
        [WIMLIB_ERR_SPECIAL_FILE]
                = "Encountered a special file that cannot be archived",
        [WIMLIB_ERR_SPLIT_INVALID]
@@ -188,8 +223,6 @@ static const char *error_strings[] = {
                = "The WIM is part of a split WIM, which is not supported for this operation",
        [WIMLIB_ERR_STAT]
                = "Could not read the metadata for a file or directory",
-       [WIMLIB_ERR_TIMEOUT]
-               = "Timed out",
        [WIMLIB_ERR_UNKNOWN_VERSION]
                = "The WIM file is marked with an unknown version number",
        [WIMLIB_ERR_UNSUPPORTED]
@@ -261,131 +294,21 @@ WIMLIBAPI int wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
 #endif
 }
 
+static bool seeded = false;
 
-
-static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1);
-
-/* Converts a string in the UTF-16 encoding to a newly allocated string in the
- * UTF-8 encoding.  */
-char *utf16_to_utf8(const char *utf16_str, size_t utf16_len,
-                   size_t *utf8_len_ret)
-{
-       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");
-                       return NULL;
-               }
-       }
-       size_t utf16_bytes_left  = utf16_len;
-       size_t utf8_bytes_left   = utf16_len;
-
-       char *utf8_str = MALLOC(utf8_bytes_left);
-       if (!utf8_str)
-               return NULL;
-
-       char *orig_utf8_str = utf8_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)) {
-               ERROR_WITH_ERRNO("Failed to convert UTF-16LE string to UTF-8 "
-                                "string");
-               FREE(orig_utf8_str);
-               return NULL;
-       }
-
-       size_t utf8_len = utf16_len - utf8_bytes_left;
-
-       *utf8_len_ret = utf8_len;
-       orig_utf8_str[utf8_len] = '\0';
-       return orig_utf8_str;
-}
-
-static iconv_t cd_utf8_to_utf16 = (iconv_t)(-1);
-
-/* Converts a string in the UTF-8 encoding to a newly allocated string in the
- * UTF-16 encoding.  */
-char *utf8_to_utf16(const char *utf8_str, size_t utf8_len,
-                   size_t *utf16_len_ret)
-{
-       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");
-                       return NULL;
-               }
-       }
-
-       size_t utf8_bytes_left   = utf8_len;
-       size_t utf16_capacity    = utf8_len * 4;
-       size_t utf16_bytes_left  = utf16_capacity;
-
-       char *utf16_str = MALLOC(utf16_capacity + 2);
-       if (!utf16_str)
-               return NULL;
-
-       char *orig_utf16_str = utf16_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)) {
-               ERROR_WITH_ERRNO("Failed to convert UTF-8 string to UTF-16LE "
-                                "string");
-               FREE(orig_utf16_str);
-               return NULL;
-       }
-
-       size_t utf16_len = utf16_capacity - utf16_bytes_left;
-
-       *utf16_len_ret = utf16_len;
-       orig_utf16_str[utf16_len] = '\0';
-       orig_utf16_str[utf16_len + 1] = '\0';
-       return orig_utf16_str;
-}
-
-/* Write @n bytes from @buf to the file descriptor @fd, retrying on interupt and
- * on short writes.
- *
- * Returns short count and set errno on failure. */
-ssize_t full_write(int fd, const void *buf, size_t n)
+static void seed_random()
 {
-       const char *p = buf;
-       ssize_t ret;
-       ssize_t total = 0;
-
-       while (total != n) {
-               ret = write(fd, p, n);
-               if (ret < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       else
-                               break;
-               }
-               total += ret;
-               p += ret;
-       }
-       return total;
+       srand(time(NULL) * getpid());
+       seeded = true;
 }
 
-
-static bool seeded = false;
-
 /* Fills @n bytes pointed to by @p with random alphanumeric characters. */
 void randomize_char_array_with_alnum(char p[], size_t n)
 {
-       int r;
-
-       if (!seeded) {
-               srand(time(NULL));
-               seeded = true;
-       }
+       if (!seeded)
+               seed_random();
        while (n--) {
-               r = rand() % 62;
+               int r = rand() % 62;
                if (r < 26)
                        *p++ = r + 'a';
                else if (r < 52)
@@ -398,10 +321,8 @@ void randomize_char_array_with_alnum(char p[], size_t n)
 /* Fills @n bytes pointer to by @p with random numbers. */
 void randomize_byte_array(u8 *p, size_t n)
 {
-       if (!seeded) {
-               srand(time(NULL));
-               seeded = true;
-       }
+       if (!seeded)
+               seed_random();
        while (n--)
                *p++ = rand();
 }
@@ -525,4 +446,10 @@ u64 get_wim_timestamp()
        return timeval_to_wim_timestamp(&tv);
 }
 
-
+void wim_timestamp_to_str(u64 timestamp, char *buf, size_t len)
+{
+       struct tm tm;
+       time_t t = wim_timestamp_to_unix(timestamp);
+       gmtime_r(&t, &tm);
+       strftime(buf, len, "%a %b %d %H:%M:%S %Y UTC", &tm);
+}