From f1c07e953597e3f6a809d35d7d5160af1ff67ed3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 14 Dec 2014 13:51:40 -0600 Subject: [PATCH] Clean up util.h and util.c - Move logging/error code into new file error.c - Remove ZERO_ARRAY() - Move path separator macros into paths.h - Comment improvements - Remove support for undocumented WIMLIB_DEBUG environmental variable --- Makefile.am | 1 + include/wimlib/error.h | 7 +- include/wimlib/paths.h | 23 +++ include/wimlib/util.h | 116 +++++------- src/dentry.c | 1 + src/error.c | 372 ++++++++++++++++++++++++++++++++++++ src/join.c | 2 +- src/util.c | 421 ++++------------------------------------- src/win32_apply.c | 1 + 9 files changed, 485 insertions(+), 459 deletions(-) create mode 100644 src/error.c diff --git a/Makefile.am b/Makefile.am index edfb187d..c19b7fcc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,6 +31,7 @@ libwim_la_SOURCES = \ src/dentry.c \ src/divsufsort.c \ src/encoding.c \ + src/error.c \ src/export_image.c \ src/extract.c \ src/file_io.c \ diff --git a/include/wimlib/error.h b/include/wimlib/error.h index 9657eda8..e584c7b9 100644 --- a/include/wimlib/error.h +++ b/include/wimlib/error.h @@ -1,12 +1,12 @@ #ifndef _WIMLIB_ERROR_H #define _WIMLIB_ERROR_H +#include + #include "wimlib.h" /* Get error code definitions */ #include "wimlib/compiler.h" #include "wimlib/types.h" -#include - static inline int _format_attribute(printf, 1, 2) dummy_tprintf(const tchar *format, ...) { @@ -64,4 +64,7 @@ wimlib_debug(const tchar *file, int line, const char *func, # define DEBUG(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__) #endif /* !ENABLE_DEBUG */ +extern void +print_byte_field(const u8 *field, size_t len, FILE *out); + #endif /* _WIMLIB_ERROR_H */ diff --git a/include/wimlib/paths.h b/include/wimlib/paths.h index 58a86fe4..e6c33177 100644 --- a/include/wimlib/paths.h +++ b/include/wimlib/paths.h @@ -19,4 +19,27 @@ do_canonicalize_path(const tchar *in, tchar *out); extern tchar * canonicalize_wim_path(const tchar *wim_path) _malloc_attribute; +/* is_any_path_separator() - characters treated as path separators in WIM path + * specifications and capture configuration files (the former will be translated + * to WIM_PATH_SEPARATOR; the latter will be translated to + * OS_PREFERRED_PATH_SEPARATOR) + * + * OS_PREFERRED_PATH_SEPARATOR - preferred (or only) path separator on the + * operating system. Used when constructing filesystem paths to extract or + * archive. + * + * WIM_PATH_SEPARATOR - character treated as path separator for WIM paths. + * Currently needs to be '/' on UNIX for the WIM mounting code to work properly. + */ + +#ifdef __WIN32__ +# define OS_PREFERRED_PATH_SEPARATOR L'\\' +# define is_any_path_separator(c) ((c) == L'/' || (c) == L'\\') +#else +# define OS_PREFERRED_PATH_SEPARATOR '/' +# define is_any_path_separator(c) ((c) == '/' || (c) == '\\') +#endif + +#define WIM_PATH_SEPARATOR WIMLIB_WIM_PATH_SEPARATOR + #endif /* _WIMLIB_PATHS_H */ diff --git a/include/wimlib/util.h b/include/wimlib/util.h index 0aa40d1b..40f6294e 100644 --- a/include/wimlib/util.h +++ b/include/wimlib/util.h @@ -1,60 +1,61 @@ +/* + * util.h - utility functions and macros + */ #ifndef _WIMLIB_UTIL_H #define _WIMLIB_UTIL_H -#include "wimlib/types.h" #include "wimlib/compiler.h" +#include "wimlib/types.h" -#include +/**************** + * General macros + *****************/ -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#ifndef container_of -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) -#endif +/* Cast a pointer to a struct member to a pointer to the containing struct. */ +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) -#define DIV_ROUND_UP(numerator, denominator) \ - (((numerator) + (denominator) - 1) / (denominator)) +/* Calculate 'n / d', but round up instead of down. */ +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) -#define MODULO_NONZERO(numerator, denominator) \ - (((numerator) % (denominator)) ? ((numerator) % (denominator)) : (denominator)) +/* Calculate 'n % d', but return 'd' if the result would be 0. */ +#define MODULO_NONZERO(n, d) (((n) % (d)) ? ((n) % (d)) : (d)) -#define ARRAY_LEN(array) (sizeof(array) / sizeof((array)[0])) +/* Get the number of elements of an array type. */ +#define ARRAY_LEN(array) (sizeof(array) / sizeof((array)[0])) -#define ZERO_ARRAY(array) memset(array, 0, sizeof(array)) +/* Maximum number of bytes that can be allocated on the stack. + * + * Note: this isn't a hard bound on the stack space used, since this is just for + * individual arrays. The full call stack could use more than this. */ +#define STACK_MAX 32768 -/* Used for buffering FILE IO in a few places */ +/* Default size of file I/O buffer. Currently assumed to be <= STACK_MAX. */ #define BUFFER_SIZE 32768 -/* Maximum number of array elements to allocate on the stack (used in various - * places when large temporary buffers are needed). */ -#define STACK_MAX 32768 +/******************* + * Memory allocation + *******************/ extern void * -wimlib_malloc(size_t) _malloc_attribute; +wimlib_malloc(size_t size) _malloc_attribute; extern void wimlib_free_memory(void *p); extern void * -wimlib_realloc(void *, size_t); +wimlib_realloc(void *ptr, size_t size); extern void * wimlib_calloc(size_t nmemb, size_t size) _malloc_attribute; +extern char * +wimlib_strdup(const char *str) _malloc_attribute; + #ifdef __WIN32__ extern wchar_t * wimlib_wcsdup(const wchar_t *str) _malloc_attribute; - #endif -extern char * -wimlib_strdup(const char *str) _malloc_attribute; extern void * wimlib_aligned_malloc(size_t size, size_t alignment) _malloc_attribute; @@ -62,18 +63,22 @@ wimlib_aligned_malloc(size_t size, size_t alignment) _malloc_attribute; extern void wimlib_aligned_free(void *ptr); -#define MALLOC wimlib_malloc -#define FREE wimlib_free_memory -#define REALLOC wimlib_realloc -#define CALLOC wimlib_calloc -#define STRDUP wimlib_strdup -#define WCSDUP wimlib_wcsdup -#define ALIGNED_MALLOC wimlib_aligned_malloc -#define ALIGNED_FREE wimlib_aligned_free - extern void * memdup(const void *mem, size_t size) _malloc_attribute; +#define MALLOC wimlib_malloc +#define FREE wimlib_free_memory +#define REALLOC wimlib_realloc +#define CALLOC wimlib_calloc +#define STRDUP wimlib_strdup +#define WCSDUP wimlib_wcsdup +#define ALIGNED_MALLOC wimlib_aligned_malloc +#define ALIGNED_FREE wimlib_aligned_free + +/******************* + * String utilities + *******************/ + #ifndef HAVE_MEMPCPY extern void * mempcpy(void *dst, const void *src, size_t n); @@ -86,10 +91,11 @@ extern void randomize_byte_array(u8 *p, size_t n); extern void -randomize_char_array_with_alnum(tchar p[], size_t n); +randomize_char_array_with_alnum(tchar *p, size_t n); -extern void -print_byte_field(const u8 field[], size_t len, FILE *out); +/************************ + * Hashing and comparison + ************************/ static inline bool is_power_of_2(unsigned long n) @@ -109,33 +115,9 @@ cmp_u64(u64 n1, u64 n2) { if (n1 < n2) return -1; - else if (n1 > n2) + if (n1 > n2) return 1; - else - return 0; + return 0; } -/* is_any_path_separator() - characters treated as path separators in WIM path - * specifications and capture configuration files (the former will be translated - * to WIM_PATH_SEPARATOR; the latter will be translated to - * OS_PREFERRED_PATH_SEPARATOR) - * - * OS_PREFERRED_PATH_SEPARATOR - preferred (or only) path separator on the - * operating system. Used when constructing filesystem paths to extract or - * archive. - * - * WIM_PATH_SEPARATOR - character treated as path separator for WIM paths. - * Currently needs to be '/' on UNIX for the WIM mounting code to work properly. - */ - -#ifdef __WIN32__ -# define OS_PREFERRED_PATH_SEPARATOR L'\\' -# define is_any_path_separator(c) ((c) == L'/' || (c) == L'\\') -#else -# define OS_PREFERRED_PATH_SEPARATOR '/' -# define is_any_path_separator(c) ((c) == '/' || (c) == '\\') -#endif - -#define WIM_PATH_SEPARATOR WIMLIB_WIM_PATH_SEPARATOR - #endif /* _WIMLIB_UTIL_H */ diff --git a/src/dentry.c b/src/dentry.c index aa626764..669b447e 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -64,6 +64,7 @@ #include "wimlib/encoding.h" #include "wimlib/endianness.h" #include "wimlib/metadata.h" +#include "wimlib/paths.h" #include diff --git a/src/error.c b/src/error.c new file mode 100644 index 00000000..8448536d --- /dev/null +++ b/src/error.c @@ -0,0 +1,372 @@ +/* + * error.c - logging and error code translation + */ + +/* + * Copyright (C) 2012, 2013, 2014 Eric Biggers + * + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + * + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Make sure the POSIX-compatible strerror_r() is declared, rather than the GNU + * version, which has a different return type. */ +#ifdef _GNU_SOURCE +# define GNU_SOURCE_WAS_DEFINED +# undef _GNU_SOURCE +# ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +# endif +#endif +#include +#ifdef GNU_SOURCE_WAS_DEFINED +# define _GNU_SOURCE +#endif + +#include +#include + +#include "wimlib.h" +#include "wimlib/error.h" +#include "wimlib/util.h" +#ifdef __WIN32__ +# include "wimlib/win32.h" +#endif + +#ifdef ENABLE_ERROR_MESSAGES +bool wimlib_print_errors = false; +FILE *wimlib_error_file = NULL; /* Set in wimlib_global_init() */ +static bool wimlib_owns_error_file = false; +#endif + +#if defined(ENABLE_ERROR_MESSAGES) || defined(ENABLE_DEBUG) +static void +wimlib_vmsg(const tchar *tag, const tchar *format, + va_list va, bool perror) +{ +#if !defined(ENABLE_DEBUG) + if (wimlib_print_errors) +#endif + { + int errno_save = errno; + fflush(stdout); + tfputs(tag, wimlib_error_file); + tvfprintf(wimlib_error_file, format, va); + if (perror && errno_save != 0) { + tchar buf[64]; + int res; + res = tstrerror_r(errno_save, buf, ARRAY_LEN(buf)); + if (res) { + tsprintf(buf, + T("unknown error (errno=%d)"), + errno_save); + } + #ifdef WIN32 + if (errno_save == EBUSY) + tstrcpy(buf, T("Resource busy")); + #endif + tfprintf(wimlib_error_file, T(": %"TS), buf); + } + tputc(T('\n'), wimlib_error_file); + fflush(wimlib_error_file); + errno = errno_save; + } +} +#endif + +#ifdef ENABLE_ERROR_MESSAGES +void +wimlib_error(const tchar *format, ...) +{ + va_list va; + + va_start(va, format); + wimlib_vmsg(T("\r[ERROR] "), format, va, false); + va_end(va); +} + +void +wimlib_error_with_errno(const tchar *format, ...) +{ + va_list va; + + va_start(va, format); + wimlib_vmsg(T("\r[ERROR] "), format, va, true); + va_end(va); +} + +void +wimlib_warning(const tchar *format, ...) +{ + va_list va; + + va_start(va, format); + wimlib_vmsg(T("\r[WARNING] "), format, va, false); + va_end(va); +} + +void +wimlib_warning_with_errno(const tchar *format, ...) +{ + va_list va; + + va_start(va, format); + wimlib_vmsg(T("\r[WARNING] "), format, va, true); + va_end(va); +} + +#endif + +#if defined(ENABLE_DEBUG) || defined(ENABLE_MORE_DEBUG) +void wimlib_debug(const tchar *filename, int line, const char *func, + const tchar *format, ...) +{ + va_list va; + tchar buf[tstrlen(filename) + strlen(func) + 30]; + + tsprintf(buf, T("[%"TS" %d] %s(): "), filename, line, func); + va_start(va, format); + wimlib_vmsg(buf, format, va, false); + va_end(va); +} +#endif + +void +print_byte_field(const u8 *field, size_t len, FILE *out) +{ + while (len--) + tfprintf(out, T("%02hhx"), *field++); +} + +WIMLIBAPI int +wimlib_set_print_errors(bool show_error_messages) +{ +#ifdef ENABLE_ERROR_MESSAGES + wimlib_print_errors = show_error_messages; +#else + if (show_error_messages) + return WIMLIB_ERR_UNSUPPORTED; +#endif + return 0; +} + +WIMLIBAPI int +wimlib_set_error_file(FILE *fp) +{ +#ifdef ENABLE_ERROR_MESSAGES + if (wimlib_owns_error_file) + fclose(wimlib_error_file); + wimlib_error_file = fp; + wimlib_print_errors = (fp != NULL); + wimlib_owns_error_file = false; + return 0; +#else + return WIMLIB_ERR_UNSUPPORTED; +#endif +} + +WIMLIBAPI int +wimlib_set_error_file_by_name(const tchar *path) +{ +#ifdef ENABLE_ERROR_MESSAGES + FILE *fp; + +#ifdef __WIN32__ + fp = win32_open_logfile(path); +#else + fp = fopen(path, "a"); +#endif + if (!fp) + return WIMLIB_ERR_OPEN; + wimlib_set_error_file(fp); + wimlib_owns_error_file = true; + return 0; +#else + return WIMLIB_ERR_UNSUPPORTED; +#endif +} + +static const tchar * const error_strings[] = { + [WIMLIB_ERR_SUCCESS] + = T("Success"), + [WIMLIB_ERR_ALREADY_LOCKED] + = T("The WIM is already locked for writing"), + [WIMLIB_ERR_DECOMPRESSION] + = T("Failed to decompress compressed data"), + [WIMLIB_ERR_FUSE] + = T("An error was returned by fuse_main()"), + [WIMLIB_ERR_GLOB_HAD_NO_MATCHES] + = T("The provided file glob did not match any files"), + [WIMLIB_ERR_ICONV_NOT_AVAILABLE] + = T("The iconv() function does not seem to work. " + "Maybe check to make sure the directory /usr/lib/gconv exists"), + [WIMLIB_ERR_IMAGE_COUNT] + = T("Inconsistent image count among the metadata " + "resources, the WIM header, and/or the XML data"), + [WIMLIB_ERR_IMAGE_NAME_COLLISION] + = T("Tried to add an image with a name that is already in use"), + [WIMLIB_ERR_INSUFFICIENT_PRIVILEGES] + = T("The user does not have sufficient privileges"), + [WIMLIB_ERR_INTEGRITY] + = T("The WIM file is corrupted (failed integrity check)"), + [WIMLIB_ERR_INVALID_CAPTURE_CONFIG] + = T("The capture configuration string was invalid"), + [WIMLIB_ERR_INVALID_CHUNK_SIZE] + = T("The compression chunk size was unrecognized"), + [WIMLIB_ERR_INVALID_COMPRESSION_TYPE] + = T("The compression type was unrecognized"), + [WIMLIB_ERR_INVALID_HEADER] + = T("The WIM header was invalid"), + [WIMLIB_ERR_INVALID_IMAGE] + = T("Tried to select an image that does not exist in the WIM"), + [WIMLIB_ERR_INVALID_INTEGRITY_TABLE] + = T("The WIM's integrity table is invalid"), + [WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY] + = T("An entry in the WIM's lookup table is invalid"), + [WIMLIB_ERR_INVALID_METADATA_RESOURCE] + = T("The metadata resource is invalid"), + [WIMLIB_ERR_INVALID_MULTIBYTE_STRING] + = T("A string was not valid in the current locale's character encoding"), + [WIMLIB_ERR_INVALID_OVERLAY] + = T("Conflicting files in overlay when creating a WIM image"), + [WIMLIB_ERR_INVALID_PARAM] + = T("An invalid parameter was given"), + [WIMLIB_ERR_INVALID_PART_NUMBER] + = T("The part number or total parts of the WIM is invalid"), + [WIMLIB_ERR_INVALID_PIPABLE_WIM] + = T("The pipable WIM is invalid"), + [WIMLIB_ERR_INVALID_REPARSE_DATA] + = T("The reparse data of a reparse point was invalid"), + [WIMLIB_ERR_INVALID_RESOURCE_HASH] + = T("The SHA1 message digest of a WIM resource did not match the expected value"), + [WIMLIB_ERR_INVALID_UTF8_STRING] + = T("A string provided as input by the user was not a valid UTF-8 string"), + [WIMLIB_ERR_INVALID_UTF16_STRING] + = T("A string in a WIM dentry is not a valid UTF-16LE string"), + [WIMLIB_ERR_IS_DIRECTORY] + = T("One of the specified paths to delete was a directory"), + [WIMLIB_ERR_IS_SPLIT_WIM] + = T("The WIM is part of a split WIM, which is not supported for this operation"), + [WIMLIB_ERR_LIBXML_UTF16_HANDLER_NOT_AVAILABLE] + = T("libxml2 was unable to find a character encoding conversion handler " + "for UTF-16LE"), + [WIMLIB_ERR_LINK] + = T("Failed to create a hard or symbolic link when extracting " + "a file from the WIM"), + [WIMLIB_ERR_METADATA_NOT_FOUND] + = T("A required metadata resource could not be located"), + [WIMLIB_ERR_MKDIR] + = T("Failed to create a directory"), + [WIMLIB_ERR_MQUEUE] + = T("Failed to create or use a POSIX message queue"), + [WIMLIB_ERR_NOMEM] + = T("Ran out of memory"), + [WIMLIB_ERR_NOTDIR] + = T("Expected a directory"), + [WIMLIB_ERR_NOTEMPTY] + = T("Directory was not empty"), + [WIMLIB_ERR_NOT_A_REGULAR_FILE] + = T("One of the specified paths to extract did not " + "correspond to a regular file"), + [WIMLIB_ERR_NOT_A_WIM_FILE] + = T("The file did not begin with the magic characters that " + "identify a WIM file"), + [WIMLIB_ERR_NO_FILENAME] + = T("The WIM is not identified with a filename"), + [WIMLIB_ERR_NOT_PIPABLE] + = T("The WIM was not captured such that it can be " + "applied from a pipe"), + [WIMLIB_ERR_NTFS_3G] + = T("NTFS-3g encountered an error (check errno)"), + [WIMLIB_ERR_OPEN] + = T("Failed to open a file"), + [WIMLIB_ERR_OPENDIR] + = T("Failed to open a directory"), + [WIMLIB_ERR_PATH_DOES_NOT_EXIST] + = T("The path does not exist in the WIM image"), + [WIMLIB_ERR_READ] + = T("Could not read data from a file"), + [WIMLIB_ERR_READLINK] + = T("Could not read the target of a symbolic link"), + [WIMLIB_ERR_RENAME] + = T("Could not rename a file"), + [WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED] + = T("Unable to complete reparse point fixup"), + [WIMLIB_ERR_RESOURCE_NOT_FOUND] + = T("A file resource needed to complete the operation was missing from the WIM"), + [WIMLIB_ERR_RESOURCE_ORDER] + = T("The components of the WIM were arranged in an unexpected order"), + [WIMLIB_ERR_SET_ATTRIBUTES] + = T("Failed to set attributes on extracted file"), + [WIMLIB_ERR_SET_REPARSE_DATA] + = T("Failed to set reparse data on extracted file"), + [WIMLIB_ERR_SET_SECURITY] + = T("Failed to set file owner, group, or other permissions on extracted file"), + [WIMLIB_ERR_SET_SHORT_NAME] + = T("Failed to set short name on extracted file"), + [WIMLIB_ERR_SET_TIMESTAMPS] + = T("Failed to set timestamps on extracted file"), + [WIMLIB_ERR_SPLIT_INVALID] + = T("The WIM is part of an invalid split WIM"), + [WIMLIB_ERR_STAT] + = T("Could not read the metadata for a file or directory"), + [WIMLIB_ERR_UNEXPECTED_END_OF_FILE] + = T("Unexpectedly reached the end of the file"), + [WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE] + = T("A Unicode string could not be represented in the current locale's encoding"), + [WIMLIB_ERR_UNKNOWN_VERSION] + = T("The WIM file is marked with an unknown version number"), + [WIMLIB_ERR_UNSUPPORTED] + = T("The requested operation is unsupported"), + [WIMLIB_ERR_UNSUPPORTED_FILE] + = T("A file in the directory tree to archive was not of a supported type"), + [WIMLIB_ERR_WIM_IS_READONLY] + = T("The WIM is read-only (file permissions, header flag, or split WIM)"), + [WIMLIB_ERR_WRITE] + = T("Failed to write data to a file"), + [WIMLIB_ERR_XML] + = T("The XML data of the WIM is invalid"), + [WIMLIB_ERR_WIM_IS_ENCRYPTED] + = T("The WIM file (or parts of it) is encrypted"), + [WIMLIB_ERR_WIMBOOT] + = T("Failed to set WIMBoot pointer data"), + [WIMLIB_ERR_ABORTED_BY_PROGRESS] + = T("The operation was aborted by the library user"), + [WIMLIB_ERR_UNKNOWN_PROGRESS_STATUS] + = T("The user-provided progress function returned an unrecognized value"), + [WIMLIB_ERR_MKNOD] + = T("Unable to create a special file (e.g. device node or socket)"), + [WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY] + = T("There are still files open on the mounted WIM image"), + [WIMLIB_ERR_NOT_A_MOUNTPOINT] + = T("There is not a WIM image mounted on the directory"), + [WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT] + = T("The current user does not have permission to unmount the WIM image"), + [WIMLIB_ERR_FVE_LOCKED_VOLUME] + = T("The volume must be unlocked before it can be used"), +}; + +WIMLIBAPI const tchar * +wimlib_get_error_string(enum wimlib_error_code _code) +{ + unsigned int code = (unsigned int)_code; + + if (code >= ARRAY_LEN(error_strings) || error_strings[code] == NULL) + return T("Unknown error"); + + return error_strings[code]; +} diff --git a/src/join.c b/src/join.c index da4ac406..7999b683 100644 --- a/src/join.c +++ b/src/join.c @@ -94,7 +94,7 @@ verify_swm_set(WIMStruct *wim, WIMStruct **additional_swms, * checked to be the same as wim->hdr.total_parts. Otherwise, it * could be unexpectedly high and cause a stack overflow. */ WIMStruct *parts_to_swms[num_additional_swms]; - ZERO_ARRAY(parts_to_swms); + memset(parts_to_swms, 0, sizeof(parts_to_swms)); for (unsigned i = 0; i < num_additional_swms; i++) { WIMStruct *swm = additional_swms[i]; diff --git a/src/util.c b/src/util.c index 3b13c503..8d841cc1 100644 --- a/src/util.c +++ b/src/util.c @@ -1,9 +1,9 @@ /* - * util.c + * util.c - utility functions */ /* - * Copyright (C) 2012, 2013 Eric Biggers + * Copyright (C) 2012, 2013, 2014 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -23,382 +23,19 @@ # include "config.h" #endif -/* Make sure the POSIX-compatible strerror_r() is declared, rather than the GNU - * version, which has a different return type. */ -#ifdef _GNU_SOURCE -# define _GNU_SOURCE_DEFINED 1 -# undef _GNU_SOURCE -# ifndef _POSIX_C_SOURCE -# define _POSIX_C_SOURCE 200112L -# endif -#endif +#include +#include #include -#ifdef _GNU_SOURCE_DEFINED -# define _GNU_SOURCE -#endif #include "wimlib.h" #include "wimlib/assert.h" -#include "wimlib/compiler.h" -#include "wimlib/encoding.h" -#include "wimlib/error.h" -#include "wimlib/types.h" +#include "wimlib/timestamp.h" #include "wimlib/util.h" #include "wimlib/xml.h" -#ifdef __WIN32__ -# include "wimlib/win32.h" /* win32_strerror_r_replacement */ -#endif - -#include -#include -#include -#include -#include - -size_t -utf16le_strlen(const utf16lechar *s) -{ - const utf16lechar *p = s; - while (*p) - p++; - return (p - s) * sizeof(utf16lechar); -} - -#ifdef ENABLE_ERROR_MESSAGES -bool wimlib_print_errors = false; -FILE *wimlib_error_file = NULL; /* Set in wimlib_global_init() */ -static bool wimlib_owns_error_file = false; -#endif - -#if defined(ENABLE_ERROR_MESSAGES) || defined(ENABLE_DEBUG) -static void -wimlib_vmsg(const tchar *tag, const tchar *format, - va_list va, bool perror) -{ -#if !defined(ENABLE_DEBUG) - if (wimlib_print_errors) -#endif - { - int errno_save = errno; - fflush(stdout); - tfputs(tag, wimlib_error_file); - tvfprintf(wimlib_error_file, format, va); - if (perror && errno_save != 0) { - tchar buf[64]; - int res; - res = tstrerror_r(errno_save, buf, ARRAY_LEN(buf)); - if (res) { - tsprintf(buf, - T("unknown error (errno=%d)"), - errno_save); - } - #ifdef WIN32 - if (errno_save == EBUSY) - tstrcpy(buf, T("Resource busy")); - #endif - tfprintf(wimlib_error_file, T(": %"TS), buf); - } - tputc(T('\n'), wimlib_error_file); - fflush(wimlib_error_file); - errno = errno_save; - } -} -#endif - -/* 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 -void -wimlib_error(const tchar *format, ...) -{ - va_list va; - - va_start(va, format); - wimlib_vmsg(T("\r[ERROR] "), format, va, false); - va_end(va); -} - -void -wimlib_error_with_errno(const tchar *format, ...) -{ - va_list va; - - va_start(va, format); - wimlib_vmsg(T("\r[ERROR] "), format, va, true); - va_end(va); -} - -void -wimlib_warning(const tchar *format, ...) -{ - va_list va; - - va_start(va, format); - wimlib_vmsg(T("\r[WARNING] "), format, va, false); - va_end(va); -} - -void -wimlib_warning_with_errno(const tchar *format, ...) -{ - va_list va; - - va_start(va, format); - wimlib_vmsg(T("\r[WARNING] "), format, va, true); - va_end(va); -} - -#endif - -#if defined(ENABLE_DEBUG) || defined(ENABLE_MORE_DEBUG) -void wimlib_debug(const tchar *file, int line, const char *func, - const tchar *format, ...) -{ - va_list va; - tchar buf[tstrlen(file) + strlen(func) + 30]; - - static bool debug_enabled = false; - if (!debug_enabled) { - char *value = getenv("WIMLIB_DEBUG"); - if (!value || strcmp(value, "0")) - debug_enabled = true; - else - return; - } - - tsprintf(buf, T("[%"TS" %d] %s(): "), file, line, func); - - va_start(va, format); - wimlib_vmsg(buf, format, va, false); - va_end(va); -} -#endif - -/* API function documented in wimlib.h */ -WIMLIBAPI int -wimlib_set_print_errors(bool show_error_messages) -{ -#ifdef ENABLE_ERROR_MESSAGES - wimlib_print_errors = show_error_messages; - return 0; -#else - if (show_error_messages) - return WIMLIB_ERR_UNSUPPORTED; - else - return 0; -#endif -} - -WIMLIBAPI int -wimlib_set_error_file(FILE *fp) -{ -#ifdef ENABLE_ERROR_MESSAGES - if (wimlib_owns_error_file) - fclose(wimlib_error_file); - wimlib_error_file = fp; - wimlib_print_errors = (fp != NULL); - wimlib_owns_error_file = false; - return 0; -#else - return WIMLIB_ERR_UNSUPPORTED; -#endif -} - -WIMLIBAPI int -wimlib_set_error_file_by_name(const tchar *path) -{ -#ifdef ENABLE_ERROR_MESSAGES - FILE *fp; - -#ifdef __WIN32__ - fp = win32_open_logfile(path); -#else - fp = fopen(path, "a"); -#endif - if (!fp) - return WIMLIB_ERR_OPEN; - wimlib_set_error_file(fp); - wimlib_owns_error_file = true; - return 0; -#else - return WIMLIB_ERR_UNSUPPORTED; -#endif -} - -static const tchar *error_strings[] = { - [WIMLIB_ERR_SUCCESS] - = T("Success"), - [WIMLIB_ERR_ALREADY_LOCKED] - = T("The WIM is already locked for writing"), - [WIMLIB_ERR_DECOMPRESSION] - = T("Failed to decompress compressed data"), - [WIMLIB_ERR_FUSE] - = T("An error was returned by fuse_main()"), - [WIMLIB_ERR_GLOB_HAD_NO_MATCHES] - = T("The provided file glob did not match any files"), - [WIMLIB_ERR_ICONV_NOT_AVAILABLE] - = T("The iconv() function does not seem to work. " - "Maybe check to make sure the directory /usr/lib/gconv exists"), - [WIMLIB_ERR_IMAGE_COUNT] - = T("Inconsistent image count among the metadata " - "resources, the WIM header, and/or the XML data"), - [WIMLIB_ERR_IMAGE_NAME_COLLISION] - = T("Tried to add an image with a name that is already in use"), - [WIMLIB_ERR_INSUFFICIENT_PRIVILEGES] - = T("The user does not have sufficient privileges"), - [WIMLIB_ERR_INTEGRITY] - = T("The WIM file is corrupted (failed integrity check)"), - [WIMLIB_ERR_INVALID_CAPTURE_CONFIG] - = T("The capture configuration string was invalid"), - [WIMLIB_ERR_INVALID_CHUNK_SIZE] - = T("The compression chunk size was unrecognized"), - [WIMLIB_ERR_INVALID_COMPRESSION_TYPE] - = T("The compression type was unrecognized"), - [WIMLIB_ERR_INVALID_HEADER] - = T("The WIM header was invalid"), - [WIMLIB_ERR_INVALID_IMAGE] - = T("Tried to select an image that does not exist in the WIM"), - [WIMLIB_ERR_INVALID_INTEGRITY_TABLE] - = T("The WIM's integrity table is invalid"), - [WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY] - = T("An entry in the WIM's lookup table is invalid"), - [WIMLIB_ERR_INVALID_METADATA_RESOURCE] - = T("The metadata resource is invalid"), - [WIMLIB_ERR_INVALID_MULTIBYTE_STRING] - = T("A string was not valid in the current locale's character encoding"), - [WIMLIB_ERR_INVALID_OVERLAY] - = T("Conflicting files in overlay when creating a WIM image"), - [WIMLIB_ERR_INVALID_PARAM] - = T("An invalid parameter was given"), - [WIMLIB_ERR_INVALID_PART_NUMBER] - = T("The part number or total parts of the WIM is invalid"), - [WIMLIB_ERR_INVALID_PIPABLE_WIM] - = T("The pipable WIM is invalid"), - [WIMLIB_ERR_INVALID_REPARSE_DATA] - = T("The reparse data of a reparse point was invalid"), - [WIMLIB_ERR_INVALID_RESOURCE_HASH] - = T("The SHA1 message digest of a WIM resource did not match the expected value"), - [WIMLIB_ERR_INVALID_UTF8_STRING] - = T("A string provided as input by the user was not a valid UTF-8 string"), - [WIMLIB_ERR_INVALID_UTF16_STRING] - = T("A string in a WIM dentry is not a valid UTF-16LE string"), - [WIMLIB_ERR_IS_DIRECTORY] - = T("One of the specified paths to delete was a directory"), - [WIMLIB_ERR_IS_SPLIT_WIM] - = T("The WIM is part of a split WIM, which is not supported for this operation"), - [WIMLIB_ERR_LIBXML_UTF16_HANDLER_NOT_AVAILABLE] - = T("libxml2 was unable to find a character encoding conversion handler " - "for UTF-16LE"), - [WIMLIB_ERR_LINK] - = T("Failed to create a hard or symbolic link when extracting " - "a file from the WIM"), - [WIMLIB_ERR_METADATA_NOT_FOUND] - = T("A required metadata resource could not be located"), - [WIMLIB_ERR_MKDIR] - = T("Failed to create a directory"), - [WIMLIB_ERR_MQUEUE] - = T("Failed to create or use a POSIX message queue"), - [WIMLIB_ERR_NOMEM] - = T("Ran out of memory"), - [WIMLIB_ERR_NOTDIR] - = T("Expected a directory"), - [WIMLIB_ERR_NOTEMPTY] - = T("Directory was not empty"), - [WIMLIB_ERR_NOT_A_REGULAR_FILE] - = T("One of the specified paths to extract did not " - "correspond to a regular file"), - [WIMLIB_ERR_NOT_A_WIM_FILE] - = T("The file did not begin with the magic characters that " - "identify a WIM file"), - [WIMLIB_ERR_NO_FILENAME] - = T("The WIM is not identified with a filename"), - [WIMLIB_ERR_NOT_PIPABLE] - = T("The WIM was not captured such that it can be " - "applied from a pipe"), - [WIMLIB_ERR_NTFS_3G] - = T("NTFS-3g encountered an error (check errno)"), - [WIMLIB_ERR_OPEN] - = T("Failed to open a file"), - [WIMLIB_ERR_OPENDIR] - = T("Failed to open a directory"), - [WIMLIB_ERR_PATH_DOES_NOT_EXIST] - = T("The path does not exist in the WIM image"), - [WIMLIB_ERR_READ] - = T("Could not read data from a file"), - [WIMLIB_ERR_READLINK] - = T("Could not read the target of a symbolic link"), - [WIMLIB_ERR_RENAME] - = T("Could not rename a file"), - [WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED] - = T("Unable to complete reparse point fixup"), - [WIMLIB_ERR_RESOURCE_NOT_FOUND] - = T("A file resource needed to complete the operation was missing from the WIM"), - [WIMLIB_ERR_RESOURCE_ORDER] - = T("The components of the WIM were arranged in an unexpected order"), - [WIMLIB_ERR_SET_ATTRIBUTES] - = T("Failed to set attributes on extracted file"), - [WIMLIB_ERR_SET_REPARSE_DATA] - = T("Failed to set reparse data on extracted file"), - [WIMLIB_ERR_SET_SECURITY] - = T("Failed to set file owner, group, or other permissions on extracted file"), - [WIMLIB_ERR_SET_SHORT_NAME] - = T("Failed to set short name on extracted file"), - [WIMLIB_ERR_SET_TIMESTAMPS] - = T("Failed to set timestamps on extracted file"), - [WIMLIB_ERR_SPLIT_INVALID] - = T("The WIM is part of an invalid split WIM"), - [WIMLIB_ERR_STAT] - = T("Could not read the metadata for a file or directory"), - [WIMLIB_ERR_UNEXPECTED_END_OF_FILE] - = T("Unexpectedly reached the end of the file"), - [WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE] - = T("A Unicode string could not be represented in the current locale's encoding"), - [WIMLIB_ERR_UNKNOWN_VERSION] - = T("The WIM file is marked with an unknown version number"), - [WIMLIB_ERR_UNSUPPORTED] - = T("The requested operation is unsupported"), - [WIMLIB_ERR_UNSUPPORTED_FILE] - = T("A file in the directory tree to archive was not of a supported type"), - [WIMLIB_ERR_WIM_IS_READONLY] - = T("The WIM is read-only (file permissions, header flag, or split WIM)"), - [WIMLIB_ERR_WRITE] - = T("Failed to write data to a file"), - [WIMLIB_ERR_XML] - = T("The XML data of the WIM is invalid"), - [WIMLIB_ERR_WIM_IS_ENCRYPTED] - = T("The WIM file (or parts of it) is encrypted"), - [WIMLIB_ERR_WIMBOOT] - = T("Failed to set WIMBoot pointer data"), - [WIMLIB_ERR_ABORTED_BY_PROGRESS] - = T("The operation was aborted by the library user"), - [WIMLIB_ERR_UNKNOWN_PROGRESS_STATUS] - = T("The user-provided progress function returned an unrecognized value"), - [WIMLIB_ERR_MKNOD] - = T("Unable to create a special file (e.g. device node or socket)"), - [WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY] - = T("There are still files open on the mounted WIM image"), - [WIMLIB_ERR_NOT_A_MOUNTPOINT] - = T("There is not a WIM image mounted on the directory"), - [WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT] - = T("The current user does not have permission to unmount the WIM image"), - [WIMLIB_ERR_FVE_LOCKED_VOLUME] - = T("The volume must be unlocked before it can be used"), -}; - -/* API function documented in wimlib.h */ -WIMLIBAPI const tchar * -wimlib_get_error_string(enum wimlib_error_code _code) -{ - unsigned int code = (unsigned int)_code; - - if (code >= ARRAY_LEN(error_strings) || error_strings[code] == NULL) - return T("Unknown error"); - - return error_strings[code]; -} - - +/******************* + * Memory allocation + *******************/ static void *(*wimlib_malloc_func) (size_t) = malloc; static void (*wimlib_free_func) (void *) = free; @@ -412,8 +49,8 @@ wimlib_malloc(size_t size) retry: ptr = (*wimlib_malloc_func)(size); if (unlikely(!ptr)) { - if (!size) { - size++; + if (size == 0) { + size = 1; goto retry; } } @@ -526,18 +163,38 @@ wimlib_set_memory_allocator(void *(*malloc_func)(size_t), return 0; } +/******************* + * String utilities + *******************/ + +#ifndef HAVE_MEMPCPY +void *mempcpy(void *dst, const void *src, size_t n) +{ + return memcpy(dst, src, n) + n; +} +#endif + +size_t +utf16le_strlen(const utf16lechar *s) +{ + const utf16lechar *p = s; + while (*p) + p++; + return (p - s) * sizeof(utf16lechar); +} + static bool seeded = false; static void seed_random(void) { - srand(time(NULL) * getpid()); + srand(now_as_wim_timestamp()); seeded = true; } /* Fills @n characters pointed to by @p with random alphanumeric characters. */ void -randomize_char_array_with_alnum(tchar p[], size_t n) +randomize_char_array_with_alnum(tchar *p, size_t n) { if (!seeded) seed_random(); @@ -561,17 +218,3 @@ randomize_byte_array(u8 *p, size_t n) while (n--) *p++ = rand(); } - - -void print_byte_field(const u8 field[], size_t len, FILE *out) -{ - while (len--) - tfprintf(out, T("%02hhx"), *field++); -} - -#ifndef HAVE_MEMPCPY -void *mempcpy(void *dst, const void *src, size_t n) -{ - return memcpy(dst, src, n) + n; -} -#endif diff --git a/src/win32_apply.c b/src/win32_apply.c index 4b6c5c66..7580a718 100644 --- a/src/win32_apply.c +++ b/src/win32_apply.c @@ -33,6 +33,7 @@ #include "wimlib/error.h" #include "wimlib/lookup_table.h" #include "wimlib/metadata.h" +#include "wimlib/paths.h" #include "wimlib/reparse.h" #include "wimlib/textfile.h" #include "wimlib/xml.h" -- 2.43.0