]> wimlib.net Git - wimlib/commitdiff
re-organize win32 code
authorEric Biggers <ebiggers3@gmail.com>
Sun, 17 Mar 2013 21:31:53 +0000 (16:31 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 17 Mar 2013 21:31:53 +0000 (16:31 -0500)
15 files changed:
Makefile.am
NEWS
README.WINDOWS
configure.ac
src/add_image.c
src/extract_image.c
src/lookup_table.c
src/mount_image.c
src/resource.c
src/security.c
src/security.h
src/wimlib_internal.h
src/win32.c
src/win32.h [new file with mode: 0644]
src/write.c

index 5dc694b7ccd49cc9bb3714e329291e63aa1e1d09..7700f46ac78bdb703939dbe6f84488882fbf5282 100644 (file)
@@ -1,13 +1,13 @@
 ACLOCAL_AMFLAGS = -I m4
 
 ACLOCAL_AMFLAGS = -I m4
 
-AM_CPPFLAGS    = -I$(top_srcdir)/src
+AM_CPPFLAGS    = -I$(top_srcdir)/src $(WINDOWS_CPPFLAGS)
 
 AM_CFLAGS      = -std=gnu99 -D_LARGEFILE_SOURCE \
                   -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 
 lib_LTLIBRARIES = libwim.la
 
 
 AM_CFLAGS      = -std=gnu99 -D_LARGEFILE_SOURCE \
                   -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 
 lib_LTLIBRARIES = libwim.la
 
-libwim_la_LDFLAGS = -version-info 4:0:2 $(WINDOWS_EXTRA_LDFLAGS)
+libwim_la_LDFLAGS = -version-info 4:0:2 $(WINDOWS_LDFLAGS)
 
 libwim_la_SOURCES =            \
        src/add_image.c         \
 
 libwim_la_SOURCES =            \
        src/add_image.c         \
@@ -53,7 +53,6 @@ libwim_la_SOURCES =           \
        src/wim.c               \
        src/wimlib.h            \
        src/wimlib_internal.h   \
        src/wim.c               \
        src/wimlib.h            \
        src/wimlib_internal.h   \
-       src/win32.c             \
        src/write.c             \
        src/xml.c               \
        src/xml.h               \
        src/write.c             \
        src/xml.c               \
        src/xml.h               \
@@ -99,8 +98,9 @@ bin_PROGRAMS   = imagex
 imagex_SOURCES   = programs/imagex.c
 imagex_LDADD    = $(top_builddir)/libwim.la
 
 imagex_SOURCES   = programs/imagex.c
 imagex_LDADD    = $(top_builddir)/libwim.la
 
-if WINDOWS_BUILD
+if WINDOWS_NATIVE_BUILD
 imagex_SOURCES += programs/imagex-win32.c programs/imagex-win32.h
 imagex_SOURCES += programs/imagex-win32.c programs/imagex-win32.h
+libwim_la_SOURCES += src/win32.c
 endif
 
 dist_bin_SCRIPTS = programs/mkwinpeimg
 endif
 
 dist_bin_SCRIPTS = programs/mkwinpeimg
@@ -160,13 +160,10 @@ if WITH_NTFS_3G
 dist_check_SCRIPTS += tests/test-imagex-ntfs
 endif
 
 dist_check_SCRIPTS += tests/test-imagex-ntfs
 endif
 
-if WINDOWS_BUILD
+if WINDOWS_NATIVE_BUILD
+# TODO: The tests need to be re-written for Windows builds.
 TESTS =
 else
 TESTS =
 else
-# TODO: The tests need to be re-written for Windows builds.  One issue (that
-# applies to both test-imagex and test-imagex-capture_and_apply) is that
-# Cygwin's 'ln -s' will create some sort of regular file with special contents
-# rather than a reparse point.
 TESTS = $(dist_check_SCRIPTS)
 endif
 
 TESTS = $(dist_check_SCRIPTS)
 endif
 
diff --git a/NEWS b/NEWS
index 31a63bc1b95d33d5e25840ae8889db4ae67f3310..5c65755892bf7c45961ee873ae1180cdf167d975 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,7 @@
 Only the most important changes more recent than version 0.6 are noted here.
 
 Version 1.3.0:
 Only the most important changes more recent than version 0.6 are noted here.
 
 Version 1.3.0:
-       Experimental support for Windows builds of wimlib has been added.
+       Added experimental support for native Windows builds.
 
        --source-list option added to `imagex capture' and `imagex append'.
 
 
        --source-list option added to `imagex capture' and `imagex append'.
 
index 952cbd85cf1ae239fbe2de95b1ec18074ae81d98..45b7ad568526e9a8453f407084dc7e57a97a3453 100644 (file)
@@ -1,23 +1,18 @@
-wimlib 1.3.0 has added experimental support for Windows builds.  These builds
-include both the "wimlib" library (built as a DLL) and the "imagex" executable.
+                                  INTRODUCTION
 
 
-The Windows builds use native Win32 calls when appropriate to handle alternate
-data streams, security descriptors, and reparse points.
+wimlib 1.3.0 has added experimental support for Windows builds.  The Windows
+build consists of both the "wimlib" library (which can be built as a DLL) and
+the "imagex" executable.
 
 
-Windows support currently has the following limitations:
+The Windows build of wimlib uses native Win32 calls when appropriate to handle
+alternate data streams, security descriptors, and reparse points.
 
 
--  It relies on the Cygwin UNIX-compatibility layer.  You do not, however, need
-   to have the Cygwin distribution installed to run it, as I have posted a ZIP
-   file on SourceForge that contains the build of wimlib and "imagex" along with
-   the DLLs needed for it to run.  Please note that these DLLs are free and open
-   source software; see http://www.cygwin.com/ for more details.
+Mounting WIM files is not supported on Windows.  Also please note that wimlib's
+"imagex" is NOT intended to be command-line compatible with Microsoft's
+"imagex", and wimlib is NOT intended to be API compatible with Microsoft's
+WIMGAPI.  They are similar, though.
 
 
--  Mounting WIM files is not supported.
-
--  wimlib's API is not compatible with Microsoft's WIMGAPI, although they offer
-   some of the same functionality.
-
-So, in terms of the "imagex" program:
+                                NOTES ABOUT IMAGEX
 
 "imagex capture", "imagex append", and "imagex apply" will work on Windows and
 have the added advantage of saving and restoring alternate data streams,
 
 "imagex capture", "imagex append", and "imagex apply" will work on Windows and
 have the added advantage of saving and restoring alternate data streams,
@@ -29,11 +24,32 @@ way on Windows as on UNIX.
 
 "imagex mount", "imagex mountrw", and "imagex unmount" will NOT work on Windows.
 
 
 "imagex mount", "imagex mountrw", and "imagex unmount" will NOT work on Windows.
 
+
 So on Windows, why would you want to use wimlib's ImageX instead of Microsoft's?
 Well, here are a few reasons:
 
 So on Windows, why would you want to use wimlib's ImageX instead of Microsoft's?
 Well, here are a few reasons:
 
-- wimlib can be freely distributed; there is no need to download a 1.8 gigabyte
-  "Windows Automated Installation Kit".
 - wimlib offers fast multithreaded compression, so making WIM images can be much
   faster.
 - wimlib offers fast multithreaded compression, so making WIM images can be much
   faster.
+
+- wimlib can correctly save and restore alternate data streams, which
+  Microsoft's ImageX sometimes captures incorrectly due to a bug.
+
 - wimlib is free software, so you can modify and/or audit the source code.
 - wimlib is free software, so you can modify and/or audit the source code.
+
+See the man page for 'imagex' for more information.
+
+                                BUILDING ON WINDOWS
+
+Actually doing the Windows build is a bit tricky, and I'd recommend you download
+precompiled binaries from http://sourceforge.net/projects/wimlib/files/ instead.
+I did it using MinGW-w64 on a Linux host, with the following configuration
+command:
+
+$ ./configure --host=i686-w64-mingw32 \
+              CPPFLAGS=-I/opt/libxml2-min/i686-w64-mingw32/include/libxml2 \
+              LDFLAGS=-L/opt/libxml2-min/i686-w64-mingw32/lib
+
+Building wimlib using Cygwin is not supported.  I was trying this for a while,
+but I ran into some issues with mixing native Win32 functions and
+Cygwin-provided functions, so I just made it possible to do a native Win32 build
+instead.
index ad04b478e3393fb15815f645ebac4bc62445a64b..1326258c792831a8fd54d511e26fc7707824b48e 100644 (file)
@@ -163,40 +163,41 @@ else
 fi
 AC_SUBST([PTHREAD_LDADD], [$PTHREAD_LDADD])
 
 fi
 AC_SUBST([PTHREAD_LDADD], [$PTHREAD_LDADD])
 
+WITH_NTFS_3G_DEFAULT="yes"
+WITH_FUSE_DEFAULT="yes"
+WINDOWS_NATIVE_BUILD="no"
+VISIBILITY_CFLAGS="-fvisibility=hidden"
+WINDOWS_CPPFLAGS=""
+WINDOWS_LDFLAGS=""
+WINDOWS_LDADD=""
+
 case "$host" in
        *-*-mingw*)
                # Native Windows
 case "$host" in
        *-*-mingw*)
                # Native Windows
-               WINDOWS_EXTRA_LDFLAGS="-no-undefined"
-               VISIBILITY_CFLAGS=""
                WITH_NTFS_3G_DEFAULT="no"
                WITH_FUSE_DEFAULT="no"
                WITH_NTFS_3G_DEFAULT="no"
                WITH_FUSE_DEFAULT="no"
-               WINDOWS_BUILD="yes"
+               WINDOWS_NATIVE_BUILD="yes"
+               VISIBILITY_CFLAGS=""
+               WINDOWS_CPPFLAGS="-D_POSIX"
+               WINDOWS_LDFLAGS="-no-undefined"
                WINDOWS_LDADD="-lshlwapi"
                ;;
        *-*-cygwin*)
                # Cygwin (WARNING: not well supported)
                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"
                WITH_NTFS_3G_DEFAULT="no"
                WITH_FUSE_DEFAULT="no"
-               WINDOWS_BUILD="yes"
-               WINDOWS_LDADD=""
+               VISIBILITY_CFLAGS=""
                ;;
        *)
                # UNIX / other
                ;;
        *)
                # UNIX / other
-               WINDOWS_EXTRA_LDFLAGS=""
-               VISIBILITY_CFLAGS="-fvisibility=hidden"
-               WITH_NTFS_3G_DEFAULT="yes"
-               WITH_FUSE_DEFAULT="yes"
-               WINDOWS_BUILD="no"
-               WINDOWS_LDADD=""
                ;;
 esac
 
                ;;
 esac
 
-AC_SUBST([WINDOWS_EXTRA_LDFLAGS], [$WINDOWS_EXTRA_LDFLAGS])
 AC_SUBST([VISIBILITY_CFLAGS], [$VISIBILITY_CFLAGS])
 AC_SUBST([VISIBILITY_CFLAGS], [$VISIBILITY_CFLAGS])
+AC_SUBST([WINDOWS_LDFLAGS], [$WINDOWS_LDFLAGS])
 AC_SUBST([WINDOWS_LDADD], [$WINDOWS_LDADD])
 AC_SUBST([WINDOWS_LDADD], [$WINDOWS_LDADD])
