summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2011-10-13 16:03:34 +0100
committerRichard Maw <richard.maw@codethink.co.uk>2011-10-13 16:03:34 +0100
commitc131cb9586bfdd5ce19c33639e908b89c44104d7 (patch)
tree0dad02a08f19141362e11343b74c283f75bd126f
parent1e9d1410e355d8ad0ab1cdcc12c396e0670882c0 (diff)
downloadtbdiff-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.c66
-rwxr-xr-xtests/05_symlink_add_remove.sh26
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
}
#############################################