]> wimlib.net Git - wimlib/blobdiff - src/extract_image.c
Windows native build
[wimlib] / src / extract_image.c
index 6735602f495d489a545598bddd85a3efe6060265..86063819ab26c2e363fbbb8257544afc9efa4efc 100644 (file)
@@ -2,11 +2,6 @@
  * extract_image.c
  *
  * Support for extracting WIM files.
- *
- * This code does NOT contain any filesystem-specific features.  In particular,
- * security information (i.e. file permissions) and alternate data streams are
- * ignored, except possibly to read an alternate data stream that contains
- * symbolic link data.
  */
 
 /*
 #include "config.h"
 
 #if defined(__CYGWIN__) || defined(__WIN32__)
-#include <windows.h>
-#ifdef ERROR
-#undef ERROR
-#endif
-#include <wchar.h>
+#      include <windows.h>
+#      ifdef ERROR
+#              undef ERROR
+#      endif
+#      include <wchar.h>
+#else
+#      include <dirent.h>
+#      ifdef HAVE_UTIME_H
+#              include <utime.h>
+#      endif
+#      include "timestamp.h"
+#      include <sys/time.h>
 #endif
 
-#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#ifdef HAVE_UTIME_H
-#include <utime.h>
-#endif
 
 #include <unistd.h>
 
 #include "dentry.h"
 #include "lookup_table.h"
-#include "timestamp.h"
 #include "wimlib_internal.h"
 #include "xml.h"
 
 
 #ifdef HAVE_ALLOCA_H
 #include <alloca.h>
-#else
-#include <stdlib.h>
+#endif
+
+#if defined(__WIN32__)
+#      define swprintf _snwprintf
+#      define mkdir(path, mode) (!CreateDirectoryA(path, NULL))
 #endif
 
 #if defined(__CYGWIN__) || defined(__WIN32__)
@@ -176,19 +174,19 @@ static int win32_extract_stream(const struct wim_inode *inode,
                /* 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: note that 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. */
