+ ret = -1;
+
+ utf8_name = utf16_to_utf8((const char*)name, name_len * 2,
+ &utf8_name_len);
+ if (!utf8_name)
+ goto out;
+
+ if (utf8_name[0] == '.' &&
+ (utf8_name[1] == '\0' ||
+ (utf8_name[1] == '.' && utf8_name[2] == '\0'))) {
+ ret = 0;
+ goto out_free_utf8_name;
+ }
+
+ ctx = dirent;
+
+ ntfs_inode *ni = ntfs_inode_open(ctx->dir_ni->vol, mref);
+ if (!ni) {
+ ERROR_WITH_ERRNO("Failed to open NTFS inode");
+ goto out_free_utf8_name;
+ }
+ path_len = ctx->path_len;
+ if (path_len != 1)
+ ctx->path[path_len++] = '/';
+ memcpy(ctx->path + path_len, utf8_name, utf8_name_len + 1);
+ path_len += utf8_name_len;
+ ret = build_dentry_tree_ntfs_recursive(&child, ctx->dir_ni,
+ ni, ctx->path, path_len, name_type,
+ ctx->lookup_table, ctx->sd_set,
+ ctx->config, ctx->ntfs_vol_p,
+ ctx->flags);
+
+ if (child)
+ dentry_add_child(ctx->parent, child);
+
+ ntfs_inode_close(ni);
+out_free_utf8_name:
+ FREE(utf8_name);
+out:
+ return ret;
+}
+
+static int change_dentry_short_name(struct dentry *dentry,
+ const char short_name_utf8[],
+ int short_name_utf8_len)
+{
+ size_t short_name_utf16_len;
+ char *short_name_utf16;
+ short_name_utf16 = utf8_to_utf16(short_name_utf8, short_name_utf8_len,
+ &short_name_utf16_len);
+ if (!short_name_utf16) {
+ ERROR_WITH_ERRNO("Failed to convert short name to UTF-16");
+ return WIMLIB_ERR_NOMEM;
+ }
+ dentry->short_name = short_name_utf16;
+ dentry->short_name_len = short_name_utf16_len;
+ return 0;
+}
+
+/* Recursively build a WIM dentry tree corresponding to a NTFS volume.
+ * At the same time, update the WIM lookup table with lookup table entries for
+ * the NTFS streams, and build an array of security descriptors.
+ */
+static int build_dentry_tree_ntfs_recursive(struct dentry **root_p,
+ ntfs_inode *dir_ni,
+ ntfs_inode *ni,
+ char path[],
+ size_t path_len,
+ int name_type,
+ struct lookup_table *lookup_table,
+ struct sd_set *sd_set,
+ const struct capture_config *config,
+ ntfs_volume **ntfs_vol_p,
+ int flags)
+{
+ u32 attributes;
+ int mrec_flags;
+ int ret;
+ char dos_name_utf8[64];
+ struct dentry *root;
+
+ mrec_flags = ni->mrec->flags;
+ struct SECURITY_CONTEXT ctx;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.vol = ni->vol;
+ ret = ntfs_xattr_system_getxattr(&ctx, XATTR_NTFS_ATTRIB,
+ ni, dir_ni, (char *)&attributes,
+ sizeof(u32));
+ if (ret != 4) {
+ ERROR_WITH_ERRNO("Failed to get NTFS attributes from `%s'",
+ path);
+ return WIMLIB_ERR_NTFS_3G;
+ }
+
+ if (exclude_path(path, config, false)) {
+ if (flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) {
+ const char *file_type;
+ if (attributes & MFT_RECORD_IS_DIRECTORY)
+ file_type = "directory";
+ else
+ file_type = "file";
+ printf("Excluding %s `%s' from capture\n",
+ file_type, path);
+ }
+ *root_p = NULL;
+ return 0;
+ }
+
+ if (flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
+ printf("Scanning `%s'\n", path);
+
+ root = new_dentry_with_timeless_inode(path_basename(path));
+ if (!root)
+ return WIMLIB_ERR_NOMEM;
+ *root_p = root;
+
+ if (dir_ni && (name_type == FILE_NAME_WIN32_AND_DOS
+ || name_type == FILE_NAME_WIN32))
+ {
+ ret = ntfs_get_ntfs_dos_name(ni, dir_ni, dos_name_utf8,
+ sizeof(dos_name_utf8));
+ if (ret > 0) {
+ DEBUG("Changing short name of `%s'", path);
+ ret = change_dentry_short_name(root, dos_name_utf8,
+ ret);
+ if (ret != 0)
+ return ret;
+ } else {
+ #ifdef ENODATA
+ if (errno != ENODATA) {
+ ERROR_WITH_ERRNO("Error getting DOS name "
+ "of `%s'", path);
+ return WIMLIB_ERR_NTFS_3G;
+ }
+ #endif
+ }
+ }
+
+ root->d_inode->creation_time = le64_to_cpu(ni->creation_time);
+ root->d_inode->last_write_time = le64_to_cpu(ni->last_data_change_time);
+ root->d_inode->last_access_time = le64_to_cpu(ni->last_access_time);
+ root->d_inode->attributes = le32_to_cpu(attributes);
+ root->d_inode->ino = ni->mft_no;
+ root->d_inode->resolved = true;