-AM_CONDITIONAL([WINDOWS_BUILD], [test "x$WINDOWS_BUILD" = "xyes"])
+AC_SUBST([WINDOWS_CPPFLAGS], [$WINDOWS_CPPFLAGS])
+AM_CONDITIONAL([WINDOWS_NATIVE_BUILD], [test "x$WINDOWS_NATIVE_BUILD" = "xyes"])
 
 AC_MSG_CHECKING([whether to include support for ntfs-3g])
 AC_ARG_WITH([ntfs-3g],
 
 AC_MSG_CHECKING([whether to include support for ntfs-3g])
 AC_ARG_WITH([ntfs-3g],
@@ -236,7 +237,7 @@ else
        LIBNTFS_3G_LDADD=
        LIBNTFS_3G_CFLAGS=
 
        LIBNTFS_3G_LDADD=
        LIBNTFS_3G_CFLAGS=
 
-       if test "x$WINDOWS_BUILD" != "xyes"; then
+       if test "x$WINDOWS_NATIVE_BUILD" != "xyes"; then
                AM_ICONV
                if test "x$am_cv_func_iconv" != "xyes"; then
                        AC_MSG_ERROR([Cannot find the iconv() function.
                AM_ICONV
                if test "x$am_cv_func_iconv" != "xyes"; then
                        AC_MSG_ERROR([Cannot find the iconv() function.
index a57541f99711d94b474df35e69400269cbaf45e2..8af2b0728fff2e016226dccba72e6ce5daac2926 100644 (file)
 
 #include "config.h"
 
 
 #include "config.h"
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
-#      include <windows.h>
-#      include <ntdef.h>
-#      include <wchar.h>
-#      ifdef ERROR
-#              undef ERROR
-#      endif
-#      include "security.h"
-#else
-#      include <dirent.h>
-#      include <sys/stat.h>
-#      include "timestamp.h"
-#endif
-
 #ifdef __WIN32__
 #ifdef __WIN32__
-#include <shlwapi.h>
+#  include "win32.h"
+#else
+#  include <dirent.h>
+#  include <sys/stat.h>
+#  include <fnmatch.h>
+#  include "timestamp.h"
 #endif
 
 #include "wimlib_internal.h"
 #include "dentry.h"
 #include "lookup_table.h"
 #include "xml.h"
 #endif
 
 #include "wimlib_internal.h"
 #include "dentry.h"
 #include "lookup_table.h"
 #include "xml.h"
+
 #include <ctype.h>
 #include <errno.h>
 #include <ctype.h>
 #include <errno.h>
-
-#ifndef __WIN32__
-#include <fnmatch.h>
-#endif
-
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -60,9 +47,6 @@
 #include <alloca.h>
 #endif
 
 #include <alloca.h>
 #endif
 
-#define WIMLIB_ADD_IMAGE_FLAG_ROOT     0x80000000
-#define WIMLIB_ADD_IMAGE_FLAG_SOURCE    0x40000000
-
 /*
  * Adds the dentry tree and security data for a new image to the image metadata
  * array of the WIMStruct.
 /*
  * Adds the dentry tree and security data for a new image to the image metadata
  * array of the WIMStruct.
@@ -114,439 +98,7 @@ err:
 
 }
 
 
 }
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
-
-static u64 FILETIME_to_u64(const FILETIME *ft)
-{
-       return ((u64)ft->dwHighDateTime << 32) | (u64)ft->dwLowDateTime;
-}
-
-
-static int build_dentry_tree(struct wim_dentry **root_ret,
-                            const char *root_disk_path,
-                            struct wim_lookup_table *lookup_table,
-                            struct wim_security_data *sd,
-                            const struct capture_config *config,
-                            int add_image_flags,
-                            wimlib_progress_func_t progress_func,
-                            void *extra_arg);
-
-static int win32_get_short_name(struct wim_dentry *dentry,
-                               const wchar_t *path_utf16)
-{
-       WIN32_FIND_DATAW dat;
-       if (FindFirstFileW(path_utf16, &dat) &&
-           dat.cAlternateFileName[0] != L'\0')
-       {
-               size_t short_name_len = wcslen(dat.cAlternateFileName) * 2;
-               size_t n = short_name_len + sizeof(wchar_t);
-               dentry->short_name = MALLOC(n);
-               if (!dentry->short_name)
-                       return WIMLIB_ERR_NOMEM;
-               memcpy(dentry->short_name, dat.cAlternateFileName, n);
-               dentry->short_name_len = short_name_len;
-       }
-       return 0;
-}
-
-static int win32_get_security_descriptor(struct wim_dentry *dentry,
-                                        struct sd_set *sd_set,
-                                        const wchar_t *path_utf16)
-{
-       SECURITY_INFORMATION requestedInformation;
-       DWORD lenNeeded = 0;
-       BOOL status;
-       DWORD err;
-
-       requestedInformation = DACL_SECURITY_INFORMATION |
-                              SACL_SECURITY_INFORMATION |
-                              OWNER_SECURITY_INFORMATION |
-                              GROUP_SECURITY_INFORMATION;
-       /* Request length of security descriptor */
-       status = GetFileSecurityW(path_utf16, requestedInformation,
-                                 NULL, 0, &lenNeeded);
-       err = GetLastError();
-       if (!status && err == ERROR_INSUFFICIENT_BUFFER) {
-               DWORD len = lenNeeded;
-               char buf[len];
-               if (GetFileSecurityW(path_utf16, requestedInformation,
-                                    (PSECURITY_DESCRIPTOR)buf, len, &lenNeeded))
-               {
-                       int security_id = sd_set_add_sd(sd_set, buf, len);
-                       if (security_id < 0)
-                               return WIMLIB_ERR_NOMEM;
-                       else {
-                               dentry->d_inode->i_security_id = security_id;
-                               return 0;
-                       }
-               } else {
-                       err = GetLastError();
-               }
-       }
-       ERROR("Win32 API: Failed to read security descriptor of \"%ls\"",
-             path_utf16);
-       win32_error(err);
-       return WIMLIB_ERR_READ;
-}
-
-/* Reads the directory entries of directory using a Win32 API and recursively
- * calls build_dentry_tree() on them. */
-static int win32_recurse_directory(struct wim_dentry *root,
-                                  const char *root_disk_path,
-                                  struct wim_lookup_table *lookup_table,
-                                  struct wim_security_data *sd,
-                                  const struct capture_config *config,
-                                  int add_image_flags,
-                                  wimlib_progress_func_t progress_func,
-                                  struct sd_set *sd_set,
-                                  const wchar_t *path_utf16,
-                                  size_t path_utf16_nchars)
-{
-       WIN32_FIND_DATAW dat;
-       HANDLE hFind;
-       DWORD err;
-       int ret;
-
-       {
-               /* Begin reading the directory by calling FindFirstFileW.
-                * Unlike UNIX opendir(), FindFirstFileW has file globbing built
-                * into it.  But this isn't what we actually want, so just add a
-                * dummy glob to get all entries. */
-               wchar_t pattern_buf[path_utf16_nchars + 3];
-               memcpy(pattern_buf, path_utf16,
-                      path_utf16_nchars * sizeof(wchar_t));
-               pattern_buf[path_utf16_nchars] = L'/';
-               pattern_buf[path_utf16_nchars + 1] = L'*';
-               pattern_buf[path_utf16_nchars + 2] = L'\0';
-               hFind = FindFirstFileW(pattern_buf, &dat);
-       }
-       if (hFind == INVALID_HANDLE_VALUE) {
-               err = GetLastError();
-               if (err == ERROR_FILE_NOT_FOUND) {
-                       return 0;
-               } else {
-                       ERROR("Win32 API: Failed to read directory \"%s\"",
-                             root_disk_path);
-                       win32_error(err);
-                       return WIMLIB_ERR_READ;
-               }
-       }
-       ret = 0;
-       do {
-               /* Skip . and .. entries */
-               if (!(dat.cFileName[0] == L'.' &&
-                     (dat.cFileName[1] == L'\0' ||
-                      (dat.cFileName[1] == L'.' && dat.cFileName[2] == L'\0'))))
-               {
-                       struct wim_dentry *child;
-
-                       char *utf8_name;
-                       size_t utf8_name_nbytes;
-                       ret = utf16_to_utf8((const char*)dat.cFileName,
-                                           wcslen(dat.cFileName) * sizeof(wchar_t),
-                                           &utf8_name,
-                                           &utf8_name_nbytes);
-                       if (ret)
-                               goto out_find_close;
-
-                       char name[strlen(root_disk_path) + 1 + utf8_name_nbytes + 1];
-                       sprintf(name, "%s/%s", root_disk_path, utf8_name);
-                       FREE(utf8_name);
-                       ret = build_dentry_tree(&child, name, lookup_table,
-                                               sd, config, add_image_flags,
-                                               progress_func, sd_set);
-                       if (ret)
-                               goto out_find_close;
-                       if (child)
-                               dentry_add_child(root, child);
-               }
-       } while (FindNextFileW(hFind, &dat));
-       err = GetLastError();
-       if (err != ERROR_NO_MORE_FILES) {
-               ERROR("Win32 API: Failed to read directory \"%s\"", root_disk_path);
-               win32_error(err);
-               if (ret == 0)
-                       ret = WIMLIB_ERR_READ;
-       }
-out_find_close:
-       FindClose(hFind);
-       return ret;
-}
-
-/* Load a reparse point into a WIM inode.  It is just stored in memory.
- *
- * @hFile:  Open handle to a reparse point, with permission to read the reparse
- *          data.
- *
- * @inode:  WIM inode for the reparse point.
- *
- * @lookup_table:  Stream lookup table for the WIM; an entry will be added to it
- *                 for the reparse point unless an entry already exists for
- *                 the exact same data stream.
- *
- * @path:  External path to the parse point (UTF-8).  Used for error messages
- *         only.
- *
- * Returns 0 on success; nonzero on failure. */
-static int win32_capture_reparse_point(HANDLE hFile,
-                                      struct wim_inode *inode,
-                                      struct wim_lookup_table *lookup_table,
-                                      const char *path)
-{
-       /* "Reparse point data, including the tag and optional GUID,
-        * cannot exceed 16 kilobytes." - MSDN  */
-       char reparse_point_buf[16 * 1024];
-       DWORD bytesReturned;
-
-       if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT,
-                            NULL, 0, reparse_point_buf,
-                            sizeof(reparse_point_buf), &bytesReturned, NULL))
-       {
-               DWORD err = GetLastError();
-               ERROR("Win32 API: Failed to get reparse data of \"%s\"", path);
-               win32_error(err);
-               return WIMLIB_ERR_READ;
-       }
-       if (bytesReturned < 8) {
-               ERROR("Reparse data on \"%s\" is invalid", path);
-               return WIMLIB_ERR_READ;
-       }
-       inode->i_reparse_tag = *(u32*)reparse_point_buf;
-       return inode_add_ads_with_data(inode, "",
-                                      (const u8*)reparse_point_buf + 8,
-                                      bytesReturned - 8, lookup_table);
-}
-
-/* Calculate the SHA1 message digest of a Win32 data stream, which may be either
- * an unnamed or named data stream.
- *
- * @path:      Path to the file, with the stream noted at the end for named
- *              streams.  UTF-16LE encoding.
- *
- * @hash:       On success, the SHA1 message digest of the stream is written to
- *              this location.
- *
- * Returns 0 on success; nonzero on failure.
- */
-static int win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE])
-{
-       HANDLE hFile;
-       SHA_CTX ctx;
-       u8 buf[32768];
-       DWORD bytesRead;
-       int ret;
-
-       hFile = win32_open_file_readonly(path);
-       if (hFile == INVALID_HANDLE_VALUE)
-               return WIMLIB_ERR_OPEN;
-
-       sha1_init(&ctx);
-       for (;;) {
-               if (!ReadFile(hFile, buf, sizeof(buf), &bytesRead, NULL)) {
-                       ret = WIMLIB_ERR_READ;
-                       goto out_close_handle;
-               }
-               if (bytesRead == 0)
-                       break;
-               sha1_update(&ctx, buf, bytesRead);
-       }
-       ret = 0;
-       sha1_final(hash, &ctx);
-out_close_handle:
-       CloseHandle(hFile);
-       return ret;
-}
-
-/* Scans an unnamed or named stream of a Win32 file (not a reparse point
- * stream); calculates its SHA1 message digest and either creates a `struct
- * wim_lookup_table_entry' in memory for it, or uses an existing 'struct
- * wim_lookup_table_entry' for an identical stream.
- *
- * @path_utf16:         Path to the file (UTF-16LE).
- *
- * @path_utf16_nchars:  Number of 2-byte characters in @path_utf16.
- *
- * @inode:              WIM inode to save the stream into.
- *
- * @lookup_table:       Stream lookup table for the WIM.
- *
- * @dat:                A `WIN32_FIND_STREAM_DATA' structure that specifies the
- *                      stream name.
- *
- * Returns 0 on success; nonzero on failure.
- */
-static int win32_capture_stream(const wchar_t *path_utf16,
-                               size_t path_utf16_nchars,
-                               struct wim_inode *inode,
-                               struct wim_lookup_table *lookup_table,
-                               WIN32_FIND_STREAM_DATA *dat)
-{
-       struct wim_ads_entry *ads_entry;
-       u8 hash[SHA1_HASH_SIZE];
-       struct wim_lookup_table_entry *lte;
-       int ret;
-       wchar_t *p, *colon;
-       bool is_named_stream;
-       wchar_t *spath;
-       size_t spath_nchars;
-       DWORD err;
-
-       /* The stream name should be returned as :NAME:TYPE */
-       p = dat->cStreamName;
-       if (*p != L':')
-               goto out_invalid_stream_name;
-       p += 1;
-       colon = wcschr(p, L':');
-       if (colon == NULL)
-               goto out_invalid_stream_name;
-
-       if (wcscmp(colon + 1, L"$DATA")) {
-               /* Not a DATA stream */
-               ret = 0;
-               goto out;
-       }
-
-       is_named_stream = (p != colon);
-       if (is_named_stream) {
-               /* Allocate an ADS entry for the named stream. */
-               char *utf8_stream_name;
-               size_t utf8_stream_name_len;
-               ret = utf16_to_utf8((const char *)p,
-                                   (colon - p) * sizeof(wchar_t),
-                                   &utf8_stream_name,
-                                   &utf8_stream_name_len);
-               if (ret)
-                       goto out;
-               ads_entry = inode_add_ads(inode, utf8_stream_name);
-               FREE(utf8_stream_name);
-               if (!ads_entry) {
-                       ret = WIMLIB_ERR_NOMEM;
-                       goto out;
-               }
-       }
-
-       /* Create a UTF-16 string @spath that gives the filename, then a colon,
-        * then the stream name.  Or, if it's an unnamed stream, just the
-        * filename.  It is MALLOC()'ed so that it can be saved in the
-        * wim_lookup_table_entry if needed. */
-       *colon = '\0';
-       spath_nchars = path_utf16_nchars;
-       if (is_named_stream)
-               spath_nchars += colon - p + 1;
-
-       spath = MALLOC((spath_nchars + 1) * sizeof(wchar_t));
-       memcpy(spath, path_utf16, path_utf16_nchars * sizeof(wchar_t));
-       if (is_named_stream) {
-               spath[path_utf16_nchars] = L':';
-               memcpy(&spath[path_utf16_nchars + 1], p, (colon - p) * sizeof(wchar_t));
-       }
-       spath[spath_nchars] = L'\0';
-
-       ret = win32_sha1sum(spath, hash);
-       if (ret) {
-               err = GetLastError();
-               ERROR("Win32 API: Failed to read \"%ls\" to calculate SHA1sum",
-                     path_utf16);
-               win32_error(err);
-               goto out_free_spath;
-       }
-
-       lte = __lookup_resource(lookup_table, hash);
-       if (lte) {
-               /* Use existing wim_lookup_table_entry that has the same SHA1
-                * message digest */
-               lte->refcnt++;
-       } else {
-               /* Make a new wim_lookup_table_entry */
-               lte = new_lookup_table_entry();
-               if (!lte) {
-                       ret = WIMLIB_ERR_NOMEM;
-                       goto out_free_spath;
-               }
-               lte->file_on_disk = (char*)spath;
-               spath = NULL;
-               lte->resource_location = RESOURCE_WIN32;
-               lte->resource_entry.original_size = (uint64_t)dat->StreamSize.QuadPart;
-               lte->resource_entry.size = (uint64_t)dat->StreamSize.QuadPart;
-               copy_hash(lte->hash, hash);
-               lookup_table_insert(lookup_table, lte);
-       }
-       if (is_named_stream)
-               ads_entry->lte = lte;
-       else
-               inode->i_lte = lte;
-out_free_spath:
-       FREE(spath);
-out:
-       return ret;
-out_invalid_stream_name:
-       ERROR("Invalid stream name: \"%ls:%ls\"", path_utf16, dat->cStreamName);
-       ret = WIMLIB_ERR_READ;
-       goto out;
-}
-
-/* Scans a Win32 file for unnamed and named data streams (not reparse point
- * streams).
- *
- * @path_utf16:         Path to the file (UTF-16LE).
- *
- * @path_utf16_nchars:  Number of 2-byte characters in @path_utf16.
- *
- * @inode:              WIM inode to save the stream into.
- *
- * @lookup_table:       Stream lookup table for the WIM.
- *
- * Returns 0 on success; nonzero on failure.
- */
-static int win32_capture_streams(const wchar_t *path_utf16,
-                                size_t path_utf16_nchars,
-                                struct wim_inode *inode,
-                                struct wim_lookup_table *lookup_table)
-{
-       WIN32_FIND_STREAM_DATA dat;
-       int ret;
-       HANDLE hFind;
-       DWORD err;
-
-       hFind = FindFirstStreamW(path_utf16, FindStreamInfoStandard, &dat, 0);
-       if (hFind == INVALID_HANDLE_VALUE) {
-               err = GetLastError();
-
-               /* Seems legal for this to return ERROR_HANDLE_EOF on reparse
-                * points and directories */
-               if ((inode->i_attributes &
-                   (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
-                   && err == ERROR_HANDLE_EOF)
-               {
-                       return 0;
-               } else {
-                       ERROR("Win32 API: Failed to look up data streams of \"%ls\"",
-                             path_utf16);
-                       win32_error(err);
-                       return WIMLIB_ERR_READ;
-               }
-       }
-       do {
-               ret = win32_capture_stream(path_utf16,
-                                          path_utf16_nchars,
-                                          inode, lookup_table,
-                                          &dat);
-               if (ret)
-                       goto out_find_close;
-       } while (FindNextStreamW(hFind, &dat));
-       err = GetLastError();
-       if (err != ERROR_HANDLE_EOF) {
-               ERROR("Win32 API: Error reading data streams from \"%ls\"", path_utf16);
-               win32_error(err);
-               ret = WIMLIB_ERR_READ;
-       }
-out_find_close:
-       FindClose(hFind);
-       return ret;
-}
-
-#endif
-
+#ifndef __WIN32__
 /*
  * build_dentry_tree():
  *     Recursively builds a tree of WIM dentries from an on-disk directory
 /*
  * build_dentry_tree():
  *     Recursively builds a tree of WIM dentries from an on-disk directory
@@ -581,14 +133,14 @@ out_find_close:
  *             the on-disk files during a call to wimlib_write() or
  *             wimlib_overwrite().
  */
  *             the on-disk files during a call to wimlib_write() or
  *             wimlib_overwrite().
  */
-static int build_dentry_tree(struct wim_dentry **root_ret,
-                            const char *root_disk_path,
-                            struct wim_lookup_table *lookup_table,
-                            struct wim_security_data *sd,
-                            const struct capture_config *config,
-                            int add_image_flags,
-                            wimlib_progress_func_t progress_func,
-                            void *extra_arg)
+static int unix_build_dentry_tree(struct wim_dentry **root_ret,
+                                 const char *root_disk_path,
+                                 struct wim_lookup_table *lookup_table,
+                                 struct wim_security_data *sd,
+                                 const struct capture_config *config,
+                                 int add_image_flags,
+                                 wimlib_progress_func_t progress_func,
+                                 void *extra_arg)
 {
        struct wim_dentry *root = NULL;
        int ret = 0;
 {
        struct wim_dentry *root = NULL;
        int ret = 0;
@@ -620,7 +172,6 @@ static int build_dentry_tree(struct wim_dentry **root_ret,
                progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
        }
 
                progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
        }
 
-#if !defined(__CYGWIN__) && !defined(__WIN32__)
        /* UNIX version of capturing a directory tree */
        struct stat root_stbuf;
        int (*stat_fn)(const char *restrict, struct stat *restrict);
        /* UNIX version of capturing a directory tree */
        struct stat root_stbuf;
        int (*stat_fn)(const char *restrict, struct stat *restrict);
@@ -789,9 +340,11 @@ static int build_dentry_tree(struct wim_dentry **root_ret,
                              || (result->d_name[1] == '.' && result->d_name[2] == '\0')))
                                        continue;
                        strcpy(name + len + 1, result->d_name);
                              || (result->d_name[1] == '.' && result->d_name[2] == '\0')))
                                        continue;
                        strcpy(name + len + 1, result->d_name);
-                       ret = build_dentry_tree(&child, name, lookup_table,
-                                               NULL, config, add_image_flags,
-                                               progress_func, NULL);
+                       ret = unix_build_dentry_tree(&child, name,
+                                                    lookup_table,
+                                                    NULL, config,
+                                                    add_image_flags,
+                                                    progress_func, NULL);
                        if (ret != 0)
                                break;
                        if (child)
                        if (ret != 0)
                                break;
                        if (child)
@@ -841,126 +394,6 @@ static int build_dentry_tree(struct wim_dentry **root_ret,
                        ret = WIMLIB_ERR_READLINK;
                }
        }
                        ret = WIMLIB_ERR_READLINK;
                }
        }
