]> wimlib.net Git - wimlib/blobdiff - src/add_image.c
do_overlay(): Do overlays recursively
[wimlib] / src / add_image.c
index e45bc1c1449b9efd72f51a7aa3cae7db4131b060..3b498c142f2de97c2620cab9f058edecafbde8b9 100644 (file)
@@ -179,53 +179,6 @@ unix_capture_directory(struct wim_dentry *dir_dentry,
        return ret;
 }
 
-static char *
-fixup_symlink(char *dest, ino_t capture_root_ino, dev_t capture_root_dev)
-{
-       char *p = dest;
-       struct stat stbuf;
-
-       for (;;) {
-               char save;
-               int ret;
-
-               while (*p == '/')
-                       p++;
-
-               save = *p;
-               *p = '\0';
-               if (stat(dest, &stbuf)) {
-                       WARNING_WITH_ERRNO("Failed to stat \"%s\": %m", dest);
-                       *p = save;
-                       /* Treat as a link pointing outside the capture root (it
-                        * most likely is). */
-                       return NULL;
-               }
-               *p = save;
-
-               if (stbuf.st_ino == capture_root_ino &&
-                   stbuf.st_dev == capture_root_dev)
-               {
-                       /* Link points inside capture root.  Return abbreviated
-                        * path. */
-                       if (*p == '\0')
-                               *(p - 1) = '/';
-                       while (p - 1 >= dest && *(p - 1) == '/')
-                               p--;
-                       return p;
-               }
-
-               if (*p == '\0') {
-                       /* Link points outside capture root. */
-                       return NULL;
-               }
-
-               do {
-                       p++;
-               } while (*p != '/' && *p != '\0');
-       }
-}
-
 static int
 unix_capture_symlink(struct wim_dentry **root_p,
                     const char *path,
@@ -269,6 +222,7 @@ unix_capture_symlink(struct wim_dentry **root_p,
                                *root_p = NULL;
                                return 0;
                        }
+                       inode->i_not_rpfixed = 0;
                }
                ret = inode_set_symlink(inode, dest,
                                        params->lookup_table, NULL);
@@ -302,11 +256,6 @@ unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        struct wim_inode *inode;
 
        if (exclude_path(path, path_len, params->config, true)) {
-               if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
-                       ERROR("Cannot exclude the root directory from capture");
-                       ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
-                       goto out;
-               }
                if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
                    && params->progress_func)
                {
@@ -434,7 +383,9 @@ unix_build_dentry_tree(struct wim_dentry **root_ret,
                        return WIMLIB_ERR_STAT;
                }
 
-               if (!S_ISDIR(root_stbuf.st_mode)) {
+               if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
+                   !S_ISDIR(root_stbuf.st_mode))
+               {
                        ERROR("Root of capture \"%s\" is not a directory",
                              root_disk_path);
                        return WIMLIB_ERR_NOTDIR;
@@ -669,9 +620,7 @@ new_filler_directory(const tchar *name, struct wim_dentry **dentry_ret)
        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. */
+/* Overlays @branch onto @target, both of which must be directories. */
 static int
 do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
 {
@@ -680,30 +629,36 @@ do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
        DEBUG("Doing overlay \"%"WS"\" => \"%"WS"\"",
              branch->file_name, target->file_name);
 
-       if (!dentry_is_directory(target)) {
-               ERROR("Cannot overlay directory \"%"WS"\" "
-                     "over non-directory", branch->file_name);
+       if (!dentry_is_directory(branch) || !dentry_is_directory(target)) {
+               ERROR("Cannot overlay \"%"WS"\" onto existing dentry: "
+                     "is not directory-on-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);
+               struct wim_dentry *existing;
+
                /* 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 \"%"WS"\" already exists "
-                             "as a child of \"%"WS"\"",
-                             child->file_name, target->file_name);
-                       return WIMLIB_ERR_INVALID_OVERLAY;
+               existing = dentry_add_child(target, child);
+
+               /* File or directory with same name already exists */
+               if (existing) {
+                       int ret;
+                       ret = do_overlay(existing, child);
+                       if (ret) {
+                               /* Overlay failed.  Revert the change to avoid
+                                * leaking the directory tree rooted at @child.
+                                * */
+                               dentry_add_child(branch, child);
+                               return ret;
+                       }
                }
        }
        free_dentry(branch);
        return 0;
-
 }
 
 /* Attach or overlay a branch onto the WIM image.
@@ -911,8 +866,13 @@ wimlib_add_image_multisource(WIMStruct *w,
 
        if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
                                WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == 0)
-               if (w->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+       {
+               /* Do reparse-point fixups by default if the header flag is set
+                * from previous images, or if this is the first image being
+                * added. */
+               if ((w->hdr.flags & WIM_HDR_FLAG_RP_FIX) || w->hdr.image_count == 0)
                        add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+       }
 
        if (!name || !*name) {
                ERROR("Must specify a non-empty string for the image name");