Windows: Load ntdll functions dynamically
authorEric Biggers <ebiggers3@gmail.com>
Wed, 21 Aug 2013 03:16:33 +0000 (22:16 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Wed, 21 Aug 2013 03:16:33 +0000 (22:16 -0500)
configure.ac
doc/imagex-capture.1.in
include/wimlib/win32_common.h
src/win32_apply.c
src/win32_capture.c
src/win32_common.c

index 3e07617..8d2271f 100644 (file)
@@ -98,33 +98,33 @@ AC_ARG_ENABLE([debug],
 AC_MSG_RESULT([$ENABLE_DEBUG])
 if test "x$ENABLE_DEBUG" = "xyes"; then
        AC_DEFINE([ENABLE_DEBUG], [1],
-                       [Define to 1 if including lots of debug messages.])
+                       [Define to 1 if including lots of debug messages.])
 fi
 
 AC_MSG_CHECKING([whether to include more debugging messages])
 AC_ARG_ENABLE([more_debug],
        AS_HELP_STRING([--enable-more-debug],
-                       [include even more debugging messages]),
+                       [include even more debugging messages]),
        [ENABLE_MORE_DEBUG=$enableval],
        [ENABLE_MORE_DEBUG=no]
        )
 AC_MSG_RESULT([$ENABLE_MORE_DEBUG])
 if test "x$ENABLE_MORE_DEBUG" = "xyes"; then
        AC_DEFINE([ENABLE_MORE_DEBUG], [1],
-                       [Define to 1 if including even more debug messages.])
+                       [Define to 1 if including even more debug messages.])
 fi
 
 AC_MSG_CHECKING([whether to include error messages])
 AC_ARG_ENABLE([error_messages],
        AS_HELP_STRING([--disable-error-messages],
-                       [do not compile in error messsages]),
+                       [do not compile in error messsages]),
        [ENABLE_ERROR_MESSAGES=$enableval],
        [ENABLE_ERROR_MESSAGES=yes]
        )
 AC_MSG_RESULT([$ENABLE_ERROR_MESSAGES])
 if test "x$ENABLE_ERROR_MESSAGES" = "xyes"; then
        AC_DEFINE([ENABLE_ERROR_MESSAGES], [1],
-                       [Define to 1 if including error messages])
+                       [Define to 1 if including error messages])
 fi
 
 AC_MSG_CHECKING([whether to support custom memory allocation functions])
@@ -181,14 +181,14 @@ fi
 AC_MSG_CHECKING([whether to include support for multi-threaded compression])
 AC_ARG_ENABLE([multithreaded-compression],
        AS_HELP_STRING([--disable-multithreaded-compression],
-                       [do not compile in the code for multi-threaded compression]),
+                       [do not compile in the code for multi-threaded compression]),
        [ENABLE_MULTITHREADED_COMPRESSION=$enableval],
        [ENABLE_MULTITHREADED_COMPRESSION=yes]
        )
 AC_MSG_RESULT([$ENABLE_MULTITHREADED_COMPRESSION])
 if test "x$ENABLE_MULTITHREADED_COMPRESSION" = "xyes"; then
        AC_DEFINE([ENABLE_MULTITHREADED_COMPRESSION], [1],
-                       [Define to 1 if including support for multithreaded
+                       [Define to 1 if including support for multithreaded
                         compression])
 fi
 
@@ -218,7 +218,7 @@ case "$host" in
                WINDOWS_LDADD="-lshlwapi"
                ENABLE_XATTR_DEFAULT="no"
                ;;
-       *-*-cygwin*)
+       *-*-cygwin*)
                # Cygwin (WARNING: not well supported)
                AC_MSG_WARN([wimlib has not been tested with Cygwin!  Please do
                             a Windows-native build with MinGW-w64 instead])
@@ -232,20 +232,21 @@ case "$host" in
 esac
 
 AC_ARG_WITH([ntdll],
-           AS_HELP_STRING([--without-ntdll], [Windows only:  do not link with
-                           ntdll.  By default, in some parts of its code,
-                           wimlib uses Windows NT system calls to work around
-                           flaws in the Win32 API.  This support can be omitted
-                           if needed, but some annoying bugs will surface (e.g.
-                           permission denied errors even when running as the
-                           Administrator).]),
+           AS_HELP_STRING([--without-ntdll], [Windows only:  do not try to
+                           use functions from ntdll.  By default, in some parts
+                           of its code, wimlib uses Windows NT system calls to
+                           work around flaws in the Win32 API.  This support
+                           can be omitted if needed, but some annoying bugs
+                           will surface (e.g.  permission denied errors even
+                                         when running as the Administrator).]),
        [WITH_NTDLL=$withval],
        [WITH_NTDLL=yes])
 
 if test "x$WINDOWS_NATIVE_BUILD" = "xyes"; then
        if test "x$WITH_NTDLL" = "xyes"; then
