+ DEBUG("Extracted encrypted file \"%ls\"", path);
+ }
+ *creationDisposition_ret = OPEN_EXISTING;
+ }
+
+ /* Set file attributes if we created the file. Otherwise, we haven't
+ * created the file set and we will set the attributes in the call to
+ * CreateFileW().
+ *
+ * The FAT filesystem does not let you change the attributes of the root
+ * directory, so treat that as a special case and do not set attributes.
+ * */
+ if (*creationDisposition_ret == OPEN_EXISTING &&
+ !path_is_root_of_drive(path))
+ {
+ if (!SetFileAttributesW(path,
+ win32_mask_attributes(inode->i_attributes)))
+ {
+ err = GetLastError();
+ ERROR("Failed to set attributes on \"%ls\"", path);
+ win32_error(err);
+ return WIMLIB_ERR_WRITE;
+ }
+ }
+ return 0;
+}
+
+/* Set security descriptor and extract stream data or reparse data (skip the
+ * unnamed data stream of encrypted files, which was already extracted). */
+static int
+win32_finish_extract_stream(HANDLE h, const struct wim_inode *inode,
+ const struct wim_lookup_table_entry *lte,
+ const wchar_t *stream_path,
+ const wchar_t *stream_name_utf16,
+ struct apply_args *args)
+{
+ int ret = 0;
+ if (stream_name_utf16 == NULL) {
+ /* Unnamed stream. */
+
+ /* Set security descriptor, unless the extract_flags indicate
+ * not to or the volume does not supported it. Note that this
+ * is only done when the unnamed stream is being extracted, as
+ * security descriptors are per-file and not per-stream. */
+ if (inode->i_security_id >= 0 &&
+ !(args->extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS)
+ && (args->vol_flags & FILE_PERSISTENT_ACLS))
+ {
+ ret = win32_set_security_data(inode, h, stream_path, args);
+ if (ret)
+ return ret;
+ }
+
+ /* Handle reparse points. The data for them needs to be set
+ * using a special ioctl. Note that the reparse point may have
+ * been created using CreateFileW() in the case of
+ * non-directories or CreateDirectoryW() in the case of
+ * directories; but the ioctl works either way. Also, it is
+ * only this step that actually sets the
+ * FILE_ATTRIBUTE_REPARSE_POINT, as it is not valid to set it
+ * using SetFileAttributesW() or CreateFileW().
+ *
+ * If the volume does not support reparse points we simply
+ * ignore the reparse data. (N.B. the code currently doesn't
+ * actually reach this case because reparse points are skipped
+ * entirely on such volumes.) */
+ if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ if (args->vol_flags & FILE_SUPPORTS_REPARSE_POINTS) {
+ ret = win32_set_reparse_data(h, inode,
+ lte, stream_path,
+ args);
+ if (ret)
+ return ret;
+ } else {
+ DEBUG("Cannot set reparse data on \"%ls\": volume "
+ "does not support reparse points", stream_path);
+ }
+ } else if (lte != NULL &&
+ !(args->vol_flags & FILE_SUPPORTS_ENCRYPTION &&
+ inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED))
+ {
+ /* Extract the data of the unnamed stream, unless the
+ * lookup table entry is NULL (indicating an empty
+ * stream for which no data needs to be extracted), or
+ * the stream is encrypted and therefore was already
+ * extracted as a special case. */
+ ret = do_win32_extract_stream(h, lte);
+ }
+ } else {
+ /* Extract the data for a named data stream. */
+ if (lte != NULL) {
+ DEBUG("Extracting named data stream \"%ls\" (len = %"PRIu64")",
+ stream_path, wim_resource_size(lte));
+ ret = do_win32_extract_stream(h, lte);