+                * 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);
+               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[1] != L'\\') {
+               if (path[0] != L'/' && path[0] != L'\\') {
                        prefix = L"./";
                        stream_path_nchars += 2;
                } else {
@@ -198,8 +196,8 @@ static int win32_extract_stream(const struct wim_inode *inode,
                swprintf(stream_path, stream_path_nchars + 1, L"%ls%ls:%ls",
                         prefix, path, stream_name_utf16);
        } else {
-               /* Unnamed stream; it's path is just the path to the file
-                * itself. */
+               /* Unnamed stream; its path is just the path to the file itself.
+                * */
                stream_path = (wchar_t*)path;
 
                /* Directories must be created with CreateDirectoryW().  Then
@@ -210,7 +208,7 @@ static int win32_extract_stream(const struct wim_inode *inode,
                                err = GetLastError();
                                if (err != ERROR_ALREADY_EXISTS) {
                                        ERROR("Failed to create directory \"%ls\"",
-                                             path);
+                                             stream_path);
                                        win32_error(err);
                                        ret = WIMLIB_ERR_MKDIR;
                                        goto fail;
@@ -227,7 +225,7 @@ static int win32_extract_stream(const struct wim_inode *inode,
 
        DEBUG("Opening \"%ls\"", stream_path);
        h = CreateFileW(stream_path,
-                       GENERIC_WRITE | WRITE_OWNER | WRITE_DAC,
+                       GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
                        0,
                        NULL,
                        creationDisposition,
@@ -252,7 +250,7 @@ static int win32_extract_stream(const struct wim_inode *inode,
                        goto fail_close_handle;
        } else {
                if (lte) {
-                       DEBUG("Extracting \"%ls\" (len = %zu)",
+                       DEBUG("Extracting \"%ls\" (len = %"PRIu64")",
                              stream_path, wim_resource_size(lte));
                        ret = do_win32_extract_stream(h, lte);
                        if (ret)
@@ -289,7 +287,7 @@ out:
  * Returns 0 on success; nonzero on failure.
  */
 static int win32_extract_streams(struct wim_inode *inode,
-                                const wchar_t *path)
+                                const wchar_t *path, u64 *completed_bytes_p)
 {
        struct wim_lookup_table_entry *unnamed_lte;
        int ret;
@@ -298,6 +296,8 @@ static int win32_extract_streams(struct wim_inode *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) {
@@ -314,6 +314,8 @@ static int win32_extract_streams(struct wim_inode *inode,
                                                   ads_entry->lte);
                        if (ret)
                                break;
+                       if (ads_entry->lte)
+                               *completed_bytes_p += wim_resource_size(ads_entry->lte);
                }
        }
 out:
@@ -327,7 +329,6 @@ out:
  * @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.
- * @path_utf8:  @path in UTF-8 for error messages only.
  *
  * Returns 0 on success; nonzero on failure.
  */
@@ -350,7 +351,7 @@ static int win32_set_security_data(const struct wim_inode *inode,
        return 0;
 }
 
-#else
+#else /* __CYGWIN__ || __WIN32__ */
 static int extract_regular_file_linked(struct wim_dentry *dentry,
                                       const char *output_path,
                                       struct apply_args *args,
@@ -619,7 +620,7 @@ static int extract_symlink(struct wim_dentry *dentry,
        return 0;
 }
 
-#endif /* !__CYGWIN__ && !__WIN32__ */
+#endif /* !(__CYGWIN__ || __WIN32__) */
 
 static int extract_directory(struct wim_dentry *dentry,
                             const char *output_path, bool is_root)
@@ -714,7 +715,8 @@ static int apply_dentry_normal(struct wim_dentry *dentry, void *arg)
        } else {
                /* Create the file, directory, or reparse point, and extract the
                 * data streams. */
-               ret = win32_extract_streams(inode, (const wchar_t*)utf16_path);
+               ret = win32_extract_streams(inode, (const wchar_t*)utf16_path,
+                                           &args->progress.extract.completed_bytes);
                if (ret)
                        goto out_free_utf16_path;
 
@@ -778,15 +780,17 @@ static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg)
        size_t utf16_path_len;
        DWORD err;
        HANDLE h;
-       BOOL bret1, bret2;
 
        ret = utf8_to_utf16(output_path, len, &utf16_path, &utf16_path_len);
        if (ret)
                return ret;
 
-       DEBUG("Opening \"%ls\" to set timestamps", utf16_path);
-       h = CreateFileW(utf16_path, GENERIC_WRITE, FILE_SHARE_READ,
-                       NULL, OPEN_EXISTING,
+       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);
 
@@ -796,12 +800,12 @@ static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg)
        if (h == INVALID_HANDLE_VALUE)
                goto fail;
 
-       FILETIME creationTime = {.dwLowDateTime = dentry->d_inode->i_creation_time & 0xffffffff,
-                                .dwHighDateTime = dentry->d_inode->i_creation_time >> 32};
-       FILETIME lastAccessTime = {.dwLowDateTime = dentry->d_inode->i_last_access_time & 0xffffffff,
-                                 .dwHighDateTime = dentry->d_inode->i_last_access_time >> 32};
-       FILETIME lastWriteTime = {.dwLowDateTime = dentry->d_inode->i_last_write_time & 0xffffffff,
-                                 .dwHighDateTime = dentry->d_inode->i_last_write_time >> 32};
+       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)) {
@@ -814,11 +818,13 @@ static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg)
                err = GetLastError();
                goto fail;
        }
-       return 0;
+       goto out;
 fail:
-       ERROR("Can't set timestamps on \"%s\"", output_path);
+       /* Only warn if setting timestamps failed. */
+       WARNING("Can't set timestamps on \"%s\"", output_path);
        win32_error(err);
-       return WIMLIB_ERR_WRITE;
+out:
+       return 0;
 #else
        /* UNIX */
 
@@ -1317,6 +1323,11 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w,
                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);
+#endif
        if (image == WIMLIB_ALL_IMAGES) {
                extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
                ret = extract_all_images(w, target, extract_flags,
@@ -1326,6 +1337,11 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w,
                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);
+#endif
 
        if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
                             WIMLIB_EXTRACT_FLAG_HARDLINK))