*/
/*
- * 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"
};
HANDLE h;
NTSTATUS status;
- u8 buf[BUFFER_SIZE] _aligned_attribute(8);
+ u8 buf[BUFFER_SIZE] __attribute__((aligned(8)));
u64 bytes_remaining;
int ret;
* 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;
* 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),
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;
{
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;
}
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,
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);
* 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;
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;
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 */
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;
}
/* 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
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);
}
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;
}
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;
set_sort_key(inode, sort_key);
- if (inode_is_directory(inode)) {
+ if (inode_is_directory(inode) && recursive) {
/* Directory: recurse to children. */
}
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);
* 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,
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. */
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. */
/* 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;
}
}
#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)
return ret;
}
-#endif /* __WIN32__ */
+#endif /* _WIN32 */