-#else
-       /* Win32 version of capturing a directory tree */
-
-       wchar_t *path_utf16;
-       size_t path_utf16_nchars;
-       struct sd_set *sd_set;
-       DWORD err;
-
-       if (extra_arg == NULL) {
-               sd_set = alloca(sizeof(struct sd_set));
-               sd_set->rb_root.rb_node = NULL,
-               sd_set->sd = sd;
-       } else {
-               sd_set = extra_arg;
-       }
-
-       ret = utf8_to_utf16(root_disk_path, strlen(root_disk_path),
-                           (char**)&path_utf16, &path_utf16_nchars);
-       if (ret)
-               goto out_destroy_sd_set;
-       path_utf16_nchars /= sizeof(wchar_t);
-
-       HANDLE hFile = win32_open_file_readonly(path_utf16);
-       if (hFile == INVALID_HANDLE_VALUE) {
-               err = GetLastError();
-               ERROR("Win32 API: Failed to open \"%s\"", root_disk_path);
-               win32_error(err);
-               ret = WIMLIB_ERR_OPEN;
-               goto out_free_path_utf16;
-       }
-
-       BY_HANDLE_FILE_INFORMATION file_info;
-       if (!GetFileInformationByHandle(hFile, &file_info)) {
-               err = GetLastError();
-               ERROR("Win32 API: Failed to get file information for \"%s\"",
-                     root_disk_path);
-               win32_error(err);
-               ret = WIMLIB_ERR_STAT;
-               goto out_close_handle;
-       }
-
-       /* Create a WIM dentry */
-       root = new_dentry_with_timeless_inode(path_basename(root_disk_path));
-       if (!root) {
-               if (errno == EILSEQ)
-                       ret = WIMLIB_ERR_INVALID_UTF8_STRING;
-               else if (errno == ENOMEM)
-                       ret = WIMLIB_ERR_NOMEM;
-               else
-                       ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE;
-               goto out_close_handle;
-       }
-
-       /* Start preparing the associated WIM inode */
-       inode = root->d_inode;
-
-       inode->i_attributes = file_info.dwFileAttributes;
-       inode->i_creation_time = FILETIME_to_u64(&file_info.ftCreationTime);
-       inode->i_last_write_time = FILETIME_to_u64(&file_info.ftLastWriteTime);
-       inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime);
-       inode->i_ino = ((u64)file_info.nFileIndexHigh << 32) |
-                       (u64)file_info.nFileIndexLow;
-
-       inode->i_resolved = 1;
-       add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
-
-       /* Get DOS name and security descriptor (if any). */
-       ret = win32_get_short_name(root, path_utf16);
-       if (ret)
-               goto out_close_handle;
-       ret = win32_get_security_descriptor(root, sd_set, path_utf16);
-       if (ret)
-               goto out_close_handle;
-
-       if (inode_is_directory(inode)) {
-               /* Directory (not a reparse point) --- recurse to children */
-
-               /* But first... directories may have alternate data streams that
-                * need to be captured. */
-               ret = win32_capture_streams(path_utf16,
-                                           path_utf16_nchars,
-                                           inode,
-                                           lookup_table);
-               if (ret)
-                       goto out_close_handle;
-               ret = win32_recurse_directory(root,
-                                             root_disk_path,
-                                             lookup_table,
-                                             sd,
-                                             config,
-                                             add_image_flags,
-                                             progress_func,
-                                             sd_set,
-                                             path_utf16,
-                                             path_utf16_nchars);
-       } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
-               /* Reparse point: save the reparse tag and data */
-               ret = win32_capture_reparse_point(hFile,
-                                                 inode,
-                                                 lookup_table,
-                                                 root_disk_path);
-       } else {
-               /* Not a directory, not a reparse point; capture the default
-                * file contents and any alternate data streams. */
-               ret = win32_capture_streams(path_utf16,
-                                           path_utf16_nchars,
-                                           inode,
-                                           lookup_table);
-       }
-out_close_handle:
-       CloseHandle(hFile);
-out_free_path_utf16:
-       FREE(path_utf16);
-out_destroy_sd_set:
-       if (extra_arg == NULL)
-               destroy_sd_set(sd_set);
-#endif
-       /* The below lines of code are common to both UNIX and Win32 builds.  It
-        * simply returns the captured directory tree if the capture was
-        * successful, or frees it if the capture was unsuccessful. */
 out:
        if (ret == 0)
                *root_ret = root;
 out:
        if (ret == 0)
                *root_ret = root;
@@ -968,6 +401,7 @@ out:
                free_dentry_tree(root, lookup_table);
        return ret;
 }
                free_dentry_tree(root, lookup_table);
        return ret;
 }
