From 6f43d71628db3c9acb9e0693216885685566b7d3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 10:48:48 +0200 Subject: directory: moved code to update.c The source directory.c mixes several libraries: directory object management, database management and database update, resulting in a 1000+ line monster. Move the whole database update code to update.c. --- src/update.c | 560 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 560 insertions(+) create mode 100644 src/update.c (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c new file mode 100644 index 000000000..6c21444b6 --- /dev/null +++ b/src/update.c @@ -0,0 +1,560 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) + * Copyright (C) 2008 Max Kellermann + * This project's homepage is: http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "update.h" +#include "log.h" +#include "ls.h" +#include "path.h" +#include "playlist.h" +#include "utils.h" +#include "main_notify.h" +#include "dirvec.h" +#include "condition.h" +#include "update.h" + +enum update_progress { + UPDATE_PROGRESS_IDLE = 0, + UPDATE_PROGRESS_RUNNING = 1, + UPDATE_PROGRESS_DONE = 2 +} progress; + +/* make this dynamic?, or maybe this is big enough... */ +static char *update_paths[32]; +static size_t update_paths_nr; + +static pthread_t update_thr; + +static const int update_task_id_max = 1 << 15; + +static int update_task_id; + +static Song *delete; + +static struct condition delete_cond; + +int isUpdatingDB(void) +{ + return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0; +} + +static void directory_set_stat(Directory * dir, const struct stat *st) +{ + dir->inode = st->st_ino; + dir->device = st->st_dev; + dir->stat = 1; +} + +static void delete_song(Directory *dir, Song *del) +{ + /* first, prevent traversers in main task from getting this */ + songvec_delete(&dir->songs, del); + + /* now take it out of the playlist (in the main_task) */ + cond_enter(&delete_cond); + assert(!delete); + delete = del; + wakeup_main_task(); + do { cond_wait(&delete_cond); } while (delete); + cond_leave(&delete_cond); + + /* finally, all possible references gone, free it */ + freeJustSong(del); +} + +struct delete_data { + char *tmp; + Directory *dir; + enum update_return ret; +}; + +/* passed to songvec_for_each */ +static int delete_song_if_removed(Song *song, void *_data) +{ + struct delete_data *data = _data; + + data->tmp = get_song_url(data->tmp, song); + assert(data->tmp); + + if (!isFile(data->tmp, NULL)) { + delete_song(data->dir, song); + data->ret = UPDATE_RETURN_UPDATED; + } + return 0; +} + +static enum update_return +removeDeletedFromDirectory(char *path_max_tmp, Directory * directory) +{ + enum update_return ret = UPDATE_RETURN_NOUPDATE; + int i; + struct dirvec *dv = &directory->children; + struct delete_data data; + + for (i = dv->nr; --i >= 0; ) { + if (isDir(dv->base[i]->path)) + continue; + LOG("removing directory: %s\n", dv->base[i]->path); + dirvec_delete(dv, dv->base[i]); + ret = UPDATE_RETURN_UPDATED; + } + + data.dir = directory; + data.tmp = path_max_tmp; + data.ret = ret; + songvec_for_each(&directory->songs, delete_song_if_removed, &data); + + return data.ret; +} + +static const char *opendir_path(char *path_max_tmp, const char *dirname) +{ + if (*dirname != '\0') + return rmp2amp_r(path_max_tmp, + utf8_to_fs_charset(path_max_tmp, dirname)); + return musicDir; +} + +static int statDirectory(Directory * dir) +{ + struct stat st; + + if (myStat(getDirectoryPath(dir), &st) < 0) + return -1; + + directory_set_stat(dir, &st); + + return 0; +} + +static int inodeFoundInParent(Directory * parent, ino_t inode, dev_t device) +{ + while (parent) { + if (!parent->stat && statDirectory(parent) < 0) + return -1; + if (parent->inode == inode && parent->device == device) { + DEBUG("recursive directory found\n"); + return 1; + } + parent = parent->parent; + } + + return 0; +} + +static enum update_return +addSubDirectoryToDirectory(Directory * directory, + const char *name, struct stat *st) +{ + Directory *subDirectory; + + if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) + return UPDATE_RETURN_NOUPDATE; + + subDirectory = newDirectory(name, directory); + directory_set_stat(subDirectory, st); + + if (exploreDirectory(subDirectory) != UPDATE_RETURN_UPDATED) { + freeDirectory(subDirectory); + return UPDATE_RETURN_NOUPDATE; + } + + dirvec_add(&directory->children, subDirectory); + + return UPDATE_RETURN_UPDATED; +} + +static enum update_return +addToDirectory(Directory * directory, const char *name) +{ + struct stat st; + + if (myStat(name, &st)) { + DEBUG("failed to stat %s: %s\n", name, strerror(errno)); + return UPDATE_RETURN_ERROR; + } + if (S_ISREG(st.st_mode) && + hasMusicSuffix(name, 0) && isMusic(name, NULL, 0)) { + Song *song; + const char *shortname = mpd_basename(name); + + if (!(song = newSong(shortname, directory))) + return -1; + songvec_add(&directory->songs, song); + LOG("added %s\n", name); + return UPDATE_RETURN_UPDATED; + } else if (S_ISDIR(st.st_mode)) { + return addSubDirectoryToDirectory(directory, name, &st); + } + + DEBUG("addToDirectory: %s is not a directory or music\n", name); + + return UPDATE_RETURN_ERROR; +} + +static enum update_return updateDirectory(Directory * directory); + +static enum update_return +updateInDirectory(Directory * directory, const char *name) +{ + Song *song; + struct stat st; + + if (myStat(name, &st)) + return UPDATE_RETURN_ERROR; + + if (S_ISREG(st.st_mode) && hasMusicSuffix(name, 0)) { + const char *shortname = mpd_basename(name); + + if (!(song = songvec_find(&directory->songs, shortname))) { + addToDirectory(directory, name); + return UPDATE_RETURN_UPDATED; + } else if (st.st_mtime != song->mtime) { + LOG("updating %s\n", name); + if (updateSongInfo(song) < 0) + delete_song(directory, song); + return UPDATE_RETURN_UPDATED; + } + } else if (S_ISDIR(st.st_mode)) { + Directory *subdir = dirvec_find(&directory->children, name); + if (subdir) { + assert(directory == subdir->parent); + directory_set_stat(subdir, &st); + return updateDirectory(subdir); + } else { + return addSubDirectoryToDirectory(directory, name, &st); + } + } + + return UPDATE_RETURN_NOUPDATE; +} + +/* we don't look at hidden files nor files with newlines in them */ +static int skip_path(const char *path) +{ + return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; +} + +enum update_return exploreDirectory(Directory * directory) +{ + DIR *dir; + const char *dirname = getDirectoryPath(directory); + struct dirent *ent; + char path_max_tmp[MPD_PATH_MAX]; + enum update_return ret = UPDATE_RETURN_NOUPDATE; + + DEBUG("explore: attempting to opendir: %s\n", dirname); + + dir = opendir(opendir_path(path_max_tmp, dirname)); + if (!dir) + return UPDATE_RETURN_ERROR; + + DEBUG("explore: %s\n", dirname); + + while ((ent = readdir(dir))) { + char *utf8; + if (skip_path(ent->d_name)) + continue; + + utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name); + if (!utf8) + continue; + + DEBUG("explore: found: %s (%s)\n", ent->d_name, utf8); + + if (directory->path) + utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), + dirname, strlen(dirname)); + if (addToDirectory(directory, path_max_tmp) == + UPDATE_RETURN_UPDATED) + ret = UPDATE_RETURN_UPDATED; + } + + closedir(dir); + + return ret; +} + +static enum update_return updateDirectory(Directory * directory) +{ + DIR *dir; + const char *dirname = getDirectoryPath(directory); + struct dirent *ent; + char path_max_tmp[MPD_PATH_MAX]; + enum update_return ret = UPDATE_RETURN_NOUPDATE; + + if (!directory->stat && statDirectory(directory) < 0) + return UPDATE_RETURN_ERROR; + else if (inodeFoundInParent(directory->parent, + directory->inode, + directory->device)) + return UPDATE_RETURN_ERROR; + + dir = opendir(opendir_path(path_max_tmp, dirname)); + if (!dir) + return UPDATE_RETURN_ERROR; + + if (removeDeletedFromDirectory(path_max_tmp, directory) > 0) + ret = UPDATE_RETURN_UPDATED; + + while ((ent = readdir(dir))) { + char *utf8; + if (skip_path(ent->d_name)) + continue; + + utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name); + if (!utf8) + continue; + + if (directory->path) + utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), + dirname, strlen(dirname)); + if (updateInDirectory(directory, path_max_tmp) > 0) + ret = UPDATE_RETURN_UPDATED; + } + + closedir(dir); + + return ret; +} + +static Directory *addDirectoryPathToDB(const char *utf8path) +{ + char path_max_tmp[MPD_PATH_MAX]; + char *parent; + Directory *parentDirectory; + Directory *directory; + Song *conflicting; + + parent = parent_path(path_max_tmp, utf8path); + + if (strlen(parent) == 0) + parentDirectory = directory_get_root(); + else + parentDirectory = addDirectoryPathToDB(parent); + + if (!parentDirectory) + return NULL; + + if ((directory = dirvec_find(&parentDirectory->children, utf8path))) { + assert(parentDirectory == directory->parent); + } else { + struct stat st; + if (myStat(utf8path, &st) < 0 || + inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev)) + return NULL; + else { + directory = newDirectory(utf8path, parentDirectory); + dirvec_add(&parentDirectory->children, directory); + } + } + + /* if we're adding directory paths, make sure to delete filenames + with potentially the same name */ + conflicting = songvec_find(&parentDirectory->songs, + mpd_basename(directory->path)); + if (conflicting) + delete_song(parentDirectory, conflicting); + + return directory; +} + +static Directory *addParentPathToDB(const char *utf8path) +{ + char *parent; + char path_max_tmp[MPD_PATH_MAX]; + Directory *parentDirectory; + + parent = parent_path(path_max_tmp, utf8path); + + if (strlen(parent) == 0) + parentDirectory = directory_get_root(); + else + parentDirectory = addDirectoryPathToDB(parent); + + if (!parentDirectory) + return NULL; + + return (Directory *) parentDirectory; +} + +static enum update_return updatePath(const char *utf8path) +{ + Directory *directory; + Directory *parentDirectory; + Song *song; + time_t mtime; + enum update_return ret = UPDATE_RETURN_NOUPDATE; + char path_max_tmp[MPD_PATH_MAX]; + + assert(utf8path); + + /* if path is in the DB try to update it, or else delete it */ + if ((directory = getDirectory(utf8path))) { + parentDirectory = directory->parent; + + /* if this update directory is successfull, we are done */ + if ((ret = updateDirectory(directory)) >= 0) { + sortDirectory(directory); + return ret; + } + /* we don't want to delete the root directory */ + else if (directory == directory_get_root()) { + return UPDATE_RETURN_NOUPDATE; + } + /* if updateDirectory fails, means we should delete it */ + else { + LOG("removing directory: %s\n", utf8path); + dirvec_delete(&parentDirectory->children, directory); + ret = UPDATE_RETURN_UPDATED; + /* don't return, path maybe a song now */ + } + } else if ((song = getSongFromDB(utf8path))) { + parentDirectory = song->parentDir; + if (!parentDirectory->stat + && statDirectory(parentDirectory) < 0) { + return UPDATE_RETURN_NOUPDATE; + } + /* if this song update is successful, we are done */ + else if (!inodeFoundInParent(parentDirectory->parent, + parentDirectory->inode, + parentDirectory->device) && + isMusic(get_song_url(path_max_tmp, song), &mtime, 0)) { + if (song->mtime == mtime) + return UPDATE_RETURN_NOUPDATE; + else if (updateSongInfo(song) == 0) + return UPDATE_RETURN_UPDATED; + else { + delete_song(parentDirectory, song); + return UPDATE_RETURN_UPDATED; + } + } + /* if updateDirectory fails, means we should delete it */ + else { + delete_song(parentDirectory, song); + ret = UPDATE_RETURN_UPDATED; + /* don't return, path maybe a directory now */ + } + } + + /* path not found in the db, see if it actually exists on the fs. + * Also, if by chance a directory was replaced by a file of the same + * name or vice versa, we need to add it to the db + */ + if (isDir(utf8path) || isMusic(utf8path, NULL, 0)) { + parentDirectory = addParentPathToDB(utf8path); + if (!parentDirectory || (!parentDirectory->stat && + statDirectory(parentDirectory) < 0)) { + } else if (0 == inodeFoundInParent(parentDirectory->parent, + parentDirectory->inode, + parentDirectory->device) + && addToDirectory(parentDirectory, utf8path) + == UPDATE_RETURN_UPDATED) { + ret = UPDATE_RETURN_UPDATED; + } + } + + return ret; +} + +static void * update_task(void *_path) +{ + enum update_return ret = UPDATE_RETURN_NOUPDATE; + + if (_path) { + ret = updatePath((char *)_path); + free(_path); + } else { + ret = updateDirectory(directory_get_root()); + } + + if (ret == UPDATE_RETURN_UPDATED && writeDirectoryDB() < 0) + ret = UPDATE_RETURN_ERROR; + progress = UPDATE_PROGRESS_DONE; + wakeup_main_task(); + return (void *)ret; +} + +static void spawn_update_task(char *path) +{ + pthread_attr_t attr; + + assert(pthread_equal(pthread_self(), main_task)); + + progress = UPDATE_PROGRESS_RUNNING; + pthread_attr_init(&attr); + if (pthread_create(&update_thr, &attr, update_task, path)) + FATAL("Failed to spawn update task: %s\n", strerror(errno)); + if (++update_task_id > update_task_id_max) + update_task_id = 1; + DEBUG("spawned thread for update job id %i\n", update_task_id); +} + +int directory_update_init(char *path) +{ + assert(pthread_equal(pthread_self(), main_task)); + + if (progress != UPDATE_PROGRESS_IDLE) { + int next_task_id; + + if (!path) + return -1; + if (update_paths_nr == ARRAY_SIZE(update_paths)) + return -1; + assert(update_paths_nr < ARRAY_SIZE(update_paths)); + update_paths[update_paths_nr++] = path; + next_task_id = update_task_id + update_paths_nr; + + return next_task_id > update_task_id_max ? 1 : next_task_id; + } + spawn_update_task(path); + return update_task_id; +} + +void reap_update_task(void) +{ + enum update_return ret; + + assert(pthread_equal(pthread_self(), main_task)); + + cond_enter(&delete_cond); + if (delete) { + char tmp[MPD_PATH_MAX]; + LOG("removing: %s\n", get_song_url(tmp, delete)); + deleteASongFromPlaylist(delete); + delete = NULL; + cond_signal(&delete_cond); + } + cond_leave(&delete_cond); + + if (progress != UPDATE_PROGRESS_DONE) + return; + if (pthread_join(update_thr, (void **)&ret)) + FATAL("error joining update thread: %s\n", strerror(errno)); + if (ret == UPDATE_RETURN_UPDATED) + playlistVersionChange(); + + if (update_paths_nr) { + char *path = update_paths[0]; + memmove(&update_paths[0], &update_paths[1], + --update_paths_nr * sizeof(char *)); + spawn_update_task(path); + } else { + progress = UPDATE_PROGRESS_IDLE; + } +} -- cgit v1.2.3 From b5d3970c075987d7439e2b60ea043606f46a3bab Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 10:48:55 +0200 Subject: update: merged exploreDirectory() into updateDirectory() exploreDirectory() duplicates some code in updateDirectory(). Merge both functions, and use directory_is_empty() to determine whether update or explore mode should be used. --- src/update.c | 60 +++++++++++++----------------------------------------------- 1 file changed, 13 insertions(+), 47 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 6c21444b6..4a2c11e94 100644 --- a/src/update.c +++ b/src/update.c @@ -169,7 +169,7 @@ addSubDirectoryToDirectory(Directory * directory, subDirectory = newDirectory(name, directory); directory_set_stat(subDirectory, st); - if (exploreDirectory(subDirectory) != UPDATE_RETURN_UPDATED) { + if (updateDirectory(subDirectory) != UPDATE_RETURN_UPDATED) { freeDirectory(subDirectory); return UPDATE_RETURN_NOUPDATE; } @@ -207,8 +207,6 @@ addToDirectory(Directory * directory, const char *name) return UPDATE_RETURN_ERROR; } -static enum update_return updateDirectory(Directory * directory); - static enum update_return updateInDirectory(Directory * directory, const char *name) { @@ -250,48 +248,9 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } -enum update_return exploreDirectory(Directory * directory) -{ - DIR *dir; - const char *dirname = getDirectoryPath(directory); - struct dirent *ent; - char path_max_tmp[MPD_PATH_MAX]; - enum update_return ret = UPDATE_RETURN_NOUPDATE; - - DEBUG("explore: attempting to opendir: %s\n", dirname); - - dir = opendir(opendir_path(path_max_tmp, dirname)); - if (!dir) - return UPDATE_RETURN_ERROR; - - DEBUG("explore: %s\n", dirname); - - while ((ent = readdir(dir))) { - char *utf8; - if (skip_path(ent->d_name)) - continue; - - utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name); - if (!utf8) - continue; - - DEBUG("explore: found: %s (%s)\n", ent->d_name, utf8); - - if (directory->path) - utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), - dirname, strlen(dirname)); - if (addToDirectory(directory, path_max_tmp) == - UPDATE_RETURN_UPDATED) - ret = UPDATE_RETURN_UPDATED; - } - - closedir(dir); - - return ret; -} - -static enum update_return updateDirectory(Directory * directory) +enum update_return updateDirectory(Directory * directory) { + int was_empty = directory_is_empty(directory); DIR *dir; const char *dirname = getDirectoryPath(directory); struct dirent *ent; @@ -309,7 +268,8 @@ static enum update_return updateDirectory(Directory * directory) if (!dir) return UPDATE_RETURN_ERROR; - if (removeDeletedFromDirectory(path_max_tmp, directory) > 0) + if (!was_empty && + removeDeletedFromDirectory(path_max_tmp, directory) > 0) ret = UPDATE_RETURN_UPDATED; while ((ent = readdir(dir))) { @@ -324,8 +284,14 @@ static enum update_return updateDirectory(Directory * directory) if (directory->path) utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), dirname, strlen(dirname)); - if (updateInDirectory(directory, path_max_tmp) > 0) - ret = UPDATE_RETURN_UPDATED; + if (was_empty) { + if (addToDirectory(directory, path_max_tmp) == + UPDATE_RETURN_UPDATED) + ret = UPDATE_RETURN_UPDATED; + } else { + if (updateInDirectory(directory, path_max_tmp) > 0) + ret = UPDATE_RETURN_UPDATED; + } } closedir(dir); -- cgit v1.2.3 From c84c73df00e5e1710d84fdb4be6352d849da8f2b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 10:49:05 +0200 Subject: directory: converted typedef Directory to struct directory The struct can be forward-declared by other headers, which relaxes the header dependencies. --- src/update.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 4a2c11e94..00561cab1 100644 --- a/src/update.c +++ b/src/update.c @@ -18,6 +18,7 @@ */ #include "update.h" +#include "directory.h" #include "log.h" #include "ls.h" #include "path.h" @@ -53,14 +54,14 @@ int isUpdatingDB(void) return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0; } -static void directory_set_stat(Directory * dir, const struct stat *st) +static void directory_set_stat(struct directory *dir, const struct stat *st) { dir->inode = st->st_ino; dir->device = st->st_dev; dir->stat = 1; } -static void delete_song(Directory *dir, Song *del) +static void delete_song(struct directory *dir, Song *del) { /* first, prevent traversers in main task from getting this */ songvec_delete(&dir->songs, del); @@ -79,7 +80,7 @@ static void delete_song(Directory *dir, Song *del) struct delete_data { char *tmp; - Directory *dir; + struct directory *dir; enum update_return ret; }; @@ -99,7 +100,7 @@ static int delete_song_if_removed(Song *song, void *_data) } static enum update_return -removeDeletedFromDirectory(char *path_max_tmp, Directory * directory) +removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) { enum update_return ret = UPDATE_RETURN_NOUPDATE; int i; @@ -130,7 +131,7 @@ static const char *opendir_path(char *path_max_tmp, const char *dirname) return musicDir; } -static int statDirectory(Directory * dir) +static int statDirectory(struct directory *dir) { struct stat st; @@ -142,7 +143,8 @@ static int statDirectory(Directory * dir) return 0; } -static int inodeFoundInParent(Directory * parent, ino_t inode, dev_t device) +static int +inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) { while (parent) { if (!parent->stat && statDirectory(parent) < 0) @@ -158,10 +160,10 @@ static int inodeFoundInParent(Directory * parent, ino_t inode, dev_t device) } static enum update_return -addSubDirectoryToDirectory(Directory * directory, +addSubDirectoryToDirectory(struct directory *directory, const char *name, struct stat *st) { - Directory *subDirectory; + struct directory *subDirectory; if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) return UPDATE_RETURN_NOUPDATE; @@ -180,7 +182,7 @@ addSubDirectoryToDirectory(Directory * directory, } static enum update_return -addToDirectory(Directory * directory, const char *name) +addToDirectory(struct directory *directory, const char *name) { struct stat st; @@ -208,7 +210,7 @@ addToDirectory(Directory * directory, const char *name) } static enum update_return -updateInDirectory(Directory * directory, const char *name) +updateInDirectory(struct directory *directory, const char *name) { Song *song; struct stat st; @@ -229,7 +231,7 @@ updateInDirectory(Directory * directory, const char *name) return UPDATE_RETURN_UPDATED; } } else if (S_ISDIR(st.st_mode)) { - Directory *subdir = dirvec_find(&directory->children, name); + struct directory *subdir = dirvec_find(&directory->children, name); if (subdir) { assert(directory == subdir->parent); directory_set_stat(subdir, &st); @@ -248,7 +250,7 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } -enum update_return updateDirectory(Directory * directory) +enum update_return updateDirectory(struct directory *directory) { int was_empty = directory_is_empty(directory); DIR *dir; @@ -299,12 +301,12 @@ enum update_return updateDirectory(Directory * directory) return ret; } -static Directory *addDirectoryPathToDB(const char *utf8path) +static struct directory * addDirectoryPathToDB(const char *utf8path) { char path_max_tmp[MPD_PATH_MAX]; char *parent; - Directory *parentDirectory; - Directory *directory; + struct directory *parentDirectory; + struct directory *directory; Song *conflicting; parent = parent_path(path_max_tmp, utf8path); @@ -340,11 +342,11 @@ static Directory *addDirectoryPathToDB(const char *utf8path) return directory; } -static Directory *addParentPathToDB(const char *utf8path) +static struct directory * addParentPathToDB(const char *utf8path) { char *parent; char path_max_tmp[MPD_PATH_MAX]; - Directory *parentDirectory; + struct directory *parentDirectory; parent = parent_path(path_max_tmp, utf8path); @@ -356,13 +358,13 @@ static Directory *addParentPathToDB(const char *utf8path) if (!parentDirectory) return NULL; - return (Directory *) parentDirectory; + return (struct directory *) parentDirectory; } static enum update_return updatePath(const char *utf8path) { - Directory *directory; - Directory *parentDirectory; + struct directory *directory; + struct directory *parentDirectory; Song *song; time_t mtime; enum update_return ret = UPDATE_RETURN_NOUPDATE; -- cgit v1.2.3 From 79e8abb461fa848cce3717333ee5cfa55ee91c71 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 10:49:11 +0200 Subject: song: converted typedef Song to struct song Again, a data type which can be forward-declared. [ew: * used "struct mpd_song" instead to avoid token duplication (like I did with "struct mpd_tag") as there's no good abbreviation for "song" and identical tokens on the same line don't read well * rewritten using perl -i -p -e 's/\bSong\b/struct mpd_song/g' src/*.[ch] since it was too hard to merge * also, I don't care much for forward declarations ] --- src/update.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 00561cab1..674ad0519 100644 --- a/src/update.c +++ b/src/update.c @@ -45,7 +45,7 @@ static const int update_task_id_max = 1 << 15; static int update_task_id; -static Song *delete; +static struct mpd_song *delete; static struct condition delete_cond; @@ -61,7 +61,7 @@ static void directory_set_stat(struct directory *dir, const struct stat *st) dir->stat = 1; } -static void delete_song(struct directory *dir, Song *del) +static void delete_song(struct directory *dir, struct mpd_song *del) { /* first, prevent traversers in main task from getting this */ songvec_delete(&dir->songs, del); @@ -85,7 +85,7 @@ struct delete_data { }; /* passed to songvec_for_each */ -static int delete_song_if_removed(Song *song, void *_data) +static int delete_song_if_removed(struct mpd_song *song, void *_data) { struct delete_data *data = _data; @@ -192,7 +192,7 @@ addToDirectory(struct directory *directory, const char *name) } if (S_ISREG(st.st_mode) && hasMusicSuffix(name, 0) && isMusic(name, NULL, 0)) { - Song *song; + struct mpd_song *song; const char *shortname = mpd_basename(name); if (!(song = newSong(shortname, directory))) @@ -212,7 +212,7 @@ addToDirectory(struct directory *directory, const char *name) static enum update_return updateInDirectory(struct directory *directory, const char *name) { - Song *song; + struct mpd_song *song; struct stat st; if (myStat(name, &st)) @@ -307,7 +307,7 @@ static struct directory * addDirectoryPathToDB(const char *utf8path) char *parent; struct directory *parentDirectory; struct directory *directory; - Song *conflicting; + struct mpd_song *conflicting; parent = parent_path(path_max_tmp, utf8path); @@ -365,7 +365,7 @@ static enum update_return updatePath(const char *utf8path) { struct directory *directory; struct directory *parentDirectory; - Song *song; + struct mpd_song *song; time_t mtime; enum update_return ret = UPDATE_RETURN_NOUPDATE; char path_max_tmp[MPD_PATH_MAX]; -- cgit v1.2.3 From d24e17ebdd5eeb16c87b897a9ecb52a5704a52b3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:05:25 +0200 Subject: song: replaced all song constructors Provide separate constructors for creating a remote song, a local song, and one for loading data from a song file. This way, we can add more assertions. --- src/update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 674ad0519..c40f25694 100644 --- a/src/update.c +++ b/src/update.c @@ -195,7 +195,7 @@ addToDirectory(struct directory *directory, const char *name) struct mpd_song *song; const char *shortname = mpd_basename(name); - if (!(song = newSong(shortname, directory))) + if (!(song = song_file_load(shortname, directory))) return -1; songvec_add(&directory->songs, song); LOG("added %s\n", name); -- cgit v1.2.3 From e6f87010949c1d659b27c5db5707e23230d3eaf0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:05:34 +0200 Subject: song: removed CamelCase CamelCase is ugly... rename all functions. --- src/update.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index c40f25694..e7a49e56e 100644 --- a/src/update.c +++ b/src/update.c @@ -75,7 +75,7 @@ static void delete_song(struct directory *dir, struct mpd_song *del) cond_leave(&delete_cond); /* finally, all possible references gone, free it */ - freeJustSong(del); + song_free(del); } struct delete_data { @@ -89,7 +89,7 @@ static int delete_song_if_removed(struct mpd_song *song, void *_data) { struct delete_data *data = _data; - data->tmp = get_song_url(data->tmp, song); + data->tmp = song_get_url(song, data->tmp); assert(data->tmp); if (!isFile(data->tmp, NULL)) { @@ -226,7 +226,7 @@ updateInDirectory(struct directory *directory, const char *name) return UPDATE_RETURN_UPDATED; } else if (st.st_mtime != song->mtime) { LOG("updating %s\n", name); - if (updateSongInfo(song) < 0) + if (song_file_update(song) < 0) delete_song(directory, song); return UPDATE_RETURN_UPDATED; } @@ -393,7 +393,7 @@ static enum update_return updatePath(const char *utf8path) /* don't return, path maybe a song now */ } } else if ((song = getSongFromDB(utf8path))) { - parentDirectory = song->parentDir; + parentDirectory = song->parent; if (!parentDirectory->stat && statDirectory(parentDirectory) < 0) { return UPDATE_RETURN_NOUPDATE; @@ -402,10 +402,10 @@ static enum update_return updatePath(const char *utf8path) else if (!inodeFoundInParent(parentDirectory->parent, parentDirectory->inode, parentDirectory->device) && - isMusic(get_song_url(path_max_tmp, song), &mtime, 0)) { + isMusic(song_get_url(song, path_max_tmp), &mtime, 0)) { if (song->mtime == mtime) return UPDATE_RETURN_NOUPDATE; - else if (updateSongInfo(song) == 0) + else if (song_file_update(song) == 0) return UPDATE_RETURN_UPDATED; else { delete_song(parentDirectory, song); @@ -503,7 +503,7 @@ void reap_update_task(void) cond_enter(&delete_cond); if (delete) { char tmp[MPD_PATH_MAX]; - LOG("removing: %s\n", get_song_url(tmp, delete)); + LOG("removing: %s\n", song_get_url(delete, tmp)); deleteASongFromPlaylist(delete); delete = NULL; cond_signal(&delete_cond); -- cgit v1.2.3 From aae48c97fb3d2b0140daa8e49459a7afe3488683 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:06:26 +0200 Subject: song: song_file_update() returns boolean Instead of returning 0 or -1, return true on success and false on failure. This seems more natural, and when the C library was designed, there was no "bool" data type. [ew: changing to bool semantics but sticking with integer type since bool is C99 and I don't require a C99 compiler, and I don't feel like writing compatibility wrappers to support it. _Bool is usually (always?) a signed int anyways. ] --- src/update.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index e7a49e56e..594e7f48c 100644 --- a/src/update.c +++ b/src/update.c @@ -226,7 +226,7 @@ updateInDirectory(struct directory *directory, const char *name) return UPDATE_RETURN_UPDATED; } else if (st.st_mtime != song->mtime) { LOG("updating %s\n", name); - if (song_file_update(song) < 0) + if (!song_file_update(song)) delete_song(directory, song); return UPDATE_RETURN_UPDATED; } @@ -405,7 +405,7 @@ static enum update_return updatePath(const char *utf8path) isMusic(song_get_url(song, path_max_tmp), &mtime, 0)) { if (song->mtime == mtime) return UPDATE_RETURN_NOUPDATE; - else if (song_file_update(song) == 0) + else if (song_file_update(song)) return UPDATE_RETURN_UPDATED; else { delete_song(parentDirectory, song); -- cgit v1.2.3 From 729523ec80f35a683c982054628cd47d2161d3d4 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:07:35 +0200 Subject: directory: moved code to database.c Taming the directory.c monster, part II: move the database management stuff to database. directory.c should only contain code which works on directory objects. --- src/update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 594e7f48c..8560dde38 100644 --- a/src/update.c +++ b/src/update.c @@ -18,7 +18,7 @@ */ #include "update.h" -#include "directory.h" +#include "database.h" #include "log.h" #include "ls.h" #include "path.h" -- cgit v1.2.3 From 4629f646077109f7c6185aab92560da52c237412 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:07:55 +0200 Subject: database: renamed functions, "db_" prefix and no CamelCase Yet another CamelCase removal patch. --- src/update.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 8560dde38..52e61167d 100644 --- a/src/update.c +++ b/src/update.c @@ -312,7 +312,7 @@ static struct directory * addDirectoryPathToDB(const char *utf8path) parent = parent_path(path_max_tmp, utf8path); if (strlen(parent) == 0) - parentDirectory = directory_get_root(); + parentDirectory = db_get_root(); else parentDirectory = addDirectoryPathToDB(parent); @@ -351,7 +351,7 @@ static struct directory * addParentPathToDB(const char *utf8path) parent = parent_path(path_max_tmp, utf8path); if (strlen(parent) == 0) - parentDirectory = directory_get_root(); + parentDirectory = db_get_root(); else parentDirectory = addDirectoryPathToDB(parent); @@ -373,7 +373,7 @@ static enum update_return updatePath(const char *utf8path) assert(utf8path); /* if path is in the DB try to update it, or else delete it */ - if ((directory = getDirectory(utf8path))) { + if ((directory = db_get_directory(utf8path))) { parentDirectory = directory->parent; /* if this update directory is successfull, we are done */ @@ -382,7 +382,7 @@ static enum update_return updatePath(const char *utf8path) return ret; } /* we don't want to delete the root directory */ - else if (directory == directory_get_root()) { + else if (directory == db_get_root()) { return UPDATE_RETURN_NOUPDATE; } /* if updateDirectory fails, means we should delete it */ @@ -392,7 +392,7 @@ static enum update_return updatePath(const char *utf8path) ret = UPDATE_RETURN_UPDATED; /* don't return, path maybe a song now */ } - } else if ((song = getSongFromDB(utf8path))) { + } else if ((song = db_get_song(utf8path))) { parentDirectory = song->parent; if (!parentDirectory->stat && statDirectory(parentDirectory) < 0) { @@ -448,10 +448,10 @@ static void * update_task(void *_path) ret = updatePath((char *)_path); free(_path); } else { - ret = updateDirectory(directory_get_root()); + ret = updateDirectory(db_get_root()); } - if (ret == UPDATE_RETURN_UPDATED && writeDirectoryDB() < 0) + if (ret == UPDATE_RETURN_UPDATED && db_save() < 0) ret = UPDATE_RETURN_ERROR; progress = UPDATE_PROGRESS_DONE; wakeup_main_task(); -- cgit v1.2.3 From a76121ea81f452c0d5e21d6a2fb6f200a80faf7b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:07:58 +0200 Subject: directory: eliminate CamelCase CamelCase is ugly, rename the functions. [ew: "directory_get_directory" was too confusing, using "directory_get_subdir" instead (old function was named "getSubDirectory")] --- src/update.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 52e61167d..989b8f943 100644 --- a/src/update.c +++ b/src/update.c @@ -135,7 +135,7 @@ static int statDirectory(struct directory *dir) { struct stat st; - if (myStat(getDirectoryPath(dir), &st) < 0) + if (myStat(directory_get_path(dir), &st) < 0) return -1; directory_set_stat(dir, &st); @@ -168,11 +168,11 @@ addSubDirectoryToDirectory(struct directory *directory, if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) return UPDATE_RETURN_NOUPDATE; - subDirectory = newDirectory(name, directory); + subDirectory = directory_new(name, directory); directory_set_stat(subDirectory, st); if (updateDirectory(subDirectory) != UPDATE_RETURN_UPDATED) { - freeDirectory(subDirectory); + directory_free(subDirectory); return UPDATE_RETURN_NOUPDATE; } @@ -254,7 +254,7 @@ enum update_return updateDirectory(struct directory *directory) { int was_empty = directory_is_empty(directory); DIR *dir; - const char *dirname = getDirectoryPath(directory); + const char *dirname = directory_get_path(directory); struct dirent *ent; char path_max_tmp[MPD_PATH_MAX]; enum update_return ret = UPDATE_RETURN_NOUPDATE; @@ -327,7 +327,7 @@ static struct directory * addDirectoryPathToDB(const char *utf8path) inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev)) return NULL; else { - directory = newDirectory(utf8path, parentDirectory); + directory = directory_new(utf8path, parentDirectory); dirvec_add(&parentDirectory->children, directory); } } @@ -378,7 +378,7 @@ static enum update_return updatePath(const char *utf8path) /* if this update directory is successfull, we are done */ if ((ret = updateDirectory(directory)) >= 0) { - sortDirectory(directory); + directory_sort(directory); return ret; } /* we don't want to delete the root directory */ -- cgit v1.2.3 From 0c46207db41840ac70af7a5261969e865b748f1d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Oct 2008 11:55:52 +0200 Subject: directory: fix update in root directory Commit 0bfe7802 broke update for new files in the root directory, because music_root->path was an empty string and not NULL. There were some NULL tests missing. Change them to !isRootDirectory(path) instead of path!=NULL. --- src/update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 989b8f943..1cf6f3537 100644 --- a/src/update.c +++ b/src/update.c @@ -283,7 +283,7 @@ enum update_return updateDirectory(struct directory *directory) if (!utf8) continue; - if (directory->path) + if (!isRootDirectory(directory->path)) utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), dirname, strlen(dirname)); if (was_empty) { -- cgit v1.2.3 From 7f79b3c6fc21d687f116b3e2a2b7bad309a191c0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:24:05 +0200 Subject: directory: moved dirvec struct declaration to dirvec.h No idea why it was created in directory.h, but it should be in dirvec.h. --- src/update.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 1cf6f3537..6e9f1572c 100644 --- a/src/update.c +++ b/src/update.c @@ -25,7 +25,6 @@ #include "playlist.h" #include "utils.h" #include "main_notify.h" -#include "dirvec.h" #include "condition.h" #include "update.h" -- cgit v1.2.3 From 4a13e19cebb8d72db6e2db9ffb9f9dbd7194ede9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:34:07 +0200 Subject: directory: added inline wrappers for accessing children Some tiny utilities... wrappers like these may become helpful when we introduce locking. --- src/update.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 6e9f1572c..b44d07075 100644 --- a/src/update.c +++ b/src/update.c @@ -230,7 +230,7 @@ updateInDirectory(struct directory *directory, const char *name) return UPDATE_RETURN_UPDATED; } } else if (S_ISDIR(st.st_mode)) { - struct directory *subdir = dirvec_find(&directory->children, name); + struct directory *subdir = directory_get_child(directory, name); if (subdir) { assert(directory == subdir->parent); directory_set_stat(subdir, &st); @@ -318,17 +318,15 @@ static struct directory * addDirectoryPathToDB(const char *utf8path) if (!parentDirectory) return NULL; - if ((directory = dirvec_find(&parentDirectory->children, utf8path))) { + if ((directory = directory_get_child(parentDirectory, utf8path))) { assert(parentDirectory == directory->parent); } else { struct stat st; if (myStat(utf8path, &st) < 0 || inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev)) return NULL; - else { - directory = directory_new(utf8path, parentDirectory); - dirvec_add(&parentDirectory->children, directory); - } + + directory = directory_new_child(parentDirectory, utf8path); } /* if we're adding directory paths, make sure to delete filenames -- cgit v1.2.3 From 8fabdfadaf2be72c5af9fd2b9804caf3cd0d14de Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:37:21 +0200 Subject: update: removed addToDirectory() Use updateInDirectory() instead of addToDirectory(). Eliminate a duplicate stat() in updateInDirectory() by calling song_file_update() directly. --- src/update.c | 48 ++++++++++-------------------------------------- 1 file changed, 10 insertions(+), 38 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index b44d07075..355821294 100644 --- a/src/update.c +++ b/src/update.c @@ -180,34 +180,6 @@ addSubDirectoryToDirectory(struct directory *directory, return UPDATE_RETURN_UPDATED; } -static enum update_return -addToDirectory(struct directory *directory, const char *name) -{ - struct stat st; - - if (myStat(name, &st)) { - DEBUG("failed to stat %s: %s\n", name, strerror(errno)); - return UPDATE_RETURN_ERROR; - } - if (S_ISREG(st.st_mode) && - hasMusicSuffix(name, 0) && isMusic(name, NULL, 0)) { - struct mpd_song *song; - const char *shortname = mpd_basename(name); - - if (!(song = song_file_load(shortname, directory))) - return -1; - songvec_add(&directory->songs, song); - LOG("added %s\n", name); - return UPDATE_RETURN_UPDATED; - } else if (S_ISDIR(st.st_mode)) { - return addSubDirectoryToDirectory(directory, name, &st); - } - - DEBUG("addToDirectory: %s is not a directory or music\n", name); - - return UPDATE_RETURN_ERROR; -} - static enum update_return updateInDirectory(struct directory *directory, const char *name) { @@ -221,7 +193,10 @@ updateInDirectory(struct directory *directory, const char *name) const char *shortname = mpd_basename(name); if (!(song = songvec_find(&directory->songs, shortname))) { - addToDirectory(directory, name); + if (!(song = song_file_load(shortname, directory))) + return -1; + songvec_add(&directory->songs, song); + LOG("added %s\n", name); return UPDATE_RETURN_UPDATED; } else if (st.st_mtime != song->mtime) { LOG("updating %s\n", name); @@ -240,6 +215,8 @@ updateInDirectory(struct directory *directory, const char *name) } } + DEBUG("update: %s is not a directory or music\n", name); + return UPDATE_RETURN_NOUPDATE; } @@ -285,14 +262,9 @@ enum update_return updateDirectory(struct directory *directory) if (!isRootDirectory(directory->path)) utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), dirname, strlen(dirname)); - if (was_empty) { - if (addToDirectory(directory, path_max_tmp) == - UPDATE_RETURN_UPDATED) - ret = UPDATE_RETURN_UPDATED; - } else { - if (updateInDirectory(directory, path_max_tmp) > 0) - ret = UPDATE_RETURN_UPDATED; - } + if (updateInDirectory(directory, path_max_tmp) == + UPDATE_RETURN_UPDATED) + ret = UPDATE_RETURN_UPDATED; } closedir(dir); @@ -428,7 +400,7 @@ static enum update_return updatePath(const char *utf8path) } else if (0 == inodeFoundInParent(parentDirectory->parent, parentDirectory->inode, parentDirectory->device) - && addToDirectory(parentDirectory, utf8path) + && updateInDirectory(parentDirectory, utf8path) == UPDATE_RETURN_UPDATED) { ret = UPDATE_RETURN_UPDATED; } -- cgit v1.2.3 From 8aed358a9770618c93c0b33417f2b62fbb9a513e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:41:02 +0200 Subject: 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. --- src/update.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'src/update.c') 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 */ } -- cgit v1.2.3 From 017e2e4a4e8e8b60446cd90fe3d7ab1b3165572e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:42:30 +0200 Subject: update: clear root after error When the root directory fails to update, its contents are invalid. Clear it then. --- src/update.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 6697a14c2..564e691d0 100644 --- a/src/update.c +++ b/src/update.c @@ -388,6 +388,7 @@ static enum update_return updatePath(const char *utf8path) } /* we don't want to delete the root directory */ else if (directory == db_get_root()) { + clear_directory(directory); return UPDATE_RETURN_NOUPDATE; } /* if updateDirectory fails, means we should delete it */ -- cgit v1.2.3 From 189e7bbfe4ca060bc26bc917bd65b71a38851d13 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:47:22 +0200 Subject: update: moved code to directory_make_child_checked() The branching looks a bit complicated in addDirectoryPathToDB() - improve its readability by moving code to a simplified separate function. --- src/update.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 564e691d0..73ab142c1 100644 --- a/src/update.c +++ b/src/update.c @@ -308,13 +308,34 @@ enum update_return updateDirectory(struct directory *directory) return ret; } -static struct directory * addDirectoryPathToDB(const char *utf8path) +static struct directory * +directory_make_child_checked(struct directory *parent, const char *path) +{ + struct directory *directory; + struct stat st; + struct mpd_song *conflicting; + + if ((directory = directory_get_child(parent, path))) + return directory; + + if (myStat(path, &st) < 0 || + inodeFoundInParent(parent, st.st_ino, st.st_dev)) + return NULL; + + /* if we're adding directory paths, make sure to delete filenames + with potentially the same name */ + if ((conflicting = songvec_find(&parent->songs, mpd_basename(path)))) + delete_song(parent, conflicting); + + return directory_new_child(parent, path); +} + +static struct directory * +addDirectoryPathToDB(const char *utf8path) { char path_max_tmp[MPD_PATH_MAX]; char *parent; struct directory *parentDirectory; - struct directory *directory; - struct mpd_song *conflicting; parent = parent_path(path_max_tmp, utf8path); @@ -326,25 +347,7 @@ static struct directory * addDirectoryPathToDB(const char *utf8path) if (!parentDirectory) return NULL; - if ((directory = directory_get_child(parentDirectory, utf8path))) { - assert(parentDirectory == directory->parent); - } else { - struct stat st; - if (myStat(utf8path, &st) < 0 || - inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev)) - return NULL; - - directory = directory_new_child(parentDirectory, utf8path); - } - - /* if we're adding directory paths, make sure to delete filenames - with potentially the same name */ - conflicting = songvec_find(&parentDirectory->songs, - mpd_basename(directory->path)); - if (conflicting) - delete_song(parentDirectory, conflicting); - - return directory; + return directory_make_child_checked(parentDirectory, utf8path); } static struct directory * addParentPathToDB(const char *utf8path) -- cgit v1.2.3 From 50f1074c1b0b156e484401c6455e881cd830c2f7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:47:59 +0200 Subject: update: delete directory after failed update When a directory cannot be updated, there must be something wrong with it, and the database contains stale data. Remove it. --- src/update.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 73ab142c1..dd48bfe78 100644 --- a/src/update.c +++ b/src/update.c @@ -243,9 +243,16 @@ updateInDirectory(struct directory *directory, const char *name) } else if (S_ISDIR(st.st_mode)) { struct directory *subdir = directory_get_child(directory, name); if (subdir) { + enum update_return ret; + assert(directory == subdir->parent); directory_set_stat(subdir, &st); - return updateDirectory(subdir); + + ret = updateDirectory(subdir); + if (ret == UPDATE_RETURN_ERROR) + delete_directory(subdir); + + return ret; } else { return addSubDirectoryToDirectory(directory, name, &st); } -- cgit v1.2.3 From f2fd7be1d7b80da32611c57360e71fb777b95c7d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:48:07 +0200 Subject: update: make addDirectoryPathToDB() non-recursive This recursive function is very dangerous because it allocates a large buffer on the stack in every iteration. That may be misused to generate a stack overflow. --- src/update.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index dd48bfe78..1415852e0 100644 --- a/src/update.c +++ b/src/update.c @@ -340,21 +340,23 @@ directory_make_child_checked(struct directory *parent, const char *path) static struct directory * addDirectoryPathToDB(const char *utf8path) { - char path_max_tmp[MPD_PATH_MAX]; - char *parent; - struct directory *parentDirectory; + struct directory *directory = db_get_root(); + char *duplicated = xstrdup(utf8path); + char *slash = duplicated; - parent = parent_path(path_max_tmp, utf8path); + while (1) { + if ((slash = strchr(slash, '/'))) + *slash = 0; - if (strlen(parent) == 0) - parentDirectory = db_get_root(); - else - parentDirectory = addDirectoryPathToDB(parent); + directory = directory_make_child_checked(directory, duplicated); + if (!directory || !slash) + break; - if (!parentDirectory) - return NULL; + *slash++ = '/'; + } - return directory_make_child_checked(parentDirectory, utf8path); + free(duplicated); + return directory; } static struct directory * addParentPathToDB(const char *utf8path) -- cgit v1.2.3 From 08ac9c4b05d51f79733b6ad27b7a79240c92fb03 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 15:48:39 +0200 Subject: update: merged addDirectoryPathToDB() into addParentPathToDB() The algorithm in addDirectoryPathToDB() can be simplified further if it is combined with the function addParentPathToDB(). Since there is no other caller of addDirectoryPathToDB(), we can do that. This saves another large stack buffer. --- src/update.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 1415852e0..c2f611e9e 100644 --- a/src/update.c +++ b/src/update.c @@ -338,15 +338,14 @@ directory_make_child_checked(struct directory *parent, const char *path) } static struct directory * -addDirectoryPathToDB(const char *utf8path) +addParentPathToDB(const char *utf8path) { struct directory *directory = db_get_root(); char *duplicated = xstrdup(utf8path); char *slash = duplicated; - while (1) { - if ((slash = strchr(slash, '/'))) - *slash = 0; + while ((slash = strchr(slash, '/'))) { + *slash = 0; directory = directory_make_child_checked(directory, duplicated); if (!directory || !slash) @@ -359,25 +358,6 @@ addDirectoryPathToDB(const char *utf8path) return directory; } -static struct directory * addParentPathToDB(const char *utf8path) -{ - char *parent; - char path_max_tmp[MPD_PATH_MAX]; - struct directory *parentDirectory; - - parent = parent_path(path_max_tmp, utf8path); - - if (strlen(parent) == 0) - parentDirectory = db_get_root(); - else - parentDirectory = addDirectoryPathToDB(parent); - - if (!parentDirectory) - return NULL; - - return (struct directory *) parentDirectory; -} - static enum update_return updatePath(const char *utf8path) { struct directory *directory; -- cgit v1.2.3 From e553fa4d36016cd4ba2162a64d8a770bef618608 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:11:49 +0200 Subject: update: never pass root path to updatePath() update_task() already checks if it has got a root path. Extend this check and in turn remove a check in the inner function updatePath(). --- src/update.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index c2f611e9e..e2afb7f81 100644 --- a/src/update.c +++ b/src/update.c @@ -378,11 +378,6 @@ static enum update_return updatePath(const char *utf8path) directory_sort(directory); return ret; } - /* we don't want to delete the root directory */ - else if (directory == db_get_root()) { - clear_directory(directory); - return UPDATE_RETURN_NOUPDATE; - } /* if updateDirectory fails, means we should delete it */ else { LOG("removing directory: %s\n", utf8path); @@ -442,7 +437,7 @@ static void * update_task(void *_path) { enum update_return ret = UPDATE_RETURN_NOUPDATE; - if (_path) { + if (_path != NULL && !isRootDirectory(_path)) { ret = updatePath((char *)_path); free(_path); } else { -- cgit v1.2.3 From 1f70121c5604be45e81c5a07d59efea2aaa1597b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:11:51 +0200 Subject: update: pass const pointer to addSubDirectoryToDirectory() The stat struct isn't going to be modified, make it const. --- src/update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index e2afb7f81..49850256c 100644 --- a/src/update.c +++ b/src/update.c @@ -196,7 +196,7 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) static enum update_return addSubDirectoryToDirectory(struct directory *directory, - const char *name, struct stat *st) + const char *name, const struct stat *st) { struct directory *subDirectory; -- cgit v1.2.3 From 6fd08bc8fad5d6c4be37ce751d53ef80b756b292 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:11:54 +0200 Subject: update: don't export updateDirectory() If the user requests database update during startup, call directory_update_init(). This should be changed to fully asynchronous update later. For this to work, main_notify has to be initialized before db_init(). --- src/update.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 49850256c..641b1d63b 100644 --- a/src/update.c +++ b/src/update.c @@ -28,6 +28,12 @@ #include "condition.h" #include "update.h" +enum update_return { + UPDATE_RETURN_ERROR = -1, + UPDATE_RETURN_NOUPDATE = 0, + UPDATE_RETURN_UPDATED = 1 +}; + enum update_progress { UPDATE_PROGRESS_IDLE = 0, UPDATE_PROGRESS_RUNNING = 1, @@ -194,6 +200,8 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) return 0; } +static enum update_return updateDirectory(struct directory *directory); + static enum update_return addSubDirectoryToDirectory(struct directory *directory, const char *name, const struct stat *st) @@ -269,7 +277,7 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } -enum update_return updateDirectory(struct directory *directory) +static enum update_return updateDirectory(struct directory *directory) { int was_empty = directory_is_empty(directory); DIR *dir; -- cgit v1.2.3 From 2d6a943bf0c84a2ece6014d7a74b25f819bc4510 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:13:02 +0200 Subject: update: rewrote updatePath() using updateInDirectory() updatePath() duplicated a lot of code from the more generic updateInDirectory(). Eliminate most of updatePath() and call updateInDirectory(). --- src/update.c | 89 +++++++++++++----------------------------------------------- 1 file changed, 19 insertions(+), 70 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 641b1d63b..e1d0268a8 100644 --- a/src/update.c +++ b/src/update.c @@ -140,6 +140,21 @@ static int delete_song_if_removed(struct mpd_song *song, void *_data) return 0; } +static enum update_return delete_path(const char *path) +{ + struct directory *directory = db_get_directory(path); + struct mpd_song *song = db_get_song(path); + + if (directory) + delete_directory(directory); + if (song) + delete_song(song->parent, song); + + return directory == NULL && song == NULL + ? UPDATE_RETURN_NOUPDATE + : UPDATE_RETURN_UPDATED; +} + static enum update_return removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) { @@ -368,77 +383,11 @@ addParentPathToDB(const char *utf8path) static enum update_return updatePath(const char *utf8path) { - struct directory *directory; - struct directory *parentDirectory; - struct mpd_song *song; - time_t mtime; - enum update_return ret = UPDATE_RETURN_NOUPDATE; - char path_max_tmp[MPD_PATH_MAX]; - - assert(utf8path); - - /* if path is in the DB try to update it, or else delete it */ - if ((directory = db_get_directory(utf8path))) { - parentDirectory = directory->parent; - - /* if this update directory is successfull, we are done */ - if ((ret = updateDirectory(directory)) >= 0) { - directory_sort(directory); - return ret; - } - /* if updateDirectory fails, means we should delete it */ - else { - LOG("removing directory: %s\n", utf8path); - delete_directory(directory); - ret = UPDATE_RETURN_UPDATED; - /* don't return, path maybe a song now */ - } - } else if ((song = db_get_song(utf8path))) { - parentDirectory = song->parent; - if (!parentDirectory->stat - && statDirectory(parentDirectory) < 0) { - return UPDATE_RETURN_NOUPDATE; - } - /* if this song update is successful, we are done */ - else if (!inodeFoundInParent(parentDirectory->parent, - parentDirectory->inode, - parentDirectory->device) && - isMusic(song_get_url(song, path_max_tmp), &mtime, 0)) { - if (song->mtime == mtime) - return UPDATE_RETURN_NOUPDATE; - else if (song_file_update(song)) - return UPDATE_RETURN_UPDATED; - else { - delete_song(parentDirectory, song); - return UPDATE_RETURN_UPDATED; - } - } - /* if updateDirectory fails, means we should delete it */ - else { - delete_song(parentDirectory, song); - ret = UPDATE_RETURN_UPDATED; - /* don't return, path maybe a directory now */ - } - } - - /* path not found in the db, see if it actually exists on the fs. - * Also, if by chance a directory was replaced by a file of the same - * name or vice versa, we need to add it to the db - */ - if (isDir(utf8path) || isMusic(utf8path, NULL, 0)) { - parentDirectory = addParentPathToDB(utf8path); - if (!parentDirectory || (!parentDirectory->stat && - statDirectory(parentDirectory) < 0)) { - } else if (0 == inodeFoundInParent(parentDirectory->parent, - parentDirectory->inode, - parentDirectory->device) - && updateInDirectory(parentDirectory, utf8path) - == UPDATE_RETURN_UPDATED) { - ret = UPDATE_RETURN_UPDATED; - } - } + struct stat st; - return ret; + if (myStat(path, &st) < 0) + return delete_path(path); + return updateInDirectory(addParentPathToDB(path), path); } static void * update_task(void *_path) -- cgit v1.2.3 From e2d7fa53aa587b874709d441ecc782f745fd4b3e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:13:03 +0200 Subject: update: avoid duplicate stat() calls Pass a pointer to the stat struct to more functions. --- src/update.c | 66 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 28 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index e1d0268a8..410d906ff 100644 --- a/src/update.c +++ b/src/update.c @@ -215,7 +215,8 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) return 0; } -static enum update_return updateDirectory(struct directory *directory); +static enum update_return +updateDirectory(struct directory *directory, const struct stat *st); static enum update_return addSubDirectoryToDirectory(struct directory *directory, @@ -227,9 +228,7 @@ addSubDirectoryToDirectory(struct directory *directory, return UPDATE_RETURN_NOUPDATE; subDirectory = directory_new(name, directory); - directory_set_stat(subDirectory, st); - - if (updateDirectory(subDirectory) != UPDATE_RETURN_UPDATED) { + if (updateDirectory(subDirectory, st) != UPDATE_RETURN_UPDATED) { directory_free(subDirectory); return UPDATE_RETURN_NOUPDATE; } @@ -240,15 +239,12 @@ addSubDirectoryToDirectory(struct directory *directory, } static enum update_return -updateInDirectory(struct directory *directory, const char *name) +updateInDirectory(struct directory *directory, + const char *name, const struct stat *st) { struct mpd_song *song; - struct stat st; - if (myStat(name, &st)) - return UPDATE_RETURN_ERROR; - - if (S_ISREG(st.st_mode) && hasMusicSuffix(name, 0)) { + if (S_ISREG(st->st_mode) && hasMusicSuffix(name, 0)) { const char *shortname = mpd_basename(name); if (!(song = songvec_find(&directory->songs, shortname))) { @@ -257,27 +253,26 @@ updateInDirectory(struct directory *directory, const char *name) songvec_add(&directory->songs, song); LOG("added %s\n", name); return UPDATE_RETURN_UPDATED; - } else if (st.st_mtime != song->mtime) { + } else if (st->st_mtime != song->mtime) { LOG("updating %s\n", name); if (!song_file_update(song)) delete_song(directory, song); return UPDATE_RETURN_UPDATED; } - } else if (S_ISDIR(st.st_mode)) { + } else if (S_ISDIR(st->st_mode)) { struct directory *subdir = directory_get_child(directory, name); if (subdir) { enum update_return ret; assert(directory == subdir->parent); - directory_set_stat(subdir, &st); - ret = updateDirectory(subdir); + ret = updateDirectory(subdir, st); if (ret == UPDATE_RETURN_ERROR) delete_directory(subdir); return ret; } else { - return addSubDirectoryToDirectory(directory, name, &st); + return addSubDirectoryToDirectory(directory, name, st); } } @@ -292,7 +287,8 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } -static enum update_return updateDirectory(struct directory *directory) +static enum update_return +updateDirectory(struct directory *directory, const struct stat *st) { int was_empty = directory_is_empty(directory); DIR *dir; @@ -300,12 +296,14 @@ static enum update_return updateDirectory(struct directory *directory) struct dirent *ent; char path_max_tmp[MPD_PATH_MAX]; enum update_return ret = UPDATE_RETURN_NOUPDATE; + enum update_return ret2; - if (!directory->stat && statDirectory(directory) < 0) - return UPDATE_RETURN_ERROR; - else if (inodeFoundInParent(directory->parent, - directory->inode, - directory->device)) + assert(S_ISDIR(st->st_mode)); + + directory_set_stat(directory, st); + + if (inodeFoundInParent(directory->parent, + directory->inode, directory->device)) return UPDATE_RETURN_ERROR; dir = opendir(opendir_path(path_max_tmp, dirname)); @@ -318,6 +316,8 @@ static enum update_return updateDirectory(struct directory *directory) while ((ent = readdir(dir))) { char *utf8; + struct stat st2; + if (skip_path(ent->d_name)) continue; @@ -328,9 +328,13 @@ static enum update_return updateDirectory(struct directory *directory) if (!isRootDirectory(directory->path)) utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), dirname, strlen(dirname)); - if (updateInDirectory(directory, path_max_tmp) == - UPDATE_RETURN_UPDATED) - ret = UPDATE_RETURN_UPDATED; + + if (myStat(path_max_tmp, &st2) == 0) + ret2 = updateInDirectory(directory, path_max_tmp, &st2); + else + ret2 = delete_path(path_max_tmp); + if (ret == UPDATE_RETURN_NOUPDATE) + ret = ret2; } closedir(dir); @@ -385,9 +389,9 @@ static enum update_return updatePath(const char *utf8path) { struct stat st; - if (myStat(path, &st) < 0) - return delete_path(path); - return updateInDirectory(addParentPathToDB(path), path); + if (myStat(utf8path, &st) < 0) + return delete_path(utf8path); + return updateInDirectory(addParentPathToDB(utf8path), utf8path, &st); } static void * update_task(void *_path) @@ -398,7 +402,13 @@ static void * update_task(void *_path) ret = updatePath((char *)_path); free(_path); } else { - ret = updateDirectory(db_get_root()); + struct directory *directory = db_get_root(); + struct stat st; + + if (myStat(directory_get_path(directory), &st) == 0) + ret = updateDirectory(directory, &st); + else + ret = UPDATE_RETURN_ERROR; } if (ret == UPDATE_RETURN_UPDATED && db_save() < 0) -- cgit v1.2.3 From 120aa4bfb5c0b6962ee50559c0263f8e850f2c88 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:14:04 +0200 Subject: update: copy stat to new directory When reading a new directory, copy the stat data (which we have anyway) to the directory struct. This may save a stat() in the future. --- src/update.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 410d906ff..c8eb33b6d 100644 --- a/src/update.c +++ b/src/update.c @@ -361,7 +361,9 @@ directory_make_child_checked(struct directory *parent, const char *path) if ((conflicting = songvec_find(&parent->songs, mpd_basename(path)))) delete_song(parent, conflicting); - return directory_new_child(parent, path); + directory = directory_new_child(parent, path); + directory_set_stat(directory, &st); + return directory; } static struct directory * -- cgit v1.2.3 From 01bf8687f27db7d4ddec019a606670d43ec14680 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:15:56 +0200 Subject: update: do the recursive directory check only once The recursive checks were performed in several functions, and sometimes a directory was checked twice. --- src/update.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index c8eb33b6d..5b2721cdb 100644 --- a/src/update.c +++ b/src/update.c @@ -224,9 +224,6 @@ addSubDirectoryToDirectory(struct directory *directory, { struct directory *subDirectory; - if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) - return UPDATE_RETURN_NOUPDATE; - subDirectory = directory_new(name, directory); if (updateDirectory(subDirectory, st) != UPDATE_RETURN_UPDATED) { directory_free(subDirectory); @@ -260,8 +257,12 @@ updateInDirectory(struct directory *directory, return UPDATE_RETURN_UPDATED; } } else if (S_ISDIR(st->st_mode)) { - struct directory *subdir = directory_get_child(directory, name); - if (subdir) { + struct directory *subdir; + + if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) + return UPDATE_RETURN_ERROR; + + if ((subdir = directory_get_child(directory, name))) { enum update_return ret; assert(directory == subdir->parent); @@ -302,10 +303,6 @@ updateDirectory(struct directory *directory, const struct stat *st) directory_set_stat(directory, st); - if (inodeFoundInParent(directory->parent, - directory->inode, directory->device)) - return UPDATE_RETURN_ERROR; - dir = opendir(opendir_path(path_max_tmp, dirname)); if (!dir) return UPDATE_RETURN_ERROR; -- cgit v1.2.3 From 7945d695e5ebcfea8e41e0c3b2dc5b72f8b0a0b9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:16:21 +0200 Subject: update: make the "song" variable more local --- src/update.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 5b2721cdb..a1e33ba22 100644 --- a/src/update.c +++ b/src/update.c @@ -239,10 +239,9 @@ static enum update_return updateInDirectory(struct directory *directory, const char *name, const struct stat *st) { - struct mpd_song *song; - if (S_ISREG(st->st_mode) && hasMusicSuffix(name, 0)) { const char *shortname = mpd_basename(name); + struct mpd_song *song; if (!(song = songvec_find(&directory->songs, shortname))) { if (!(song = song_file_load(shortname, directory))) -- cgit v1.2.3 From 516540ba565d47c79ac18f8bfe395e0d38598fea Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:17:25 +0200 Subject: update: eliminated addSubDirectoryToDirectory() In updateInDirectory(), add new directories immediately and delete them when they turn out to be empty. This simplifies the code and allows us to eliminate addSubDirectoryToDirectory(). --- src/update.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index a1e33ba22..69ae9794d 100644 --- a/src/update.c +++ b/src/update.c @@ -218,23 +218,6 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) static enum update_return updateDirectory(struct directory *directory, const struct stat *st); -static enum update_return -addSubDirectoryToDirectory(struct directory *directory, - const char *name, const struct stat *st) -{ - struct directory *subDirectory; - - subDirectory = directory_new(name, directory); - if (updateDirectory(subDirectory, st) != UPDATE_RETURN_UPDATED) { - directory_free(subDirectory); - return UPDATE_RETURN_NOUPDATE; - } - - dirvec_add(&directory->children, subDirectory); - - return UPDATE_RETURN_UPDATED; -} - static enum update_return updateInDirectory(struct directory *directory, const char *name, const struct stat *st) @@ -257,23 +240,21 @@ updateInDirectory(struct directory *directory, } } else if (S_ISDIR(st->st_mode)) { struct directory *subdir; + enum update_return ret; if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) return UPDATE_RETURN_ERROR; - if ((subdir = directory_get_child(directory, name))) { - enum update_return ret; + if (!(subdir = directory_get_child(directory, name))) + subdir = directory_new_child(directory, name); - assert(directory == subdir->parent); + assert(directory == subdir->parent); - ret = updateDirectory(subdir, st); - if (ret == UPDATE_RETURN_ERROR) - delete_directory(subdir); + ret = updateDirectory(subdir, st); + if (ret == UPDATE_RETURN_ERROR || directory_is_empty(subdir)) + delete_directory(subdir); - return ret; - } else { - return addSubDirectoryToDirectory(directory, name, st); - } + return ret; } DEBUG("update: %s is not a directory or music\n", name); -- cgit v1.2.3 From 0d4cc41ae07ca3f2e079fced38d9bd244c787df8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:17:26 +0200 Subject: updated: always call removeDeletedFromDirectory() Removed the local variable "was_empty": don't remember if the directory is new. Always call removeDeletedFromDirectory(). --- src/update.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 69ae9794d..4498449bd 100644 --- a/src/update.c +++ b/src/update.c @@ -271,7 +271,6 @@ static int skip_path(const char *path) static enum update_return updateDirectory(struct directory *directory, const struct stat *st) { - int was_empty = directory_is_empty(directory); DIR *dir; const char *dirname = directory_get_path(directory); struct dirent *ent; @@ -287,8 +286,7 @@ updateDirectory(struct directory *directory, const struct stat *st) if (!dir) return UPDATE_RETURN_ERROR; - if (!was_empty && - removeDeletedFromDirectory(path_max_tmp, directory) > 0) + if (removeDeletedFromDirectory(path_max_tmp, directory) > 0) ret = UPDATE_RETURN_UPDATED; while ((ent = readdir(dir))) { -- cgit v1.2.3 From 0775237e40087ee328888eb2b16953dc0cb332e0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:17:33 +0200 Subject: update: fixed stack corruption due to pthread_join() call pthread_join() expects a "pointer to a pointer" parameter, but it got a "pointer to an enum". On AMD64, an enum is smaller than a pointer, leading to a buffer overflow. --- src/update.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 4498449bd..34ec1ba77 100644 --- a/src/update.c +++ b/src/update.c @@ -433,6 +433,7 @@ int directory_update_init(char *path) void reap_update_task(void) { + void *thread_return; enum update_return ret; assert(pthread_equal(pthread_self(), main_task)); @@ -449,8 +450,9 @@ void reap_update_task(void) if (progress != UPDATE_PROGRESS_DONE) return; - if (pthread_join(update_thr, (void **)&ret)) + if (pthread_join(update_thr, &thread_return)) FATAL("error joining update thread: %s\n", strerror(errno)); + ret = (enum update_return)(size_t)thread_return; if (ret == UPDATE_RETURN_UPDATED) playlistVersionChange(); -- cgit v1.2.3 From e5c747982adfae06c51b60819ec6a4ef5a34ffe2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:17:38 +0200 Subject: update: check progress!=IDLE in reap_update_task() When the update task is idle, there is no need to check for deleted songs. Return early from reap_update_task(). --- src/update.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 34ec1ba77..f5619a1d4 100644 --- a/src/update.c +++ b/src/update.c @@ -438,6 +438,9 @@ void reap_update_task(void) assert(pthread_equal(pthread_self(), main_task)); + if (progress == UPDATE_PROGRESS_IDLE) + return; + cond_enter(&delete_cond); if (delete) { char tmp[MPD_PATH_MAX]; -- cgit v1.2.3 From 1d59716731f3ed8569d60ae84c291bd93eb7d582 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:17:44 +0200 Subject: update: job ID must be positive The documentation for directory_update_init() was incorrect: a job ID must be positive, not non-negative. If the update queue is full and no job was created, it makes more sense to return 0 instead of -1, because it is more consistent with the return value of isUpdatingDB(). --- src/update.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index f5619a1d4..7dc50b5aa 100644 --- a/src/update.c +++ b/src/update.c @@ -418,9 +418,9 @@ int directory_update_init(char *path) int next_task_id; if (!path) - return -1; + return 0; if (update_paths_nr == ARRAY_SIZE(update_paths)) - return -1; + return 0; assert(update_paths_nr < ARRAY_SIZE(update_paths)); update_paths[update_paths_nr++] = path; next_task_id = update_task_id + update_paths_nr; -- cgit v1.2.3 From e3ac6a123a442cf9d1f9147b122f21a1f3f1ebb2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:20:05 +0200 Subject: update: make the job id unsigned Since the return value cannot be -1 anymore, we can make it unsigned. --- src/update.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 7dc50b5aa..68e030b78 100644 --- a/src/update.c +++ b/src/update.c @@ -46,15 +46,15 @@ static size_t update_paths_nr; static pthread_t update_thr; -static const int update_task_id_max = 1 << 15; +static const unsigned update_task_id_max = 1 << 15; -static int update_task_id; +static unsigned update_task_id; static struct mpd_song *delete; static struct condition delete_cond; -int isUpdatingDB(void) +unsigned isUpdatingDB(void) { return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0; } @@ -410,12 +410,12 @@ static void spawn_update_task(char *path) DEBUG("spawned thread for update job id %i\n", update_task_id); } -int directory_update_init(char *path) +unsigned directory_update_init(char *path) { assert(pthread_equal(pthread_self(), main_task)); if (progress != UPDATE_PROGRESS_IDLE) { - int next_task_id; + unsigned next_task_id; if (!path) return 0; -- cgit v1.2.3 From ab7e9dd283abdea1ec94c75b94e450ba39fa3835 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:20:54 +0200 Subject: update: fix memory leak in directory_update_init() When the update queue is full, directory_update_init() did not free the path argument. --- src/update.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 68e030b78..b910486e0 100644 --- a/src/update.c +++ b/src/update.c @@ -419,8 +419,11 @@ unsigned directory_update_init(char *path) if (!path) return 0; - if (update_paths_nr == ARRAY_SIZE(update_paths)) + if (update_paths_nr == ARRAY_SIZE(update_paths)) { + free(path); return 0; + } + assert(update_paths_nr < ARRAY_SIZE(update_paths)); update_paths[update_paths_nr++] = path; next_task_id = update_task_id + update_paths_nr; -- cgit v1.2.3 From 04c4ea74f7d633d262ab2c54751cae29d4995621 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:20:59 +0200 Subject: update: don't print debug message when song was not modified When a song file was not modified, MPD printed the debug message "not a directory or music", because the first "if" branch did not return. --- src/update.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index b910486e0..40f47a26a 100644 --- a/src/update.c +++ b/src/update.c @@ -238,6 +238,8 @@ updateInDirectory(struct directory *directory, delete_song(directory, song); return UPDATE_RETURN_UPDATED; } + + return UPDATE_RETURN_NOUPDATE; } else if (S_ISDIR(st->st_mode)) { struct directory *subdir; enum update_return ret; @@ -255,11 +257,10 @@ updateInDirectory(struct directory *directory, delete_directory(subdir); return ret; + } else { + DEBUG("update: %s is not a directory or music\n", name); + return UPDATE_RETURN_NOUPDATE; } - - DEBUG("update: %s is not a directory or music\n", name); - - return UPDATE_RETURN_NOUPDATE; } /* we don't look at hidden files nor files with newlines in them */ -- cgit v1.2.3 From 9ae9c1f8cff904cdc2451ddbee88a30e0570d2f5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:31:31 +0200 Subject: update: make the variable "progress" static --- src/update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 40f47a26a..f0905b5db 100644 --- a/src/update.c +++ b/src/update.c @@ -34,7 +34,7 @@ enum update_return { UPDATE_RETURN_UPDATED = 1 }; -enum update_progress { +static enum update_progress { UPDATE_PROGRESS_IDLE = 0, UPDATE_PROGRESS_RUNNING = 1, UPDATE_PROGRESS_DONE = 2 -- cgit v1.2.3 From e71207440ebdf492e00fd5ac73b0833c82366ac6 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 9 Oct 2008 19:41:58 +0200 Subject: update: replaced update_return with global "modified" flag There is only once update thread at a time. Make the "modified" flag global and remove the return values of most functions. Propagating an error is only useful for updateDirectory(), since updateInDirectory() will delete failed subdirectories. --- src/update.c | 107 ++++++++++++++++++++++------------------------------------- 1 file changed, 39 insertions(+), 68 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index f0905b5db..928aac5c5 100644 --- a/src/update.c +++ b/src/update.c @@ -28,18 +28,14 @@ #include "condition.h" #include "update.h" -enum update_return { - UPDATE_RETURN_ERROR = -1, - UPDATE_RETURN_NOUPDATE = 0, - UPDATE_RETURN_UPDATED = 1 -}; - static enum update_progress { UPDATE_PROGRESS_IDLE = 0, UPDATE_PROGRESS_RUNNING = 1, UPDATE_PROGRESS_DONE = 2 } progress; +static int modified; + /* make this dynamic?, or maybe this is big enough... */ static char *update_paths[32]; static size_t update_paths_nr; @@ -122,7 +118,6 @@ static void delete_directory(struct directory *directory) struct delete_data { char *tmp; struct directory *dir; - enum update_return ret; }; /* passed to songvec_for_each */ @@ -135,30 +130,29 @@ static int delete_song_if_removed(struct mpd_song *song, void *_data) if (!isFile(data->tmp, NULL)) { delete_song(data->dir, song); - data->ret = UPDATE_RETURN_UPDATED; + modified = 1; } return 0; } -static enum update_return delete_path(const char *path) +static void delete_path(const char *path) { struct directory *directory = db_get_directory(path); struct mpd_song *song = db_get_song(path); - if (directory) + if (directory) { delete_directory(directory); - if (song) + modified = 1; + } + if (song) { delete_song(song->parent, song); - - return directory == NULL && song == NULL - ? UPDATE_RETURN_NOUPDATE - : UPDATE_RETURN_UPDATED; + modified = 1; + } } -static enum update_return +static void removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) { - enum update_return ret = UPDATE_RETURN_NOUPDATE; int i; struct dirvec *dv = &directory->children; struct delete_data data; @@ -168,15 +162,12 @@ removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) continue; LOG("removing directory: %s\n", dv->base[i]->path); dirvec_delete(dv, dv->base[i]); - ret = UPDATE_RETURN_UPDATED; + modified = 1; } data.dir = directory; data.tmp = path_max_tmp; - data.ret = ret; songvec_for_each(&directory->songs, delete_song_if_removed, &data); - - return data.ret; } static const char *opendir_path(char *path_max_tmp, const char *dirname) @@ -215,10 +206,9 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) return 0; } -static enum update_return -updateDirectory(struct directory *directory, const struct stat *st); +static int updateDirectory(struct directory *directory, const struct stat *st); -static enum update_return +static void updateInDirectory(struct directory *directory, const char *name, const struct stat *st) { @@ -228,38 +218,31 @@ updateInDirectory(struct directory *directory, if (!(song = songvec_find(&directory->songs, shortname))) { if (!(song = song_file_load(shortname, directory))) - return -1; + return; songvec_add(&directory->songs, song); + modified = 1; LOG("added %s\n", name); - return UPDATE_RETURN_UPDATED; } else if (st->st_mtime != song->mtime) { LOG("updating %s\n", name); if (!song_file_update(song)) delete_song(directory, song); - return UPDATE_RETURN_UPDATED; + modified = 1; } - - return UPDATE_RETURN_NOUPDATE; } else if (S_ISDIR(st->st_mode)) { struct directory *subdir; - enum update_return ret; if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) - return UPDATE_RETURN_ERROR; + return; if (!(subdir = directory_get_child(directory, name))) subdir = directory_new_child(directory, name); assert(directory == subdir->parent); - ret = updateDirectory(subdir, st); - if (ret == UPDATE_RETURN_ERROR || directory_is_empty(subdir)) + if (!updateDirectory(subdir, st)) delete_directory(subdir); - - return ret; } else { DEBUG("update: %s is not a directory or music\n", name); - return UPDATE_RETURN_NOUPDATE; } } @@ -269,26 +252,21 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } -static enum update_return -updateDirectory(struct directory *directory, const struct stat *st) +static int updateDirectory(struct directory *directory, const struct stat *st) { DIR *dir; const char *dirname = directory_get_path(directory); struct dirent *ent; char path_max_tmp[MPD_PATH_MAX]; - enum update_return ret = UPDATE_RETURN_NOUPDATE; - enum update_return ret2; assert(S_ISDIR(st->st_mode)); directory_set_stat(directory, st); - dir = opendir(opendir_path(path_max_tmp, dirname)); - if (!dir) - return UPDATE_RETURN_ERROR; + if (!(dir = opendir(opendir_path(path_max_tmp, dirname)))) + return 0; - if (removeDeletedFromDirectory(path_max_tmp, directory) > 0) - ret = UPDATE_RETURN_UPDATED; + removeDeletedFromDirectory(path_max_tmp, directory); while ((ent = readdir(dir))) { char *utf8; @@ -306,16 +284,14 @@ updateDirectory(struct directory *directory, const struct stat *st) dirname, strlen(dirname)); if (myStat(path_max_tmp, &st2) == 0) - ret2 = updateInDirectory(directory, path_max_tmp, &st2); + updateInDirectory(directory, path_max_tmp, &st2); else - ret2 = delete_path(path_max_tmp); - if (ret == UPDATE_RETURN_NOUPDATE) - ret = ret2; + delete_path(path_max_tmp); } closedir(dir); - return ret; + return 1; } static struct directory * @@ -363,37 +339,34 @@ addParentPathToDB(const char *utf8path) return directory; } -static enum update_return updatePath(const char *utf8path) +static void updatePath(const char *utf8path) { struct stat st; if (myStat(utf8path, &st) < 0) - return delete_path(utf8path); - return updateInDirectory(addParentPathToDB(utf8path), utf8path, &st); + delete_path(utf8path); + else + updateInDirectory(addParentPathToDB(utf8path), utf8path, &st); } static void * update_task(void *_path) { - enum update_return ret = UPDATE_RETURN_NOUPDATE; - if (_path != NULL && !isRootDirectory(_path)) { - ret = updatePath((char *)_path); + updatePath((char *)_path); free(_path); } else { struct directory *directory = db_get_root(); struct stat st; if (myStat(directory_get_path(directory), &st) == 0) - ret = updateDirectory(directory, &st); - else - ret = UPDATE_RETURN_ERROR; + updateDirectory(directory, &st); } - if (ret == UPDATE_RETURN_UPDATED && db_save() < 0) - ret = UPDATE_RETURN_ERROR; + if (modified) + db_save(); progress = UPDATE_PROGRESS_DONE; wakeup_main_task(); - return (void *)ret; + return NULL; } static void spawn_update_task(char *path) @@ -403,6 +376,7 @@ static void spawn_update_task(char *path) assert(pthread_equal(pthread_self(), main_task)); progress = UPDATE_PROGRESS_RUNNING; + modified = 0; pthread_attr_init(&attr); if (pthread_create(&update_thr, &attr, update_task, path)) FATAL("Failed to spawn update task: %s\n", strerror(errno)); @@ -437,9 +411,6 @@ unsigned directory_update_init(char *path) void reap_update_task(void) { - void *thread_return; - enum update_return ret; - assert(pthread_equal(pthread_self(), main_task)); if (progress == UPDATE_PROGRESS_IDLE) @@ -457,10 +428,10 @@ void reap_update_task(void) if (progress != UPDATE_PROGRESS_DONE) return; - if (pthread_join(update_thr, &thread_return)) + if (pthread_join(update_thr, NULL)) FATAL("error joining update thread: %s\n", strerror(errno)); - ret = (enum update_return)(size_t)thread_return; - if (ret == UPDATE_RETURN_UPDATED) + + if (modified) playlistVersionChange(); if (update_paths_nr) { -- cgit v1.2.3 From 6e2b0ca9edaed200f250ef487701ad161aa4a168 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 11 Oct 2008 19:49:14 -0700 Subject: directory: don't use identical struct and variable names Duplicated tokens in close proximity takes too long for my head to parse; and "dir" is an easy and common abbreviation for "directory". --- src/update.c | 107 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 53 insertions(+), 54 deletions(-) (limited to 'src/update.c') diff --git a/src/update.c b/src/update.c index 928aac5c5..ca3640b73 100644 --- a/src/update.c +++ b/src/update.c @@ -81,9 +81,9 @@ static void delete_song(struct directory *dir, struct mpd_song *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); + struct directory *dir = data; + assert(song->parent == dir); + delete_song(dir, song); return 0; } @@ -91,28 +91,27 @@ static int delete_each_song(struct mpd_song *song, mpd_unused void *data) * Recursively remove all sub directories and songs from a directory, * leaving an empty directory. */ -static void clear_directory(struct directory *directory) +static void clear_directory(struct directory *dir) { int i; - for (i = directory->children.nr; --i >= 0;) - clear_directory(directory->children.base[i]); - dirvec_clear(&directory->children); + for (i = dir->children.nr; --i >= 0;) + clear_directory(dir->children.base[i]); + dirvec_clear(&dir->children); - songvec_for_each(&directory->songs, delete_each_song, directory); + songvec_for_each(&dir->songs, delete_each_song, dir); } /** * Recursively free a directory and all its contents. */ -static void delete_directory(struct directory *directory) +static void delete_directory(struct directory *dir) { - assert(directory->parent != NULL); + assert(dir->parent != NULL); - clear_directory(directory); - - dirvec_delete(&directory->parent->children, directory); - directory_free(directory); + clear_directory(dir); + dirvec_delete(&dir->parent->children, dir); + directory_free(dir); } struct delete_data { @@ -137,11 +136,11 @@ static int delete_song_if_removed(struct mpd_song *song, void *_data) static void delete_path(const char *path) { - struct directory *directory = db_get_directory(path); + struct directory *dir = db_get_directory(path); struct mpd_song *song = db_get_song(path); - if (directory) { - delete_directory(directory); + if (dir) { + delete_directory(dir); modified = 1; } if (song) { @@ -151,10 +150,10 @@ static void delete_path(const char *path) } static void -removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) +removeDeletedFromDirectory(char *path_max_tmp, struct directory *dir) { int i; - struct dirvec *dv = &directory->children; + struct dirvec *dv = &dir->children; struct delete_data data; for (i = dv->nr; --i >= 0; ) { @@ -165,9 +164,9 @@ removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory) modified = 1; } - data.dir = directory; + data.dir = dir; data.tmp = path_max_tmp; - songvec_for_each(&directory->songs, delete_song_if_removed, &data); + songvec_for_each(&dir->songs, delete_song_if_removed, &data); } static const char *opendir_path(char *path_max_tmp, const char *dirname) @@ -206,38 +205,38 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) return 0; } -static int updateDirectory(struct directory *directory, const struct stat *st); +static int updateDirectory(struct directory *dir, const struct stat *st); static void -updateInDirectory(struct directory *directory, +updateInDirectory(struct directory *dir, const char *name, const struct stat *st) { if (S_ISREG(st->st_mode) && hasMusicSuffix(name, 0)) { const char *shortname = mpd_basename(name); struct mpd_song *song; - if (!(song = songvec_find(&directory->songs, shortname))) { - if (!(song = song_file_load(shortname, directory))) + if (!(song = songvec_find(&dir->songs, shortname))) { + if (!(song = song_file_load(shortname, dir))) return; - songvec_add(&directory->songs, song); + songvec_add(&dir->songs, song); modified = 1; LOG("added %s\n", name); } else if (st->st_mtime != song->mtime) { LOG("updating %s\n", name); if (!song_file_update(song)) - delete_song(directory, song); + delete_song(dir, song); modified = 1; } } else if (S_ISDIR(st->st_mode)) { struct directory *subdir; - if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) + if (inodeFoundInParent(dir, st->st_ino, st->st_dev)) return; - if (!(subdir = directory_get_child(directory, name))) - subdir = directory_new_child(directory, name); + if (!(subdir = directory_get_child(dir, name))) + subdir = directory_new_child(dir, name); - assert(directory == subdir->parent); + assert(dir == subdir->parent); if (!updateDirectory(subdir, st)) delete_directory(subdir); @@ -252,23 +251,23 @@ static int skip_path(const char *path) return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0; } -static int updateDirectory(struct directory *directory, const struct stat *st) +static int updateDirectory(struct directory *dir, const struct stat *st) { - DIR *dir; - const char *dirname = directory_get_path(directory); + DIR *fs_dir; + const char *dirname = directory_get_path(dir); struct dirent *ent; char path_max_tmp[MPD_PATH_MAX]; assert(S_ISDIR(st->st_mode)); - directory_set_stat(directory, st); + directory_set_stat(dir, st); - if (!(dir = opendir(opendir_path(path_max_tmp, dirname)))) + if (!(fs_dir = opendir(opendir_path(path_max_tmp, dirname)))) return 0; - removeDeletedFromDirectory(path_max_tmp, directory); + removeDeletedFromDirectory(path_max_tmp, dir); - while ((ent = readdir(dir))) { + while ((ent = readdir(fs_dir))) { char *utf8; struct stat st2; @@ -279,17 +278,17 @@ static int updateDirectory(struct directory *directory, const struct stat *st) if (!utf8) continue; - if (!isRootDirectory(directory->path)) + if (!isRootDirectory(dir->path)) utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), dirname, strlen(dirname)); if (myStat(path_max_tmp, &st2) == 0) - updateInDirectory(directory, path_max_tmp, &st2); + updateInDirectory(dir, path_max_tmp, &st2); else delete_path(path_max_tmp); } - closedir(dir); + closedir(fs_dir); return 1; } @@ -297,12 +296,12 @@ static int updateDirectory(struct directory *directory, const struct stat *st) static struct directory * directory_make_child_checked(struct directory *parent, const char *path) { - struct directory *directory; + struct directory *dir; struct stat st; struct mpd_song *conflicting; - if ((directory = directory_get_child(parent, path))) - return directory; + if ((dir = directory_get_child(parent, path))) + return dir; if (myStat(path, &st) < 0 || inodeFoundInParent(parent, st.st_ino, st.st_dev)) @@ -313,30 +312,30 @@ directory_make_child_checked(struct directory *parent, const char *path) if ((conflicting = songvec_find(&parent->songs, mpd_basename(path)))) delete_song(parent, conflicting); - directory = directory_new_child(parent, path); - directory_set_stat(directory, &st); - return directory; + dir = directory_new_child(parent, path); + directory_set_stat(dir, &st); + return dir; } static struct directory * addParentPathToDB(const char *utf8path) { - struct directory *directory = db_get_root(); + struct directory *dir = db_get_root(); char *duplicated = xstrdup(utf8path); char *slash = duplicated; while ((slash = strchr(slash, '/'))) { *slash = 0; - directory = directory_make_child_checked(directory, duplicated); - if (!directory || !slash) + dir = directory_make_child_checked(dir, duplicated); + if (!dir || !slash) break; *slash++ = '/'; } free(duplicated); - return directory; + return dir; } static void updatePath(const char *utf8path) @@ -355,11 +354,11 @@ static void * update_task(void *_path) updatePath((char *)_path); free(_path); } else { - struct directory *directory = db_get_root(); + struct directory *dir = db_get_root(); struct stat st; - if (myStat(directory_get_path(directory), &st) == 0) - updateDirectory(directory, &st); + if (myStat(directory_get_path(dir), &st) == 0) + updateDirectory(dir, &st); } if (modified) -- cgit v1.2.3