# include "config.h"
#endif
+#include <errno.h>
#include <locale.h>
#include <string.h>
desc_size = sd->sizes[inode->i_security_id];
ret = ntfs_3g_set_security_descriptor(ni, desc, desc_size);
- if (ret) {
- if (wimlib_print_errors) {
- ERROR_WITH_ERRNO("Failed to set security descriptor "
- "on \"%s\" in NTFS volume",
- dentry_full_path(one_dentry));
+
+ if (unlikely(ret)) {
+ int err = errno;
+ ERROR_WITH_ERRNO("Failed to set security descriptor on "
+ "\"%s\" in NTFS volume",
+ dentry_full_path(one_dentry));
+ if (err == EINVAL && wimlib_print_errors) {
fprintf(wimlib_error_file,
"The security descriptor is: ");
print_byte_field(desc, desc_size, wimlib_error_file);
fprintf(wimlib_error_file, "\n");
+ fprintf(wimlib_error_file,
+ "\nThis error occurred because libntfs-3g thinks "
+ "the security descriptor is invalid. If you "
+ "are extracting a Windows 10 image, this may be "
+ "caused by a known bug in libntfs-3g. See: "
+ "http://wimlib.net/forums/viewtopic.php?f=1&t=4 "
+ "for more information.\n\n");
}
return ret;
}
root->d_inode->i_mft_no = FILE_root;
- ret = ntfs_3g_create_dirs_recursive(root_ni, root, ctx);
+ ret = ntfs_3g_set_metadata(root_ni, root->d_inode, ctx);
+ if (!ret)
+ ret = ntfs_3g_create_empty_attributes(root_ni, root->d_inode, ctx);
+ if (!ret)
+ ret = ntfs_3g_create_dirs_recursive(root_ni, root, ctx);
if (ntfs_inode_close(root_ni) && !ret) {
ERROR_WITH_ERRNO("Error closing root of NTFS volume");
struct ntfs_3g_apply_ctx *ctx)
{
struct wim_dentry *one_dentry = inode_first_extraction_dentry(inode);
+ ntfschar *stream_name;
size_t stream_name_nchars;
ntfs_attr *attr;
/* It's a data stream (may be unnamed or named). */
wimlib_assert(strm->stream_type == STREAM_TYPE_DATA);
- stream_name_nchars = utf16le_len_chars(strm->stream_name);
+ if (unlikely(stream_is_named(strm))) {
+ stream_name = strm->stream_name;
+ stream_name_nchars = utf16le_len_chars(stream_name);
- if (stream_name_nchars &&
- (ntfs_attr_add(ni, AT_DATA, strm->stream_name,
- stream_name_nchars, NULL, 0)))
- {
- ERROR_WITH_ERRNO("Failed to create named data stream of \"%s\"",
- dentry_full_path(one_dentry));
- return WIMLIB_ERR_NTFS_3G;
+ if (ntfs_attr_add(ni, AT_DATA, stream_name,
+ stream_name_nchars, NULL, 0))
+ {
+ ERROR_WITH_ERRNO("Failed to create named data stream of \"%s\"",
+ dentry_full_path(one_dentry));
+ return WIMLIB_ERR_NTFS_3G;
+ }
+ } else {
+ /* Don't pass an empty string other than AT_UNNAMED to
+ * ntfs_attr_open() --- it violates assumptions made by
+ * libntfs-3g. */
+ stream_name = AT_UNNAMED;
+ stream_name_nchars = 0;
}
/* This should be ensured by extract_blob_list() */
wimlib_assert(ctx->num_open_attrs < MAX_OPEN_FILES);
- attr = ntfs_attr_open(ni, AT_DATA, strm->stream_name,
- stream_name_nchars);
+ attr = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_nchars);
if (!attr) {
ERROR_WITH_ERRNO("Failed to open data stream of \"%s\"",
dentry_full_path(one_dentry));
return ret;
}
+/* Note: contrary to its documentation, ntfs_attr_pwrite() can return a short
+ * count in non-error cases --- specifically, when writing to a compressed
+ * attribute and the requested count exceeds the size of an NTFS "compression
+ * block". Therefore, we must continue calling ntfs_attr_pwrite() until all
+ * bytes have been written or a real error has occurred. */
+static bool
+ntfs_3g_full_pwrite(ntfs_attr *na, u64 offset, size_t size, const u8 *data)
+{
+ while (size) {
+ s64 res = ntfs_attr_pwrite(na, offset, size, data);
+ if (unlikely(res <= 0))
+ return false;
+ wimlib_assert(res <= size);
+ offset += res;
+ size -= res;
+ data += res;
+ }
+ return true;
+}
+
static int
ntfs_3g_extract_chunk(const void *chunk, size_t size, void *_ctx)
{
struct ntfs_3g_apply_ctx *ctx = _ctx;
- s64 res;
for (unsigned i = 0; i < ctx->num_open_attrs; i++) {
- res = ntfs_attr_pwrite(ctx->open_attrs[i],
- ctx->offset, size, chunk);
- if (res != size) {
+ if (!ntfs_3g_full_pwrite(ctx->open_attrs[i],
+ ctx->offset, size, chunk))
+ {
ERROR_WITH_ERRNO("Error writing data to NTFS volume");
return WIMLIB_ERR_NTFS_3G;
}