- DWORD err;
- USHORT compression_format = COMPRESSION_FORMAT_DEFAULT;
- DWORD bytes_returned;
-
- h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
- if (h == INVALID_HANDLE_VALUE)
- goto error;
-
- if (attributes & FILE_ATTRIBUTE_SPARSE_FILE)
- if (!DeviceIoControl(h, FSCTL_SET_SPARSE,
- NULL, 0,
- NULL, 0,
- &bytes_returned, NULL))
- goto error_close_handle;
-
- if (attributes & FILE_ATTRIBUTE_COMPRESSED)
- if (!DeviceIoControl(h, FSCTL_SET_COMPRESSION,
- &compression_format, sizeof(USHORT),
- NULL, 0,
- &bytes_returned, NULL))
- goto error_close_handle;
-
- if (!CloseHandle(h))
- goto error;
-
- if (attributes & FILE_ATTRIBUTE_ENCRYPTED)
- if (!EncryptFile(path))
- goto error;
-
- return TRUE;
-
-error_close_handle:
- err = GetLastError();
- CloseHandle(h);
- SetLastError(err);
-error:
- return FALSE;
+ NTSTATUS status;
+
+ if (unlikely(stream_name))
+ stream_name_nchars = wcslen(stream_name);
+
+ if (unlikely(stream_name_nchars)) {
+ build_extraction_path_with_ads(dentry, ctx,
+ stream_name, stream_name_nchars);
+ } else {
+ build_extraction_path(dentry, ctx);
+ }
+
+ /* Reparse point? */
+ if (unlikely(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (stream_name_nchars == 0))
+ {
+ if (!ctx->common.supported_features.reparse_points)
+ return 0;
+
+ /* We can't write the reparse stream directly; we must set it
+ * with FSCTL_SET_REPARSE_POINT, which requires that all the
+ * data be available. So, stage the data in a buffer. */
+
+ list_add_tail(&dentry->tmp_list, &ctx->reparse_dentries);
+ return prepare_data_buffer(ctx, stream->size);
+ }
+
+ /* Encrypted file? */
+ if (unlikely(inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)
+ && (stream_name_nchars == 0))
+ {
+ if (!ctx->common.supported_features.encrypted_files)
+ return 0;
+
+ /* We can't write encrypted file streams directly; we must use
+ * WriteEncryptedFileRaw(), which requires providing the data
+ * through a callback function. This can't easily be combined
+ * with our own callback-based approach.
+ *
+ * The current workaround is to simply read the stream into
+ * memory and write the encrypted file from that.
+ *
+ * TODO: This isn't sufficient for extremely large encrypted
+ * files. Perhaps we should create an extra thread to write
+ * such files... */
+ list_add_tail(&dentry->tmp_list, &ctx->encrypted_dentries);
+ return prepare_data_buffer(ctx, stream->size);
+ }
+
+ /* Extracting unnamed data stream in WIMBoot mode? */
+ if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)
+ && (stream_name_nchars == 0)
+ && (stream->resource_location == RESOURCE_IN_WIM)
+ && (stream->rspec->wim == ctx->common.wim)
+ && (stream->size == stream->rspec->uncompressed_size))
+ {
+ int ret = calculate_dentry_full_path(dentry);
+ if (ret)
+ return ret;
+ if (in_prepopulate_list(dentry, ctx)) {
+ union wimlib_progress_info info;
+
+ info.wimboot_exclude.path_in_wim = dentry->_full_path;
+ info.wimboot_exclude.extraction_path = current_path(ctx);
+
+ ret = call_progress(ctx->common.progfunc,
+ WIMLIB_PROGRESS_MSG_WIMBOOT_EXCLUDE,
+ &info, ctx->common.progctx);
+ FREE(dentry->_full_path);
+ dentry->_full_path = NULL;
+ if (ret)
+ return ret;
+ /* Go on and open the file for normal extraction. */
+ } else {
+ FREE(dentry->_full_path);
+ dentry->_full_path = NULL;
+ return wimboot_set_pointer(&ctx->attr,
+ current_path(ctx),
+ stream,
+ ctx->wimboot.data_source_id,
+ ctx->wimboot.wim_lookup_table_hash,
+ ctx->wimboot.wof_running);
+ }
+ }
+
+ /* Too many open handles? */
+ if (ctx->num_open_handles == MAX_OPEN_HANDLES) {
+ ERROR("Can't extract data: too many open files!");
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+
+ /* Open a new handle */
+ status = do_create_file(&h,
+ FILE_WRITE_DATA | SYNCHRONIZE,
+ NULL, 0, FILE_OPEN_IF,
+ FILE_SEQUENTIAL_ONLY |
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ ctx);
+ if (!NT_SUCCESS(status)) {
+ set_errno_from_nt_status(status);
+ ERROR_WITH_ERRNO("Can't open \"%ls\" for writing "
+ "(status=0x%08"PRIx32")",
+ current_path(ctx), (u32)status);
+ return WIMLIB_ERR_OPEN;
+ }
+
+ ctx->open_handles[ctx->num_open_handles++] = h;
+
+ /* Allocate space for the data. */
+ alloc_info.AllocationSize.QuadPart = stream->size;
+ (*func_NtSetInformationFile)(h, &ctx->iosb,
+ &alloc_info, sizeof(alloc_info),
+ FileAllocationInformation);
+ return 0;