+#endif /* !__WIN32__ */
 
 enum pattern_type {
        NONE = 0,
 
 enum pattern_type {
        NONE = 0,
@@ -1146,19 +580,6 @@ static int capture_config_set_prefix(struct capture_config *config,
        return 0;
 }
 
        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)
 {
 static bool match_pattern(const char *path, const char *path_basename,
                          const struct pattern_list *list)
 {
@@ -1177,7 +598,12 @@ static bool match_pattern(const char *path, const char *path_basename,
                                string = path_basename;
                }
 
                                string = path_basename;
                }
 
-               if (path_matches_pattern(string, pat)) {
+               if (fnmatch(pat, string, FNM_PATHNAME
+                               #ifdef FNM_CASEFOLD
+                                       | FNM_CASEFOLD
+                               #endif
+                           ) == 0)
+               {
                        DEBUG("`%s' matches the pattern \"%s\"",
                              string, pat);
                        return true;
                        DEBUG("`%s' matches the pattern \"%s\"",
                              string, pat);
                        return true;
@@ -1232,7 +658,7 @@ static const char *canonicalize_target_path(char *target_path)
        return target_path;
 }
 
        return target_path;
 }
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
 static void zap_backslashes(char *s)
 {
        while (*s) {
 static void zap_backslashes(char *s)
 {
        while (*s) {
@@ -1251,7 +677,7 @@ static void canonicalize_targets(struct wimlib_capture_source *sources,
                DEBUG("Canonicalizing { source: \"%s\", target=\"%s\"}",
                      sources->fs_source_path,
                      sources->wim_target_path);
                DEBUG("Canonicalizing { source: \"%s\", target=\"%s\"}",
                      sources->fs_source_path,
                      sources->wim_target_path);
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
                /* The Windows API can handle forward slashes.  Just get rid of
                 * backslashes to avoid confusing other parts of the library
                 * code. */
                /* The Windows API can handle forward slashes.  Just get rid of
                 * backslashes to avoid confusing other parts of the library
                 * code. */
@@ -1504,11 +930,15 @@ WIMLIBAPI int wimlib_add_image_multisource(WIMStruct *w,
                return WIMLIB_ERR_UNSUPPORTED;
 #endif
        } else {
                return WIMLIB_ERR_UNSUPPORTED;
 #endif
        } else {
-               capture_tree = build_dentry_tree;
+       #ifdef __WIN32__
+               capture_tree = win32_build_dentry_tree;
+       #else
+               capture_tree = unix_build_dentry_tree;
+       #endif
                extra_arg = NULL;
        }
 
                extra_arg = NULL;
        }
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
        if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
                ERROR("Capturing UNIX-specific data is not supported on Windows");
                return WIMLIB_ERR_INVALID_PARAM;
        if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
                ERROR("Capturing UNIX-specific data is not supported on Windows");
                return WIMLIB_ERR_INVALID_PARAM;
@@ -1572,11 +1002,10 @@ WIMLIBAPI int wimlib_add_image_multisource(WIMStruct *w,
        } else {
                size_t i;
 
        } else {
                size_t i;
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
-               win32_acquire_privilege(SE_BACKUP_NAME);
-               win32_acquire_privilege(SE_SECURITY_NAME);
-               win32_acquire_privilege(SE_TAKE_OWNERSHIP_NAME);
-#endif
+       #ifdef __WIN32__
+               win32_acquire_capture_privileges();
+       #endif
+
                root_dentry = NULL;
                i = 0;
                do {
                root_dentry = NULL;
                i = 0;
                do {
@@ -1670,10 +1099,8 @@ out_free_security_data:
 out_destroy_capture_config:
        destroy_capture_config(&config);
 out:
 out_destroy_capture_config:
        destroy_capture_config(&config);
 out:
-#if defined(__CYGWIN__) || defined(__WIN32__)
-       win32_release_privilege(SE_BACKUP_NAME);
-       win32_release_privilege(SE_SECURITY_NAME);
-       win32_release_privilege(SE_TAKE_OWNERSHIP_NAME);
+#ifdef __WIN32__
+       win32_release_capture_privileges();
 #endif
        return ret;
 }
 #endif
        return ret;
 }
index 86063819ab26c2e363fbbb8257544afc9efa4efc..7955417f88c0798255f5de04f6e8a72821995802 100644 (file)
 
 #include "config.h"
 
 
 #include "config.h"
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
-#      include <windows.h>
-#      ifdef ERROR
-#              undef ERROR
-#      endif
-#      include <wchar.h>
+#include <dirent.h>
+
+#ifdef __WIN32__
+#  include "win32.h"
 #else
 #else
-#      include <dirent.h>
-#      ifdef HAVE_UTIME_H
-#              include <utime.h>
-#      endif
-#      include "timestamp.h"
-#      include <sys/time.h>
+#  ifdef HAVE_UTIME_H
+#    include <utime.h>
+#  endif
+#  include "timestamp.h"
+#  include <sys/time.h>
 #endif
 
 #include <errno.h>
 #endif
 
 #include <errno.h>
 #include "xml.h"
 
 #ifdef WITH_NTFS_3G
 #include "xml.h"
 
 #ifdef WITH_NTFS_3G
-#include <ntfs-3g/volume.h>
+#  include <ntfs-3g/volume.h>
 #endif
 
 #ifdef HAVE_ALLOCA_H
 #endif
 
 #ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#endif
-
-#if defined(__WIN32__)
-#      define swprintf _snwprintf
-#      define mkdir(path, mode) (!CreateDirectoryA(path, NULL))
+#  include <alloca.h>
 #endif
 
 #endif
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
-
-static int win32_set_reparse_data(HANDLE h,
-                                 u32 reparse_tag,
-                                 const struct wim_lookup_table_entry *lte,
-                                 const wchar_t *path)
-{
-       int ret;
-       u8 *buf;
-       size_t len;
-
-       if (!lte) {
-               WARNING("\"%ls\" is marked as a reparse point but had no reparse data",
-                       path);
-               return 0;
-       }
-       len = wim_resource_size(lte);
-       if (len > 16 * 1024 - 8) {
-               WARNING("\"%ls\": reparse data too long!", path);
-               return 0;
-       }
-
-       /* The WIM stream omits the ReparseTag and ReparseDataLength fields, so
-        * leave 8 bytes of space for them at the beginning of the buffer, then
-        * set them manually. */
-       buf = alloca(len + 8);
-       ret = read_full_wim_resource(lte, buf + 8, 0);
-       if (ret)
-               return ret;
-       *(u32*)(buf + 0) = reparse_tag;
-       *(u16*)(buf + 4) = len;
-       *(u16*)(buf + 6) = 0;
-
-       /* Set the reparse data on the open file using the
-        * FSCTL_SET_REPARSE_POINT ioctl.
-        *
-        * There are contradictions in Microsoft's documentation for this:
-        *
-        * "If hDevice was opened without specifying FILE_FLAG_OVERLAPPED,
-        * lpOverlapped is ignored."
-        *
-        * --- So setting lpOverlapped to NULL is okay since it's ignored.
-        *
-        * "If lpOverlapped is NULL, lpBytesReturned cannot be NULL. Even when an
-        * operation returns no output data and lpOutBuffer is NULL,
-        * DeviceIoControl makes use of lpBytesReturned. After such an
-        * operation, the value of lpBytesReturned is meaningless."
-        *
-        * --- So lpOverlapped not really ignored, as it affects another
-        *  parameter.  This is the actual behavior: lpBytesReturned must be
-        *  specified, even though lpBytesReturned is documented as:
-        *
-        *  "Not used with this operation; set to NULL."
-        */
-       DWORD bytesReturned;
-       if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, buf, len + 8,
-                            NULL, 0,
-                            &bytesReturned /* lpBytesReturned */,
-                            NULL /* lpOverlapped */))
-       {
-               DWORD err = GetLastError();
-               ERROR("Failed to set reparse data on \"%ls\"", path);
-               win32_error(err);
-               return WIMLIB_ERR_WRITE;
-       }
-       return 0;
-}
-
-
-static int win32_extract_chunk(const u8 *buf, size_t len, u64 offset, void *arg)
-{
-       HANDLE hStream = arg;
-
-       DWORD nbytes_written;
-       wimlib_assert(len <= 0xffffffff);
-
-       if (!WriteFile(hStream, buf, len, &nbytes_written, NULL) ||
-           nbytes_written != len)
-       {
-               DWORD err = GetLastError();
-               ERROR("WriteFile(): write error");
-               win32_error(err);
-               return WIMLIB_ERR_WRITE;
-       }
-       return 0;
-}
-
-static int do_win32_extract_stream(HANDLE hStream, struct wim_lookup_table_entry *lte)
-{
-       return extract_wim_resource(lte, wim_resource_size(lte),
-                                   win32_extract_chunk, hStream);
-}
-
-static int win32_extract_stream(const struct wim_inode *inode,
-                               const wchar_t *path,
-                               const wchar_t *stream_name_utf16,
-                               struct wim_lookup_table_entry *lte)
-{
-       wchar_t *stream_path;
-       HANDLE h;
-       int ret;
-       DWORD err;
-       DWORD creationDisposition = CREATE_ALWAYS;
-
-       if (stream_name_utf16) {
-               /* Named stream.  Create a buffer that contains the UTF-16LE
-                * string [./]@path:@stream_name_utf16.  This is needed to
-                * create and open the stream using CreateFileW().  I'm not
-                * aware of any other APIs to do this.  Note: the '$DATA' suffix
-                * seems to be unneeded.  Additional note: a "./" prefix needs
-                * to be added when the path is not absolute to avoid ambiguity
-                * with drive letters. */
-               size_t stream_path_nchars;
-               size_t path_nchars;
-               size_t stream_name_nchars;
-               const wchar_t *prefix;
-
-               path_nchars = wcslen(path);
-               stream_name_nchars = wcslen(stream_name_utf16);
-               stream_path_nchars = path_nchars + 1 + stream_name_nchars;
-               if (path[0] != L'/' && path[0] != L'\\') {
-                       prefix = L"./";
-                       stream_path_nchars += 2;
-               } else {
-                       prefix = L"";
-               }
-               stream_path = alloca((stream_path_nchars + 1) * sizeof(wchar_t));
-               swprintf(stream_path, stream_path_nchars + 1, L"%ls%ls:%ls",
-                        prefix, path, stream_name_utf16);
-       } else {
-               /* Unnamed stream; its path is just the path to the file itself.
-                * */
-               stream_path = (wchar_t*)path;
-
-               /* Directories must be created with CreateDirectoryW().  Then
-                * the call to CreateFileW() will merely open the directory that
-                * was already created rather than creating a new file. */
-               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
-                       if (!CreateDirectoryW(stream_path, NULL)) {
-                               err = GetLastError();
-                               if (err != ERROR_ALREADY_EXISTS) {
-                                       ERROR("Failed to create directory \"%ls\"",
-                                             stream_path);
-                                       win32_error(err);
-                                       ret = WIMLIB_ERR_MKDIR;
-                                       goto fail;
-                               }
-                       }
-                       DEBUG("Created directory \"%ls\"", stream_path);
-                       if (!(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
-                               ret = 0;
-                               goto out;
-                       }
-                       creationDisposition = OPEN_EXISTING;
-               }
-       }
-
-       DEBUG("Opening \"%ls\"", stream_path);
-       h = CreateFileW(stream_path,
-                       GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
-                       0,
-                       NULL,
-                       creationDisposition,
-                       FILE_FLAG_OPEN_REPARSE_POINT |
-                           FILE_FLAG_BACKUP_SEMANTICS |
-                           inode->i_attributes,
-                       NULL);
-       if (h == INVALID_HANDLE_VALUE) {
-               err = GetLastError();
-               ERROR("Failed to create \"%ls\"", stream_path);
-               win32_error(err);
-               ret = WIMLIB_ERR_OPEN;
-               goto fail;
-       }
-
-       if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
-           stream_name_utf16 == NULL)
-       {
-               DEBUG("Setting reparse data on \"%ls\"", path);
-               ret = win32_set_reparse_data(h, inode->i_reparse_tag, lte, path);
-               if (ret)
-                       goto fail_close_handle;
-       } else {
-               if (lte) {
-                       DEBUG("Extracting \"%ls\" (len = %"PRIu64")",
-                             stream_path, wim_resource_size(lte));
-                       ret = do_win32_extract_stream(h, lte);
-                       if (ret)
-                               goto fail_close_handle;
-               }
-       }
-
-       DEBUG("Closing \"%ls\"", stream_path);
-       if (!CloseHandle(h)) {
-               err = GetLastError();
-               ERROR("Failed to close \"%ls\"", stream_path);
-               win32_error(err);
-               ret = WIMLIB_ERR_WRITE;
-               goto fail;
-       }
-       ret = 0;
-       goto out;
-fail_close_handle:
-       CloseHandle(h);
-fail:
-       ERROR("Error extracting %ls", stream_path);
-out:
-       return ret;
-}
-
-/*
- * Creates a file, directory, or reparse point and extracts all streams to it
- * (unnamed data stream and/or reparse point stream, plus any alternate data
- * streams).  This in Win32-specific code.
- *
- * @inode:     WIM inode for this file or directory.
- * @path:      UTF-16LE external path to extract the inode to.
- *
- * Returns 0 on success; nonzero on failure.
- */
-static int win32_extract_streams(struct wim_inode *inode,
-                                const wchar_t *path, u64 *completed_bytes_p)
-{
-       struct wim_lookup_table_entry *unnamed_lte;
-       int ret;
-
-       unnamed_lte = inode_unnamed_lte_resolved(inode);
-       ret = win32_extract_stream(inode, path, NULL, unnamed_lte);
-       if (ret)
-               goto out;
-       if (unnamed_lte)
-               *completed_bytes_p += wim_resource_size(unnamed_lte);
-       for (u16 i = 0; i < inode->i_num_ads; i++) {
-               const struct wim_ads_entry *ads_entry = &inode->i_ads_entries[i];
-               if (ads_entry->stream_name_len != 0) {
-                       /* Skip special UNIX data entries (see documentation for
-                        * WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */
-                       if (ads_entry->stream_name_len == WIMLIB_UNIX_DATA_TAG_LEN
-                           && !memcmp(ads_entry->stream_name_utf8,
-                                      WIMLIB_UNIX_DATA_TAG,
-                                      WIMLIB_UNIX_DATA_TAG_LEN))
-                               continue;
-                       ret = win32_extract_stream(inode,
-                                                  path,
-                                                  (const wchar_t*)ads_entry->stream_name,
-                                                  ads_entry->lte);
-                       if (ret)
-                               break;
-                       if (ads_entry->lte)
-                               *completed_bytes_p += wim_resource_size(ads_entry->lte);
-               }
-       }
-out:
-       return ret;
-}
-
-/*
- * Sets the security descriptor on an extracted file.  This is Win32-specific
- * code.
- *
- * @inode:     The WIM inode that was extracted and has a security descriptor.
- * @path:      UTF-16LE external path that the inode was extracted to.
- * @sd:                Security data for the WIM image.
- *
- * Returns 0 on success; nonzero on failure.
- */
-static int win32_set_security_data(const struct wim_inode *inode,
-                                  const wchar_t *path,
-                                  const struct wim_security_data *sd)
-{
-       SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION |
-                                                  SACL_SECURITY_INFORMATION |
-                                                  OWNER_SECURITY_INFORMATION |
-                                                  GROUP_SECURITY_INFORMATION;
-       if (!SetFileSecurityW(path, securityInformation,
-                             (PSECURITY_DESCRIPTOR)sd->descriptors[inode->i_security_id]))
-       {
-               DWORD err = GetLastError();
-               ERROR("Can't set security descriptor on \"%ls\"", path);
-               win32_error(err);
-               return WIMLIB_ERR_WRITE;
-       }
-       return 0;
-}
-
-#else /* __CYGWIN__ || __WIN32__ */
+#ifndef __WIN32__
 static int extract_regular_file_linked(struct wim_dentry *dentry,
                                       const char *output_path,
                                       struct apply_args *args,
 static int extract_regular_file_linked(struct wim_dentry *dentry,
                                       const char *output_path,
                                       struct apply_args *args,
@@ -620,7 +327,7 @@ static int extract_symlink(struct wim_dentry *dentry,
        return 0;
 }
 
        return 0;
 }
 
-#endif /* !(__CYGWIN__ || __WIN32__) */
+#endif /* !__WIN32__ */
 
 static int extract_directory(struct wim_dentry *dentry,
                             const char *output_path, bool is_root)
 
 static int extract_directory(struct wim_dentry *dentry,
                             const char *output_path, bool is_root)
@@ -652,7 +359,7 @@ static int extract_directory(struct wim_dentry *dentry,
        }
 dir_exists:
        ret = 0;
        }
 dir_exists:
        ret = 0;
-#if !defined(__CYGWIN__) && !defined(__WIN32__)
+#ifndef __WIN32__
        if (dentry) {
                struct wimlib_unix_data unix_data;
                ret = inode_get_unix_data(dentry->d_inode, &unix_data, NULL);
        if (dentry) {
                struct wimlib_unix_data unix_data;
                ret = inode_get_unix_data(dentry->d_inode, &unix_data, NULL);
@@ -667,82 +374,14 @@ dir_exists:
        return ret;
 }
 
        return ret;
 }
 
-/* Extracts a file, directory, or symbolic link from the WIM archive. */
-static int apply_dentry_normal(struct wim_dentry *dentry, void *arg)
+#ifndef __WIN32__
+static int unix_apply_dentry(const char *output_path,
+                            size_t output_path_len,
+                            const struct wim_dentry *dentry,
+                            const struct apply_args *args)
 {
 {
-       struct apply_args *args = arg;
-       struct wim_inode *inode = dentry->d_inode;
-       size_t len;
-       char *output_path;
-
-       len = strlen(args->target);
-       if (dentry_is_root(dentry)) {
-               output_path = (char*)args->target;
-       } else {
-               output_path = alloca(len + dentry->full_path_utf8_len + 1);
-               memcpy(output_path, args->target, len);
-               memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
-               output_path[len + dentry->full_path_utf8_len] = '\0';
-               len += dentry->full_path_utf8_len;
-       }
-
-#if defined(__CYGWIN__) || defined(__WIN32__)
-       char *utf16_path;
-       size_t utf16_path_len;
-       DWORD err;
-       int ret;
-       ret = utf8_to_utf16(output_path, len, &utf16_path, &utf16_path_len);
-       if (ret)
-               return ret;
+       const struct wim_inode *inode = dentry->d_inode;
 
 
-       if (inode->i_nlink > 1 && inode->i_extracted_file != NULL) {
-               /* Linked file, with another name already extracted.  Create a
-                * hard link. */
-               DEBUG("Creating hard link \"%ls => %ls\"",
-                     (const wchar_t*)utf16_path,
-                     (const wchar_t*)inode->i_extracted_file);
-               if (!CreateHardLinkW((const wchar_t*)utf16_path,
-                                    (const wchar_t*)inode->i_extracted_file,
-                                    NULL))
-               {
-                       err = GetLastError();
-                       ERROR("Can't create hard link \"%ls => %ls\"",
-                             (const wchar_t*)utf16_path,
-                             (const wchar_t*)inode->i_extracted_file);
-                       ret = WIMLIB_ERR_LINK;
-                       win32_error(err);
-               }
-       } else {
-               /* Create the file, directory, or reparse point, and extract the
-                * data streams. */
-               ret = win32_extract_streams(inode, (const wchar_t*)utf16_path,
-                                           &args->progress.extract.completed_bytes);
-               if (ret)
-                       goto out_free_utf16_path;
-
-               /* Set security descriptor if present */
-               if (inode->i_security_id != -1) {
-                       DEBUG("Setting security descriptor %d on %s",
-                             inode->i_security_id, output_path);
-                       ret = win32_set_security_data(inode,
-                                                     (const wchar_t*)utf16_path,
-                                                     wim_const_security_data(args->w));
-                       if (ret)
-                               goto out_free_utf16_path;
-               }
-               if (inode->i_nlink > 1) {
-                       /* Save extracted path for a later call to
-                        * CreateHardLinkW() if this inode has multiple links.
-                        * */
-                       inode->i_extracted_file = utf16_path;
-                       goto out;
-               }
-       }
-out_free_utf16_path:
-       FREE(utf16_path);
-out:
-       return ret;
-#else
        if (inode_is_symlink(inode))
                return extract_symlink(dentry, args, output_path);
        else if (inode_is_directory(inode))
        if (inode_is_symlink(inode))
                return extract_symlink(dentry, args, output_path);
        else if (inode_is_directory(inode))
@@ -751,83 +390,14 @@ out:
                                         output_path, false);
        else
                return extract_regular_file(dentry, args, output_path);
                                         output_path, false);
        else
                return extract_regular_file(dentry, args, output_path);
-#endif
 }
 
 }
 
-/* Apply timestamps to an extracted file or directory */
-static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg)
+static int unix_apply_dentry_timestamps(const char *output_path,
+                                       size_t output_path_len,
+                                       const struct wim_dentry *dentry,
+                                       struct apply_args *args)
 {
 {
-       struct apply_args *args = arg;
-       size_t len;
-       char *output_path;
        int ret;
        int ret;
-       const struct wim_inode *inode = dentry->d_inode;
-
-       len = strlen(args->target);
-       if (dentry_is_root(dentry)) {
-               output_path = (char*)args->target;
-       } else {
-               output_path = alloca(len + dentry->full_path_utf8_len + 1);
-               memcpy(output_path, args->target, len);
-               memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
-               output_path[len + dentry->full_path_utf8_len] = '\0';
-               len += dentry->full_path_utf8_len;
-       }
-
-#if defined(__CYGWIN__) || defined(__WIN32__)
-       /* Win32 */
-       char *utf16_path;
-       size_t utf16_path_len;
-       DWORD err;
-       HANDLE h;
-
-       ret = utf8_to_utf16(output_path, len, &utf16_path, &utf16_path_len);
-       if (ret)
-               return ret;
-
-       DEBUG("Opening \"%s\" to set timestamps", output_path);
-       h = CreateFileW((const wchar_t*)utf16_path,
-                       GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
-                       FILE_SHARE_READ,
-                       NULL,
-                       OPEN_EXISTING,
-                       FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
-                       NULL);
-
-       if (h == INVALID_HANDLE_VALUE)
-               err = GetLastError();
-       FREE(utf16_path);
-       if (h == INVALID_HANDLE_VALUE)
-               goto fail;
-
-       FILETIME creationTime = {.dwLowDateTime = inode->i_creation_time & 0xffffffff,
-                                .dwHighDateTime = inode->i_creation_time >> 32};
-       FILETIME lastAccessTime = {.dwLowDateTime = inode->i_last_access_time & 0xffffffff,
-                                 .dwHighDateTime = inode->i_last_access_time >> 32};
-       FILETIME lastWriteTime = {.dwLowDateTime = inode->i_last_write_time & 0xffffffff,
-                                 .dwHighDateTime = inode->i_last_write_time >> 32};
-
-       DEBUG("Calling SetFileTime() on \"%s\"", output_path);
-       if (!SetFileTime(h, &creationTime, &lastAccessTime, &lastWriteTime)) {
-               err = GetLastError();
-               CloseHandle(h);
-               goto fail;
-       }
-       DEBUG("Closing \"%s\"", output_path);
-       if (!CloseHandle(h)) {
-               err = GetLastError();
-               goto fail;
-       }
-       goto out;
-fail:
-       /* Only warn if setting timestamps failed. */
-       WARNING("Can't set timestamps on \"%s\"", output_path);
-       win32_error(err);
-out:
-       return 0;
-#else
-       /* UNIX */
-
        /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
         * into struct timeval's. */
        struct timeval tv[2];
        /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
         * into struct timeval's. */
        struct timeval tv[2];
@@ -856,6 +426,56 @@ out:
                }
        }
        return 0;
                }
        }
        return 0;
