diff options
author | Richard Maw <richard.maw@codethink.co.uk> | 2011-10-13 16:03:34 +0100 |
---|---|---|
committer | Richard Maw <richard.maw@codethink.co.uk> | 2011-10-13 16:03:34 +0100 |
commit | c131cb9586bfdd5ce19c33639e908b89c44104d7 (patch) | |
tree | 0dad02a08f19141362e11343b74c283f75bd126f | |
parent | 1e9d1410e355d8ad0ab1cdcc12c396e0670882c0 (diff) | |
download | tbdiff-c131cb9586bfdd5ce19c33639e908b89c44104d7.tar.gz |
Tests and fix for a horrific bug where removing a symlink to a
directory would remove the directory
-rw-r--r-- | libtbd_apply.c | 66 | ||||
-rwxr-xr-x | tests/05_symlink_add_remove.sh | 26 |
2 files changed, 59 insertions, 33 deletions
diff --git a/libtbd_apply.c b/libtbd_apply.c index 62b1399..2e62087 100644 --- a/libtbd_apply.c +++ b/libtbd_apply.c @@ -320,45 +320,61 @@ tbd_apply_cmd_file_delta(FILE *stream) return 0; } -static int -tbd_apply_cmd_entity_delete_for_name(const char *name) +static int tbd_apply_cmd_entity_delete_for_name(const char*); +static int tbd_apply_cmd_dir_delete(const char *name) { - DIR *dp = opendir(name); - if(dp == NULL) { - if(remove(name) != 0) - return TBD_ERROR(TBD_ERROR_UNABLE_TO_REMOVE_FILE); - - return 0; + int err = TBD_ERROR_SUCCESS; + DIR *dp; + struct dirent *entry; + if ((dp = opendir(name)) == NULL) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_REMOVE_FILE); } - if(chdir(name) != 0) { + if (chdir(name) != 0) { closedir(dp); return TBD_ERROR(TBD_ERROR_UNABLE_TO_CHANGE_DIR); } - struct dirent *entry; - - while((entry = readdir(dp)) != NULL) { - if((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) + while ((entry = readdir(dp)) != NULL) { + if ((strcmp(entry->d_name, ".") == 0) || + (strcmp(entry->d_name, "..") == 0)) { continue; + } + if ((err = tbd_apply_cmd_entity_delete_for_name(entry->d_name)) + != TBD_ERROR_SUCCESS) { + goto cleanup; + } + } - int err; - if((err = tbd_apply_cmd_entity_delete_for_name(entry->d_name)) != 0) { - closedir(dp); + if (chdir("..") != 0) { + err = TBD_ERROR(TBD_ERROR_UNABLE_TO_CHANGE_DIR); + goto cleanup; + } + if (rmdir(name) != 0) { + err = TBD_ERROR(TBD_ERROR_UNABLE_TO_REMOVE_FILE); + } +cleanup: + closedir(dp); + return err; +} - if(chdir("..") != 0) - return TBD_ERROR(TBD_ERROR_UNABLE_TO_CHANGE_DIR); +static int +tbd_apply_cmd_entity_delete_for_name(const char *name) +{ + struct stat info; + if (lstat(name, &info) != 0) { + return TBD_ERROR(TBD_ERROR_UNABLE_TO_STAT_FILE); + } - return err; - } + if (S_ISDIR(info.st_mode)) { + return tbd_apply_cmd_dir_delete(name); } - closedir(dp); - if(chdir("..") != 0) - return TBD_ERROR(TBD_ERROR_UNABLE_TO_CHANGE_DIR); - if(remove(name) != 0) + if (unlink(name) != 0) { return TBD_ERROR(TBD_ERROR_UNABLE_TO_REMOVE_FILE); - return 0; + } + + return TBD_ERROR_SUCCESS; } static int diff --git a/tests/05_symlink_add_remove.sh b/tests/05_symlink_add_remove.sh index 5e841bf..0c8b0ac 100755 --- a/tests/05_symlink_add_remove.sh +++ b/tests/05_symlink_add_remove.sh @@ -12,17 +12,27 @@ TEST_TOOLS=$3 ############# Test specific code ############ setup () { - ln -s /foo $ORIGIN/remove && \ - ln -s /bar $TARGET/add && \ - chown -h :cdrom $TARGET/add + ln -s /foo $ORIGIN/remove && + ln -s /bar $TARGET/add && + chown -h :cdrom $TARGET/add && + for dir in $ORIGIN $TARGET; do + ( + cd $dir && mkdir -p data && + touch data/a data/b + ); done && + (cd $ORIGIN && ln -s data datalink) } check_results () { - test -L $ORIGIN/add && \ - test ! -L $ORIGIN/remove && \ - check_symlink $ORIGIN/add "/bar" && \ - check_same_mtime $ORIGIN/add $TARGET/add && \ - check_same_uidgid $ORIGIN/add $TARGET/add + test -L $ORIGIN/add && + test ! -L $ORIGIN/remove && + check_symlink $ORIGIN/add "/bar" && + check_same_mtime $ORIGIN/add $TARGET/add && + check_same_uidgid $ORIGIN/add $TARGET/add && + test ! -L $ORIGIN/datalink && + test -d $ORIGIN/data && + test -f $ORIGIN/data/a && + test -f $ORIGIN/data/b } ############################################# |