-               WINDOWS_LDADD="$WINDOWS_LDADD -lntdll"
-               AC_DEFINE([WITH_NTDLL], [1], [Define to 1 if linking with ntdll])
+               WINDOWS_LDADD="$WINDOWS_LDADD"
+               AC_DEFINE([WITH_NTDLL], [1], [Define to 1 to try to use ntdll
+                                               functions])
        fi
 fi
 
@@ -360,7 +361,7 @@ fi
 AC_MSG_CHECKING([whether to use SSSE3-accelerated SHA1 ])
 AC_ARG_ENABLE([ssse3-sha1],
            AS_HELP_STRING([--enable-ssse3-sha1], [use assembly language implementation
-                               of SHA1 from Intel, accelerated with vector
+                               of SHA1 from Intel, accelerated with vector
                                instructions (SSSE3-enabled CPU required)]),
        [ENABLE_SSSE3_SHA1=$enableval],
        [ENABLE_SSSE3_SHA1=no]
@@ -369,7 +370,7 @@ AC_ARG_ENABLE([ssse3-sha1],
 AC_MSG_RESULT([$ENABLE_SSSE3_SHA1])
 if test "x$ENABLE_SSSE3_SHA1" = "xyes"; then
        AC_DEFINE([ENABLE_SSSE3_SHA1], [1],
-                       [Define to 1 if using vectorized implementation of SHA1])
+                       [Define to 1 if using vectorized implementation of SHA1])
        SSSE3_SHA1_OBJ=sha1-ssse3.lo
        AX_PROG_NASM
        AC_SUBST([NASM], [$nasm])
@@ -383,7 +384,7 @@ if test "x$ENABLE_SSSE3_SHA1" = "xyes"; then
 else
        AC_ARG_WITH([libcrypto],
            AS_HELP_STRING([--without-libcrypto], [build in the SHA1 algorithm,
-                                       rather than use external libcrypto from
+                                       rather than use external libcrypto from
                                        OpenSSL (default is autodetect)]),
        [WITH_LIBCRYPTO=$withval],
        [AC_CHECK_LIB([crypto], [SHA1],
index 407f063..940bae1 100644 (file)
@@ -133,9 +133,7 @@ supported.
 On Windows, \fB@IMAGEX_PROGNAME@ capture\fR and \fB@IMAGEX_PROGNAME@ append\fR
 try to archive as much data and metadata as possible, including:
 .IP \[bu] 4
-All data streams of all files, unless running on a version of Windows prior to
-Vista, in which case named data streams (if supported by the source filesystem)
-will not be captured.
+All data streams of all files.
 .IP \[bu]
 Reparse points, including symbolic links, junction points, and other reparse
 points, if supported by the source filesystem.  (Note: see \fB--rpfix\fR and
index 499dad4..019dd7d 100644 (file)
@@ -9,6 +9,11 @@
 #include "wimlib/types.h"
 #include "wimlib/win32.h"
 
+#ifdef WITH_NTDLL
+#  include <ntstatus.h>
+#  include <winternl.h>
+#endif
+
 extern void
 set_errno_from_GetLastError(void);
 
@@ -17,7 +22,7 @@ set_errno_from_win32_error(DWORD err);
 
 #ifdef WITH_NTDLL
 extern void
-set_errno_from_nt_status(DWORD status);
+set_errno_from_nt_status(NTSTATUS status);
 #endif
 
 extern bool
@@ -45,6 +50,44 @@ extern BOOL (WINAPI *win32func_CreateSymbolicLinkW)(const wchar_t *lpSymlinkFile
                                                    const wchar_t *lpTargetFileName,
                                                    DWORD dwFlags);
 
+/* ntdll functions  */
+
+#ifdef WITH_NTDLL
+
+extern NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
+                                                     PIO_STATUS_BLOCK IoStatusBlock,
+                                                     PVOID FileInformation,
+                                                     ULONG Length,
+                                                     FILE_INFORMATION_CLASS FileInformationClass);
+
+extern NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
+                                                    SECURITY_INFORMATION SecurityInformation,
+                                                    PSECURITY_DESCRIPTOR SecurityDescriptor,
+                                                    ULONG Length,
+                                                    PULONG LengthNeeded);
+
+extern NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
+                                                    HANDLE Event,
+                                                    PIO_APC_ROUTINE ApcRoutine,
+                                                    PVOID ApcContext,
+                                                    PIO_STATUS_BLOCK IoStatusBlock,
+                                                    PVOID FileInformation,
+                                                    ULONG Length,
+                                                    FILE_INFORMATION_CLASS FileInformationClass,
+                                                    BOOLEAN ReturnSingleEntry,
+                                                    PUNICODE_STRING FileName,
+                                                    BOOLEAN RestartScan);
+
+
+extern NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
+                                                  SECURITY_INFORMATION SecurityInformation,
+                                                  PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+extern DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
+#endif
+
+
+
 extern bool
 windows_version_is_at_least(unsigned major, unsigned minor);
 
index b125395..4c66575 100644 (file)
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 
-#ifdef WITH_NTDLL
-#  include <winternl.h>
-#  include <ntstatus.h>
-NTSTATUS WINAPI
-NtSetSecurityObject(HANDLE Handle,
-                   SECURITY_INFORMATION SecurityInformation,
-                   PSECURITY_DESCRIPTOR SecurityDescriptor);
-#endif
-
 static int
 win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
 {
@@ -480,13 +471,15 @@ do_win32_set_security_descriptor(HANDLE h, const wchar_t *path,
                                 PSECURITY_DESCRIPTOR desc)
 {
 #ifdef WITH_NTDLL
-       return RtlNtStatusToDosError(NtSetSecurityObject(h, info, desc));
-#else
+       if (func_NtSetSecurityObject) {
+               return (*func_RtlNtStatusToDosError)(
+                               (*func_NtSetSecurityObject)(h, info, desc));
+       }
+#endif
        if (SetFileSecurity(path, info, desc))
                return ERROR_SUCCESS;
        else
                return GetLastError();
-#endif
 }
 
 static int
@@ -503,10 +496,12 @@ win32_set_security_descriptor(const wchar_t *path, const u8 *desc,
        h = INVALID_HANDLE_VALUE;
 
 #ifdef WITH_NTDLL
-       h = win32_open_existing_file(path, MAXIMUM_ALLOWED);
-       if (h == INVALID_HANDLE_VALUE) {
-               ERROR_WITH_ERRNO("Can't open %ls (%u)", path, GetLastError());
-               goto error;
+       if (func_NtSetSecurityObject) {
+               h = win32_open_existing_file(path, MAXIMUM_ALLOWED);
+               if (h == INVALID_HANDLE_VALUE) {
+                       ERROR_WITH_ERRNO("Can't open %ls (%u)", path, GetLastError());
+                       goto error;
+               }
        }
 #endif
 
@@ -541,7 +536,8 @@ win32_set_security_descriptor(const wchar_t *path, const u8 *desc,
        ret = 0;
 out_close:
 #ifdef WITH_NTDLL
-       CloseHandle(h);
+       if (func_NtSetSecurityObject)
+               CloseHandle(h);
 #endif
        return ret;
 
index 14a6c13..ed4bb7f 100644 (file)
 #include "wimlib/paths.h"
 #include "wimlib/reparse.h"
 
-#ifdef WITH_NTDLL
-#  include <winternl.h>
-#  include <ntstatus.h>
-
-NTSTATUS WINAPI
-NtQuerySecurityObject(HANDLE handle,
-                     SECURITY_INFORMATION SecurityInformation,
-                     PSECURITY_DESCRIPTOR SecurityDescriptor,
-                     ULONG Length,
-                     PULONG LengthNeeded);
-NTSTATUS WINAPI
-NtQueryDirectoryFile(HANDLE FileHandle,
-                    HANDLE Event,
-                    PIO_APC_ROUTINE ApcRoutine,
-                    PVOID ApcContext,
-                    PIO_STATUS_BLOCK IoStatusBlock,
-                    PVOID FileInformation,
-                    ULONG Length,
-                    FILE_INFORMATION_CLASS FileInformationClass,
-                    BOOLEAN ReturnSingleEntry,
-                    PUNICODE_STRING FileName,
-                    BOOLEAN RestartScan);
-#endif
-
 #define MAX_GET_SD_ACCESS_DENIED_WARNINGS 1
 #define MAX_GET_SACL_PRIV_NOTHELD_WARNINGS 1
 #define MAX_CAPTURE_LONG_PATH_WARNINGS 5
@@ -269,25 +245,28 @@ win32_get_short_name(HANDLE hFile, const wchar_t *path, struct wim_dentry *dentr
         * call ourselves, and it saves a dumb call to FindFirstFile() which of
         * course has to create its own handle.  */
 #ifdef WITH_NTDLL
-       NTSTATUS status;
-       IO_STATUS_BLOCK io_status;
-       u8 buf[128] _aligned_attribute(8);
-       const FILE_NAME_INFORMATION *info;
-
-       status = NtQueryInformationFile(hFile, &io_status, buf, sizeof(buf),
-                                       FileAlternateNameInformation);
-       info = (const FILE_NAME_INFORMATION*)buf;
-       if (status == STATUS_SUCCESS && info->FileNameLength != 0) {
-               dentry->short_name = MALLOC(info->FileNameLength + 2);
-               if (!dentry->short_name)
-                       return WIMLIB_ERR_NOMEM;
-               memcpy(dentry->short_name, info->FileName,
-                      info->FileNameLength);
-               dentry->short_name[info->FileNameLength / 2] = L'\0';
-               dentry->short_name_nbytes = info->FileNameLength;
+       if (func_NtQueryInformationFile) {
+               NTSTATUS status;
+               IO_STATUS_BLOCK io_status;
+               u8 buf[128] _aligned_attribute(8);
+               const FILE_NAME_INFORMATION *info;
+
+               status = (*func_NtQueryInformationFile)(hFile, &io_status, buf, sizeof(buf),
+                                                       FileAlternateNameInformation);
+               info = (const FILE_NAME_INFORMATION*)buf;
+               if (status == STATUS_SUCCESS && info->FileNameLength != 0) {
+                       dentry->short_name = MALLOC(info->FileNameLength + 2);
+                       if (!dentry->short_name)
+                               return WIMLIB_ERR_NOMEM;
+                       memcpy(dentry->short_name, info->FileName,
+                              info->FileNameLength);
+                       dentry->short_name[info->FileNameLength / 2] = L'\0';
+                       dentry->short_name_nbytes = info->FileNameLength;
+               }
+               return 0;
        }
-       return 0;
-#else
+#endif
+
        WIN32_FIND_DATAW dat;
        HANDLE hFind;
        int ret = 0;
@@ -310,7 +289,6 @@ win32_get_short_name(HANDLE hFile, const wchar_t *path, struct wim_dentry *dentr
                FindClose(hFind);
        }
        return ret;
-#endif
 }
 
 /*
@@ -347,24 +325,26 @@ win32_query_security_descriptor(HANDLE hFile, const wchar_t *path,
                                DWORD bufsize, DWORD *lengthNeeded)
 {
 #ifdef WITH_NTDLL
-       NTSTATUS status;
-
-       status = NtQuerySecurityObject(hFile, requestedInformation, buf,
-                                      bufsize, lengthNeeded);
-       /* Since it queries an already-open handle, NtQuerySecurityObject()
-        * apparently returns STATUS_ACCESS_DENIED rather than
-        * STATUS_PRIVILEGE_NOT_HELD.  */
-       if (status == STATUS_ACCESS_DENIED)
-               return ERROR_PRIVILEGE_NOT_HELD;
-       else
-               return RtlNtStatusToDosError(status);
-#else
+       if (func_NtQuerySecurityObject) {
+               NTSTATUS status;
+
+               status = (*func_NtQuerySecurityObject)(hFile,
+                                                      requestedInformation, buf,
+                                                      bufsize, lengthNeeded);
+               /* Since it queries an already-open handle, NtQuerySecurityObject()
+                * apparently returns STATUS_ACCESS_DENIED rather than
+                * STATUS_PRIVILEGE_NOT_HELD.  */
+               if (status == STATUS_ACCESS_DENIED)
+                       return ERROR_PRIVILEGE_NOT_HELD;
+               else
+                       return (*func_RtlNtStatusToDosError)(status);
+       }
+#endif
        if (GetFileSecurity(path, requestedInformation, buf,
                            bufsize, lengthNeeded))
                return ERROR_SUCCESS;
        else
                return GetLastError();
-#endif
 }
 
 static int
@@ -467,76 +447,78 @@ win32_recurse_directory(HANDLE hDir,
         * which we opened with FILE_FLAG_BACKUP_SEMANTICS (probably not the
         * case for the FindFirstFile() API; it's not documented).  */
 #ifdef WITH_NTDLL
-       NTSTATUS status;
-       IO_STATUS_BLOCK io_status;
-       const size_t bufsize = 8192;
-       u8 *buf;
-       BOOL restartScan = TRUE;
-       const FILE_NAMES_INFORMATION *info;
-
-       buf = MALLOC(bufsize);
-       if (!buf)
-               return WIMLIB_ERR_NOMEM;
-       for (;;) {
-               status = NtQueryDirectoryFile(hDir, NULL, NULL, NULL,
-                                             &io_status, buf, bufsize,
-                                             FileNamesInformation,
-                                             FALSE, NULL, restartScan);
-               restartScan = FALSE;
-               if (status != STATUS_SUCCESS) {
-                       if (status == STATUS_NO_MORE_FILES ||
-                           status == STATUS_NO_MORE_ENTRIES ||
-                           status == STATUS_NO_MORE_MATCHES) {
-                               ret = 0;
-                       } else {
-                               set_errno_from_nt_status(status);
-                               ERROR_WITH_ERRNO("Failed to read directory "
-                                                "\"%ls\"", dir_path);
-                               ret = WIMLIB_ERR_READ;
-                       }
-                       goto out_free_buf;
-               }
-               wimlib_assert(io_status.Information != 0);
-               info = (const FILE_NAMES_INFORMATION*)buf;
+       if (func_NtQueryDirectoryFile) {
+               NTSTATUS status;
+               IO_STATUS_BLOCK io_status;
+               const size_t bufsize = 8192;
+               u8 *buf;
+               BOOL restartScan = TRUE;
+               const FILE_NAMES_INFORMATION *info;
+
+               buf = MALLOC(bufsize);
+               if (!buf)
+                       return WIMLIB_ERR_NOMEM;
                for (;;) {
-                       if (!(info->FileNameLength == 2 && info->FileName[0] == L'.') &&
-                           !(info->FileNameLength == 4 && info->FileName[0] == L'.' &&
-                                                          info->FileName[1] == L'.'))
-                       {
-                               wchar_t *p;
-                               struct wim_dentry *child;
-
-                               p = dir_path + dir_path_num_chars;
-                               *p++ = L'\\';
-                               p = wmempcpy(p, info->FileName,
-                                            info->FileNameLength / 2);
-                               *p = '\0';
-
-                               ret = win32_build_dentry_tree_recursive(
-                                                               &child,
-                                                               dir_path,
-                                                               p - dir_path,
-                                                               params,
-                                                               state,
-                                                               vol_flags);
-
-                               dir_path[dir_path_num_chars] = L'\0';
-
-                               if (ret)
-                                       goto out_free_buf;
-                               if (child)
-                                       dentry_add_child(root, child);
+                       status = (*func_NtQueryDirectoryFile)(hDir, NULL, NULL, NULL,
+                                                             &io_status, buf, bufsize,
+                                                             FileNamesInformation,
+                                                             FALSE, NULL, restartScan);
+                       restartScan = FALSE;
+                       if (status != STATUS_SUCCESS) {
+                               if (status == STATUS_NO_MORE_FILES ||
+                                   status == STATUS_NO_MORE_ENTRIES ||
+                                   status == STATUS_NO_MORE_MATCHES) {
+                                       ret = 0;
+                               } else {
+                                       set_errno_from_nt_status(status);
+                                       ERROR_WITH_ERRNO("Failed to read directory "
+                                                        "\"%ls\"", dir_path);
+                                       ret = WIMLIB_ERR_READ;
+                               }
+                               goto out_free_buf;
+                       }
+                       wimlib_assert(io_status.Information != 0);
+                       info = (const FILE_NAMES_INFORMATION*)buf;
+                       for (;;) {
+                               if (!(info->FileNameLength == 2 && info->FileName[0] == L'.') &&
+                                   !(info->FileNameLength == 4 && info->FileName[0] == L'.' &&
+                                                                  info->FileName[1] == L'.'))
+                               {
+                                       wchar_t *p;
+                                       struct wim_dentry *child;
+
+                                       p = dir_path + dir_path_num_chars;
+                                       *p++ = L'\\';
+                                       p = wmempcpy(p, info->FileName,
+                                                    info->FileNameLength / 2);
+                                       *p = '\0';
+
+                                       ret = win32_build_dentry_tree_recursive(
+                                                                       &child,
+                                                                       dir_path,
+                                                                       p - dir_path,
+                                                                       params,
+                                                                       state,
+                                                                       vol_flags);
+
+                                       dir_path[dir_path_num_chars] = L'\0';
+
+                                       if (ret)
+                                               goto out_free_buf;
+                                       if (child)
+                                               dentry_add_child(root, child);
+                               }
+                               if (info->NextEntryOffset == 0)
+                                       break;
+                               info = (const FILE_NAMES_INFORMATION*)
+                                               ((const u8*)info + info->NextEntryOffset);
                        }
-                       if (info->NextEntryOffset == 0)
-                               break;
-                       info = (const FILE_NAMES_INFORMATION*)
-                                       ((const u8*)info + info->NextEntryOffset);
                }
+       out_free_buf:
+               FREE(buf);
+               return ret;
        }
-out_free_buf:
-       FREE(buf);
-       return ret;
-#else
+#endif
        WIN32_FIND_DATAW dat;
        HANDLE hFind;
        DWORD err;
@@ -601,7 +583,6 @@ out_free_buf:
 out_find_close:
        FindClose(hFind);
        return ret;
-#endif
 }
 
 /* Reparse point fixup status code */
@@ -1019,96 +1000,96 @@ win32_capture_streams(HANDLE *hFile_p,
        IO_STATUS_BLOCK io_status;
        NTSTATUS status;
        const FILE_STREAM_INFORMATION *info;
-#else
+#endif
        HANDLE hFind;
        DWORD err;
-#endif
 
        DEBUG("Capturing streams from \"%ls\"", path);
 
        if (!(vol_flags & FILE_NAMED_STREAMS))
                goto unnamed_only;
-#ifndef WITH_NTDLL
-       if (win32func_FindFirstStreamW == NULL)
-               goto unnamed_only;
-#endif
 
 #ifdef WITH_NTDLL
-       buf = _buf;
-       bufsize = sizeof(_buf);
+       if (func_NtQueryInformationFile) {
+               buf = _buf;
+               bufsize = sizeof(_buf);
 
-       /* Get a buffer containing the stream information.  */
-       for (;;) {
-               status = NtQueryInformationFile(*hFile_p, &io_status, buf, bufsize,
-                                               FileStreamInformation);
-               if (status == STATUS_SUCCESS) {
-                       break;
-               } else if (status == STATUS_BUFFER_OVERFLOW) {
-                       u8 *newbuf;
+               /* Get a buffer containing the stream information.  */
+               for (;;) {
+                       status = (*func_NtQueryInformationFile)(*hFile_p, &io_status,
+                                                               buf, bufsize,
+                                                               FileStreamInformation);
+                       if (status == STATUS_SUCCESS) {
+                               break;
+                       } else if (status == STATUS_BUFFER_OVERFLOW) {
+                               u8 *newbuf;
 
-                       bufsize *= 2;
-                       if (buf == _buf)
-                               newbuf = MALLOC(bufsize);
-                       else
-                               newbuf = REALLOC(buf, bufsize);
+                               bufsize *= 2;
+                               if (buf == _buf)
+                                       newbuf = MALLOC(bufsize);
+                               else
+                                       newbuf = REALLOC(buf, bufsize);
 
-                       if (!newbuf) {
-                               ret = WIMLIB_ERR_NOMEM;
+                               if (!newbuf) {
+                                       ret = WIMLIB_ERR_NOMEM;
+                                       goto out_free_buf;
+                               }
+                               buf = newbuf;
+                       } else {
+                               set_errno_from_nt_status(status);
+                               ERROR_WITH_ERRNO("Failed to read streams of %ls", path);
+                               ret = WIMLIB_ERR_READ;
                                goto out_free_buf;
                        }
-                       buf = newbuf;
-               } else {
-                       set_errno_from_nt_status(status);
-                       ERROR_WITH_ERRNO("Failed to read streams of %ls", path);
-                       ret = WIMLIB_ERR_READ;
-                       goto out_free_buf;
                }
-       }
 
-       if (io_status.Information == 0) {
-               /* No stream information.  */
-               ret = 0;
-               goto out_free_buf;
-       }
-
-       if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
-               /* OpenEncryptedFileRaw() seems to fail with
-                * ERROR_SHARING_VIOLATION if there are any handles opened to
-                * the file.  */
-               CloseHandle(*hFile_p);
-               *hFile_p = INVALID_HANDLE_VALUE;
-       }
+               if (io_status.Information == 0) {
+                       /* No stream information.  */
+                       ret = 0;
+                       goto out_free_buf;
+               }
 
-       /* Parse one or more stream information structures.  */
-       info = (const FILE_STREAM_INFORMATION*)buf;
-       for (;;) {
-               if (info->StreamNameLength <= sizeof(dat.cStreamName) - 2) {
-                       dat.StreamSize = info->StreamSize;
-                       memcpy(dat.cStreamName, info->StreamName, info->StreamNameLength);
-                       dat.cStreamName[info->StreamNameLength / 2] = L'\0';
-
-                       /* Capture the stream.  */
-                       ret = win32_capture_stream(path, path_num_chars, inode,
-                                                  lookup_table, &dat);
-                       if (ret)
-                               goto out_free_buf;
+               if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
+                       /* OpenEncryptedFileRaw() seems to fail with
+                        * ERROR_SHARING_VIOLATION if there are any handles opened to
+                        * the file.  */
+                       CloseHandle(*hFile_p);
+                       *hFile_p = INVALID_HANDLE_VALUE;
                }
-               if (info->NextEntryOffset == 0) {
-                       /* No more stream information.  */
-                       ret = 0;
-                       break;
+
+               /* Parse one or more stream information structures.  */
+               info = (const FILE_STREAM_INFORMATION*)buf;
+               for (;;) {
+                       if (info->StreamNameLength <= sizeof(dat.cStreamName) - 2) {
+                               dat.StreamSize = info->StreamSize;
+                               memcpy(dat.cStreamName, info->StreamName, info->StreamNameLength);
+                               dat.cStreamName[info->StreamNameLength / 2] = L'\0';
+
+                               /* Capture the stream.  */
+                               ret = win32_capture_stream(path, path_num_chars, inode,
+                                                          lookup_table, &dat);
+                               if (ret)
+                                       goto out_free_buf;
+                       }
+                       if (info->NextEntryOffset == 0) {
+                               /* No more stream information.  */
+                               ret = 0;
+                               break;
+                       }
+                       /* Advance to next stream information.  */
+                       info = (const FILE_STREAM_INFORMATION*)
+                                       ((const u8*)info + info->NextEntryOffset);
                }
-               /* Advance to next stream information.  */
-               info = (const FILE_STREAM_INFORMATION*)
-                               ((const u8*)info + info->NextEntryOffset);
+       out_free_buf:
+               /* Free buffer if allocated on heap.  */
+               if (buf != _buf)
+                       FREE(buf);
+               return ret;
        }
-out_free_buf:
-       /* Free buffer if allocated on heap.  */
-       if (buf != _buf)
-               FREE(buf);
-       return ret;
+#endif /* WITH_NTDLL */
 
-#else /* WITH_NTDLL */
+       if (win32func_FindFirstStreamW == NULL)
+               goto unnamed_only;
        hFind = win32func_FindFirstStreamW(path, FindStreamInfoStandard, &dat, 0);
        if (hFind == INVALID_HANDLE_VALUE) {
                err = GetLastError();
@@ -1155,7 +1136,6 @@ out_free_buf:
 out_find_close:
        FindClose(hFind);
        return ret;
-#endif /* !WITH_NTDLL */
 
 unnamed_only:
        /* FindFirstStream() API is not available, or the volume does not
@@ -1411,12 +1391,15 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        DWORD dret;
        bool need_prefix_free = false;
 
-#ifndef WITH_NTDLL
-       if (!win32func_FindFirstStreamW) {
+       if (!win32func_FindFirstStreamW
+#ifdef WITH_NTDLL
+           && !func_NtQueryInformationFile
+#endif
+          )
+       {
                WARNING("Running on Windows XP or earlier; "
                        "alternate data streams will not be captured.");
        }
-#endif
 
        path_nchars = wcslen(root_disk_path);
        if (path_nchars > WINDOWS_NT_MAX_PATH)
index 051720a..26a4d75 100644 (file)
@@ -322,9 +322,9 @@ set_errno_from_GetLastError(void)
 
 #ifdef WITH_NTDLL
 void
-set_errno_from_nt_status(DWORD status)
+set_errno_from_nt_status(NTSTATUS status)
 {
-       set_errno_from_win32_error(RtlNtStatusToDosError(status));
+       set_errno_from_win32_error((*func_RtlNtStatusToDosError)(status));
 }
 #endif
 
@@ -512,7 +512,6 @@ win32_open_existing_file(const wchar_t *path, DWORD dwDesiredAccess)
                           NULL /* hTemplateFile */);
 }
 
-#ifndef WITH_NTDLL
 /* Pointers to functions that are not available on all targetted versions of
  * Windows (XP and later).  NOTE: The WINAPI annotations seem to be important; I
  * assume it specifies a certain calling convention. */
@@ -526,19 +525,56 @@ HANDLE (WINAPI *win32func_FindFirstStreamW)(LPCWSTR lpFileName,
 /* Vista and later */
 BOOL (WINAPI *win32func_FindNextStreamW)(HANDLE hFindStream,
                                         LPVOID lpFindStreamData) = NULL;
-#endif /* !WITH_NTDLL */
 
 /* Vista and later */
 BOOL (WINAPI *win32func_CreateSymbolicLinkW)(const wchar_t *lpSymlinkFileName,
                                             const wchar_t *lpTargetFileName,
                                             DWORD dwFlags) = NULL;
 
+#ifdef WITH_NTDLL
+
+DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
+
+NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
+                                              PIO_STATUS_BLOCK IoStatusBlock,
+                                              PVOID FileInformation,
+                                              ULONG Length,
+                                              FILE_INFORMATION_CLASS FileInformationClass);
+
+NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
+                                             SECURITY_INFORMATION SecurityInformation,
+                                             PSECURITY_DESCRIPTOR SecurityDescriptor,
+                                             ULONG Length,
+                                             PULONG LengthNeeded);
+
+NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
+                                             HANDLE Event,
+                                             PIO_APC_ROUTINE ApcRoutine,
+                                             PVOID ApcContext,
+                                             PIO_STATUS_BLOCK IoStatusBlock,
+                                             PVOID FileInformation,
+                                             ULONG Length,
+                                             FILE_INFORMATION_CLASS FileInformationClass,
+                                             BOOLEAN ReturnSingleEntry,
+                                             PUNICODE_STRING FileName,
+                                             BOOLEAN RestartScan);
+
+NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
+                                           SECURITY_INFORMATION SecurityInformation,
+                                           PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+#endif /* WITH_NTDLL */
+
 static OSVERSIONINFO windows_version_info = {
        .dwOSVersionInfoSize = sizeof(OSVERSIONINFO),
 };
 
 static HMODULE hKernel32 = NULL;
 
+#ifdef WITH_NTDLL
+static HMODULE hNtdll = NULL;
+#endif
+
 static bool acquired_privileges = false;
 
 bool
@@ -572,7 +608,6 @@ win32_global_init(int init_flags)
                hKernel32 = LoadLibrary(L"Kernel32.dll");
 
        if (hKernel32) {
-       #ifndef WITH_NTDLL
                win32func_FindFirstStreamW = (void*)GetProcAddress(hKernel32,
                                                                   "FindFirstStreamW");
                if (win32func_FindFirstStreamW) {
@@ -581,10 +616,43 @@ win32_global_init(int init_flags)
                        if (!win32func_FindNextStreamW)
                                win32func_FindFirstStreamW = NULL;
                }
-       #endif /* !WITH_NTDLL */
                win32func_CreateSymbolicLinkW = (void*)GetProcAddress(hKernel32,
                                                                      "CreateSymbolicLinkW");
        }
+
+#ifdef WITH_NTDLL
+       if (hNtdll == NULL)
+               hNtdll = LoadLibrary(L"ntdll.dll");
+
+       if (hNtdll) {
+               func_RtlNtStatusToDosError  =
+                       (void*)GetProcAddress(hNtdll, "RtlNtStatusToDosError");
+               if (func_RtlNtStatusToDosError) {
+
+                       func_NtQuerySecurityObject  =
+                               (void*)GetProcAddress(hNtdll, "NtQuerySecurityObject");
+
+                       func_NtQueryDirectoryFile   =
+                               (void*)GetProcAddress(hNtdll, "NtQueryDirectoryFile");
+
+                       func_NtQueryInformationFile =
+                               (void*)GetProcAddress(hNtdll, "NtQueryInformationFile");
+
+                       func_NtSetSecurityObject    =
+                               (void*)GetProcAddress(hNtdll, "NtSetSecurityObject");
+               }
+       }
+
+       DEBUG("FindFirstStreamW       @ %p", win32func_FindFirstStreamW);
+       DEBUG("FindNextStreamW        @ %p", win32func_FindNextStreamW);
+       DEBUG("CreateSymbolicLinkW    @ %p", win32func_CreateSymbolicLinkW);
+       DEBUG("RtlNtStatusToDosError  @ %p", func_RtlNtStatusToDosError);
+       DEBUG("NtQuerySecurityObject  @ %p", func_NtQuerySecurityObject);
+       DEBUG("NtQueryDirectoryFile   @ %p", func_NtQueryDirectoryFile);
+       DEBUG("NtQueryInformationFile @ %p", func_NtQueryInformationFile);
+       DEBUG("NtSetSecurityObject    @ %p", func_NtSetSecurityObject);
+#endif
+
        return 0;
 
 insufficient_privileges:
@@ -601,6 +669,12 @@ win32_global_cleanup(void)
                FreeLibrary(hKernel32);
                hKernel32 = NULL;
        }
+#ifdef WITH_NTDLL
+       if (hNtdll != NULL) {
+               FreeLibrary(hNtdll);
+               hNtdll = NULL;
+       }
+#endif
 }
 
 #endif /* __WIN32__ */