]> wimlib.net Git - wimlib/blobdiff - src/win32_capture.c
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / src / win32_capture.c
index df908b02465ce539de6b7fcace3b9e6538373b4c..958147e65cab03c201a556f98a440dee67260c4b 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (C) 2013-2018 Eric Biggers
+ * Copyright (C) 2013-2021 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
  * details.
  *
  * You should have received a copy of the GNU Lesser General Public License
- * along with this file; if not, see http://www.gnu.org/licenses/.
+ * along with this file; if not, see https://www.gnu.org/licenses/.
  */
 
-#ifdef __WIN32__
+#ifdef _WIN32
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
@@ -330,7 +330,7 @@ read_winnt_stream_prefix(const struct windows_file *file,
        };
        HANDLE h;
        NTSTATUS status;
-       u8 buf[BUFFER_SIZE] _aligned_attribute(8);
+       u8 buf[BUFFER_SIZE] __attribute__((aligned(8)));
        u64 bytes_remaining;
        int ret;
 
@@ -488,7 +488,8 @@ read_win32_encrypted_file_prefix(const wchar_t *path, bool is_dir, u64 size,
  * described by @blob.  */
 int
 read_windows_file_prefix(const struct blob_descriptor *blob, u64 size,
-                        const struct consume_chunk_callback *cb)
+                        const struct consume_chunk_callback *cb,
+                        bool recover_data)
 {
        const struct windows_file *file = blob->windows_file;
 
@@ -511,7 +512,7 @@ winnt_get_short_name(HANDLE h, struct wim_dentry *dentry)
         * course has to create its own handle.  */
        NTSTATUS status;
        IO_STATUS_BLOCK iosb;
-       u8 buf[128] _aligned_attribute(8);
+       u8 buf[128] __attribute__((aligned(8)));
        const FILE_NAME_INFORMATION *info;
 
        status = NtQueryInformationFile(h, &iosb, buf, sizeof(buf),
@@ -536,7 +537,7 @@ winnt_load_security_descriptor(HANDLE h, struct wim_inode *inode,
                               struct winnt_scan_ctx *ctx)
 {
        SECURITY_INFORMATION requestedInformation;
-       u8 _buf[4096] _aligned_attribute(8);
+       u8 _buf[4096] __attribute__((aligned(8)));
        u8 *buf;
        ULONG bufsize;
        ULONG len_needed;
@@ -674,7 +675,8 @@ winnt_load_object_id(HANDLE h, struct wim_inode *inode,
        if (status == STATUS_OBJECTID_NOT_FOUND) /* No object ID  */
                return 0;
 
-       if (status == STATUS_INVALID_DEVICE_REQUEST) {
+       if (status == STATUS_INVALID_DEVICE_REQUEST ||
+           status == STATUS_NOT_SUPPORTED /* Samba volume, WinXP */) {
                /* The filesystem claimed to support object IDs, but we can't
                 * actually read them.  This happens with Samba.  */
                ctx->vol_flags &= ~FILE_SUPPORTS_OBJECT_IDS;
@@ -703,7 +705,7 @@ winnt_load_xattrs(HANDLE h, struct wim_inode *inode,
 {
        IO_STATUS_BLOCK iosb;
        NTSTATUS status;
-       u8 _buf[1024] _aligned_attribute(4);
+       u8 _buf[1024] __attribute__((aligned(4)));
        u8 *buf = _buf;
        const FILE_FULL_EA_INFORMATION *ea;
        struct wim_xattr_entry *entry;
@@ -802,12 +804,13 @@ out:
 }
 
 static int
-winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret,
-                                 HANDLE cur_dir,
-                                 const wchar_t *relative_path,
-                                 size_t relative_path_nchars,
-                                 const wchar_t *filename,
-                                 struct winnt_scan_ctx *ctx);
+winnt_build_dentry_tree(struct wim_dentry **root_ret,
+                       HANDLE cur_dir,
+                       const wchar_t *relative_path,
+                       size_t relative_path_nchars,
+                       const wchar_t *filename,
+                       struct winnt_scan_ctx *ctx,
+                       bool recursive);
 
 static int
 winnt_recurse_directory(HANDLE h,
@@ -849,13 +852,14 @@ winnt_recurse_directory(HANDLE h,
                                if (!filename)
                                        goto out_free_buf;
 
-                               ret = winnt_build_dentry_tree_recursive(
+                               ret = winnt_build_dentry_tree(
                                                        &child,
                                                        h,
                                                        filename,
                                                        info->FileNameLength / 2,
                                                        filename,
-                                                       ctx);
+                                                       ctx,
+                                                       true);
 
                                pathbuf_truncate(ctx->params, orig_path_nchars);
 
@@ -1317,22 +1321,17 @@ winnt_scan_data_stream(wchar_t *raw_stream_name, size_t raw_stream_name_nchars,
  * Load information about the data streams of an open file into a WIM inode.
  *
  * We use the NtQueryInformationFile() system call instead of FindFirstStream()
- * and FindNextStream().  This is done for two reasons:
- *
- * - FindFirstStream() opens its own handle to the file or directory and
- *   apparently does so without specifying FILE_FLAG_BACKUP_SEMANTICS, thereby
- *   causing access denied errors on certain files (even when running as the
- *   Administrator).
- * - FindFirstStream() and FindNextStream() is only available on Windows Vista
- *   and later, whereas the stream support in NtQueryInformationFile() was
- *   already present in Windows XP.
+ * and FindNextStream(), since FindFirstStream() opens its own handle to the
+ * file or directory and apparently does so without specifying
+ * FILE_FLAG_BACKUP_SEMANTICS.  This causing access denied errors on certain
+ * files, even when running as the Administrator.
  */
 static noinline_for_stack int
 winnt_scan_data_streams(HANDLE h, struct wim_inode *inode, u64 file_size,
                        struct winnt_scan_ctx *ctx)
 {
        int ret;
-       u8 _buf[4096] _aligned_attribute(8);
+       u8 _buf[4096] __attribute__((aligned(8)));
        u8 *buf;
        size_t bufsize;
        IO_STATUS_BLOCK iosb;
@@ -1514,7 +1513,7 @@ try_to_use_wimboot_hash(HANDLE h, struct wim_inode *inode,
        if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
                struct reparse_buffer_disk rpbuf;
                struct {
-                       struct wof_external_info wof_info;
+                       WOF_EXTERNAL_INFO wof_info;
                        struct wim_provider_rpdata wim_info;
                } *rpdata = (void *)rpbuf.rpdata;
                struct blob_descriptor *reparse_blob;
@@ -1532,8 +1531,8 @@ try_to_use_wimboot_hash(HANDLE h, struct wim_inode *inode,
                if (ret)
                        return ret;
 
-               if (rpdata->wof_info.version != WOF_CURRENT_VERSION ||
-                   rpdata->wof_info.provider != WOF_PROVIDER_WIM ||
+               if (rpdata->wof_info.Version != WOF_CURRENT_VERSION ||
+                   rpdata->wof_info.Provider != WOF_PROVIDER_WIM ||
                    rpdata->wim_info.version != 2)
                        return 0;  /* Not a WIM-backed file  */
 
@@ -1541,8 +1540,8 @@ try_to_use_wimboot_hash(HANDLE h, struct wim_inode *inode,
                copy_hash(hash, rpdata->wim_info.unnamed_data_stream_hash);
        } else {
                struct {
-                       struct wof_external_info wof_info;
-                       struct wim_provider_external_info wim_info;
+                       WOF_EXTERNAL_INFO wof_info;
+                       WIM_PROVIDER_EXTERNAL_INFO wim_info;
                } out;
                NTSTATUS status;
 
@@ -1576,13 +1575,13 @@ try_to_use_wimboot_hash(HANDLE h, struct wim_inode *inode,
                }
 
                /* Is this file backed by a WIM?  */
-               if (out.wof_info.version != WOF_CURRENT_VERSION ||
-                   out.wof_info.provider != WOF_PROVIDER_WIM ||
-                   out.wim_info.version != WIM_PROVIDER_CURRENT_VERSION)
+               if (out.wof_info.Version != WOF_CURRENT_VERSION ||
+                   out.wof_info.Provider != WOF_PROVIDER_WIM ||
+                   out.wim_info.Version != WIM_PROVIDER_CURRENT_VERSION)
                        return 0;
 
                /* Okay, this is a WIM backed file.  Get its SHA-1 hash.  */
-               copy_hash(hash, out.wim_info.unnamed_data_stream_hash);
+               copy_hash(hash, out.wim_info.ResourceHash);
        }
 
        /* If the file's unnamed data stream is nonempty, then fill in its hash
@@ -1600,7 +1599,8 @@ try_to_use_wimboot_hash(HANDLE h, struct wim_inode *inode,
                        return 0;
                back_ptr = retrieve_pointer_to_unhashed_blob(blob);
                copy_hash(blob->hash, hash);
-               if (after_blob_hashed(blob, back_ptr, blob_table) != blob)
+               if (after_blob_hashed(blob, back_ptr, blob_table,
+                                     inode) != blob)
                        free_blob_descriptor(blob);
        }
 
@@ -1654,7 +1654,8 @@ get_file_info(HANDLE h, struct file_info *info)
 static void
 get_volume_information(HANDLE h, struct winnt_scan_ctx *ctx)
 {
-       u8 _attr_info[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 128] _aligned_attribute(8);
+       u8 _attr_info[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 128]
+               __attribute__((aligned(8)));
        FILE_FS_ATTRIBUTE_INFORMATION *attr_info = (void *)_attr_info;
        FILE_FS_VOLUME_INFORMATION vol_info;
        struct file_info file_info;
@@ -1700,12 +1701,13 @@ get_volume_information(HANDLE h, struct winnt_scan_ctx *ctx)
 }
 
 static int
-winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret,
-                                 HANDLE cur_dir,
-                                 const wchar_t *relative_path,
-                                 size_t relative_path_nchars,
-                                 const wchar_t *filename,
-                                 struct winnt_scan_ctx *ctx)
+winnt_build_dentry_tree(struct wim_dentry **root_ret,
+                       HANDLE cur_dir,
+                       const wchar_t *relative_path,
+                       size_t relative_path_nchars,
+                       const wchar_t *filename,
+                       struct winnt_scan_ctx *ctx,
+                       bool recursive)
 {
        struct wim_dentry *root = NULL;
        struct wim_inode *inode = NULL;
@@ -1882,7 +1884,7 @@ winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret,
 
        set_sort_key(inode, sort_key);
 
-       if (inode_is_directory(inode)) {
+       if (inode_is_directory(inode) && recursive) {
 
                /* Directory: recurse to children.  */
 
@@ -1906,10 +1908,16 @@ winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        }
 
 out_progress:
-       if (likely(root))
-               ret = do_scan_progress(ctx->params, WIMLIB_SCAN_DENTRY_OK, inode);
-       else
-               ret = do_scan_progress(ctx->params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
+       ret = 0;
+       if (recursive) { /* if !recursive, caller handles progress */
+               if (likely(root))
+                       ret = do_scan_progress(ctx->params,
+                                              WIMLIB_SCAN_DENTRY_OK, inode);
+               else
+                       ret = do_scan_progress(ctx->params,
+                                              WIMLIB_SCAN_DENTRY_EXCLUDED,
+                                              NULL);
+       }
 out:
        if (likely(h))
                NtClose(h);
@@ -2568,7 +2576,9 @@ load_files_from_mft(const wchar_t *path, struct ntfs_inode_map *inode_map)
         * all files have been enumerated.  */
        if (status != STATUS_END_OF_FILE) {
                if (status == STATUS_INVALID_DEVICE_REQUEST /* old OS */ ||
-                   status == STATUS_INVALID_PARAMETER /* not root directory */ ) {
+                   status == STATUS_NOT_SUPPORTED /* Samba volume, WinXP */ ||
+                   status == STATUS_INVALID_PARAMETER /* not root directory */ )
+               {
                        /* Silently try standard recursive scan instead  */
                        ret = -1;
                } else {
@@ -2707,10 +2717,10 @@ security_map_destroy(struct security_map *map)
  *     ntfs_stream     => wim_inode_stream
  *
  * This also handles things such as exclusions and issuing progress messages.
- * It's similar to winnt_build_dentry_tree_recursive(), but this is much faster
- * because almost all information we need is already loaded in memory in the
- * ntfs_* structures.  However, in some cases we still fall back to
- * winnt_build_dentry_tree_recursive() and/or opening the file.
+ * It's similar to winnt_build_dentry_tree(), but this is much faster because
+ * almost all information we need is already loaded in memory in the ntfs_*
+ * structures.  However, in some cases we still fall back to
+ * winnt_build_dentry_tree() and/or opening the file.
  */
 static int
 generate_wim_structures_recursive(struct wim_dentry **root_ret,
@@ -2729,7 +2739,7 @@ generate_wim_structures_recursive(struct wim_dentry **root_ret,
        if (NTFS_IS_SPECIAL_FILE(ni->ino))
                goto out;
 
-       /* Fall back to a recursive scan for unhandled cases.  Reparse points,
+       /* Fall back to the standard scan for unhandled cases.  Reparse points,
         * in particular, can't be properly handled here because a commonly used
         * filter driver (WOF) hides reparse points from regular filesystem APIs
         * but not from FSCTL_QUERY_FILE_LAYOUT.  */
@@ -2737,13 +2747,16 @@ generate_wim_structures_recursive(struct wim_dentry **root_ret,
                              FILE_ATTRIBUTE_ENCRYPTED) ||
            ni->special_streams != 0)
        {
-               ret = winnt_build_dentry_tree_recursive(&root,
-                                                       NULL,
-                                                       ctx->params->cur_path,
-                                                       ctx->params->cur_path_nchars,
-                                                       filename,
-                                                       ctx);
-               goto out;
+               ret = winnt_build_dentry_tree(&root, NULL,
+                                             ctx->params->cur_path,
+                                             ctx->params->cur_path_nchars,
+                                             filename, ctx, false);
+               if (ret) /* Error? */
+                       goto out;
+               if (!root) /* Excluded? */
+                       goto out_progress;
+               inode = root->d_inode;
+               goto process_children;
        }
 
        /* Test for exclusion based on path.  */
@@ -2863,6 +2876,7 @@ generate_wim_structures_recursive(struct wim_dentry **root_ret,
        /* If processing a directory, then recurse to its children.  In this
         * version there is no need to go to disk, as we already have the list
         * of children cached from the MFT.  */
+process_children:
        if (inode_is_directory(inode)) {
                const struct ntfs_dentry *nd = ni->first_child;
 
@@ -3024,10 +3038,8 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
                }
        }
 #endif
-       ret = winnt_build_dentry_tree_recursive(root_ret, NULL,
-                                               params->cur_path,
-                                               params->cur_path_nchars,
-                                               L"", &ctx);
+       ret = winnt_build_dentry_tree(root_ret, NULL, params->cur_path,
+                                     params->cur_path_nchars, L"", &ctx, true);
 out:
        vss_put_snapshot(ctx.snapshot);
        if (ret == 0)
@@ -3035,4 +3047,4 @@ out:
        return ret;
 }
 
-#endif /* __WIN32__ */
+#endif /* _WIN32 */