aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2008-10-09 15:41:02 +0200
committerEric Wong <normalperson@yhbt.net>2008-10-11 19:21:50 -0700
commit8aed358a9770618c93c0b33417f2b62fbb9a513e (patch)
tree656cfa8336175370054d67f9880c10e1d4b9fd9e
parent997d4c2ac9d6ea91cfcab8de195d3e7e40849a20 (diff)
downloadmpd-8aed358a9770618c93c0b33417f2b62fbb9a513e.tar.gz
mpd-8aed358a9770618c93c0b33417f2b62fbb9a513e.tar.xz
mpd-8aed358a9770618c93c0b33417f2b62fbb9a513e.zip
update: locked delete after update error
When a directory failed to update, it was removed from the database, without freeing all children and songs (memory leak), and without locking (race condition). Introduce the functions clear_directory() and delete_directory(), which do both.
-rw-r--r--src/update.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/update.c b/src/update.c
index 355821294..6697a14c2 100644
--- a/src/update.c
+++ b/src/update.c
@@ -77,6 +77,42 @@ static void delete_song(struct directory *dir, struct mpd_song *del)
song_free(del);
}
+static int delete_each_song(struct mpd_song *song, mpd_unused void *data)
+{
+ struct directory *directory = data;
+ assert(song->parent == directory);
+ delete_song(directory, song);
+ return 0;
+}
+
+/**
+ * Recursively remove all sub directories and songs from a directory,
+ * leaving an empty directory.
+ */
+static void clear_directory(struct directory *directory)
+{
+ int i;
+
+ for (i = directory->children.nr; --i >= 0;)
+ clear_directory(directory->children.base[i]);
+ dirvec_clear(&directory->children);
+
+ songvec_for_each(&directory->songs, delete_each_song, directory);
+}
+
+/**
+ * Recursively free a directory and all its contents.
+ */
+static void delete_directory(struct directory *directory)
+{
+ assert(directory->parent != NULL);
+
+ clear_directory(directory);
+
+ dirvec_delete(&directory->parent->children, directory);
+ directory_free(directory);
+}
+
struct delete_data {
char *tmp;
struct directory *dir;
@@ -357,7 +393,7 @@ static enum update_return updatePath(const char *utf8path)
/* if updateDirectory fails, means we should delete it */
else {
LOG("removing directory: %s\n", utf8path);
- dirvec_delete(&parentDirectory->children, directory);
+ delete_directory(directory);
ret = UPDATE_RETURN_UPDATED;
/* don't return, path maybe a song now */
}