From 89ba540e6d76aae0a594daebb9db8524ea3ed528 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 24 Sep 2009 21:55:40 +0200 Subject: command: added command "rescan" "rescan" is the same as "update", but it discards existing songs in the database. --- doc/protocol.xml | 14 ++++++++++++++ src/command.c | 24 +++++++++++++++++++++++- src/main.c | 2 +- src/update.c | 12 ++++++++---- src/update.h | 2 +- src/update_internal.h | 6 +++--- src/update_queue.c | 34 ++++++++++++++++++++++------------ src/update_walk.c | 14 +++++++++----- 8 files changed, 81 insertions(+), 27 deletions(-) diff --git a/doc/protocol.xml b/doc/protocol.xml index 922d27676..29cb09a43 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -1245,6 +1245,20 @@ OK + + + + rescan + URI + + + + + Same as update, but also rescans + unmodified files. + + + diff --git a/src/command.c b/src/command.c index 8298a4048..7c2743975 100644 --- a/src/command.c +++ b/src/command.c @@ -1025,7 +1025,28 @@ handle_update(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (argc == 2) path = argv[1]; - ret = update_enqueue(path); + ret = update_enqueue(path, false); + if (ret > 0) { + client_printf(client, "updating_db: %i\n", ret); + return COMMAND_RETURN_OK; + } else { + command_error(client, ACK_ERROR_UPDATE_ALREADY, + "already updating"); + return COMMAND_RETURN_ERROR; + } +} + +static enum command_return +handle_rescan(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + const char *path = NULL; + unsigned ret; + + assert(argc <= 2); + if (argc == 2) + path = argv[1]; + + ret = update_enqueue(path, true); if (ret > 0) { client_printf(client, "updating_db: %i\n", ret); return COMMAND_RETURN_OK; @@ -1731,6 +1752,7 @@ static const struct command commands[] = { { "random", PERMISSION_CONTROL, 1, 1, handle_random }, { "rename", PERMISSION_CONTROL, 2, 2, handle_rename }, { "repeat", PERMISSION_CONTROL, 1, 1, handle_repeat }, + { "rescan", PERMISSION_ADMIN, 0, 1, handle_rescan }, { "rm", PERMISSION_CONTROL, 1, 1, handle_rm }, { "save", PERMISSION_CONTROL, 1, 1, handle_save }, { "search", PERMISSION_READ, 2, -1, handle_search }, diff --git a/src/main.c b/src/main.c index 952e6d1fe..56627b665 100644 --- a/src/main.c +++ b/src/main.c @@ -362,7 +362,7 @@ int main(int argc, char *argv[]) if (create_db) { /* the database failed to load: recreate the database */ - unsigned job = update_enqueue(NULL); + unsigned job = update_enqueue(NULL, true); if (job == 0) g_error("directory update failed"); } diff --git a/src/update.c b/src/update.c index a8d4f3e10..8570d8ab3 100644 --- a/src/update.c +++ b/src/update.c @@ -52,6 +52,9 @@ static unsigned update_task_id; /** used by the main thread to notify the update thread */ struct notify update_notify; +/* XXX this flag is passed to update_task() */ +static bool discard; + unsigned isUpdatingDB(void) { @@ -62,7 +65,7 @@ static void * update_task(void *_path) { const char *path = _path; - modified = update_walk(path); + modified = update_walk(path, discard); g_free(_path); if (modified || !db_exists()) @@ -93,7 +96,7 @@ spawn_update_task(const char *path) } unsigned -update_enqueue(const char *path) +update_enqueue(const char *path, bool _discard) { assert(g_thread_self() == main_task); @@ -102,13 +105,14 @@ update_enqueue(const char *path) if (progress != UPDATE_PROGRESS_IDLE) { unsigned next_task_id = - update_queue_push(path, update_task_id); + update_queue_push(path, discard, update_task_id); if (next_task_id == 0) return 0; return next_task_id > update_task_id_max ? 1 : next_task_id; } + discard = _discard; spawn_update_task(path); idle_add(IDLE_UPDATE); @@ -135,7 +139,7 @@ static void update_finished_event(void) idle_add(IDLE_DATABASE); } - path = update_queue_shift(); + path = update_queue_shift(&discard); if (path != NULL) { /* schedule the next path */ spawn_update_task(path); diff --git a/src/update.h b/src/update.h index 9a51afc01..109126299 100644 --- a/src/update.h +++ b/src/update.h @@ -35,6 +35,6 @@ isUpdatingDB(void); * @return the job id, or 0 on error */ unsigned -update_enqueue(const char *path); +update_enqueue(const char *path, bool discard); #endif diff --git a/src/update_internal.h b/src/update_internal.h index b22b3c6b2..14701feb5 100644 --- a/src/update_internal.h +++ b/src/update_internal.h @@ -33,10 +33,10 @@ struct directory; extern struct notify update_notify; unsigned -update_queue_push(const char *path, unsigned base); +update_queue_push(const char *path, bool discard, unsigned base); char * -update_queue_shift(void); +update_queue_shift(bool *discard_r); void update_walk_global_init(void); @@ -48,7 +48,7 @@ update_walk_global_finish(void); * Returns true if the database was modified. */ bool -update_walk(const char *path); +update_walk(const char *path, bool discard); void update_remove_global_init(void); diff --git a/src/update_queue.c b/src/update_queue.c index ef1753c21..60e752a62 100644 --- a/src/update_queue.c +++ b/src/update_queue.c @@ -25,31 +25,41 @@ #include /* make this dynamic?, or maybe this is big enough... */ -static char *update_paths[32]; -static size_t update_paths_nr; +static struct { + char *path; + bool discard; +} update_queue[32]; + +static size_t update_queue_length; unsigned -update_queue_push(const char *path, unsigned base) +update_queue_push(const char *path, bool discard, unsigned base) { - assert(update_paths_nr <= G_N_ELEMENTS(update_paths)); + assert(update_queue_length <= G_N_ELEMENTS(update_queue)); - if (update_paths_nr == G_N_ELEMENTS(update_paths)) + if (update_queue_length == G_N_ELEMENTS(update_queue)) return 0; - update_paths[update_paths_nr++] = g_strdup(path); - return base + update_paths_nr; + update_queue[update_queue_length].path = g_strdup(path); + update_queue[update_queue_length].discard = discard; + + ++update_queue_length; + + return base + update_queue_length; } char * -update_queue_shift(void) +update_queue_shift(bool *discard_r) { char *path; - if (update_paths_nr == 0) + if (update_queue_length == 0) return NULL; - path = update_paths[0]; - memmove(&update_paths[0], &update_paths[1], - --update_paths_nr * sizeof(char *)); + path = update_queue[0].path; + *discard_r = update_queue[0].discard; + + memmove(&update_queue[0], &update_queue[1], + --update_queue_length * sizeof(update_queue[0])); return path; } diff --git a/src/update_walk.c b/src/update_walk.c index 967795cff..b79e95ae0 100644 --- a/src/update_walk.c +++ b/src/update_walk.c @@ -39,6 +39,7 @@ #include #include +static bool walk_discard; static bool modified; #ifndef WIN32 @@ -350,7 +351,8 @@ update_archive_file(struct directory *parent, const char *name, char *filepath; directory = dirvec_find(&parent->children, name); - if (directory != NULL && directory->mtime == st->st_mtime) + if (directory != NULL && directory->mtime == st->st_mtime && + !walk_discard) /* MPD has already scanned the archive, and it hasn't changed since - don't consider updating it */ return; @@ -405,7 +407,7 @@ update_container_file( struct directory* directory, if (contdir != NULL) { // modification time not eq. file mod. time - if (contdir->mtime != st->st_mtime) + if (contdir->mtime != st->st_mtime || walk_discard) { g_message("removing container file: %s", pathname); @@ -470,7 +472,8 @@ update_regular_file(struct directory *directory, { struct song* song = songvec_find(&directory->songs, name); - if (!(song != NULL && st->st_mtime == song->mtime) && + if (!(song != NULL && st->st_mtime == song->mtime && + !walk_discard) && plugin->container_scan != NULL) { if (update_container_file(directory, name, st, plugin)) @@ -491,7 +494,7 @@ update_regular_file(struct directory *directory, modified = true; g_message("added %s/%s", directory_get_path(directory), name); - } else if (st->st_mtime != song->mtime) { + } else if (st->st_mtime != song->mtime || walk_discard) { g_message("updating %s/%s", directory_get_path(directory), name); if (!song_file_update(song)) @@ -737,8 +740,9 @@ updatePath(const char *path) } bool -update_walk(const char *path) +update_walk(const char *path, bool discard) { + walk_discard = discard; modified = false; if (path != NULL && !isRootDirectory(path)) { -- cgit v1.2.3