+}
+#endif /* !__WIN32__ */
+
+/* Extracts a file, directory, or symbolic link from the WIM archive. */
+static int apply_dentry_normal(struct wim_dentry *dentry, void *arg)
+{
+       struct apply_args *args = arg;
+       struct wim_inode *inode = dentry->d_inode;
+       size_t len;
+       char *output_path;
+
+       len = strlen(args->target);
+       if (dentry_is_root(dentry)) {
+               output_path = (char*)args->target;
+       } else {
+               output_path = alloca(len + dentry->full_path_utf8_len + 1);
+               memcpy(output_path, args->target, len);
+               memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
+               output_path[len + dentry->full_path_utf8_len] = '\0';
+               len += dentry->full_path_utf8_len;
+       }
+#ifdef __WIN32__
+       return win32_apply_dentry(output_path, len, dentry, args);
+#else
+       return unix_apply_dentry(output_path, len, dentry, args);
+#endif
+}
+
+
+/* Apply timestamps to an extracted file or directory */
+static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg)
+{
+       struct apply_args *args = arg;
+       size_t len;
+       char *output_path;
+
+       len = strlen(args->target);
+       if (dentry_is_root(dentry)) {
+               output_path = (char*)args->target;
+       } else {
+               output_path = alloca(len + dentry->full_path_utf8_len + 1);
+               memcpy(output_path, args->target, len);
+               memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
+               output_path[len + dentry->full_path_utf8_len] = '\0';
+               len += dentry->full_path_utf8_len;
+       }
+#ifdef __WIN32__
+       return win32_apply_dentry_timestamps(output_path, len, dentry, args);
+#else
+       return unix_apply_dentry_timestamps(output_path, len, dentry, args);
 #endif
 }
 
 #endif
 }
 
