X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fwin32_capture.c;h=bc05d70779459c59871530c88cae5585d4ead1f5;hb=HEAD;hp=df908b02465ce539de6b7fcace3b9e6538373b4c;hpb=3770d244330395ed3325d8832d5eebb43ebfe980;p=wimlib diff --git a/src/win32_capture.c b/src/win32_capture.c index df908b02..958147e6 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -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 @@ -18,10 +18,10 @@ * 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 */