X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Futil.c;h=5421a6b5c53beab448e4c23a9d9be1004b92f8ea;hb=f002af145a92af4a6753f654a9bd6f35abcc186a;hp=1e26a6f4349b74dd40c3570e99f707b729629b76;hpb=670a54f5de37bff02c49f37d690b26654cf7fa1d;p=wimlib diff --git a/src/util.c b/src/util.c index 1e26a6f4..5421a6b5 100644 --- a/src/util.c +++ b/src/util.c @@ -23,27 +23,35 @@ #include "config.h" -#define MINGW_HAS_SECURE_API #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 + #define _GNU_SOURCE -#include "wimlib_internal.h" #include "endianness.h" #include "timestamp.h" +#include "wimlib_internal.h" #include #include -#include #include +#include +#include -#include /* for getpid() */ -size_t +#ifdef __WIN32__ +# include "win32.h" +# define pread win32_pread +# define pwrite win32_pwrite +# define writev win32_writev +#else +# include /* for writev() and `struct iovec' */ +#endif + +static size_t utf16le_strlen(const utf16lechar *s) { const utf16lechar *p = s; @@ -52,62 +60,59 @@ utf16le_strlen(const utf16lechar *s) return (p - s) * sizeof(utf16lechar); } -/* Handle %W for UTF16-LE printing and %U for UTF-8 printing. +#ifdef __WIN32__ +# define wimlib_vfprintf vfwprintf +#else +/* Handle %W for UTF16-LE printing. * * TODO: this is not yet done properly--- it's assumed that if the format string - * contains %W and/or %U, then it contains no other format specifiers. + * contains %W, then it contains no other format specifiers. */ static int wimlib_vfprintf(FILE *fp, const tchar *format, va_list va) { const tchar *p; + int n; for (p = format; *p; p++) - if (*p == '%' && (*(p + 1) == T('W') || *(p + 1) == T('U'))) + if (*p == T('%') && *(p + 1) == T('W')) goto special; return tvfprintf(fp, format, va); special: - /* XXX */ - wimlib_assert(0); -#if 0 - ; - int n = 0; + n = 0; for (p = format; *p; p++) { - if (*p == T('%') && (*(p + 1) == T('W') || *(p + 1) == T('U'))) { + if (*p == T('%') && (*(p + 1) == T('W'))) { int ret; - tchar *mbs; - size_t mbs_nbytes; + tchar *tstr; + size_t tstr_nbytes; + utf16lechar *ucs = va_arg(va, utf16lechar*); - if (*(p + 1) == T('W')) { - utf16lechar *ucs = va_arg(va, utf16lechar*); + if (ucs) { size_t ucs_nbytes = utf16le_strlen(ucs); - ret = utf16le_to_mbs(ucs, ucs_nbytes, - &mbs, &mbs_nbytes); - } else { - utf8char *ucs = va_arg(va, utf8char*); - size_t ucs_nbytes = strlen(ucs); - ret = utf8_to_mbs(ucs, ucs_nbytes, - &mbs, &mbs_nbytes); - } - if (ret) { - ret = tfprintf(fp, T("??????")); + + ret = utf16le_to_tstr(ucs, ucs_nbytes, + &tstr, &tstr_nbytes); + if (ret) { + ret = tfprintf(fp, T("??????")); + } else { + ret = tfprintf(fp, T("%"TS), tstr); + FREE(tstr); + } + if (ret < 0) + return -1; + else + n += ret; } else { - ret = tfprintf(fp, T("%s"), mbs); - FREE(mbs); + n += tfprintf(fp, T("(null)")); } - if (ret < 0) - return -1; - else - n += ret; p++; } else { - if (putc(*p, fp) == EOF) + if (tputc(*p, fp) == EOF) return -1; n++; } } return n; -#endif } int @@ -133,6 +138,7 @@ wimlib_fprintf(FILE *fp, const tchar *format, ...) va_end(va); return ret; } +#endif #if defined(ENABLE_ERROR_MESSAGES) || defined(ENABLE_DEBUG) static void @@ -158,6 +164,7 @@ wimlib_vmsg(const tchar *tag, const tchar *format, tfprintf(stderr, T(": %"TS), buf); } tputc(T('\n'), stderr); + fflush(stderr); errno = errno_save; #ifndef DEBUG } @@ -177,7 +184,7 @@ wimlib_error(const tchar *format, ...) va_list va; va_start(va, format); - wimlib_vmsg(T("[ERROR] "), format, va, false); + wimlib_vmsg(T("\r[ERROR] "), format, va, false); va_end(va); } @@ -187,7 +194,7 @@ wimlib_error_with_errno(const tchar *format, ...) va_list va; va_start(va, format); - wimlib_vmsg(T("[ERROR] "), format, va, true); + wimlib_vmsg(T("\r[ERROR] "), format, va, true); va_end(va); } @@ -197,7 +204,7 @@ wimlib_warning(const tchar *format, ...) va_list va; va_start(va, format); - wimlib_vmsg(T("[WARNING] "), format, va, false); + wimlib_vmsg(T("\r[WARNING] "), format, va, false); va_end(va); } @@ -207,7 +214,7 @@ wimlib_warning_with_errno(const tchar *format, ...) va_list va; va_start(va, format); - wimlib_vmsg(T("[WARNING] "), format, va, true); + wimlib_vmsg(T("\r[WARNING] "), format, va, true); va_end(va); } @@ -217,11 +224,10 @@ wimlib_warning_with_errno(const tchar *format, ...) void wimlib_debug(const tchar *file, int line, const char *func, const tchar *format, ...) { - va_list va; tchar buf[tstrlen(file) + strlen(func) + 30]; - tsprintf(buf, "[%"TS" %d] %s(): ", file, line, func); + tsprintf(buf, T("[%"TS" %d] %s(): "), file, line, func); va_start(va, format); wimlib_vmsg(buf, format, va, false); @@ -269,6 +275,8 @@ static const tchar *error_strings[] = { [WIMLIB_ERR_IMAGE_COUNT] = T("Inconsistent image count among the metadata " "resources, the WIM header, and/or the XML data"), + [WIMLIB_ERR_INSUFFICIENT_PRIVILEGES_TO_EXTRACT] + = T("User does not have sufficient privileges to correctly extract the data"), [WIMLIB_ERR_IMAGE_NAME_COLLISION] = T("Tried to add an image with a name that is already in use"), [WIMLIB_ERR_INTEGRITY] @@ -299,6 +307,8 @@ static const tchar *error_strings[] = { = 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_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_RESOURCE_SIZE] @@ -343,8 +353,8 @@ static const tchar *error_strings[] = { = T("Could not read the target of a symbolic link"), [WIMLIB_ERR_RENAME] = T("Could not rename a file"), - [WIMLIB_ERR_REOPEN] - = T("Could not re-open the WIM after overwriting it"), + [WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED] + = T("Unable to complete reparse point fixup"), [WIMLIB_ERR_RESOURCE_ORDER] = T("The components of the WIM were arranged in an unexpected order"), [WIMLIB_ERR_SPECIAL_FILE] @@ -363,6 +373,8 @@ static const tchar *error_strings[] = { = T("The WIM file is marked with an unknown version number"), [WIMLIB_ERR_UNSUPPORTED] = T("The requested operation is unsupported"), + [WIMLIB_ERR_VOLUME_LACKS_FEATURES] + = T("The volume did not support a feature necessary to complete the operation"), [WIMLIB_ERR_WRITE] = T("Failed to write data to a file"), [WIMLIB_ERR_XML] @@ -486,21 +498,6 @@ randomize_byte_array(u8 *p, size_t n) *p++ = rand(); } -/* Takes in a path of length @len in @buf, and transforms it into a string for - * the path of its parent directory. */ -void -to_parent_name(tchar *buf, size_t len) -{ - ssize_t i = (ssize_t)len - 1; - while (i >= 0 && buf[i] == T('/')) - i--; - while (i >= 0 && buf[i] != T('/')) - i--; - while (i >= 0 && buf[i] == T('/')) - i--; - buf[i + 1] = T('\0'); -} - const tchar * path_basename_with_len(const tchar *path, size_t len) { @@ -544,82 +541,162 @@ path_stream_name(const tchar *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. - * - * @path: The file path to split. - * @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 - * null byte in the case of a path without any '/'. - */ -const tchar * -path_next_part(const tchar *path, size_t *first_part_len_ret) +u64 +get_wim_timestamp() { - size_t i; - const tchar *next_part; - - i = 0; - while (path[i] != T('/') && path[i] != T('\0')) - i++; - if (first_part_len_ret) - *first_part_len_ret = i; - next_part = &path[i]; - while (*next_part == T('/')) - next_part++; - return next_part; + struct timeval tv; + gettimeofday(&tv, NULL); + return timeval_to_wim_timestamp(tv); } -/* Returns the number of components of @path. */ -int -get_num_path_components(const char *path) +void +wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len) { - int num_components = 0; - while (*path) { - while (*path == '/') - path++; - if (*path) - num_components++; - while (*path && *path != '/') - path++; + struct tm tm; + time_t t = wim_timestamp_to_unix(timestamp); + gmtime_r(&t, &tm); + tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm); +} + +void +zap_backslashes(tchar *s) +{ + if (s) { + while (*s != T('\0')) { + if (*s == T('\\')) + *s = T('/'); + s++; + } } - return num_components; } +/* Like read(), but keep trying until everything has been written or we know for + * sure that there was an error (or end-of-file). */ +size_t +full_read(int fd, void *buf, size_t count) +{ + ssize_t bytes_read; + size_t bytes_remaining; + + for (bytes_remaining = count; + bytes_remaining != 0; + bytes_remaining -= bytes_read, buf += bytes_read) + { + bytes_read = read(fd, buf, bytes_remaining); + if (bytes_read <= 0) { + if (bytes_read == 0) + errno = EIO; + else if (errno == EINTR) + continue; + break; + } + } + return count - bytes_remaining; +} -/* - * Prints a string. Printable characters are printed as-is, while unprintable - * characters are printed as their octal escape codes. - */ -void -print_string(const void *string, size_t len) +/* Like write(), but keep trying until everything has been written or we know + * for sure that there was an error. */ +size_t +full_write(int fd, const void *buf, size_t count) { - const u8 *p = string; + ssize_t bytes_written; + size_t bytes_remaining; + + for (bytes_remaining = count; + bytes_remaining != 0; + bytes_remaining -= bytes_written, buf += bytes_written) + { + bytes_written = write(fd, buf, bytes_remaining); + if (bytes_written < 0) { + if (errno == EINTR) + continue; + break; + } + } + return count - bytes_remaining; +} - while (len--) { - if (isprint(*p)) - putchar(*p); - else - printf("\\%03hho", *p); - p++; +/* Like pread(), but keep trying until everything has been read or we know for + * sure that there was an error (or end-of-file) */ +size_t +full_pread(int fd, void *buf, size_t count, off_t offset) +{ + ssize_t bytes_read; + size_t bytes_remaining; + + for (bytes_remaining = count; + bytes_remaining != 0; + bytes_remaining -= bytes_read, buf += bytes_read, + offset += bytes_read) + { + bytes_read = pread(fd, buf, bytes_remaining, offset); + if (bytes_read <= 0) { + if (bytes_read == 0) + errno = EIO; + else if (errno == EINTR) + continue; + break; + } } + return count - bytes_remaining; } -u64 -get_wim_timestamp() +/* Like pwrite(), but keep trying until everything has been written or we know + * for sure that there was an error. */ +size_t +full_pwrite(int fd, const void *buf, size_t count, off_t offset) { - struct timeval tv; - gettimeofday(&tv, NULL); - return timeval_to_wim_timestamp(tv); + ssize_t bytes_written; + size_t bytes_remaining; + + for (bytes_remaining = count; + bytes_remaining != 0; + bytes_remaining -= bytes_written, buf += bytes_written, + offset += bytes_written) + { + bytes_written = pwrite(fd, buf, bytes_remaining, offset); + if (bytes_written < 0) { + if (errno == EINTR) + continue; + break; + } + } + return count - bytes_remaining; } -void -wim_timestamp_to_str(u64 timestamp, tchar *buf, size_t len) +/* Like writev(), but keep trying until everything has been written or we know + * for sure that there was an error. */ +size_t +full_writev(int fd, struct iovec *iov, int iovcnt) { - struct tm tm; - time_t t = wim_timestamp_to_unix(timestamp); - gmtime_r(&t, &tm); - tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm); + size_t total_bytes_written = 0; + while (iovcnt > 0) { + ssize_t bytes_written; + + bytes_written = writev(fd, iov, iovcnt); + if (bytes_written < 0) { + if (errno == EINTR) + continue; + break; + } + total_bytes_written += bytes_written; + while (bytes_written) { + if (bytes_written >= iov[0].iov_len) { + bytes_written -= iov[0].iov_len; + iov++; + iovcnt--; + } else { + iov[0].iov_base += bytes_written; + iov[0].iov_len -= bytes_written; + bytes_written = 0; + } + } + } + return total_bytes_written; +} + +off_t +filedes_offset(int fd) +{ + return lseek(fd, 0, SEEK_CUR); }