diff options
author | Max Kellermann <max@duempel.org> | 2008-10-09 15:41:02 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-10-09 15:41:02 +0200 |
commit | 2bb7bcc7b6a12abd47c9cf56255045f5e78dba84 (patch) | |
tree | c60b826e2989177e604de883753d71c3eca4fb41 | |
parent | 96c681e2db9f8f707f80061360c9b6b680fe72e3 (diff) | |
download | mpd-2bb7bcc7b6a12abd47c9cf56255045f5e78dba84.tar.gz mpd-2bb7bcc7b6a12abd47c9cf56255045f5e78dba84.tar.xz mpd-2bb7bcc7b6a12abd47c9cf56255045f5e78dba84.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.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/src/update.c b/src/update.c index 55740bfc4..36f866325 100644 --- a/src/update.c +++ b/src/update.c @@ -81,6 +81,45 @@ delete_song(struct directory *dir, struct song *del) song_free(del); } +static int +delete_each_song(struct 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; @@ -374,7 +413,7 @@ static enum update_return updatePath(const char *utf8path) /* if updateDirectory fails, means we should delete it */ else { LOG("removing directory: %s\n", path); - dirvec_delete(&parentDirectory->children, directory); + delete_directory(directory); ret = UPDATE_RETURN_UPDATED; /* don't return, path maybe a song now */ } |