@@ -1276,7 +896,7 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w,
                        == (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
                return WIMLIB_ERR_INVALID_PARAM;
 
                        == (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
                return WIMLIB_ERR_INVALID_PARAM;
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
        if (extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
                ERROR("Extracting UNIX data is not supported on Windows");
                return WIMLIB_ERR_INVALID_PARAM;
        if (extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
                ERROR("Extracting UNIX data is not supported on Windows");
                return WIMLIB_ERR_INVALID_PARAM;
@@ -1323,10 +943,8 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w,
                w->lookup_table = joined_tab;
        }
 
                w->lookup_table = joined_tab;
        }
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
-       win32_acquire_privilege(SE_RESTORE_NAME);
-       win32_acquire_privilege(SE_SECURITY_NAME);
-       win32_acquire_privilege(SE_TAKE_OWNERSHIP_NAME);
+#ifdef __WIN32__
+       win32_acquire_restore_privileges();
 #endif
        if (image == WIMLIB_ALL_IMAGES) {
                extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
 #endif
        if (image == WIMLIB_ALL_IMAGES) {
                extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
@@ -1337,10 +955,8 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w,
                ret = extract_single_image(w, image, target, extract_flags,
                                           progress_func);
        }
                ret = extract_single_image(w, image, target, extract_flags,
                                           progress_func);
        }
-#if defined(__CYGWIN__) || defined(__WIN32__)
-       win32_release_privilege(SE_RESTORE_NAME);
-       win32_release_privilege(SE_SECURITY_NAME);
-       win32_release_privilege(SE_TAKE_OWNERSHIP_NAME);
+#ifdef __WIN32__
+       win32_release_restore_privileges();
 #endif
 
        if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
 #endif
 
        if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
index fee69cbb6cc26c5adcfb478e8103bdc508c9be0d..ab13e5e11c91d50a42706c49bad21f0d1755674b 100644 (file)
@@ -86,7 +86,7 @@ clone_lookup_table_entry(const struct wim_lookup_table_entry *old)
        switch (new->resource_location) {
        case RESOURCE_IN_STAGING_FILE:
        case RESOURCE_IN_FILE_ON_DISK:
        switch (new->resource_location) {
        case RESOURCE_IN_STAGING_FILE:
        case RESOURCE_IN_FILE_ON_DISK:
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
        case RESOURCE_WIN32:
 #endif
                BUILD_BUG_ON((void*)&old->file_on_disk !=
        case RESOURCE_WIN32:
 #endif
                BUILD_BUG_ON((void*)&old->file_on_disk !=
@@ -141,7 +141,7 @@ void free_lookup_table_entry(struct wim_lookup_table_entry *lte)
                case RESOURCE_IN_STAGING_FILE:
                case RESOURCE_IN_ATTACHED_BUFFER:
                case RESOURCE_IN_FILE_ON_DISK:
                case RESOURCE_IN_STAGING_FILE:
                case RESOURCE_IN_ATTACHED_BUFFER:
                case RESOURCE_IN_FILE_ON_DISK:
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
                case RESOURCE_WIN32:
 #endif
                        BUILD_BUG_ON((void*)&lte->file_on_disk !=
                case RESOURCE_WIN32:
 #endif
                        BUILD_BUG_ON((void*)&lte->file_on_disk !=
index 839acbc86f51947378fcbd3aa0ec9884bf1755e9..a17bf5026cc360c6491732d9d3a42ba15305b8b3 100644 (file)
@@ -2625,7 +2625,7 @@ out:
 
 static inline int mount_unsupported_error()
 {
 
 static inline int mount_unsupported_error()
 {
-#if defined(__CYGWIN__) || defined (__WIN32__)
+#if defined(__WIN32__)
        ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
 #else
        ERROR("wimlib was compiled with --without-fuse, which disables support "
        ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
 #else
        ERROR("wimlib was compiled with --without-fuse, which disables support "
index 8d61761414c9b718a1e4b0dab9312359616711ab..db9c635bc4ce4f125ed4281da17cec6b7461be29 100644 (file)
 #include "xpress.h"
 #include "sha1.h"
 
 #include "xpress.h"
 #include "sha1.h"
 
+#ifdef __WIN32__
+#  include "win32.h"
+#endif
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #ifdef WITH_NTFS_3G
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #ifdef WITH_NTFS_3G
-#include <time.h>
-#include <ntfs-3g/attrib.h>
-#include <ntfs-3g/inode.h>
-#include <ntfs-3g/dir.h>
+#  include <time.h>
+#  include <ntfs-3g/attrib.h>
+#  include <ntfs-3g/inode.h>
+#  include <ntfs-3g/dir.h>
 #endif
 
 /*
 #endif
 
 /*
@@ -558,7 +562,7 @@ int read_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[],
                if (fp != lte->file_on_disk_fp)
                        fclose(fp);
                break;
                if (fp != lte->file_on_disk_fp)
                        fclose(fp);
                break;
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
        case RESOURCE_WIN32:
                wimlib_assert(lte->file_on_disk_fp != NULL);
                ret = win32_read_file(lte->file_on_disk, lte->file_on_disk_fp,
        case RESOURCE_WIN32:
                wimlib_assert(lte->file_on_disk_fp != NULL);
                ret = win32_read_file(lte->file_on_disk, lte->file_on_disk_fp,
index 9c55ef2d30d09f0c5d6da72d3c64a8c7c2c9f05a..2e60aa53a33c496a09b24fc0ec6d07c96c35bf31 100644 (file)
@@ -560,7 +560,9 @@ void free_security_data(struct wim_security_data *sd)
        }
 }
 
        }
 }
 
-#if defined(WITH_NTFS_3G) || defined(__CYGWIN__) || defined(__WIN32__)
+/* The security tree stuff is only needed when NTFS capture is supported, either
+ * through NTFS-3G or through a native Windows build. */
+#if defined(WITH_NTFS_3G) || defined(__WIN32__)
 struct sd_node {
        int security_id;
        u8 hash[SHA1_HASH_SIZE];
 struct sd_node {
        int security_id;
        u8 hash[SHA1_HASH_SIZE];
@@ -686,4 +688,4 @@ out_free_node:
 out:
        return -1;
 }
 out:
        return -1;
 }
-#endif /* WITH_NTFS_3G || __CYGWIN__ || __WIN32__ */
+#endif /* WITH_NTFS_3G || __WIN32__ */
index d6d7d60a55c99743579cd937b9ad8a13ef67cc42..4d701d0c0106c6617c37fba2da1b2d48d14b67c9 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef _WIMLIB_SECURITY_H
 #define _WIMLIB_SECURITY_H
 
 #ifndef _WIMLIB_SECURITY_H
 #define _WIMLIB_SECURITY_H
 
-#if defined(WITH_NTFS_3G) || defined(__CYGWIN__) || defined(__WIN32__)
+#if defined(WITH_NTFS_3G) || defined(__WIN32__)
 /* Red-black tree that maps SHA1 message digests of security descriptors to
  * security IDs, which are themselves indices into the table of security
  * descriptors in the 'struct wim_security_data'. */
 /* Red-black tree that maps SHA1 message digests of security descriptors to
  * security IDs, which are themselves indices into the table of security
  * descriptors in the 'struct wim_security_data'. */
index 5a076a5c7d3bd2ca0a4cef8557979c4d2f9e1b33..3f05d8823b40396829e687e6c544673c90bb2d3b 100644 (file)
@@ -528,23 +528,6 @@ extern int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *));
 extern void destroy_image_metadata(struct wim_image_metadata *imd,
                                   struct wim_lookup_table *lt);
 
 extern void destroy_image_metadata(struct wim_image_metadata *imd,
                                   struct wim_lookup_table *lt);
 
-/* win32.c */
-
-#if defined(__CYGWIN__) || defined(__WIN32__)
-extern int win32_read_file(const char *filename, void *handle, u64 offset,
-                          size_t size, u8 *buf);
-extern void *win32_open_file_readonly(const void *path_utf16);
-extern void win32_close_file(void *handle);
-extern bool win32_acquire_privilege(const char *privilege);
-extern bool win32_release_privilege(const char *privilege);
-#ifdef ENABLE_ERROR_MESSAGES
-extern void win32_error(u32 err);
-#else
-#define win32_error(err)
-#endif
-#endif
-
-
 /* write.c */
 
 /* Internal use only */
 /* write.c */
 
 /* Internal use only */
@@ -553,6 +536,10 @@ extern void win32_error(u32 err);
 #define WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML  0x20000000
 #define WIMLIB_WRITE_MASK_PUBLIC               0x1fffffff
 
 #define WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML  0x20000000
 #define WIMLIB_WRITE_MASK_PUBLIC               0x1fffffff
 
+#define WIMLIB_ADD_IMAGE_FLAG_ROOT     0x80000000
+#define WIMLIB_ADD_IMAGE_FLAG_SOURCE    0x40000000
+
+
 extern int begin_write(WIMStruct *w, const char *path, int write_flags);
 extern void close_wim_writable(WIMStruct *w);
 
 extern int begin_write(WIMStruct *w, const char *path, int write_flags);
 extern void close_wim_writable(WIMStruct *w);
 
index 3ac8deca0ba2dd4934488e386ae17e3812224b4a..e2dc6a1b4396c2152413700b855232235d379fde 100644 (file)
@@ -1,13 +1,52 @@
-#include "config.h"
+/*
+ * win32.c
+ *
+ * All the code specific to native Windows builds is in here.
+ */
+
+/*
+ * Copyright (C) 2013 Eric Biggers
+ *
+ * This file is part of wimlib, a library for working with WIM files.
+ *
+ * wimlib is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * wimlib 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ */
+
+#ifndef __WIN32__
+#  error "This file contains Windows code"
+#endif
 
 
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#include "config.h"
 #include <windows.h>
 #include <windows.h>
-#      ifdef ERROR
-#              undef ERROR
-#      endif
+#include <ntdef.h>
+#include <wchar.h>
+#include <shlwapi.h>
+#ifdef ERROR
+#  undef ERROR
+#endif
+
+
+/* Microsoft's swprintf() violates the C standard and they require programmers
+ * to do this weird define to get the correct function.  */
+#define swprintf _snwprintf
 
 
-#include "wimlib_internal.h"
+#include "win32.h"
+#include "dentry.h"
+#include "lookup_table.h"
+#include "security.h"
 
 
+#include <errno.h>
 
 #ifdef ENABLE_ERROR_MESSAGES
 void win32_error(u32 err_code)
 
 #ifdef ENABLE_ERROR_MESSAGES
 void win32_error(u32 err_code)
@@ -110,15 +149,1068 @@ out:
        return ret;
 }
 
        return ret;
 }
 
-bool win32_acquire_privilege(const char *privilege)
+static bool win32_acquire_privilege(const char *privilege)
 {
        return win32_modify_privilege(privilege, true);
 }
 
 {
        return win32_modify_privilege(privilege, true);
 }
 
-bool win32_release_privilege(const char *privilege)
+static bool win32_release_privilege(const char *privilege)
 {
        return win32_modify_privilege(privilege, false);
 }
 
 
 {
        return win32_modify_privilege(privilege, false);
 }
 
 
-#endif /* __CYGWIN__ || __WIN32__ */
+void win32_acquire_capture_privileges()
+{
+       win32_acquire_privilege(SE_BACKUP_NAME);
+       win32_acquire_privilege(SE_SECURITY_NAME);
+}
+
+void win32_release_capture_privileges()
+{
+       win32_release_privilege(SE_BACKUP_NAME);
+       win32_release_privilege(SE_SECURITY_NAME);
+}
+
+void win32_acquire_restore_privileges()
+{
+       win32_acquire_privilege(SE_RESTORE_NAME);
+       win32_acquire_privilege(SE_SECURITY_NAME);
+       win32_acquire_privilege(SE_TAKE_OWNERSHIP_NAME);
+}
+
+void win32_release_restore_privileges()
+{
+       win32_release_privilege(SE_RESTORE_NAME);
+       win32_release_privilege(SE_SECURITY_NAME);
+       win32_release_privilege(SE_TAKE_OWNERSHIP_NAME);
+}
+
+static u64 FILETIME_to_u64(const FILETIME *ft)
+{
+       return ((u64)ft->dwHighDateTime << 32) | (u64)ft->dwLowDateTime;
+}
+
+
+int win32_build_dentry_tree(struct wim_dentry **root_ret,
+                           const char *root_disk_path,
+                           struct wim_lookup_table *lookup_table,
+                           struct wim_security_data *sd,
+                           const struct capture_config *config,
+                           int add_image_flags,
+                           wimlib_progress_func_t progress_func,
+                           void *extra_arg);
+
+static int win32_get_short_name(struct wim_dentry *dentry,
+                               const wchar_t *path_utf16)
+{
+       WIN32_FIND_DATAW dat;
+       if (FindFirstFileW(path_utf16, &dat) &&
+           dat.cAlternateFileName[0] != L'\0')
+       {
+               size_t short_name_len = wcslen(dat.cAlternateFileName) * 2;
+               size_t n = short_name_len + sizeof(wchar_t);
+               dentry->short_name = MALLOC(n);
+               if (!dentry->short_name)
+                       return WIMLIB_ERR_NOMEM;
+               memcpy(dentry->short_name, dat.cAlternateFileName, n);
+               dentry->short_name_len = short_name_len;
+       }
+       return 0;
+}
+
+static int win32_get_security_descriptor(struct wim_dentry *dentry,
+                                        struct sd_set *sd_set,
+                                        const wchar_t *path_utf16)
+{
+       SECURITY_INFORMATION requestedInformation;
+       DWORD lenNeeded = 0;
+       BOOL status;
+       DWORD err;
+
+       requestedInformation = DACL_SECURITY_INFORMATION |
+                              SACL_SECURITY_INFORMATION |
+                              OWNER_SECURITY_INFORMATION |
+                              GROUP_SECURITY_INFORMATION;
+       /* Request length of security descriptor */
+       status = GetFileSecurityW(path_utf16, requestedInformation,
+                                 NULL, 0, &lenNeeded);
+       err = GetLastError();
+       if (!status && err == ERROR_INSUFFICIENT_BUFFER) {
+               DWORD len = lenNeeded;
+               char buf[len];
+               if (GetFileSecurityW(path_utf16, requestedInformation,
+                                    (PSECURITY_DESCRIPTOR)buf, len, &lenNeeded))
+               {
+                       int security_id = sd_set_add_sd(sd_set, buf, len);
+                       if (security_id < 0)
+                               return WIMLIB_ERR_NOMEM;
+                       else {
+                               dentry->d_inode->i_security_id = security_id;
+                               return 0;
+                       }
+               } else {
+                       err = GetLastError();
+               }
+       }
+       ERROR("Win32 API: Failed to read security descriptor of \"%ls\"",
+             path_utf16);
+       win32_error(err);
+       return WIMLIB_ERR_READ;
+}
+
+/* Reads the directory entries of directory using a Win32 API and recursively
+ * calls build_dentry_tree() on them. */
+static int win32_recurse_directory(struct wim_dentry *root,
+                                  const char *root_disk_path,
+                                  struct wim_lookup_table *lookup_table,
+                                  struct wim_security_data *sd,
+                                  const struct capture_config *config,
+                                  int add_image_flags,
+                                  wimlib_progress_func_t progress_func,
+                                  struct sd_set *sd_set,
+                                  const wchar_t *path_utf16,
+                                  size_t path_utf16_nchars)
+{
+       WIN32_FIND_DATAW dat;
+       HANDLE hFind;
+       DWORD err;
+       int ret;
+
+       {
+               /* Begin reading the directory by calling FindFirstFileW.
+                * Unlike UNIX opendir(), FindFirstFileW has file globbing built
+                * into it.  But this isn't what we actually want, so just add a
+                * dummy glob to get all entries. */
+               wchar_t pattern_buf[path_utf16_nchars + 3];
+               memcpy(pattern_buf, path_utf16,
+                      path_utf16_nchars * sizeof(wchar_t));
+               pattern_buf[path_utf16_nchars] = L'/';
+               pattern_buf[path_utf16_nchars + 1] = L'*';
+               pattern_buf[path_utf16_nchars + 2] = L'\0';
+               hFind = FindFirstFileW(pattern_buf, &dat);
+       }
+       if (hFind == INVALID_HANDLE_VALUE) {
+               err = GetLastError();
+               if (err == ERROR_FILE_NOT_FOUND) {
+                       return 0;
+               } else {
+                       ERROR("Win32 API: Failed to read directory \"%s\"",
+                             root_disk_path);
+                       win32_error(err);
+                       return WIMLIB_ERR_READ;
+               }
+       }
+       ret = 0;
+       do {
+               /* Skip . and .. entries */
+               if (!(dat.cFileName[0] == L'.' &&
+                     (dat.cFileName[1] == L'\0' ||
+                      (dat.cFileName[1] == L'.' && dat.cFileName[2] == L'\0'))))
+               {
+                       struct wim_dentry *child;
+
+                       char *utf8_name;
+                       size_t utf8_name_nbytes;
+                       ret = utf16_to_utf8((const char*)dat.cFileName,
+                                           wcslen(dat.cFileName) * sizeof(wchar_t),
+                                           &utf8_name,
+                                           &utf8_name_nbytes);
+                       if (ret)
+                               goto out_find_close;
+
+                       char name[strlen(root_disk_path) + 1 + utf8_name_nbytes + 1];
+                       sprintf(name, "%s/%s", root_disk_path, utf8_name);
+                       FREE(utf8_name);
+                       ret = win32_build_dentry_tree(&child, name, lookup_table,
+                                                     sd, config, add_image_flags,
+                                                     progress_func, sd_set);
+                       if (ret)
+                               goto out_find_close;
+                       if (child)
+                               dentry_add_child(root, child);
+               }
+       } while (FindNextFileW(hFind, &dat));
+       err = GetLastError();
+       if (err != ERROR_NO_MORE_FILES) {
+               ERROR("Win32 API: Failed to read directory \"%s\"", root_disk_path);
+               win32_error(err);
+               if (ret == 0)
+                       ret = WIMLIB_ERR_READ;
+       }
+out_find_close:
+       FindClose(hFind);
+       return ret;
+}
+
+/* Load a reparse point into a WIM inode.  It is just stored in memory.
+ *
+ * @hFile:  Open handle to a reparse point, with permission to read the reparse
+ *          data.
+ *
+ * @inode:  WIM inode for the reparse point.
+ *
+ * @lookup_table:  Stream lookup table for the WIM; an entry will be added to it
+ *                 for the reparse point unless an entry already exists for
+ *                 the exact same data stream.
+ *
+ * @path:  External path to the parse point (UTF-8).  Used for error messages
+ *         only.
+ *
+ * Returns 0 on success; nonzero on failure. */
+static int win32_capture_reparse_point(HANDLE hFile,
+                                      struct wim_inode *inode,
+                                      struct wim_lookup_table *lookup_table,
+                                      const char *path)
+{
+       /* "Reparse point data, including the tag and optional GUID,
+        * cannot exceed 16 kilobytes." - MSDN  */
+       char reparse_point_buf[16 * 1024];
+       DWORD bytesReturned;
+
+       if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT,
+                            NULL, 0, reparse_point_buf,
+                            sizeof(reparse_point_buf), &bytesReturned, NULL))
+       {
+               DWORD err = GetLastError();
+               ERROR("Win32 API: Failed to get reparse data of \"%s\"", path);
+               win32_error(err);
+               return WIMLIB_ERR_READ;
+       }
+       if (bytesReturned < 8) {
+               ERROR("Reparse data on \"%s\" is invalid", path);
+               return WIMLIB_ERR_READ;
+       }
+       inode->i_reparse_tag = *(u32*)reparse_point_buf;
+       return inode_add_ads_with_data(inode, "",
+                                      (const u8*)reparse_point_buf + 8,
+                                      bytesReturned - 8, lookup_table);
+}
+
+/* Calculate the SHA1 message digest of a Win32 data stream, which may be either
+ * an unnamed or named data stream.
+ *
+ * @path:      Path to the file, with the stream noted at the end for named
+ *              streams.  UTF-16LE encoding.
+ *
+ * @hash:       On success, the SHA1 message digest of the stream is written to
+ *              this location.
+ *
+ * Returns 0 on success; nonzero on failure.
+ */
+static int win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE])
+{
+       HANDLE hFile;
+       SHA_CTX ctx;
+       u8 buf[32768];
+       DWORD bytesRead;
+       int ret;
+
+       hFile = win32_open_file_readonly(path);
+       if (hFile == INVALID_HANDLE_VALUE)
+               return WIMLIB_ERR_OPEN;
+
+       sha1_init(&ctx);
+       for (;;) {
+               if (!ReadFile(hFile, buf, sizeof(buf), &bytesRead, NULL)) {
+                       ret = WIMLIB_ERR_READ;
+                       goto out_close_handle;
+               }
+               if (bytesRead == 0)
+                       break;
+               sha1_update(&ctx, buf, bytesRead);
+       }
+       ret = 0;
+       sha1_final(hash, &ctx);
+out_close_handle:
+       CloseHandle(hFile);
+       return ret;
+}
+
+/* Scans an unnamed or named stream of a Win32 file (not a reparse point
+ * stream); calculates its SHA1 message digest and either creates a `struct
+ * wim_lookup_table_entry' in memory for it, or uses an existing 'struct
+ * wim_lookup_table_entry' for an identical stream.
+ *
+ * @path_utf16:         Path to the file (UTF-16LE).
+ *
+ * @path_utf16_nchars:  Number of 2-byte characters in @path_utf16.
+ *
+ * @inode:              WIM inode to save the stream into.
+ *
+ * @lookup_table:       Stream lookup table for the WIM.
+ *
+ * @dat:                A `WIN32_FIND_STREAM_DATA' structure that specifies the
+ *                      stream name.
+ *
+ * Returns 0 on success; nonzero on failure.
+ */
+static int win32_capture_stream(const wchar_t *path_utf16,
+                               size_t path_utf16_nchars,
+                               struct wim_inode *inode,
+                               struct wim_lookup_table *lookup_table,
+                               WIN32_FIND_STREAM_DATA *dat)
+{
+       struct wim_ads_entry *ads_entry;
+       u8 hash[SHA1_HASH_SIZE];
+       struct wim_lookup_table_entry *lte;
+       int ret;
+       wchar_t *p, *colon;
+       bool is_named_stream;
+       wchar_t *spath;
+       size_t spath_nchars;
+       DWORD err;
+
+       /* The stream name should be returned as :NAME:TYPE */
+       p = dat->cStreamName;
+       if (*p != L':')
+               goto out_invalid_stream_name;
+       p += 1;
+       colon = wcschr(p, L':');
+       if (colon == NULL)
+               goto out_invalid_stream_name;
+
+       if (wcscmp(colon + 1, L"$DATA")) {
+               /* Not a DATA stream */
+               ret = 0;
+               goto out;
+       }
+
+       is_named_stream = (p != colon);
+       if (is_named_stream) {
+               /* Allocate an ADS entry for the named stream. */
+               char *utf8_stream_name;
+               size_t utf8_stream_name_len;
+               ret = utf16_to_utf8((const char *)p,
+                                   (colon - p) * sizeof(wchar_t),
+                                   &utf8_stream_name,
+                                   &utf8_stream_name_len);
+               if (ret)
+                       goto out;
+               ads_entry = inode_add_ads(inode, utf8_stream_name);
+               FREE(utf8_stream_name);
+               if (!ads_entry) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out;
+               }
+       }
+
+       /* Create a UTF-16 string @spath that gives the filename, then a colon,
+        * then the stream name.  Or, if it's an unnamed stream, just the
+        * filename.  It is MALLOC()'ed so that it can be saved in the
+        * wim_lookup_table_entry if needed. */
+       *colon = '\0';
+       spath_nchars = path_utf16_nchars;
+       if (is_named_stream)
+               spath_nchars += colon - p + 1;
+
+       spath = MALLOC((spath_nchars + 1) * sizeof(wchar_t));
+       memcpy(spath, path_utf16, path_utf16_nchars * sizeof(wchar_t));
+       if (is_named_stream) {
+               spath[path_utf16_nchars] = L':';
+               memcpy(&spath[path_utf16_nchars + 1], p, (colon - p) * sizeof(wchar_t));
+       }
+       spath[spath_nchars] = L'\0';
+
+       ret = win32_sha1sum(spath, hash);
+       if (ret) {
+               err = GetLastError();
+               ERROR("Win32 API: Failed to read \"%ls\" to calculate SHA1sum",
+                     path_utf16);
+               win32_error(err);
+               goto out_free_spath;
+       }
+
+       lte = __lookup_resource(lookup_table, hash);
+       if (lte) {
+               /* Use existing wim_lookup_table_entry that has the same SHA1
+                * message digest */
+               lte->refcnt++;
+       } else {
+               /* Make a new wim_lookup_table_entry */
+               lte = new_lookup_table_entry();
+               if (!lte) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out_free_spath;
+               }
+               lte->file_on_disk = (char*)spath;
+               spath = NULL;
+               lte->resource_location = RESOURCE_WIN32;
+               lte->resource_entry.original_size = (uint64_t)dat->StreamSize.QuadPart;
+               lte->resource_entry.size = (uint64_t)dat->StreamSize.QuadPart;
+               copy_hash(lte->hash, hash);
+               lookup_table_insert(lookup_table, lte);
+       }
+       if (is_named_stream)
+               ads_entry->lte = lte;
+       else
+               inode->i_lte = lte;
+out_free_spath:
+       FREE(spath);
+out:
+       return ret;
+out_invalid_stream_name:
+       ERROR("Invalid stream name: \"%ls:%ls\"", path_utf16, dat->cStreamName);
+       ret = WIMLIB_ERR_READ;
+       goto out;
+}
+
+/* Scans a Win32 file for unnamed and named data streams (not reparse point
+ * streams).
+ *
+ * @path_utf16:         Path to the file (UTF-16LE).
+ *
+ * @path_utf16_nchars:  Number of 2-byte characters in @path_utf16.
+ *
+ * @inode:              WIM inode to save the stream into.
+ *
+ * @lookup_table:       Stream lookup table for the WIM.
+ *
+ * Returns 0 on success; nonzero on failure.
+ */
+static int win32_capture_streams(const wchar_t *path_utf16,
+                                size_t path_utf16_nchars,
+                                struct wim_inode *inode,
+                                struct wim_lookup_table *lookup_table)
+{
+       WIN32_FIND_STREAM_DATA dat;
+       int ret;
+       HANDLE hFind;
+       DWORD err;
+
+       hFind = FindFirstStreamW(path_utf16, FindStreamInfoStandard, &dat, 0);
+       if (hFind == INVALID_HANDLE_VALUE) {
+               err = GetLastError();
+
+               /* Seems legal for this to return ERROR_HANDLE_EOF on reparse
+                * points and directories */
+               if ((inode->i_attributes &
+                   (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
+                   && err == ERROR_HANDLE_EOF)
+               {
+                       return 0;
+               } else {
+                       ERROR("Win32 API: Failed to look up data streams of \"%ls\"",
+                             path_utf16);
+                       win32_error(err);
+                       return WIMLIB_ERR_READ;
+               }
+       }
+       do {
+               ret = win32_capture_stream(path_utf16,
+                                          path_utf16_nchars,
+                                          inode, lookup_table,
+                                          &dat);
+               if (ret)
+                       goto out_find_close;
+       } while (FindNextStreamW(hFind, &dat));
+       err = GetLastError();
+       if (err != ERROR_HANDLE_EOF) {
+               ERROR("Win32 API: Error reading data streams from \"%ls\"", path_utf16);
+               win32_error(err);
+               ret = WIMLIB_ERR_READ;
+       }
+out_find_close:
+       FindClose(hFind);
+       return ret;
+}
+
+/* Win32 version of capturing a directory tree */
+int win32_build_dentry_tree(struct wim_dentry **root_ret,
+                           const char *root_disk_path,
+                           struct wim_lookup_table *lookup_table,
+                           struct wim_security_data *sd,
+                           const struct capture_config *config,
+                           int add_image_flags,
+                           wimlib_progress_func_t progress_func,
+                           void *extra_arg)
+{
+       struct wim_dentry *root = NULL;
+       int ret = 0;
+       struct wim_inode *inode;
+
+       wchar_t *path_utf16;
+       size_t path_utf16_nchars;
+       struct sd_set *sd_set;
+       DWORD err;
+
+       if (exclude_path(root_disk_path, config, true)) {
+               if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
+                       ERROR("Cannot exclude the root directory from capture");
+                       ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
+                       goto out;
+               }
+               if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
+                   && progress_func)
+               {
+                       union wimlib_progress_info info;
+                       info.scan.cur_path = root_disk_path;
+                       info.scan.excluded = true;
+                       progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+               }
+               goto out;
+       }
+
+       if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
+           && progress_func)
+       {
+               union wimlib_progress_info info;
+               info.scan.cur_path = root_disk_path;
+               info.scan.excluded = false;
+               progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+       }
+
+       if (extra_arg == NULL) {
+               sd_set = alloca(sizeof(struct sd_set));
+               sd_set->rb_root.rb_node = NULL,
+               sd_set->sd = sd;
+       } else {
+               sd_set = extra_arg;
+       }
+
+       ret = utf8_to_utf16(root_disk_path, strlen(root_disk_path),
+                           (char**)&path_utf16, &path_utf16_nchars);
+       if (ret)
+               goto out_destroy_sd_set;
+       path_utf16_nchars /= sizeof(wchar_t);
+
+       HANDLE hFile = win32_open_file_readonly(path_utf16);
+       if (hFile == INVALID_HANDLE_VALUE) {
+               err = GetLastError();
+               ERROR("Win32 API: Failed to open \"%s\"", root_disk_path);
+               win32_error(err);
+               ret = WIMLIB_ERR_OPEN;
+               goto out_free_path_utf16;
+       }
+
+       BY_HANDLE_FILE_INFORMATION file_info;
+       if (!GetFileInformationByHandle(hFile, &file_info)) {
+               err = GetLastError();
+               ERROR("Win32 API: Failed to get file information for \"%s\"",
+                     root_disk_path);
+               win32_error(err);
+               ret = WIMLIB_ERR_STAT;
+               goto out_close_handle;
+       }
+
+       /* Create a WIM dentry */
+       root = new_dentry_with_timeless_inode(path_basename(root_disk_path));
+       if (!root) {
+               if (errno == EILSEQ)
+                       ret = WIMLIB_ERR_INVALID_UTF8_STRING;
+               else if (errno == ENOMEM)
+                       ret = WIMLIB_ERR_NOMEM;
+               else
+                       ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE;
+               goto out_close_handle;
+       }
+
+       /* Start preparing the associated WIM inode */
+       inode = root->d_inode;
+
+       inode->i_attributes = file_info.dwFileAttributes;
+       inode->i_creation_time = FILETIME_to_u64(&file_info.ftCreationTime);
+       inode->i_last_write_time = FILETIME_to_u64(&file_info.ftLastWriteTime);
+       inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime);
+       inode->i_ino = ((u64)file_info.nFileIndexHigh << 32) |
+                       (u64)file_info.nFileIndexLow;
+
+       inode->i_resolved = 1;
+       add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
+
+       /* Get DOS name and security descriptor (if any). */
+       ret = win32_get_short_name(root, path_utf16);
+       if (ret)
+               goto out_close_handle;
+       ret = win32_get_security_descriptor(root, sd_set, path_utf16);
+       if (ret)
+               goto out_close_handle;
+
+       if (inode_is_directory(inode)) {
+               /* Directory (not a reparse point) --- recurse to children */
+
+               /* But first... directories may have alternate data streams that
+                * need to be captured. */
+               ret = win32_capture_streams(path_utf16,
+                                           path_utf16_nchars,
+                                           inode,
+                                           lookup_table);
+               if (ret)
+                       goto out_close_handle;
+               ret = win32_recurse_directory(root,
+                                             root_disk_path,
+                                             lookup_table,
+                                             sd,
+                                             config,
+                                             add_image_flags,
+                                             progress_func,
+                                             sd_set,
+                                             path_utf16,
+                                             path_utf16_nchars);
+       } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+               /* Reparse point: save the reparse tag and data */
+               ret = win32_capture_reparse_point(hFile,
+                                                 inode,
+                                                 lookup_table,
+                                                 root_disk_path);
+       } else {
+               /* Not a directory, not a reparse point; capture the default
+                * file contents and any alternate data streams. */
+               ret = win32_capture_streams(path_utf16,
+                                           path_utf16_nchars,
+                                           inode,
+                                           lookup_table);
+       }
+out_close_handle:
+       CloseHandle(hFile);
+out_free_path_utf16:
+       FREE(path_utf16);
+out_destroy_sd_set:
+       if (extra_arg == NULL)
+               destroy_sd_set(sd_set);
+out:
+       if (ret == 0)
+               *root_ret = root;
+       else
+               free_dentry_tree(root, lookup_table);
+       return ret;
+}
+
+/* Replacement for POSIX fnmatch() (partial functionality only) */
+extern int fnmatch(const char *pattern, const char *string, int flags)
+{
+       if (PathMatchSpecA(string, pattern))
+               return 0;
+       else
+               return FNM_NOMATCH;
+}
+
+static int win32_set_reparse_data(HANDLE h,
+                                 u32 reparse_tag,
+                                 const struct wim_lookup_table_entry *lte,
+                                 const wchar_t *path)
+{
+       int ret;
+       u8 *buf;
+       size_t len;
+
+       if (!lte) {
+               WARNING("\"%ls\" is marked as a reparse point but had no reparse data",
+                       path);
+               return 0;
+       }
+       len = wim_resource_size(lte);
+       if (len > 16 * 1024 - 8) {
+               WARNING("\"%ls\": reparse data too long!", path);
+               return 0;
+       }
+
+       /* The WIM stream omits the ReparseTag and ReparseDataLength fields, so
+        * leave 8 bytes of space for them at the beginning of the buffer, then
+        * set them manually. */
+       buf = alloca(len + 8);
+       ret = read_full_wim_resource(lte, buf + 8, 0);
+       if (ret)
+               return ret;
+       *(u32*)(buf + 0) = reparse_tag;
+       *(u16*)(buf + 4) = len;
+       *(u16*)(buf + 6) = 0;
+
+       /* Set the reparse data on the open file using the
+        * FSCTL_SET_REPARSE_POINT ioctl.
+        *
+        * There are contradictions in Microsoft's documentation for this:
+        *
+        * "If hDevice was opened without specifying FILE_FLAG_OVERLAPPED,
+        * lpOverlapped is ignored."
+        *
+        * --- So setting lpOverlapped to NULL is okay since it's ignored.
+        *
+        * "If lpOverlapped is NULL, lpBytesReturned cannot be NULL. Even when an
+        * operation returns no output data and lpOutBuffer is NULL,
+        * DeviceIoControl makes use of lpBytesReturned. After such an
+        * operation, the value of lpBytesReturned is meaningless."
+        *
+        * --- So lpOverlapped not really ignored, as it affects another
+        *  parameter.  This is the actual behavior: lpBytesReturned must be
+        *  specified, even though lpBytesReturned is documented as:
+        *
+        *  "Not used with this operation; set to NULL."
+        */
+       DWORD bytesReturned;
+       if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, buf, len + 8,
+                            NULL, 0,
+                            &bytesReturned /* lpBytesReturned */,
+                            NULL /* lpOverlapped */))
+       {
+               DWORD err = GetLastError();
+               ERROR("Failed to set reparse data on \"%ls\"", path);
+               win32_error(err);
+               return WIMLIB_ERR_WRITE;
+       }
+       return 0;
+}
+
+
+static int win32_extract_chunk(const u8 *buf, size_t len, u64 offset, void *arg)
+{
+       HANDLE hStream = arg;
+
+       DWORD nbytes_written;
+       wimlib_assert(len <= 0xffffffff);
+
+       if (!WriteFile(hStream, buf, len, &nbytes_written, NULL) ||
+           nbytes_written != len)
+       {
+               DWORD err = GetLastError();
+               ERROR("WriteFile(): write error");
+               win32_error(err);
+               return WIMLIB_ERR_WRITE;
+       }
+       return 0;
+}
+
+static int do_win32_extract_stream(HANDLE hStream, struct wim_lookup_table_entry *lte)
+{
+       return extract_wim_resource(lte, wim_resource_size(lte),
+                                   win32_extract_chunk, hStream);
+}
+
+static int win32_extract_stream(const struct wim_inode *inode,
+                               const wchar_t *path,
+                               const wchar_t *stream_name_utf16,
+                               struct wim_lookup_table_entry *lte)
+{
+       wchar_t *stream_path;
+       HANDLE h;
+       int ret;
+       DWORD err;
+       DWORD creationDisposition = CREATE_ALWAYS;
+
+       if (stream_name_utf16) {
+               /* Named stream.  Create a buffer that contains the UTF-16LE
+                * string [./]@path:@stream_name_utf16.  This is needed to
+                * create and open the stream using CreateFileW().  I'm not
+                * aware of any other APIs to do this.  Note: the '$DATA' suffix
+                * seems to be unneeded.  Additional note: a "./" prefix needs
+                * to be added when the path is not absolute to avoid ambiguity
+                * with drive letters. */
+               size_t stream_path_nchars;
+               size_t path_nchars;
+               size_t stream_name_nchars;
+               const wchar_t *prefix;
+
+               path_nchars = wcslen(path);
+               stream_name_nchars = wcslen(stream_name_utf16);
+               stream_path_nchars = path_nchars + 1 + stream_name_nchars;
+               if (path[0] != L'/' && path[0] != L'\\') {
+                       prefix = L"./";
+                       stream_path_nchars += 2;
+               } else {
+                       prefix = L"";
+               }
+               stream_path = alloca((stream_path_nchars + 1) * sizeof(wchar_t));
+               swprintf(stream_path, stream_path_nchars + 1, L"%ls%ls:%ls",
+                        prefix, path, stream_name_utf16);
+       } else {
+               /* Unnamed stream; its path is just the path to the file itself.
+                * */
+               stream_path = (wchar_t*)path;
+
+               /* Directories must be created with CreateDirectoryW().  Then
+                * the call to CreateFileW() will merely open the directory that
+                * was already created rather than creating a new file. */
+               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
+                       if (!CreateDirectoryW(stream_path, NULL)) {
+                               err = GetLastError();
+                               if (err != ERROR_ALREADY_EXISTS) {
+                                       ERROR("Failed to create directory \"%ls\"",
+                                             stream_path);
+                                       win32_error(err);
+                                       ret = WIMLIB_ERR_MKDIR;
+                                       goto fail;
+                               }
+                       }
+                       DEBUG("Created directory \"%ls\"", stream_path);
+                       if (!(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+                               ret = 0;
+                               goto out;
+                       }
+                       creationDisposition = OPEN_EXISTING;
+               }
+       }
+
+       DEBUG("Opening \"%ls\"", stream_path);
+       h = CreateFileW(stream_path,
+                       GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
+                       0,
+                       NULL,
+                       creationDisposition,
+                       FILE_FLAG_OPEN_REPARSE_POINT |
+                           FILE_FLAG_BACKUP_SEMANTICS |
+                           inode->i_attributes,
+                       NULL);
+       if (h == INVALID_HANDLE_VALUE) {
+               err = GetLastError();
+               ERROR("Failed to create \"%ls\"", stream_path);
+               win32_error(err);
+               ret = WIMLIB_ERR_OPEN;
+               goto fail;
+       }
+
+       if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
+           stream_name_utf16 == NULL)
+       {
+               DEBUG("Setting reparse data on \"%ls\"", path);
+               ret = win32_set_reparse_data(h, inode->i_reparse_tag, lte, path);
+               if (ret)
+                       goto fail_close_handle;
+       } else {
+               if (lte) {
+                       DEBUG("Extracting \"%ls\" (len = %"PRIu64")",
+                             stream_path, wim_resource_size(lte));
+                       ret = do_win32_extract_stream(h, lte);
+                       if (ret)
+                               goto fail_close_handle;
+               }
+       }
+
+       DEBUG("Closing \"%ls\"", stream_path);
+       if (!CloseHandle(h)) {
+               err = GetLastError();
+               ERROR("Failed to close \"%ls\"", stream_path);
+               win32_error(err);
+               ret = WIMLIB_ERR_WRITE;
+               goto fail;
+       }
+       ret = 0;
+       goto out;
+fail_close_handle:
+       CloseHandle(h);
+fail:
+       ERROR("Error extracting %ls", stream_path);
+out:
+       return ret;
+}
+
+/*
+ * Creates a file, directory, or reparse point and extracts all streams to it
+ * (unnamed data stream and/or reparse point stream, plus any alternate data
+ * streams).  This in Win32-specific code.
+ *
+ * @inode:     WIM inode for this file or directory.
+ * @path:      UTF-16LE external path to extract the inode to.
+ *
+ * Returns 0 on success; nonzero on failure.
+ */
+static int win32_extract_streams(const struct wim_inode *inode,
+                                const wchar_t *path, u64 *completed_bytes_p)
+{
+       struct wim_lookup_table_entry *unnamed_lte;
+       int ret;
+
+       unnamed_lte = inode_unnamed_lte_resolved(inode);
+       ret = win32_extract_stream(inode, path, NULL, unnamed_lte);
+       if (ret)
+               goto out;
+       if (unnamed_lte)
+               *completed_bytes_p += wim_resource_size(unnamed_lte);
+       for (u16 i = 0; i < inode->i_num_ads; i++) {
+               const struct wim_ads_entry *ads_entry = &inode->i_ads_entries[i];
+               if (ads_entry->stream_name_len != 0) {
+                       /* Skip special UNIX data entries (see documentation for
+                        * WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */
+                       if (ads_entry->stream_name_len == WIMLIB_UNIX_DATA_TAG_LEN
+                           && !memcmp(ads_entry->stream_name_utf8,
+                                      WIMLIB_UNIX_DATA_TAG,
+                                      WIMLIB_UNIX_DATA_TAG_LEN))
+                               continue;
+                       ret = win32_extract_stream(inode,
+                                                  path,
+                                                  (const wchar_t*)ads_entry->stream_name,
+                                                  ads_entry->lte);
+                       if (ret)
+                               break;
+                       if (ads_entry->lte)
+                               *completed_bytes_p += wim_resource_size(ads_entry->lte);
+               }
+       }
+out:
+       return ret;
+}
+
+/*
+ * Sets the security descriptor on an extracted file.  This is Win32-specific
+ * code.
+ *
+ * @inode:     The WIM inode that was extracted and has a security descriptor.
+ * @path:      UTF-16LE external path that the inode was extracted to.
+ * @sd:                Security data for the WIM image.
+ *
+ * Returns 0 on success; nonzero on failure.
+ */
+static int win32_set_security_data(const struct wim_inode *inode,
+                                  const wchar_t *path,
+                                  const struct wim_security_data *sd)
+{
+       SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION |
+                                                  SACL_SECURITY_INFORMATION |
+                                                  OWNER_SECURITY_INFORMATION |
+                                                  GROUP_SECURITY_INFORMATION;
+       if (!SetFileSecurityW(path, securityInformation,
+                             (PSECURITY_DESCRIPTOR)sd->descriptors[inode->i_security_id]))
+       {
+               DWORD err = GetLastError();
+               ERROR("Can't set security descriptor on \"%ls\"", path);
+               win32_error(err);
+               return WIMLIB_ERR_WRITE;
+       }
+       return 0;
+}
+
+int win32_apply_dentry(const char *output_path,
+                      size_t output_path_len,
+                      const struct wim_dentry *dentry,
+                      struct apply_args *args)
+{
+       char *utf16_path;
+       size_t utf16_path_len;
+       DWORD err;
+       int ret;
+       struct wim_inode *inode = dentry->d_inode;
+
+       ret = utf8_to_utf16(output_path, output_path_len,
+                           &utf16_path, &utf16_path_len);
+       if (ret)
+               return ret;
+
+       if (inode->i_nlink > 1 && inode->i_extracted_file != NULL) {
+               /* Linked file, with another name already extracted.  Create a
+                * hard link. */
+               DEBUG("Creating hard link \"%ls => %ls\"",
+                     (const wchar_t*)utf16_path,
+                     (const wchar_t*)inode->i_extracted_file);
+               if (!CreateHardLinkW((const wchar_t*)utf16_path,
+                                    (const wchar_t*)inode->i_extracted_file,
+                                    NULL))
+               {
+                       err = GetLastError();
+                       ERROR("Can't create hard link \"%ls => %ls\"",
+                             (const wchar_t*)utf16_path,
+                             (const wchar_t*)inode->i_extracted_file);
+                       ret = WIMLIB_ERR_LINK;
+                       win32_error(err);
+               }
+       } else {
+               /* Create the file, directory, or reparse point, and extract the
+                * data streams. */
+               ret = win32_extract_streams(inode, (const wchar_t*)utf16_path,
+                                           &args->progress.extract.completed_bytes);
+               if (ret)
+                       goto out_free_utf16_path;
+
+               /* Set security descriptor if present */
+               if (inode->i_security_id != -1) {
+                       DEBUG("Setting security descriptor %d on %s",
+                             inode->i_security_id, output_path);
+                       ret = win32_set_security_data(inode,
+                                                     (const wchar_t*)utf16_path,
+                                                     wim_const_security_data(args->w));
+                       if (ret)
+                               goto out_free_utf16_path;
+               }
+               if (inode->i_nlink > 1) {
+                       /* Save extracted path for a later call to
+                        * CreateHardLinkW() if this inode has multiple links.
+                        * */
+                       inode->i_extracted_file = utf16_path;
+                       goto out;
+               }
+       }
+out_free_utf16_path:
+       FREE(utf16_path);
+out:
+       return ret;
+}
+
+int win32_apply_dentry_timestamps(const char *output_path,
+                                 size_t output_path_len,
+                                 const struct wim_dentry *dentry,
+                                 const struct apply_args *args)
+{
+       /* Win32 */
+       char *utf16_path;
+       size_t utf16_path_len;
+       DWORD err;
+       HANDLE h;
+       int ret;
+       const struct wim_inode *inode = dentry->d_inode;
+
+       ret = utf8_to_utf16(output_path, output_path_len,
+                           &utf16_path, &utf16_path_len);
+       if (ret)
+               return ret;
+
+       DEBUG("Opening \"%s\" to set timestamps", output_path);
+       h = CreateFileW((const wchar_t*)utf16_path,
+                       GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
+                       FILE_SHARE_READ,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+                       NULL);
+
+       if (h == INVALID_HANDLE_VALUE)
+               err = GetLastError();
+       FREE(utf16_path);
+       if (h == INVALID_HANDLE_VALUE)
+               goto fail;
+
+       FILETIME creationTime = {.dwLowDateTime = inode->i_creation_time & 0xffffffff,
+                                .dwHighDateTime = inode->i_creation_time >> 32};
+       FILETIME lastAccessTime = {.dwLowDateTime = inode->i_last_access_time & 0xffffffff,
+                                 .dwHighDateTime = inode->i_last_access_time >> 32};
+       FILETIME lastWriteTime = {.dwLowDateTime = inode->i_last_write_time & 0xffffffff,
+                                 .dwHighDateTime = inode->i_last_write_time >> 32};
+
+       DEBUG("Calling SetFileTime() on \"%s\"", output_path);
+       if (!SetFileTime(h, &creationTime, &lastAccessTime, &lastWriteTime)) {
+               err = GetLastError();
+               CloseHandle(h);
+               goto fail;
+       }
+       DEBUG("Closing \"%s\"", output_path);
+       if (!CloseHandle(h)) {
+               err = GetLastError();
+               goto fail;
+       }
+       goto out;
+fail:
+       /* Only warn if setting timestamps failed. */
+       WARNING("Can't set timestamps on \"%s\"", output_path);
+       win32_error(err);
+out:
+       return 0;
+}
+
+/* Replacement for POSIX fsync() */
+int fsync(int fd)
+{
+       HANDLE h = (HANDLE)_get_osfhandle(fd);
+       if (h == INVALID_HANDLE_VALUE) {
+               errno = EBADF;
+               return -1;
+       }
+       if (!FlushFileBuffers(h)) {
+               errno = EIO;
+               return -1;
+       }
+       return 0;
+}
+
+unsigned win32_get_number_of_processors()
+{
+       SYSTEM_INFO sysinfo;
+       GetSystemInfo(&sysinfo);
+       return sysinfo.dwNumberOfProcessors;
+}
diff --git a/src/win32.h b/src/win32.h
new file mode 100644 (file)
index 0000000..e702d69
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _WIMLIB_WIN32_H
+#define _WIMLIB_WIN32_H
+
+#include "wimlib_internal.h"
+#include <direct.h>
+
+extern void win32_release_capture_privileges();
+extern void win32_acquire_capture_privileges();
+
+extern void win32_release_restore_privileges();
+extern void win32_acquire_restore_privileges();
+
+extern int win32_build_dentry_tree(struct wim_dentry **root_ret,
+                                  const char *root_disk_path,
+                                  struct wim_lookup_table *lookup_table,
+                                  struct wim_security_data *sd,
+                                  const struct capture_config *config,
+                                  int add_image_flags,
+                                  wimlib_progress_func_t progress_func,
+                                  void *extra_arg);
+
+extern int win32_read_file(const char *filename, void *handle, u64 offset,
+                          size_t size, u8 *buf);
+extern void *win32_open_file_readonly(const void *path_utf16);
+extern void win32_close_file(void *handle);
+
+#ifdef ENABLE_ERROR_MESSAGES
+extern void win32_error(u32 err);
+#else
+#  define win32_error(err)
+#endif
+
+#define FNM_PATHNAME 0x1
+#define FNM_NOMATCH 1
+extern int fnmatch(const char *pattern, const char *string, int flags);
+
+#define mkdir(name, mode) _mkdir(name)
+
+extern int win32_apply_dentry(const char *output_path,
+                             size_t output_path_len,
+                             const struct wim_dentry *dentry,
+                             struct apply_args *args);
+
+extern int win32_apply_dentry_timestamps(const char *output_path,
+                                        size_t output_path_len,
+                                        const struct wim_dentry *dentry,
+                                        const struct apply_args *args);
+
+extern int fsync(int fd);
+
+extern unsigned win32_get_number_of_processors();
+
+#endif /* _WIMLIB_WIN32_H */
index ea3f583c77442ec960ec4517b515caee91a3e8f5..77257767ff9acab0b6ce7132f6b190f91bc3ff47 100644 (file)
 #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
 /* On BSD, this should be included before "list.h" so that "list.h" can
  * overwrite the LIST_HEAD macro. */
 #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
 /* On BSD, this should be included before "list.h" so that "list.h" can
  * overwrite the LIST_HEAD macro. */
