+out_replace:
+ {
+ utf16lechar utf16_name_copy[dentry->file_name_nbytes / 2];
+
+ memcpy(utf16_name_copy, dentry->file_name, dentry->file_name_nbytes);
+ file_name_valid(utf16_name_copy, dentry->file_name_nbytes / 2, true);
+
+ tchar *tchar_name;
+ size_t tchar_nchars;
+ #ifdef __WIN32__
+ tchar_name = utf16_name_copy;
+ tchar_nchars = dentry->file_name_nbytes / 2;
+ #else
+ ret = utf16le_to_tstr(utf16_name_copy,
+ dentry->file_name_nbytes,
+ &tchar_name, &tchar_nchars);
+ if (ret)
+ return ret;
+ #endif
+ size_t fixed_name_num_chars = tchar_nchars;
+ tchar fixed_name[tchar_nchars + 50];
+
+ tmemcpy(fixed_name, tchar_name, tchar_nchars);
+ fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars,
+ T(" (invalid filename #%lu)"),
+ ++ctx->invalid_sequence);
+ #ifndef __WIN32__
+ FREE(tchar_name);
+ #endif
+ dentry->extraction_name = memdup(fixed_name,
+ 2 * fixed_name_num_chars + 2);
+ if (!dentry->extraction_name)
+ return WIMLIB_ERR_NOMEM;
+ dentry->extraction_name_nchars = fixed_name_num_chars;
+ }
+ return 0;
+
+skip_dentry:
+ for_dentry_in_tree(dentry, dentry_mark_skipped, NULL);
+ return 0;
+}
+
+/* Clean up dentry and inode structure after extraction. */
+static int
+dentry_reset_needs_extraction(struct wim_dentry *dentry, void *_ignore)
+{
+ struct wim_inode *inode = dentry->d_inode;
+
+ dentry->extraction_skipped = 0;
+ dentry->was_hardlinked = 0;
+ inode->i_visited = 0;
+ FREE(inode->i_extracted_file);
+ inode->i_extracted_file = NULL;
+ if ((void*)dentry->extraction_name != (void*)dentry->file_name)
+ FREE(dentry->extraction_name);
+ dentry->extraction_name = NULL;
+ return 0;
+}
+
+/* Tally features necessary to extract a dentry and the corresponding inode. */
+static int
+dentry_tally_features(struct wim_dentry *dentry, void *_features)
+{
+ struct wim_features *features = _features;
+ struct wim_inode *inode = dentry->d_inode;
+
+ if (inode->i_attributes & FILE_ATTRIBUTE_ARCHIVE)
+ features->archive_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_HIDDEN)
+ features->hidden_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_SYSTEM)
+ features->system_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED)
+ features->compressed_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
+ features->encrypted_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+ features->not_context_indexed_files++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE)
+ features->sparse_files++;
+ if (inode_has_named_stream(inode))
+ features->named_data_streams++;
+ if (inode->i_visited)
+ features->hard_links++;
+ if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ features->reparse_points++;
+ if (inode_is_symlink(inode))
+ features->symlink_reparse_points++;
+ else
+ features->other_reparse_points++;
+ }
+ if (inode->i_security_id != -1)
+ features->security_descriptors++;
+ if (dentry->short_name_nbytes)
+ features->short_names++;
+ if (inode_has_unix_data(inode))
+ features->unix_data++;
+ inode->i_visited = 1;
+ return 0;
+}
+
+static int
+dentry_clear_inode_visited(struct wim_dentry *dentry, void *_ignore)
+{
+ dentry->d_inode->i_visited = 0;
+ return 0;
+}
+
+/* Tally the features necessary to extract a dentry tree. */
+static void
+dentry_tree_get_features(struct wim_dentry *root, struct wim_features *features)
+{
+ memset(features, 0, sizeof(struct wim_features));
+ for_dentry_in_tree(root, dentry_tally_features, features);
+ for_dentry_in_tree(root, dentry_clear_inode_visited, NULL);
+}
+
+static int
+do_feature_check(const struct wim_features *required_features,
+ const struct wim_features *supported_features,
+ int extract_flags,
+ const struct apply_operations *ops)
+{
+ if (required_features->archive_files && !supported_features->archive_files)
+ {
+ WARNING(
+ "%lu files are marked as archived, but this attribute\n"
+" is not supported in this extraction mode or volume.",
+ required_features->archive_files);
+ }
+
+ if (required_features->hidden_files && !supported_features->hidden_files)
+ {
+ WARNING(
+ "%lu files are marked as hidden, but this attribute\n"
+" is not supported in this extraction mode or volume.",
+ required_features->hidden_files);
+ }
+
+ if (required_features->system_files && !supported_features->system_files)
+ {
+ WARNING(
+ "%lu files are marked as system files, but this attribute\n"
+" is not supported in this extraction mode or volume.",
+ required_features->system_files);
+ }
+
+ if (required_features->compressed_files && !supported_features->compressed_files)
+ {
+ WARNING(
+ "%lu files are marked as being transparently compressed, but\n"
+" transparent compression is not supported in this extraction\n"
+" mode or volume. These files will be extracted as uncompressed.",
+ required_features->compressed_files);
+ }
+
+ if (required_features->encrypted_files && !supported_features->encrypted_files)
+ {
+ WARNING(
+ "%lu files are marked as being encrypted, but encryption is not\n"
+" supported in this extraction mode or volume. These files will be\n"
+" extracted as raw encrypted data instead.",
+ required_features->encrypted_files);
+ }
+
+ if (required_features->not_context_indexed_files &&
+ !supported_features->not_context_indexed_files)
+ {
+ WARNING(
+ "%lu files are marked as not content indexed, but this attribute\n"
+" is not supported in this extraction mode or volume.",
+ required_features->not_context_indexed_files);
+ }
+
+ if (required_features->sparse_files && !supported_features->sparse_files)
+ {
+ WARNING(
+ "%lu files are marked as sparse, but creating sparse files is not\n"
+" supported in this extraction mode or volume. These files will be\n"
+" extracted as non-sparse.",
+ required_features->not_context_indexed_files);
+ }
+
+ if (required_features->named_data_streams &&
+ !supported_features->named_data_streams)
+ {
+ WARNING(
+ "%lu files contain one or more alternate (named) data streams,\n"
+" which are not supported in this extraction mode or volume.\n"
+" Alternate data streams will NOT be extracted.",
+ required_features->named_data_streams);
+ }
+
+ if (unlikely(extract_flags & (WIMLIB_EXTRACT_FLAG_HARDLINK |
+ WIMLIB_EXTRACT_FLAG_SYMLINK)) &&
+ required_features->named_data_streams &&
+ supported_features->named_data_streams)
+ {
+ WARNING(
+ "%lu files contain one or more alternate (named) data streams,\n"
+" which are not supported in linked extraction mode.\n"
+" Alternate data streams will NOT be extracted.",
+ required_features->named_data_streams);
+ }
+
+ if (required_features->hard_links && !supported_features->hard_links)
+ {
+ WARNING(
+ "%lu files are hard links, but hard links are not supported in\n"
+" this extraction mode or volume. Hard links will be extracted as\n"
+" duplicate copies of the linked files.",
+ required_features->hard_links);
+ }
+
+ if (required_features->reparse_points && !supported_features->reparse_points)
+ {
+ if (supported_features->symlink_reparse_points) {
+ if (required_features->other_reparse_points) {
+ WARNING(
+ "%lu files are reparse points that are neither symbolic links\n"
+" nor junction points and are not supported in this extraction mode\n"
+" or volume. These reparse points will not be extracted.",
+ required_features->other_reparse_points);
+ }
+ } else {
+ WARNING(
+ "%lu files are reparse points, which are not supported in this\n"
+" extraction mode or volume and will not be extracted.",
+ required_features->reparse_points);
+ }
+ }
+
+ if (required_features->security_descriptors &&
+ !supported_features->security_descriptors)
+ {
+ WARNING(
+ "%lu files have Windows NT security descriptors, but extracting\n"
+" security descriptors is not supported in this extraction mode\n"
+" or volume. No security descriptors will be extracted.",
+ required_features->security_descriptors);
+ }
+
+ if (required_features->short_names && !supported_features->short_names)
+ {
+ WARNING(
+ "%lu files have short (DOS) names, but extracting short names\n"
+" is not supported in this extraction mode or volume. Short names\n"
+" will not be extracted.\n",
+ required_features->short_names);
+ }
+
+ if ((extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
+ required_features->unix_data && !supported_features->unix_data)
+ {
+ ERROR("UNIX data not supported in this extraction mode "
+ "or volume", ops->name);
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+ if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES) &&
+ required_features->short_names && !supported_features->short_names)
+ {
+ ERROR("Short names are not supported in this extraction "
+ "mode or volume", ops->name);
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+ if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS) &&
+ !ops->set_timestamps)
+ {
+ ERROR("Timestamps are not supported in this extraction "
+ "mode or volume", ops->name);
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+ if (((extract_flags & (WIMLIB_EXTRACT_FLAG_STRICT_ACLS |
+ WIMLIB_EXTRACT_FLAG_UNIX_DATA))
+ == WIMLIB_EXTRACT_FLAG_STRICT_ACLS) &&
+ required_features->security_descriptors &&
+ !supported_features->security_descriptors)
+ {
+ ERROR("Security descriptors not supported in this extraction "
+ "mode or volume.");
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+
+ if ((extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) &&
+ !supported_features->hard_links)