+/* Strip leading and trailing forward slashes from a string. Modifies it in
+ * place and returns the stripped string. */
+static const char *
+canonicalize_target_path(char *target_path)
+{
+ char *p;
+ if (target_path == NULL)
+ return "";
+ for (;;) {
+ if (*target_path == '\0')
+ return target_path;
+ else if (*target_path == '/')
+ target_path++;
+ else
+ break;
+ }
+
+ p = target_path + strlen(target_path) - 1;
+ while (*p == '/')
+ *p-- = '\0';
+ return target_path;
+}
+
+#ifdef __WIN32__
+static void
+zap_backslashes(char *s)
+{
+ while (*s) {
+ if (*s == '\\')
+ *s = '/';
+ s++;
+ }
+}
+#endif
+
+/* Strip leading and trailing slashes from the target paths */
+static void
+canonicalize_targets(struct wimlib_capture_source *sources, size_t num_sources)
+{
+ while (num_sources--) {
+ DEBUG("Canonicalizing { source: \"%s\", target=\"%s\"}",
+ sources->fs_source_path,
+ sources->wim_target_path);
+#ifdef __WIN32__
+ /* The Windows API can handle forward slashes. Just get rid of
+ * backslashes to avoid confusing other parts of the library
+ * code. */
+ zap_backslashes(sources->fs_source_path);
+ if (sources->wim_target_path)
+ zap_backslashes(sources->wim_target_path);
+#endif
+ sources->wim_target_path =
+ (char*)canonicalize_target_path(sources->wim_target_path);
+ DEBUG("Canonical target: \"%s\"", sources->wim_target_path);
+ sources++;
+ }
+}
+
+static int
+capture_source_cmp(const void *p1, const void *p2)
+{
+ const struct wimlib_capture_source *s1 = p1, *s2 = p2;
+ return strcmp(s1->wim_target_path, s2->wim_target_path);
+}
+
+/* Sorts the capture sources lexicographically by target path. This occurs
+ * after leading and trailing forward slashes are stripped.
+ *
+ * One purpose of this is to make sure that target paths that are inside other
+ * target paths are added after the containing target paths. */
+static void
+sort_sources(struct wimlib_capture_source *sources, size_t num_sources)
+{
+ qsort(sources, num_sources, sizeof(sources[0]), capture_source_cmp);
+}
+
+static int
+check_sorted_sources(struct wimlib_capture_source *sources, size_t num_sources,
+ int add_image_flags)
+{
+ 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)