X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwin32_capture.c;h=60d212d13ce102f62de70ebd711e045bb68e1db7;hp=854428e4dfd20266780858558bed72b608c9f465;hb=c0f97d52b487123a1a68a6a07fa0d9be81ee1f72;hpb=b87b3beaacd32c045ab77dc56c6b90677d882830 diff --git a/src/win32_capture.c b/src/win32_capture.c index 854428e4..60d212d1 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -38,6 +38,7 @@ #include "wimlib/error.h" #include "wimlib/paths.h" #include "wimlib/reparse.h" +#include "wimlib/wof.h" struct winnt_scan_stats { unsigned long num_get_sd_access_denied; @@ -137,10 +138,16 @@ read_winnt_stream_prefix(const struct blob_descriptor *blob, u64 size, status = (*func_NtReadFile)(h, NULL, NULL, NULL, &iosb, buf, count, NULL, NULL); - if (!NT_SUCCESS(status)) { - winnt_error(status, L"\"%ls\": Error reading data", - printable_path(path)); - ret = WIMLIB_ERR_READ; + if (unlikely(!NT_SUCCESS(status))) { + if (status == STATUS_END_OF_FILE) { + ERROR("\"%ls\": File was concurrently truncated", + printable_path(path)); + ret = WIMLIB_ERR_CONCURRENT_MODIFICATION_DETECTED; + } else { + winnt_error(status, L"\"%ls\": Error reading data", + printable_path(path)); + ret = WIMLIB_ERR_READ; + } break; } @@ -449,8 +456,7 @@ winnt_recurse_directory(HANDLE h, if (ret) goto out_free_buf; - if (child) - dentry_add_child(parent, child); + attach_scanned_tree(parent, child, params->blob_table); } if (info->NextEntryOffset == 0) break; @@ -629,7 +635,7 @@ winnt_try_rpfix(struct reparse_buffer_disk *rpbuf, u16 *rpbuflen_p, * SYMBOLIC_LINK_RELATIVE. We will use this information, although this * may not always do what the user expects, since drive-relative * symbolic links such as "\Users\Public" have SYMBOLIC_LINK_RELATIVE - * set, in addition to truely relative symbolic links such as "Users" or + * set, in addition to truly relative symbolic links such as "Users" or * "Users\Public". However, WIMGAPI (as of Windows 8.1) has this same * behavior. * @@ -1107,6 +1113,55 @@ set_sort_key(struct wim_inode *inode, u64 sort_key) } } +/* Special case to better support in-place updates of backing WIM files: in + * WIMBOOT mode, if the file is backed by a WIM (perhaps the WIM being updated) + * and WOF is not attached to the volume, then capture the file as the + * "dereferenced file" rather than as the "pointer file". Note that this only + * requires stream manipulation --- there is no special handling of metadata + * such as security descriptors required. */ +static noinline_for_stack int +fixup_wim_backed_file(struct wim_inode *inode, struct blob_table *blob_table) +{ + struct wim_inode_stream *strm; + struct blob_descriptor *blob; + u8 _rpdata[REPARSE_DATA_MAX_SIZE] _aligned_attribute(8); + struct { + struct wof_external_info wof_info; + struct wim_provider_rpdata wim_info; + } *rpdata = (void *)_rpdata; + int ret; + + strm = inode_get_unnamed_stream(inode, STREAM_TYPE_REPARSE_POINT); + blob = stream_blob_resolved(strm); + if (!blob || blob->size < sizeof(*rpdata)) + return 0; + + ret = read_blob_into_buf(blob, rpdata); + if (ret) + return ret; + + if (rpdata->wof_info.version != WOF_CURRENT_VERSION || + rpdata->wof_info.provider != WOF_PROVIDER_WIM || + rpdata->wim_info.version != 2) + return 0; + + blob = lookup_blob(blob_table, rpdata->wim_info.unnamed_data_stream_hash); + if (!blob) + return 0; + + /* All okay --- remove the reparse point and redirect the unnamed data + * stream to the "dereferenced" one. */ + inode_remove_stream(inode, strm, blob_table); + strm = inode_get_unnamed_data_stream(inode); + wimlib_assert(strm != NULL); + inode_replace_stream_blob(inode, strm, blob, blob_table); + inode->i_attributes &= ~(FILE_ATTRIBUTE_REPARSE_POINT | + FILE_ATTRIBUTE_SPARSE_FILE); + if (inode->i_attributes == 0) + inode->i_attributes = FILE_ATTRIBUTE_NORMAL; + return 0; +} + static noinline_for_stack u32 get_volume_information(HANDLE h, const wchar_t *full_path, struct capture_params *params) @@ -1291,8 +1346,7 @@ retry_open: filename, file_info.ino, params->capture_root_dev, - (file_info.num_links <= 1 || - (file_info.attributes & FILE_ATTRIBUTE_DIRECTORY)), + (file_info.num_links <= 1), &root); if (ret) goto out; @@ -1385,6 +1439,15 @@ retry_open: goto out; } + if (unlikely((params->add_flags & WIMLIB_ADD_FLAG_WIMBOOT) && + (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_WOF))) + { + ret = fixup_wim_backed_file(inode, params->blob_table); + if (ret) + goto out; + } + set_sort_key(inode, sort_key); if (inode_is_directory(inode)) {