From: Eric Biggers Date: Thu, 25 Apr 2013 01:33:49 +0000 (-0500) Subject: do_overlay(): Do overlays recursively X-Git-Tag: v1.3.3~46 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=594502d26951aa89e374599de862486c1e7a6878;ds=sidebyside do_overlay(): Do overlays recursively --- diff --git a/src/add_image.c b/src/add_image.c index 2a7f938e..3b498c14 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -620,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) { @@ -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); - 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. diff --git a/src/dentry.c b/src/dentry.c index 5da7e8db..8f591c3d 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -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. */ -bool +struct wim_dentry * 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 - return false; + return this; } 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. */ diff --git a/src/dentry.h b/src/dentry.h index 5e42e91f..9ff234d5 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -411,7 +411,7 @@ free_dentry_tree(struct wim_dentry *root, 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); diff --git a/tests/test-imagex-capture_and_apply b/tests/test-imagex-capture_and_apply index 90145e30..5de3b0e2 100755 --- a/tests/test-imagex-capture_and_apply +++ b/tests/test-imagex-capture_and_apply @@ -153,6 +153,7 @@ then 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 @@ -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 - 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 "**********************************************************"