From 2a33c303e30fd740f740e21632fd06b9e414b0c7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 17 Mar 2013 14:38:41 -0500 Subject: [PATCH 1/1] Windows native build --- Makefile.am | 9 +++++-- configure.ac | 50 ++++++++++++++++++++++++--------------- programs/imagex.c | 14 ++++++++--- src/add_image.c | 31 ++++++++++++++++++------ src/dentry.c | 2 ++ src/dentry.h | 4 ++++ src/encoding.c | 57 +++++++++++++++++++++++++++++++++++++-------- src/extract_image.c | 5 ++++ src/util.c | 12 +++++++++- src/util.h | 2 +- src/wim.c | 34 +++++++++++++++++++++++++++ src/write.c | 28 ++++++++++++++++++++-- 12 files changed, 203 insertions(+), 45 deletions(-) diff --git a/Makefile.am b/Makefile.am index 70f42876..5dc694b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ AM_CFLAGS = -std=gnu99 -D_LARGEFILE_SOURCE \ lib_LTLIBRARIES = libwim.la -libwim_la_LDFLAGS = -version-info 4:0:2 $(CYGWIN_EXTRA_LDFLAGS) +libwim_la_LDFLAGS = -version-info 4:0:2 $(WINDOWS_EXTRA_LDFLAGS) libwim_la_SOURCES = \ src/add_image.c \ @@ -83,7 +83,8 @@ libwim_la_LIBADD = \ $(LTLIBICONV) \ $(LIBCRYPTO_LDADD) \ $(SSSE3_SHA1_OBJ) \ - $(PTHREAD_LDADD) + $(PTHREAD_LDADD) \ + $(WINDOWS_LDADD) libwim_la_CFLAGS = \ $(AM_CFLAGS) \ @@ -98,6 +99,10 @@ bin_PROGRAMS = imagex imagex_SOURCES = programs/imagex.c imagex_LDADD = $(top_builddir)/libwim.la +if WINDOWS_BUILD +imagex_SOURCES += programs/imagex-win32.c programs/imagex-win32.h +endif + dist_bin_SCRIPTS = programs/mkwinpeimg include_HEADERS = src/wimlib.h diff --git a/configure.ac b/configure.ac index 1b90c485..ad04b478 100644 --- a/configure.ac +++ b/configure.ac @@ -28,11 +28,12 @@ AC_CONFIG_FILES([Makefile ]) AC_PROG_CC AM_PROG_CC_C_O +AC_CANONICAL_HOST AC_CHECK_FUNCS([utimensat lutimes utime flock]) AC_CHECK_HEADERS([endian.h byteswap.h sys/byteorder.h sys/endian.h \ sys/param.h machine/endian.h alloca.h stdlib.h stdarg.h \ - errno.h attr/xattr.h utime.h sys/file.h]) + errno.h attr/xattr.h utime.h sys/file.h glob.h]) AC_CHECK_MEMBER([struct stat.st_mtim], [AC_DEFINE([HAVE_STAT_NANOSECOND_PRECISION], [1], @@ -41,15 +42,6 @@ AC_CHECK_MEMBER([struct stat.st_mtim], [], [[#include ]]) -AM_ICONV -if test "x$am_cv_func_iconv" != "xyes"; then - AC_MSG_ERROR([Cannot find the iconv() function. - iconv() is used to convert between UTF-8 and UTF-16 encodings of WIM - filenames and XML data. Wimlib cannot be compiled without it. iconv() - is available in the latest version of glibc and sometimes in other - libraries.]) -fi - AC_ARG_WITH(pkgconfigdir, [ --with-pkgconfigdir=DIR pkgconfig file in DIR @<:@LIBDIR/pkgconfig@:>@], @@ -172,29 +164,38 @@ fi AC_SUBST([PTHREAD_LDADD], [$PTHREAD_LDADD]) case "$host" in - *-*-cygwin*) - dnl -no-undefined is needed to build a DLL in a Cygwin environment. - CYGWIN_EXTRA_LDFLAGS="-no-undefined" - - dnl -fvisibility=hidden should not be used when building PE - dnl binaries on Windows + *-*-mingw*) + # Native Windows + WINDOWS_EXTRA_LDFLAGS="-no-undefined" VISIBILITY_CFLAGS="" - WITH_NTFS_3G_DEFAULT="no" WITH_FUSE_DEFAULT="no" WINDOWS_BUILD="yes" + WINDOWS_LDADD="-lshlwapi" + ;; + *-*-cygwin*) + # Cygwin (WARNING: not well supported) + WINDOWS_EXTRA_LDFLAGS="-no-undefined" + VISIBILITY_CFLAGS="" + WITH_NTFS_3G_DEFAULT="no" + WITH_FUSE_DEFAULT="no" + WINDOWS_BUILD="yes" + WINDOWS_LDADD="" ;; *) - CYGWIN_EXTRA_LDFLAGS="" + # UNIX / other + WINDOWS_EXTRA_LDFLAGS="" VISIBILITY_CFLAGS="-fvisibility=hidden" WITH_NTFS_3G_DEFAULT="yes" WITH_FUSE_DEFAULT="yes" WINDOWS_BUILD="no" + WINDOWS_LDADD="" ;; esac -AC_SUBST([CYGWIN_EXTRA_LDFLAGS], [$CYGWIN_EXTRA_LDFLAGS]) +AC_SUBST([WINDOWS_EXTRA_LDFLAGS], [$WINDOWS_EXTRA_LDFLAGS]) AC_SUBST([VISIBILITY_CFLAGS], [$VISIBILITY_CFLAGS]) +AC_SUBST([WINDOWS_LDADD], [$WINDOWS_LDADD]) AM_CONDITIONAL([WINDOWS_BUILD], [test "x$WINDOWS_BUILD" = "xyes"]) AC_MSG_CHECKING([whether to include support for ntfs-3g]) @@ -234,6 +235,17 @@ if test "x$WITH_NTFS_3G" = "xyes"; then else LIBNTFS_3G_LDADD= LIBNTFS_3G_CFLAGS= + + if test "x$WINDOWS_BUILD" != "xyes"; then + AM_ICONV + if test "x$am_cv_func_iconv" != "xyes"; then + AC_MSG_ERROR([Cannot find the iconv() function. + iconv() is used to convert between UTF-8 and UTF-16 encodings of WIM + filenames and XML data. Wimlib cannot be compiled without it. iconv() + is available in the latest version of glibc and sometimes in other + libraries.]) + fi + fi fi AM_CONDITIONAL([WITH_NTFS_3G], [test "x$WITH_NTFS_3G" = "xyes"]) diff --git a/programs/imagex.c b/programs/imagex.c index d6d26171..19725058 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -29,7 +29,7 @@ #include #include #include -#include + #include #include #include @@ -43,6 +43,12 @@ #include #endif +#ifdef __WIN32__ +# include "imagex-win32.h" +#else +# include +#endif + #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) #define for_opt(c, opts) while ((c = getopt_long_only(argc, (char**)argv, "", \ @@ -733,6 +739,7 @@ static int open_swms_from_glob(const char *swm_glob, glob_t globbuf; int ret; + /* Warning: glob() is replaced in Windows native builds */ ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); if (ret != 0) { if (ret == GLOB_NOMATCH) { @@ -1322,9 +1329,10 @@ static int imagex_export(int argc, char **argv) wim_is_new = false; /* Destination file exists. */ - if (!S_ISREG(stbuf.st_mode) && !S_ISLNK(stbuf.st_mode)) { + + if (!S_ISREG(stbuf.st_mode)) { imagex_error("`%s' is not a regular file", - dest_wimfile); + dest_wimfile); ret = -1; goto out; } diff --git a/src/add_image.c b/src/add_image.c index b5f8c069..a57541f9 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -37,13 +37,21 @@ # include "timestamp.h" #endif +#ifdef __WIN32__ +#include +#endif + #include "wimlib_internal.h" #include "dentry.h" #include "lookup_table.h" #include "xml.h" #include #include + +#ifndef __WIN32__ #include +#endif + #include #include #include @@ -162,7 +170,7 @@ static int win32_get_security_descriptor(struct wim_dentry *dentry, DWORD len = lenNeeded; char buf[len]; if (GetFileSecurityW(path_utf16, requestedInformation, - buf, len, &lenNeeded)) + (PSECURITY_DESCRIPTOR)buf, len, &lenNeeded)) { int security_id = sd_set_add_sd(sd_set, buf, len); if (security_id < 0) @@ -1138,6 +1146,19 @@ static int capture_config_set_prefix(struct capture_config *config, return 0; } +static bool path_matches_pattern(const char *path, const char *pattern) +{ +#ifdef __WIN32__ + return PathMatchSpecA(path, pattern); +#else + return fnmatch(pattern, path, FNM_PATHNAME + #ifdef FNM_CASEFOLD + | FNM_CASEFOLD + #endif + ) == 0; +#endif +} + static bool match_pattern(const char *path, const char *path_basename, const struct pattern_list *list) { @@ -1155,12 +1176,8 @@ static bool match_pattern(const char *path, const char *path_basename, /* A file name pattern */ string = path_basename; } - if (fnmatch(pat, string, FNM_PATHNAME - #ifdef FNM_CASEFOLD - | FNM_CASEFOLD - #endif - ) == 0) - { + + if (path_matches_pattern(string, pat)) { DEBUG("`%s' matches the pattern \"%s\"", string, pat); return true; diff --git a/src/dentry.c b/src/dentry.c index 58869af4..15a44cee 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -974,6 +974,7 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, inode->i_num_ads--; } +#ifndef __WIN32__ int inode_get_unix_data(const struct wim_inode *inode, struct wimlib_unix_data *unix_data, u16 *stream_idx_ret) @@ -1043,6 +1044,7 @@ int inode_set_unix_data(struct wim_inode *inode, inode_remove_ads(inode, stream_idx, lookup_table); return ret; } +#endif /* !__WIN32__ */ /* * Reads the alternate data stream entries of a WIM dentry. diff --git a/src/dentry.h b/src/dentry.h index f5e4687e..76087320 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -413,6 +413,9 @@ struct wimlib_unix_data { u16 gid; u16 mode; } PACKED; + +#ifndef __WIN32__ + #define NO_UNIX_DATA (-1) #define BAD_UNIX_DATA (-2) extern int inode_get_unix_data(const struct wim_inode *inode, @@ -428,6 +431,7 @@ extern int inode_set_unix_data(struct wim_inode *inode, uid_t uid, gid_t gid, mode_t mode, struct wim_lookup_table *lookup_table, int which); +#endif extern int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, u64 offset, struct wim_dentry *dentry); diff --git a/src/encoding.c b/src/encoding.c index d823f1dd..bddb1810 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -21,6 +21,7 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ +#include "config.h" #include "wimlib.h" #include "util.h" #include "endianness.h" @@ -28,10 +29,13 @@ #include #ifdef WITH_NTFS_3G -#include -#include +# include +# include +#elif defined(__WIN32__) +# include +# include #else -#include +# include #endif /* @@ -41,7 +45,7 @@ * libntfs-3g/unistr.c in the NTFS-3g sources. (Modified slightly to remove * unneeded functionality.) */ -#ifndef WITH_NTFS_3G +#if !defined(WITH_NTFS_3G) && !defined(__WIN32__) /* * Return the amount of 8-bit elements in UTF-8 needed (without the terminating * null) to store a given UTF-16LE string. @@ -130,9 +134,7 @@ static int utf8_to_utf16_size(const char *s) } return count; } -#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); @@ -171,7 +173,7 @@ void iconv_global_cleanup() if (cd_utf16_to_utf8 != (iconv_t)(-1)) iconv_close(cd_utf16_to_utf8); } -#endif +#endif /* !WITH_NTFS_3G && !__WIN32__ */ /* Converts a string in the UTF-16LE encoding to a newly allocated string in the * UTF-8 encoding. @@ -208,8 +210,24 @@ int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes, else ret = WIMLIB_ERR_INVALID_UTF16_STRING; } -#else /* !WITH_NTFS_3G */ - +#elif defined(__WIN32__) + char *utf8_str; + size_t utf8_nbytes; + utf8_nbytes = wcstombs(NULL, (const wchar_t*)utf16_str, 0); + if (utf8_nbytes == (size_t)(-1)) { + ret = WIMLIB_ERR_INVALID_UTF16_STRING; + } else { + utf8_str = MALLOC(utf8_nbytes + 1); + if (!utf8_str) { + ret = WIMLIB_ERR_NOMEM; + } else { + wcstombs(utf8_str, (const wchar_t*)utf16_str, utf8_nbytes + 1); + *utf8_str_ret = utf8_str; + *utf8_nbytes_ret = utf8_nbytes; + ret = 0; + } + } +#else ret = iconv_global_init(); if (ret != 0) return ret; @@ -296,8 +314,27 @@ int utf8_to_utf16(const char *utf8_str, size_t utf8_nbytes, else ret = WIMLIB_ERR_INVALID_UTF8_STRING; } -#else /* !WITH_NTFS_3G */ +#elif defined(__WIN32__) + char *utf16_str; + size_t utf16_nchars; + utf16_nchars = mbstowcs(NULL, utf8_str, 0); + if (utf16_nchars == (size_t)(-1)) { + ret = WIMLIB_ERR_INVALID_UTF8_STRING; + } else { + utf16_str = MALLOC((utf16_nchars + 1) * sizeof(wchar_t)); + if (!utf16_str) { + ret = WIMLIB_ERR_NOMEM; + } else { + mbstowcs((wchar_t*)utf16_str, utf8_str, + utf16_nchars + 1); + *utf16_str_ret = utf16_str; + *utf16_nbytes_ret = utf16_nchars * sizeof(wchar_t); + ret = 0; + } + } + +#else ret = iconv_global_init(); if (ret != 0) return ret; diff --git a/src/extract_image.c b/src/extract_image.c index 8e5d130e..86063819 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -61,6 +61,11 @@ #include #endif +#if defined(__WIN32__) +# define swprintf _snwprintf +# define mkdir(path, mode) (!CreateDirectoryA(path, NULL)) +#endif + #if defined(__CYGWIN__) || defined(__WIN32__) static int win32_set_reparse_data(HANDLE h, diff --git a/src/util.c b/src/util.c index 9db817ac..31b51ff4 100644 --- a/src/util.c +++ b/src/util.c @@ -21,6 +21,10 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ +#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. */ @@ -38,6 +42,11 @@ #include /* for getpid() */ +/* Windoze compatibility */ +#ifdef __WIN32__ +# define strerror_r(errnum, buf, bufsize) strerror_s(buf, bufsize, errnum) +#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 @@ -54,7 +63,8 @@ static void wimlib_vmsg(const char *tag, const char *format, vfprintf(stderr, format, va); if (perror && errno_save != 0) { char buf[50]; - int res = strerror_r(errno_save, buf, sizeof(buf)); + int res; + res = strerror_r(errno_save, buf, sizeof(buf)); if (res) { snprintf(buf, sizeof(buf), "unknown error (errno=%d)", errno_save); diff --git a/src/util.h b/src/util.h index 2dc79437..b56fa4fa 100644 --- a/src/util.h +++ b/src/util.h @@ -175,7 +175,7 @@ extern char *wimlib_strdup(const char *str); /* encoding.c */ -#ifdef WITH_NTFS_3G +#if defined(WITH_NTFS_3G) || defined(__WIN32__) static inline int iconv_global_init() { return 0; diff --git a/src/wim.c b/src/wim.c index bd31c5b3..1ffc3fef 100644 --- a/src/wim.c +++ b/src/wim.c @@ -24,6 +24,14 @@ */ #include "config.h" + +#ifdef __WIN32__ +# include +# ifdef ERROR +# undef ERROR +# endif +#endif + #include #include #include @@ -43,6 +51,32 @@ #include "lookup_table.h" #include "xml.h" +#ifdef __WIN32__ +static char *realpath(const char *path, char *resolved_path) +{ + DWORD ret; + wimlib_assert(resolved_path == NULL); + + ret = GetFullPathNameA(path, 0, NULL, NULL); + if (!ret) + goto fail_win32; + + resolved_path = MALLOC(ret + 1); + if (!resolved_path) + goto fail; + ret = GetFullPathNameA(path, ret, resolved_path, NULL); + if (!ret) { + free(resolved_path); + goto fail_win32; + } + return resolved_path; +fail_win32: + win32_error(GetLastError()); +fail: + return NULL; +} +#endif + static int image_print_metadata(WIMStruct *w) { DEBUG("Printing metadata for image %d", w->current_image); diff --git a/src/write.c b/src/write.c index 4e59b851..ea3f583c 100644 --- a/src/write.c +++ b/src/write.c @@ -32,6 +32,13 @@ #include #endif +#ifdef __WIN32__ +# include +# ifdef ERROR +# undef ERROR +# endif +#endif + #include "list.h" #include "wimlib_internal.h" #include "buffer_io.h" @@ -61,6 +68,13 @@ #include #endif +#ifdef __WIN32__ +# ifdef fsync +# undef fsync +# endif +# define fsync(fd) 0 +#endif + static int fflush_and_ftruncate(FILE *fp, off_t size) { int ret; @@ -1205,6 +1219,16 @@ out: return ret; } +static long get_default_num_threads() +{ +#ifdef __WIN32__ + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +#else + return sysconf(_SC_NPROCESSORS_ONLN); +#endif +} static int write_stream_list_parallel(struct list_head *stream_list, FILE *out_fp, @@ -1220,8 +1244,8 @@ static int write_stream_list_parallel(struct list_head *stream_list, pthread_t *compressor_threads = NULL; if (num_threads == 0) { - long nthreads = sysconf(_SC_NPROCESSORS_ONLN); - if (nthreads < 1) { + long nthreads = get_default_num_threads(); + if (nthreads < 1 || nthreads > UINT_MAX) { WARNING("Could not determine number of processors! Assuming 1"); goto out_serial; } else { -- 2.43.0