diff options
author | Max Kellermann <max@duempel.org> | 2008-10-09 15:41:02 +0200 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2008-10-11 19:21:50 -0700 |
commit | 8aed358a9770618c93c0b33417f2b62fbb9a513e (patch) | |
tree | 656cfa8336175370054d67f9880c10e1d4b9fd9e /src | |
parent | 997d4c2ac9d6ea91cfcab8de195d3e7e40849a20 (diff) | |
download | mpd-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.
Diffstat (limited to 'src')
-rw-r--r-- | src/update.c | 38 |
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 */ } |