-#include <sys/file.h>
+#  include <sys/file.h>
 #endif
 
 #ifdef __WIN32__
 #endif
 
 #ifdef __WIN32__
-#      include <windows.h>
-#      ifdef ERROR
-#              undef ERROR
-#      endif
+#  include <win32.h>
 #endif
 
 #include "list.h"
 #endif
 
 #include "list.h"
 #include "xpress.h"
 
 #ifdef ENABLE_MULTITHREADED_COMPRESSION
 #include "xpress.h"
 
 #ifdef ENABLE_MULTITHREADED_COMPRESSION
-#include <pthread.h>
+#  include <pthread.h>
 #endif
 
 #include <unistd.h>
 #include <errno.h>
 
 #ifdef WITH_NTFS_3G
 #endif
 
 #include <unistd.h>
 #include <errno.h>
 
 #ifdef WITH_NTFS_3G
-#include <time.h>
-#include <ntfs-3g/attrib.h>
-#include <ntfs-3g/inode.h>
-#include <ntfs-3g/dir.h>
+#  include <time.h>
+#  include <ntfs-3g/attrib.h>
+#  include <ntfs-3g/inode.h>
+#  include <ntfs-3g/dir.h>
 #endif
 
 #ifdef HAVE_ALLOCA_H
 #endif
 
 #ifdef HAVE_ALLOCA_H
