+ if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
+ if (num_sources != 1) {
+ ERROR("Must specify exactly 1 capture source "
+ "(the NTFS volume) in NTFS mode!");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ if (sources[0].wim_target_path[0] != '\0') {
+ ERROR("In NTFS capture mode the target path inside "
+ "the image must be the root directory!");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ } else if (num_sources != 0) {
+ /* This code is disabled because the current code
+ * unconditionally attempts to do overlays. So, duplicate
+ * target paths are OK. */
+ #if 0
+ if (num_sources > 1 && sources[0].wim_target_path[0] == '\0') {
+ ERROR("Cannot specify root target when using multiple "
+ "capture sources!");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ for (size_t i = 0; i < num_sources - 1; i++) {
+ size_t len = strlen(sources[i].wim_target_path);
+ size_t j = i + 1;
+ const char *target1 = sources[i].wim_target_path;
+ do {
+ const char *target2 = sources[j].wim_target_path;
+ DEBUG("target1=%s, target2=%s",
+ target1,target2);
+ if (strncmp(target1, target2, len) ||
+ target2[len] > '/')
+ break;
+ if (target2[len] == '/') {
+ ERROR("Invalid target `%s': is a prefix of `%s'",
+ target1, target2);
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ if (target2[len] == '\0') {
+ ERROR("Invalid target `%s': is a duplicate of `%s'",
+ target1, target2);
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+ } while (++j != num_sources);
+ }
+ #endif
+ }
+ return 0;
+
+}
+
+/* Creates a new directory to place in the WIM image. This is to create parent
+ * directories that are not part of any target as needed. */
+static int
+new_filler_directory(const mbchar *name, struct wim_dentry **dentry_ret)
+{
+ int ret;
+ struct wim_dentry *dentry;
+
+ DEBUG("Creating filler directory \"%s\"", name);
+ ret = new_dentry_with_inode(name, &dentry);
+ if (ret == 0) {
+ /* Leave the inode number as 0 for now. The final inode number
+ * will be assigned later by assign_inode_numbers(). */
+ dentry->d_inode->i_resolved = 1;
+ dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ *dentry_ret = dentry;
+ }
+ return ret;
+}
+
+/* Transfers the children of @branch to @target. It is an error if @target is
+ * not a directory or if both @branch and @target contain a child dentry with
+ * the same name. */
+static int
+do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
+{
+ struct rb_root *rb_root;
+
+ DEBUG("Doing overlay \"%W\" => \"%W\"",
+ branch->file_name, target->file_name);
+
+ if (!dentry_is_directory(target)) {
+ ERROR("Cannot overlay directory \"%W\" over non-directory",
+ branch->file_name);
+ return WIMLIB_ERR_INVALID_OVERLAY;
+ }
+
+ rb_root = &branch->d_inode->i_children;
+ while (rb_root->rb_node) { /* While @branch has children... */
+ struct wim_dentry *child = rbnode_dentry(rb_root->rb_node);
+ /* Move @child to the directory @target */
+ unlink_dentry(child);
+ if (!dentry_add_child(target, child)) {
+ /* Revert the change to avoid leaking the directory tree
+ * rooted at @child */
+ dentry_add_child(branch, child);
+ ERROR("Overlay error: file \"%W\" already exists "
+ "as a child of \"%W\"",
+ child->file_name, target->file_name);
+ return WIMLIB_ERR_INVALID_OVERLAY;
+ }
+ }
+ free_dentry(branch);
+ return 0;
+
+}
+
+/* Attach or overlay a branch onto the WIM image.
+ *
+ * @root_p:
+ * Pointer to the root of the WIM image, or pointer to NULL if it has not
+ * been created yet.
+ * @branch
+ * Branch to add.
+ * @target_path:
+ * Path in the WIM image to add the branch, with leading and trailing
+ * slashes stripped.
+ */
+static int
+attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch,
+ mbchar *target_path)
+{
+ mbchar *slash;
+ struct wim_dentry *dentry, *parent, *target;
+ int ret;
+
+ DEBUG("Attaching branch \"%W\" => \"%s\"",
+ branch->file_name, target_path);
+
+ if (*target_path == '\0') {
+ /* Target: root directory */
+ if (*root_p) {
+ /* Overlay on existing root */
+ return do_overlay(*root_p, branch);
+ } else {
+ /* Set as root */
+ *root_p = branch;
+ return 0;
+ }
+ }
+
+ /* Adding a non-root branch. Create root if it hasn't been created
+ * already. */
+ if (!*root_p) {
+ ret = new_filler_directory("", root_p);
+ if (ret)
+ return ret;
+ }
+
+ /* Walk the path to the branch, creating filler directories as needed.
+ * */
+ parent = *root_p;
+ while ((slash = strchr(target_path, '/'))) {
+ *slash = '\0';
+ dentry = get_dentry_child_with_name(parent, target_path);
+ if (!dentry) {
+ ret = new_filler_directory(target_path, &dentry);
+ if (ret)
+ return ret;
+ dentry_add_child(parent, dentry);
+ }
+ parent = dentry;
+ target_path = slash;
+ /* Skip over slashes. Note: this cannot overrun the length of
+ * the string because the last character cannot be a slash, as
+ * trailing slashes were tripped. */
+ do {
+ ++target_path;
+ } while (*target_path == '/');
+ }
+
+ /* If the target path already existed, overlay the branch onto it.
+ * Otherwise, set the branch as the target path. */
+ target = get_dentry_child_with_utf16le_name(parent, branch->file_name,
+ branch->file_name_nbytes);
+ if (target) {
+ return do_overlay(target, branch);
+ } else {
+ dentry_add_child(parent, branch);
+ return 0;
+ }
+}
+
+WIMLIBAPI int
+wimlib_add_image_multisource(WIMStruct *w,
+ struct wimlib_capture_source *sources,
+ size_t num_sources,
+ const utf8char *name,
+ const mbchar *config_str,
+ size_t config_len,
+ int add_image_flags,
+ wimlib_progress_func_t progress_func)
+{
+ int (*capture_tree)(struct wim_dentry **,
+ const mbchar *,
+ struct wim_lookup_table *,