X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Futil.c;h=a5899bcd349db00366206ce934ab20cb82260527;hb=1e167170cdc048c6a93db6d994d9da161f8553d9;hp=b688ac216f4be3e490480d220984bea5833af0b8;hpb=c6a1140e085f633273fcf47a6462bd9382ce118a;p=wimlib diff --git a/src/util.c b/src/util.c index b688ac21..a5899bcd 100644 --- a/src/util.c +++ b/src/util.c @@ -23,26 +23,32 @@ #include "config.h" + #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() */ #ifdef __WIN32__ -#include "win32.h" +# 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 @@ -80,20 +86,25 @@ special: tchar *tstr; size_t tstr_nbytes; utf16lechar *ucs = va_arg(va, utf16lechar*); - size_t ucs_nbytes = utf16le_strlen(ucs); - ret = utf16le_to_tstr(ucs, ucs_nbytes, - &tstr, &tstr_nbytes); - if (ret) { - ret = tfprintf(fp, T("??????")); + if (ucs) { + size_t ucs_nbytes = utf16le_strlen(ucs); + + 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("%"TS), tstr); - FREE(tstr); + n += tfprintf(fp, T("(null)")); } - if (ret < 0) - return -1; - else - n += ret; p++; } else { if (tputc(*p, fp) == EOF) @@ -153,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 } @@ -172,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); } @@ -182,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); } @@ -192,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); } @@ -202,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); } @@ -212,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); @@ -264,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] @@ -294,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] @@ -307,6 +322,8 @@ static const tchar *error_strings[] = { = 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_LIBXML_UTF16_HANDLER_NOT_AVAILABLE] = T("libxml2 was unable to find a character encoding conversion handler " "for UTF-16LE"), @@ -321,9 +338,14 @@ static const tchar *error_strings[] = { = T("Ran out of memory"), [WIMLIB_ERR_NOTDIR] = T("Expected a directory"), + [WIMLIB_ERR_NOTEMPTY] + = T("Directory was not empty"), [WIMLIB_ERR_NOT_A_WIM_FILE] = T("The file did not begin with the magic characters that " "identify a WIM file"), + [WIMLIB_ERR_NOT_A_REGULAR_FILE] + = T("One of the specified paths to extract did not " + "correspond to a regular file"), [WIMLIB_ERR_NO_FILENAME] = T("The WIM is not identified with a filename"), [WIMLIB_ERR_NTFS_3G] @@ -332,14 +354,16 @@ static const tchar *error_strings[] = { = 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_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] @@ -358,6 +382,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] @@ -552,3 +578,173 @@ zap_backslashes(tchar *s) } } } + +tchar * +canonicalize_fs_path(const tchar *fs_path) +{ + tchar *canonical_path; + + if (!fs_path) + fs_path = T(""); + canonical_path = TSTRDUP(fs_path); + zap_backslashes(canonical_path); + return canonical_path; +} + +/* Strip leading and trailing slashes from a string. Also translates + * backslashes into forward slashes. */ +tchar * +canonicalize_wim_path(const tchar *wim_path) +{ + tchar *p; + tchar *canonical_path; + + if (wim_path == NULL) { + wim_path = T(""); + } else { + while (*wim_path == T('/') || *wim_path == T('\\')) + wim_path++; + } + canonical_path = TSTRDUP(wim_path); + if (canonical_path) { + zap_backslashes(canonical_path); + for (p = tstrchr(canonical_path, T('\0')) - 1; + p >= canonical_path && *p == T('/'); + p--) + { + *p = T('\0'); + } + } + return canonical_path; +} + +/* 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; +} + +/* 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) +{ + 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; +} + +/* 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; +} + +/* 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) +{ + 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; +} + +/* 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) +{ + 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); +}