/* WIMBoot information, only filled in if WIMLIB_EXTRACT_FLAG_WIMBOOT
* was provided */
struct {
- u64 data_source_id;
+ /* This array contains the WIM files registered with WOF on the
+ * target volume for this extraction operation. All WIMStructs
+ * in this array are distinct and have ->filename != NULL. */
+ struct wimboot_wim {
+ WIMStruct *wim;
+ u64 data_source_id;
+ u8 blob_table_hash[SHA1_HASH_SIZE];
+ } *wims;
+ size_t num_wims;
struct string_set *prepopulate_pats;
void *mem_prepopulate_pats;
- u8 blob_table_hash[SHA1_HASH_SIZE];
bool wof_running;
bool tried_to_load_prepopulate_list;
+
+ bool have_wrong_version_wims;
+ bool have_uncompressed_wims;
+ bool have_unsupported_compressed_resources;
+ bool have_huge_resources;
} wimboot;
/* Open handle to the target directory */
* beginning of the array) */
unsigned num_open_handles;
- /* List of dentries, joined by @tmp_list, that need to have reparse data
- * extracted as soon as the whole blob has been read into @data_buffer.
- * */
+ /* List of dentries, joined by @d_tmp_list, that need to have reparse
+ * data extracted as soon as the whole blob has been read into
+ * @data_buffer. */
struct list_head reparse_dentries;
- /* List of dentries, joined by @tmp_list, that need to have raw
+ /* List of dentries, joined by @d_tmp_list, that need to have raw
* encrypted data extracted as soon as the whole blob has been read into
* @data_buffer. */
struct list_head encrypted_dentries;
{
const wchar_t *path = L"\\Windows\\System32\\WimBootCompress.ini";
struct wim_dentry *dentry;
- struct blob_descriptor *blob;
+ const struct blob_descriptor *blob;
int ret;
void *buf;
struct string_set *s;
!(blob = inode_get_blob_for_unnamed_data_stream(dentry->d_inode,
ctx->common.wim->blob_table)))
{
- WARNING("%ls does not exist in WIM image!", path);
+ WARNING("%ls does not exist in the WIM image.\n"
+ " The default configuration will be used instead; it assumes that all\n"
+ " files are valid for external backing regardless of path, equivalent\n"
+ " to an empty [PrepopulateList] section.", path);
return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
}
- ret = read_full_blob_into_alloc_buf(blob, &buf);
+ ret = read_blob_into_alloc_buf(blob, &buf);
if (ret)
return ret;
return true;
}
+static bool
+is_resource_valid_for_external_backing(const struct wim_resource_descriptor *rdesc,
+ struct win32_apply_ctx *ctx)
+{
+ /* Must be the original WIM file format. This check excludes pipable
+ * resources and solid resources. It also excludes other resources
+ * contained in such files even if they would be otherwise compatible.
+ */
+ if (rdesc->wim->hdr.magic != WIM_MAGIC ||
+ rdesc->wim->hdr.wim_version != WIM_VERSION_DEFAULT)
+ {
+ ctx->wimboot.have_wrong_version_wims = true;
+ return false;
+ }
+
+ /*
+ * Whitelist of compression types and chunk sizes supported by
+ * Microsoft's WOF driver.
+ *
+ * Notes:
+ * - Uncompressed WIMs result in BSOD. However, this only applies to
+ * the WIM file itself, not to uncompressed resources in a WIM file
+ * that is otherwise compressed.
+ * - XPRESS 64K sometimes appears to work, but sometimes it causes
+ * reads to fail with STATUS_UNSUCCESSFUL.
+ */
+ switch (rdesc->compression_type) {
+ case WIMLIB_COMPRESSION_TYPE_NONE:
+ if (rdesc->wim->compression_type == WIMLIB_COMPRESSION_TYPE_NONE) {
+ ctx->wimboot.have_uncompressed_wims = true;
+ return false;
+ }
+ break;
+ case WIMLIB_COMPRESSION_TYPE_XPRESS:
+ switch (rdesc->chunk_size) {
+ case 4096:
+ case 8192:
+ case 16384:
+ case 32768:
+ break;
+ default:
+ ctx->wimboot.have_unsupported_compressed_resources = true;
+ return false;
+ }
+ break;
+ case WIMLIB_COMPRESSION_TYPE_LZX:
+ switch (rdesc->chunk_size) {
+ case 32768:
+ break;
+ default:
+ ctx->wimboot.have_unsupported_compressed_resources = true;
+ return false;
+ }
+ break;
+ default:
+ ctx->wimboot.have_unsupported_compressed_resources = true;
+ return false;
+ }
+
+ /* Microsoft's WoF driver errors out if it tries to satisfy a read with
+ * ending offset >= 4 GiB from an externally backed file. */
+ if (rdesc->uncompressed_size > 4200000000) {
+ ctx->wimboot.have_huge_resources = true;
+ return false;
+ }
+
+ return true;
+}
+
#define WIM_BACKING_NOT_ENABLED -1
#define WIM_BACKING_NOT_POSSIBLE -2
#define WIM_BACKING_EXCLUDED -3
will_externally_back_inode(struct wim_inode *inode, struct win32_apply_ctx *ctx,
const struct wim_dentry **excluded_dentry_ret)
{
- struct list_head *next;
struct wim_dentry *dentry;
struct blob_descriptor *blob;
int ret;
blob = inode_get_blob_for_unnamed_data_stream_resolved(inode);
- /* Note: Microsoft's WoF driver errors out if it tries to satisfy a
- * read, with ending offset >= 4 GiB, from an externally backed file. */
- if (!blob ||
- blob->blob_location != BLOB_IN_WIM ||
- blob->rdesc->wim != ctx->common.wim ||
- blob->size != blob->rdesc->uncompressed_size ||
- blob->size > 4200000000)
+ if (!blob || blob->blob_location != BLOB_IN_WIM ||
+ !is_resource_valid_for_external_backing(blob->rdesc, ctx))
return WIM_BACKING_NOT_POSSIBLE;
/*
* We need to check the patterns in [PrepopulateList] against every name
* of the inode, in case any of them match.
*/
- next = inode->i_extraction_aliases.next;
- do {
- dentry = list_entry(next, struct wim_dentry,
- d_extraction_alias_node);
+
+ inode_for_each_extraction_alias(dentry, inode) {
ret = calculate_dentry_full_path(dentry);
if (ret)
return ret;
- if (!can_externally_back_path(dentry->_full_path,
- wcslen(dentry->_full_path), ctx))
+ if (!can_externally_back_path(dentry->d_full_path,
+ wcslen(dentry->d_full_path), ctx))
{
if (excluded_dentry_ret)
*excluded_dentry_ret = dentry;
return WIM_BACKING_EXCLUDED;
}
- next = next->next;
- } while (next != &inode->i_extraction_aliases);
+ }
inode->i_can_externally_back = 1;
return 0;
return will_externally_back_inode(dentry->d_inode, ctx, NULL);
}
+/* Find the WOF registration information for the specified WIM file. */
+static struct wimboot_wim *
+find_wimboot_wim(WIMStruct *wim_to_find, struct win32_apply_ctx *ctx)
+{
+ for (size_t i = 0; i < ctx->wimboot.num_wims; i++)
+ if (wim_to_find == ctx->wimboot.wims[i].wim)
+ return &ctx->wimboot.wims[i];
+
+ wimlib_assert(0);
+ return NULL;
+}
+
static int
set_external_backing(HANDLE h, struct wim_inode *inode, struct win32_apply_ctx *ctx)
{
int ret;
const struct wim_dentry *excluded_dentry;
+ const struct blob_descriptor *blob;
+ const struct wimboot_wim *wimboot_wim;
ret = will_externally_back_inode(inode, ctx, &excluded_dentry);
if (ret > 0) /* Error. */
build_extraction_path(excluded_dentry, ctx);
- info.wimboot_exclude.path_in_wim = excluded_dentry->_full_path;
+ info.wimboot_exclude.path_in_wim = excluded_dentry->d_full_path;
info.wimboot_exclude.extraction_path = current_path(ctx);
return call_progress(ctx->common.progfunc,
WIMLIB_PROGRESS_MSG_WIMBOOT_EXCLUDE,
&info, ctx->common.progctx);
- } else {
- /* Externally backing. */
- if (unlikely(!wimboot_set_pointer(h,
- inode_get_blob_for_unnamed_data_stream_resolved(inode),
- ctx->wimboot.data_source_id,
- ctx->wimboot.blob_table_hash,
- ctx->wimboot.wof_running)))
- {
- const DWORD err = GetLastError();
+ }
- build_extraction_path(inode_first_extraction_dentry(inode), ctx);
- win32_error(err, L"\"%ls\": Couldn't set WIMBoot pointer data",
- current_path(ctx));
- return WIMLIB_ERR_WIMBOOT;
- }
- return 0;
+ /* Externally backing. */
+
+ blob = inode_get_blob_for_unnamed_data_stream_resolved(inode);
+ wimboot_wim = find_wimboot_wim(blob->rdesc->wim, ctx);
+
+ if (unlikely(!wimboot_set_pointer(h,
+ blob,
+ wimboot_wim->data_source_id,
+ wimboot_wim->blob_table_hash,
+ ctx->wimboot.wof_running)))
+ {
+ const DWORD err = GetLastError();
+
+ build_extraction_path(inode_first_extraction_dentry(inode), ctx);
+ win32_error(err, L"\"%ls\": Couldn't set WIMBoot pointer data",
+ current_path(ctx));
+ return WIMLIB_ERR_WIMBOOT;
}
+ return 0;
}
/* Calculates the SHA-1 message digest of the WIM's blob table. */
return wim_reshdr_to_hash(&wim->hdr.blob_table_reshdr, wim, hash);
}
+static int
+register_wim_with_wof(WIMStruct *wim, struct win32_apply_ctx *ctx)
+{
+ struct wimboot_wim *p;
+ int ret;
+
+ /* Check if already registered */
+ for (size_t i = 0; i < ctx->wimboot.num_wims; i++)
+ if (wim == ctx->wimboot.wims[i].wim)
+ return 0;
+
+ /* Not yet registered */
+
+ p = REALLOC(ctx->wimboot.wims,
+ (ctx->wimboot.num_wims + 1) * sizeof(ctx->wimboot.wims[0]));
+ if (!p)
+ return WIMLIB_ERR_NOMEM;
+ ctx->wimboot.wims = p;
+
+ ctx->wimboot.wims[ctx->wimboot.num_wims].wim = wim;
+
+ ret = hash_blob_table(wim, ctx->wimboot.wims[ctx->wimboot.num_wims].blob_table_hash);
+ if (ret)
+ return ret;
+
+ ret = wimboot_alloc_data_source_id(wim->filename,
+ wim->hdr.guid,
+ ctx->common.wim->current_image,
+ ctx->common.target,
+ &ctx->wimboot.wims[ctx->wimboot.num_wims].data_source_id,
+ &ctx->wimboot.wof_running);
+ if (ret)
+ return ret;
+
+ ctx->wimboot.num_wims++;
+ return 0;
+}
+
/* Prepare for doing a "WIMBoot" extraction by loading patterns from
- * [PrepopulateList] of WimBootCompress.ini and allocating a WOF data source ID
- * on the target volume. */
+ * [PrepopulateList] of WimBootCompress.ini and registering each source WIM file
+ * with WOF on the target volume. */
static int
-start_wimboot_extraction(struct win32_apply_ctx *ctx)
+start_wimboot_extraction(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
{
int ret;
- WIMStruct *wim = ctx->common.wim;
+ struct wim_dentry *dentry;
if (!ctx->wimboot.tried_to_load_prepopulate_list)
if (load_prepopulate_pats(ctx) == WIMLIB_ERR_NOMEM)
return WIMLIB_ERR_NOMEM;
- if (!wim_info_get_wimboot(wim->wim_info, wim->current_image))
- WARNING("Image is not marked as WIMBoot compatible!");
+ if (!wim_info_get_wimboot(ctx->common.wim->wim_info,
+ ctx->common.wim->current_image))
+ WARNING("The WIM image is not marked as WIMBoot compatible. This usually\n"
+ " means it is not intended to be used to back a Windows operating\n"
+ " system. Proceeding anyway.");
- ret = hash_blob_table(ctx->common.wim, ctx->wimboot.blob_table_hash);
- if (ret)
- return ret;
+ list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
+ struct blob_descriptor *blob;
+
+ ret = win32_will_externally_back(dentry, &ctx->common);
+ if (ret > 0) /* Error */
+ return ret;
+ if (ret < 0) /* Won't externally back */
+ continue;
+
+ blob = inode_get_blob_for_unnamed_data_stream_resolved(dentry->d_inode);
+ ret = register_wim_with_wof(blob->rdesc->wim, ctx);
+ if (ret)
+ return ret;
+ }
+
+ if (ctx->wimboot.have_wrong_version_wims) {
+ WARNING("At least one of the source WIM files uses a version of the WIM\n"
+" file format that not supported by Microsoft's wof.sys driver.\n"
+" Files whose data is contained in one of these WIM files will be\n"
+" extracted as full files rather than externally backed.");
+ }
+
+ if (ctx->wimboot.have_uncompressed_wims) {
+ WARNING("At least one of the source WIM files is uncompressed. Files whose\n"
+" data is contained in an uncompressed WIM file will be extracted as\n"
+" full files rather than externally backed, since uncompressed WIM\n"
+" files are not supported by Microsoft's wof.sys driver.");
+ }
+
+ if (ctx->wimboot.have_unsupported_compressed_resources) {
+ WARNING("At least one of the source WIM files uses a compression format that\n"
+" is not supported by Microsoft's wof.sys driver. Files whose data is\n"
+" contained in a compressed resource in one of these WIM files will be\n"
+" extracted as full files rather than externally backed. (The\n"
+" compression formats supported by wof.sys are: XPRESS 4K, XPRESS 8K,\n"
+" XPRESS 16K, XPRESS 32K, and LZX 32K.)");
+ }
+
+ if (ctx->wimboot.have_huge_resources) {
+ WARNING("Some files exceeded 4.2 GB in size. Such files will be extracted\n"
+" as full files rather than externally backed, since very large files\n"
+" are not supported by Microsoft's wof.sys driver.");
+ }
- return wimboot_alloc_data_source_id(wim->filename,
- wim->hdr.guid,
- wim->current_image,
- ctx->common.target,
- &ctx->wimboot.data_source_id,
- &ctx->wimboot.wof_running);
+ return 0;
}
static void
const struct wim_inode_stream *strm = &inode->i_streams[i];
if (!stream_is_named_data_stream(strm))
continue;
- size_t len = utf16le_len_bytes(strm->stream_name);
+ size_t len = utf16le_len_chars(strm->stream_name);
if (len > max)
max = len;
}
if (max)
- max = 1 + (max / sizeof(wchar_t));
+ max += 1;
return max;
}
static struct wim_dentry *
first_extraction_alias(const struct wim_inode *inode)
{
- struct list_head *next = inode->i_extraction_aliases.next;
struct wim_dentry *dentry;
- do {
- dentry = list_entry(next, struct wim_dentry,
- d_extraction_alias_node);
+ inode_for_each_extraction_alias(dentry, inode)
if (dentry_has_short_name(dentry))
- break;
- next = next->next;
- } while (next != &inode->i_extraction_aliases);
- return dentry;
+ return dentry;
+ return inode_first_extraction_dentry(inode);
}
/*
name = &ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)];
while (name != ctx->pathbuf.Buffer && *(name - 1) != L'\\')
name--;
- end = mempcpy(name, dentry->short_name, dentry->short_name_nbytes);
+ end = mempcpy(name, dentry->d_short_name, dentry->d_short_name_nbytes);
ctx->pathbuf.Length = ((u8 *)end - (u8 *)ctx->pathbuf.Buffer);
/* Open the conflicting file (by short name). */
*/
size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
- max(dentry->short_name_nbytes, sizeof(wchar_t)) +
+ max(dentry->d_short_name_nbytes, sizeof(wchar_t)) +
sizeof(wchar_t);
u8 buf[bufsize] _aligned_attribute(8);
FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
memset(buf, 0, bufsize);
- info->FileNameLength = dentry->short_name_nbytes;
- memcpy(info->FileName, dentry->short_name, dentry->short_name_nbytes);
+ info->FileNameLength = dentry->d_short_name_nbytes;
+ memcpy(info->FileName, dentry->d_short_name, dentry->d_short_name_nbytes);
retry:
status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize,
return 0;
if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) {
- if (dentry->short_name_nbytes == 0)
+ if (dentry->d_short_name_nbytes == 0)
return 0;
if (!ctx->tried_to_enable_short_names) {
wchar_t volume[7];
* from files.
*/
if (unlikely(status == STATUS_OBJECT_NAME_COLLISION) &&
- dentry->short_name_nbytes && !tried_to_remove_existing)
+ dentry->d_short_name_nbytes && !tried_to_remove_existing)
{
tried_to_remove_existing = true;
status = remove_conflicting_short_name(dentry, ctx);
/* By default, failure to set short names is not an error (since short
* names aren't too important anymore...). */
if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES)) {
- if (dentry->short_name_nbytes)
+ if (dentry->d_short_name_nbytes)
ctx->num_set_short_name_failures++;
else
ctx->num_remove_short_name_failures++;
create_links(HANDLE h, const struct wim_dentry *first_dentry,
struct win32_apply_ctx *ctx)
{
- const struct wim_inode *inode;
- const struct list_head *next;
+ const struct wim_inode *inode = first_dentry->d_inode;
const struct wim_dentry *dentry;
int ret;
- inode = first_dentry->d_inode;
- next = inode->i_extraction_aliases.next;
- do {
- dentry = list_entry(next, struct wim_dentry,
- d_extraction_alias_node);
+ inode_for_each_extraction_alias(dentry, inode) {
if (dentry != first_dentry) {
ret = create_link(h, dentry, ctx);
if (ret)
return ret;
}
- next = next->next;
- } while (next != &inode->i_extraction_aliases);
+ }
return 0;
}
* data be available. So, stage the data in a buffer. */
if (!prepare_data_buffer(ctx, blob->size))
return WIMLIB_ERR_NOMEM;
- list_add_tail(&dentry->tmp_list, &ctx->reparse_dentries);
+ list_add_tail(&dentry->d_tmp_list, &ctx->reparse_dentries);
return 0;
}
* such files... */
if (!prepare_data_buffer(ctx, blob->size))
return WIMLIB_ERR_NOMEM;
- list_add_tail(&dentry->tmp_list, &ctx->encrypted_dentries);
+ list_add_tail(&dentry->d_tmp_list, &ctx->encrypted_dentries);
return 0;
}
return 0;
}
-/* Set the reparse data @rpbuf of length @rpbuflen on the extracted file
+/* Set the reparse point @rpbuf of length @rpbuflen on the extracted file
* corresponding to the WIM dentry @dentry. */
static int
-do_set_reparse_data(const struct wim_dentry *dentry,
- const void *rpbuf, u16 rpbuflen,
- struct win32_apply_ctx *ctx)
+do_set_reparse_point(const struct wim_dentry *dentry,
+ const struct reparse_buffer_disk *rpbuf, u16 rpbuflen,
+ struct win32_apply_ctx *ctx)
{
NTSTATUS status;
HANDLE h;
L"\\DosDevices\\",
L"\\Device\\",
};
- size_t first_dir_len = 0;
const wchar_t * const end = path + path_nchars;
for (size_t i = 0; i < ARRAY_LEN(dirs); i++) {
size_t len = wcslen(dirs[i]);
- if (len <= (end - path) && !wcsnicmp(path, dirs[i], len)) {
- first_dir_len = len;
- break;
+ if (len <= (end - path) && !wmemcmp(path, dirs[i], len)) {
+ path += len;
+ while (path != end && *path == L'\\')
+ path++;
+ return path;
}
}
- if (first_dir_len == 0)
- return path;
- path += first_dir_len;
- while (path != end && *path == L'\\')
- path++;
return path;
}
-/* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
- * pointer to the suffix of the path that is device-relative, such as
- * Windows\System32.
+/*
+ * Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
+ * pointer to the suffix of the path that is device-relative but possibly with
+ * leading slashes, such as \Windows\System32.
*
* The path has an explicit length and is not necessarily null terminated.
- *
- * If the path just something like \??\e: then the returned pointer will point
- * just past the colon. In this case the length of the result will be 0
- * characters. */
+ */
static const wchar_t *
get_device_relative_path(const wchar_t *path, size_t path_nchars)
{
if (path == orig_path)
return orig_path;
- path = wmemchr(path, L'\\', (end - path));
- if (!path)
- return end;
- do {
+ while (path != end && *path != L'\\')
path++;
- } while (path != end && *path == L'\\');
+
return path;
}
/*
- * Given a reparse point buffer for a symbolic link or junction, adjust its
- * contents so that the target of the link is consistent with the new location
- * of the files.
+ * Given a reparse point buffer for an inode for which the absolute link target
+ * was relativized when it was archived, de-relative the link target to be
+ * consistent with the actual extraction location.
*/
static void
-try_rpfix(u8 *rpbuf, u16 *rpbuflen_p, struct win32_apply_ctx *ctx)
+try_rpfix(struct reparse_buffer_disk *rpbuf, u16 *rpbuflen_p,
+ struct win32_apply_ctx *ctx)
{
- struct reparse_data rpdata;
+ struct link_reparse_point link;
size_t orig_subst_name_nchars;
const wchar_t *relpath;
size_t relpath_nchars;
const wchar_t *fixed_print_name;
size_t fixed_print_name_nchars;
- if (parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata)) {
- /* Do nothing if the reparse data is invalid. */
+ /* Do nothing if the reparse data is invalid. */
+ if (parse_link_reparse_point(rpbuf, *rpbuflen_p, &link))
return;
- }
- if (rpdata.rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
- (rpdata.rpflags & SYMBOLIC_LINK_RELATIVE))
- {
- /* Do nothing if it's a relative symbolic link. */
+ /* Do nothing if the reparse point is a relative symbolic link. */
+ if (link_is_relative_symlink(&link))
return;
- }
/* Build the new substitute name from the NT namespace path to the
* target directory, then a path separator, then the "device relative"
* part of the old substitute name. */
- orig_subst_name_nchars = rpdata.substitute_name_nbytes / sizeof(wchar_t);
+ orig_subst_name_nchars = link.substitute_name_nbytes / sizeof(wchar_t);
- relpath = get_device_relative_path(rpdata.substitute_name,
+ relpath = get_device_relative_path(link.substitute_name,
orig_subst_name_nchars);
relpath_nchars = orig_subst_name_nchars -
- (relpath - rpdata.substitute_name);
+ (relpath - link.substitute_name);
target_ntpath_nchars = ctx->target_ntpath.Length / sizeof(wchar_t);
- fixed_subst_name_nchars = target_ntpath_nchars;
- if (relpath_nchars)
- fixed_subst_name_nchars += 1 + relpath_nchars;
+ fixed_subst_name_nchars = target_ntpath_nchars + relpath_nchars;
+
wchar_t fixed_subst_name[fixed_subst_name_nchars];
- wmemcpy(fixed_subst_name, ctx->target_ntpath.Buffer,
- target_ntpath_nchars);
- if (relpath_nchars) {
- fixed_subst_name[target_ntpath_nchars] = L'\\';
- wmemcpy(&fixed_subst_name[target_ntpath_nchars + 1],
- relpath, relpath_nchars);
- }
+ wmemcpy(fixed_subst_name, ctx->target_ntpath.Buffer, target_ntpath_nchars);
+ wmemcpy(&fixed_subst_name[target_ntpath_nchars], relpath, relpath_nchars);
/* Doesn't need to be null-terminated. */
/* Print name should be Win32, but not all NT names can even be
fixed_print_name_nchars = fixed_subst_name_nchars - (fixed_print_name -
fixed_subst_name);
- rpdata.substitute_name = fixed_subst_name;
- rpdata.substitute_name_nbytes = fixed_subst_name_nchars * sizeof(wchar_t);
- rpdata.print_name = (wchar_t *)fixed_print_name;
- rpdata.print_name_nbytes = fixed_print_name_nchars * sizeof(wchar_t);
- make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p);
+ link.substitute_name = fixed_subst_name;
+ link.substitute_name_nbytes = fixed_subst_name_nchars * sizeof(wchar_t);
+ link.print_name = (wchar_t *)fixed_print_name;
+ link.print_name_nbytes = fixed_print_name_nchars * sizeof(wchar_t);
+ make_link_reparse_point(&link, rpbuf, rpbuflen_p);
}
-/* Sets reparse data on the specified file. This handles "fixing" the targets
- * of absolute symbolic links and junctions if WIMLIB_EXTRACT_FLAG_RPFIX was
- * specified. */
+/* Sets the reparse point on the specified file. This handles "fixing" the
+ * targets of absolute symbolic links and junctions if WIMLIB_EXTRACT_FLAG_RPFIX
+ * was specified. */
static int
-set_reparse_data(const struct wim_dentry *dentry,
- const void *_rpbuf, u16 rpbuflen, struct win32_apply_ctx *ctx)
+set_reparse_point(const struct wim_dentry *dentry,
+ const struct reparse_buffer_disk *rpbuf, u16 rpbuflen,
+ struct win32_apply_ctx *ctx)
{
- const struct wim_inode *inode = dentry->d_inode;
- const void *rpbuf = _rpbuf;
-
if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX)
- && !inode->i_not_rpfixed
- && (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
- inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
+ && !(dentry->d_inode->i_rp_flags & WIM_RP_FLAG_NOT_FIXED))
{
- memcpy(&ctx->rpfixbuf, _rpbuf, rpbuflen);
- try_rpfix((u8 *)&ctx->rpfixbuf, &rpbuflen, ctx);
+ memcpy(&ctx->rpfixbuf, rpbuf, rpbuflen);
+ try_rpfix(&ctx->rpfixbuf, &rpbuflen, ctx);
rpbuf = &ctx->rpfixbuf;
}
- return do_set_reparse_data(dentry, rpbuf, rpbuflen, ctx);
+ return do_set_reparse_point(dentry, rpbuf, rpbuflen, ctx);
}
} else {
/* Hard links not supported. Extract the blob
* separately to each alias of the inode. */
- struct list_head *next;
-
- next = inode->i_extraction_aliases.next;
- do {
- dentry = list_entry(next, struct wim_dentry,
- d_extraction_alias_node);
+ inode_for_each_extraction_alias(dentry, inode) {
ret = begin_extract_blob_instance(blob, dentry, strm, ctx);
ret = check_apply_error(dentry, ctx, ret);
if (ret)
goto fail;
- next = next->next;
- } while (next != &inode->i_extraction_aliases);
+ }
}
}
if (!list_empty(&ctx->reparse_dentries)) {
if (blob->size > REPARSE_DATA_MAX_SIZE) {
dentry = list_first_entry(&ctx->reparse_dentries,
- struct wim_dentry, tmp_list);
+ struct wim_dentry, d_tmp_list);
build_extraction_path(dentry, ctx);
ERROR("Reparse data of \"%ls\" has size "
"%"PRIu64" bytes (exceeds %u bytes)",
ret = WIMLIB_ERR_INVALID_REPARSE_DATA;
return check_apply_error(dentry, ctx, ret);
}
- /* In the WIM format, reparse point streams are just the reparse
- * data and omit the header. But we can reconstruct the header.
- */
+ /* Reparse data */
memcpy(ctx->rpbuf.rpdata, ctx->data_buffer, blob->size);
- ctx->rpbuf.rpdatalen = blob->size;
- ctx->rpbuf.rpreserved = 0;
- list_for_each_entry(dentry, &ctx->reparse_dentries, tmp_list) {
- ctx->rpbuf.rptag = dentry->d_inode->i_reparse_tag;
- ret = set_reparse_data(dentry, &ctx->rpbuf,
- blob->size + REPARSE_DATA_OFFSET,
- ctx);
+
+ list_for_each_entry(dentry, &ctx->reparse_dentries, d_tmp_list) {
+
+ /* Reparse point header */
+ complete_reparse_point(&ctx->rpbuf, dentry->d_inode,
+ blob->size);
+
+ ret = set_reparse_point(dentry, &ctx->rpbuf,
+ REPARSE_DATA_OFFSET + blob->size,
+ ctx);
ret = check_apply_error(dentry, ctx, ret);
if (ret)
return ret;
if (!list_empty(&ctx->encrypted_dentries)) {
ctx->encrypted_size = blob->size;
- list_for_each_entry(dentry, &ctx->encrypted_dentries, tmp_list) {
+ list_for_each_entry(dentry, &ctx->encrypted_dentries, d_tmp_list) {
ret = extract_encrypted_file(dentry, ctx);
ret = check_apply_error(dentry, ctx, ret);
if (ret)
NTSTATUS status;
/* Set security descriptor if present and not in NO_ACLS mode */
- if (inode->i_security_id >= 0 &&
+ if (inode_has_security_descriptor(inode) &&
!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS))
{
const struct wim_security_data *sd;
}
}
-static uint64_t
+static u64
count_dentries(const struct list_head *dentry_list)
{
const struct list_head *cur;
- uint64_t count = 0;
+ u64 count = 0;
list_for_each(cur, dentry_list)
count++;
{
int ret;
struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
- uint64_t dentry_count;
+ u64 dentry_count;
ret = prepare_target(dentry_list, ctx);
if (ret)
goto out;
if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)) {
- ret = start_wimboot_extraction(ctx);
+ ret = start_wimboot_extraction(dentry_list, ctx);
if (ret)
goto out;
}
if (ret)
goto out;
- struct read_blob_list_callbacks cbs = {
- .begin_blob = begin_extract_blob,
- .begin_blob_ctx = ctx,
- .consume_chunk = extract_chunk,
- .consume_chunk_ctx = ctx,
- .end_blob = end_extract_blob,
- .end_blob_ctx = ctx,
+ struct read_blob_callbacks cbs = {
+ .begin_blob = begin_extract_blob,
+ .consume_chunk = extract_chunk,
+ .end_blob = end_extract_blob,
+ .ctx = ctx,
};
ret = extract_blob_list(&ctx->common, &cbs);
if (ret)
HeapFree(GetProcessHeap(), 0, ctx->target_ntpath.Buffer);
FREE(ctx->pathbuf.Buffer);
FREE(ctx->print_buffer);
+ FREE(ctx->wimboot.wims);
if (ctx->wimboot.prepopulate_pats) {
FREE(ctx->wimboot.prepopulate_pats->strings);
FREE(ctx->wimboot.prepopulate_pats);