do_overlay(): Do overlays recursively
authorEric Biggers <ebiggers3@gmail.com>
Thu, 25 Apr 2013 01:33:49 +0000 (20:33 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 25 Apr 2013 01:33:49 +0000 (20:33 -0500)
src/add_image.c
src/dentry.c
src/dentry.h
tests/test-imagex-capture_and_apply

index 2a7f938..3b498c1 100644 (file)
@@ -620,9 +620,7 @@ new_filler_directory(const tchar *name, struct wim_dentry **dentry_ret)
        return 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)
 {
 static int
 do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
 {
@@ -631,30 +629,36 @@ do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
        DEBUG("Doing overlay \"%"WS"\" => \"%"WS"\"",
              branch->file_name, target->file_name);
 
        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);
                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);
                /* 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;
                }
        }
        free_dentry(branch);
        return 0;
-
 }
 
 /* Attach or overlay a branch onto the WIM image.
 }
 
 /* Attach or overlay a branch onto the WIM image.
index 5da7e8d..8f591c3 100644 (file)
@@ -927,7 +927,7 @@ free_dentry_tree(struct wim_dentry *root, struct wim_lookup_table *lookup_table)
  * @parent: The dentry that will be the parent of @dentry.
  * @dentry: The dentry to link.
  */
  * @parent: The dentry that will be the parent of @dentry.
  * @dentry: The dentry to link.
  */
-bool
+struct wim_dentry *
 dentry_add_child(struct wim_dentry * restrict parent,
                 struct wim_dentry * restrict child)
 {
 dentry_add_child(struct wim_dentry * restrict parent,
                 struct wim_dentry * restrict child)
 {
@@ -948,12 +948,12 @@ dentry_add_child(struct wim_dentry * restrict parent,
                else if (result > 0)
                        new = &((*new)->rb_right);
                else
                else if (result > 0)
                        new = &((*new)->rb_right);
                else
-                       return false;
+                       return this;
        }
        child->parent = parent;
        rb_link_node(&child->rb_node, rb_parent, new);
        rb_insert_color(&child->rb_node, root);
        }
        child->parent = parent;
        rb_link_node(&child->rb_node, rb_parent, new);
        rb_insert_color(&child->rb_node, root);
-       return true;
+       return NULL;
 }
 
 /* Unlink a WIM dentry from the directory entry tree. */
 }
 
 /* Unlink a WIM dentry from the directory entry tree. */
index 5e42e91..9ff234d 100644 (file)
@@ -411,7 +411,7 @@ free_dentry_tree(struct wim_dentry *root,
 extern void
 unlink_dentry(struct wim_dentry *dentry);
 
 extern void
 unlink_dentry(struct wim_dentry *dentry);
 
-extern bool
+extern struct wim_dentry *
 dentry_add_child(struct wim_dentry * restrict parent,
                 struct wim_dentry * restrict child);
 
 dentry_add_child(struct wim_dentry * restrict parent,
                 struct wim_dentry * restrict child);
 
index 90145e3..5de3b0e 100755 (executable)
@@ -153,6 +153,7 @@ then
 fi
 
 # Make sure source list mode is working as expected
 fi
 
 # Make sure source list mode is working as expected
+__msg "Testing source list capture mode"
 rm -rf in.dir out.dir
 mkdir in.dir
 echo 1 > in.dir/1
 rm -rf in.dir out.dir
 mkdir in.dir
 echo 1 > in.dir/1
@@ -189,7 +190,38 @@ imagex capture srclist --source-list test.wim
 imagex apply test.wim out.dir
 if [[ ! -f out.dir/5 || ! -f out.dir/1 || ! -f out.dir/1link || \
       ! -f out.dir/otherdir/A || ! -f out.dir/otherdir/B ]]; then
 imagex apply test.wim out.dir
 if [[ ! -f out.dir/5 || ! -f out.dir/1 || ! -f out.dir/1link || \
       ! -f out.dir/otherdir/A || ! -f out.dir/otherdir/B ]]; then
-       error "source list capture (with quoted names and overlay) failed to work as expected"
+       error "source list capture (with quoted names and basic overlay) failed to work as expected"
+fi
+
+# Try deep overlay
+rm -rf in.dir out.dir "overlay dir 1" "overlay dir 2"
+mkdir -p in.dir.1/subdir/subdir2 in.dir.2/subdir/subdir2
+cat > srclist << EOF
+in.dir.1       /
+in.dir.2       /
+EOF
+echo 1 > in.dir.1/subdir/1
+echo 2 > in.dir.2/subdir/2
+echo 3 > in.dir.1/subdir/subdir2/3
+echo 4 > in.dir.2/subdir/subdir2/4
+imagex capture srclist --source-list test.wim
+imagex apply test.wim out.dir
+if [[ ! -f out.dir/subdir/1 || ! -f out.dir/subdir/2 ||        \
+       ! -f out.dir/subdir/subdir2/3 || ! -f out.dir/subdir/subdir2/4 ]]; then
+       error "source list capture (with deep overlay) failed to work as expected"
+fi
+
+# Try bad overlay
+__msg "Testing bad overlay (errors expected)"
+rm -rf out.dir
+echo 5 > 5
+cat > srclist << EOF
+in.dir.1       /
+in.dir.2       /
+5              /subdir
+EOF
+if imagex capture srclist --source-list test.wim; then
+       error "unexpected success in bad overlay with --source-list!"
 fi
 
 echo "**********************************************************"
 fi
 
 echo "**********************************************************"