-#include <alloca.h>
+#  include <alloca.h>
 #else
 #else
-#include <stdlib.h>
-#endif
-
-#ifdef __WIN32__
-#      ifdef fsync
-#              undef fsync
-#      endif
-#      define fsync(fd) 0
+#  include <stdlib.h>
 #endif
 
 static int fflush_and_ftruncate(FILE *fp, off_t size)
 #endif
 
 static int fflush_and_ftruncate(FILE *fp, off_t size)
@@ -308,7 +298,7 @@ static int prepare_resource_for_read(struct wim_lookup_table_entry *lte
                }
                break;
 #endif
                }
                break;
 #endif
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
        case RESOURCE_WIN32:
                if (!lte->file_on_disk_fp) {
                        lte->file_on_disk_fp = win32_open_file_readonly(lte->file_on_disk);
        case RESOURCE_WIN32:
                if (!lte->file_on_disk_fp) {
                        lte->file_on_disk_fp = win32_open_file_readonly(lte->file_on_disk);
@@ -347,7 +337,7 @@ static void end_wim_resource_read(struct wim_lookup_table_entry *lte
                        ntfs_inode_close(ni);
        }
 #endif
                        ntfs_inode_close(ni);
        }
 #endif
-#if defined(__CYGWIN__) || defined(__WIN32__)
+#ifdef __WIN32__
        else if (lte->resource_location == RESOURCE_WIN32
                 && lte->file_on_disk_fp)
        {
        else if (lte->resource_location == RESOURCE_WIN32
                 && lte->file_on_disk_fp)
        {
@@ -1222,9 +1212,7 @@ out:
 static long get_default_num_threads()
 {
 #ifdef __WIN32__
 static long get_default_num_threads()
 {
 #ifdef __WIN32__
-       SYSTEM_INFO sysinfo;
-       GetSystemInfo(&sysinfo);
-       return sysinfo.dwNumberOfProcessors;
+       return win32_get_number_of_processors();
 #else
        return sysconf(_SC_NPROCESSORS_ONLN);
 #endif
 #else
        return sysconf(_SC_NPROCESSORS_ONLN);
 #endif