diff options
-rw-r--r-- | src/command.c | 79 | ||||
-rw-r--r-- | src/directory.c | 105 | ||||
-rw-r--r-- | src/directory.h | 10 |
3 files changed, 83 insertions, 111 deletions
diff --git a/src/command.c b/src/command.c index 822ee05bf..3dda2f3c2 100644 --- a/src/command.c +++ b/src/command.c @@ -36,6 +36,7 @@ #include "tag.h" #include "client.h" #include "tag_print.h" +#include "path.h" #include "os_compat.h" #define COMMAND_PLAY "play" @@ -153,8 +154,6 @@ static const char check_non_negative[] = "\"%s\" is not an integer >= 0"; static const char *current_command; static int command_listNum; -static CommandEntry *getCommandEntryFromString(char *string, int permission); - static List *commandList; static CommandEntry *newCommandEntry(void) @@ -814,55 +813,31 @@ static int handlePlaylistMove(struct client *client, return print_playlist_result(client, result); } -static int listHandleUpdate(struct client *client, - mpd_unused int argc, - char *argv[], - struct strnode *cmdnode, CommandEntry * cmd) +static int print_update_result(struct client *client, int ret) { - List *pathList = makeList(NULL, 1); - CommandEntry *nextCmd = NULL; - struct strnode *next = cmdnode->next; - - if (argc == 2) - insertInList(pathList, argv[1], NULL); - else - insertInList(pathList, "", NULL); - - if (next) - nextCmd = getCommandEntryFromString(next->data, - client_get_permission(client)); - - if (cmd != nextCmd) { - int ret = updateInit(pathList); - if (ret == -1) - command_error(client, ACK_ERROR_UPDATE_ALREADY, - "already updating"); - - return ret; + if (ret >= 0) { + client_printf(client, "updating_db: %i\n", ret); + return 0; } - - return 0; + if (ret == -2) + command_error(client, ACK_ERROR_ARG, "invalid path"); + else + command_error(client, ACK_ERROR_UPDATE_ALREADY, + "already updating"); + return -1; } static int handleUpdate(struct client *client, mpd_unused int argc, char *argv[]) { - int ret; + char *path = NULL; - if (argc == 2) { - List *pathList = makeList(NULL, 1); - insertInList(pathList, argv[1], NULL); - ret = updateInit(pathList); - } else { - ret = updateInit(NULL); + assert(argc <= 2); + if (argc == 2 && !(path = sanitizePathDup(argv[1]))) { + command_error(client, ACK_ERROR_ARG, "invalid path"); + return -1; } - - if (ret == -1) - command_error(client, ACK_ERROR_UPDATE_ALREADY, - "already updating"); - - client_printf(client, "updating_db: %i\n", ret); - return 0; + return print_update_result(client, directory_update_init(path)); } static int handleNext(mpd_unused struct client *client, @@ -1307,7 +1282,7 @@ void initCommands(void) addCommand(COMMAND_PLAYLISTINFO, PERMISSION_READ, 0, 1, handlePlaylistInfo, NULL); addCommand(COMMAND_FIND, PERMISSION_READ, 2, -1, handleFind, NULL); addCommand(COMMAND_SEARCH, PERMISSION_READ, 2, -1, handleSearch, NULL); - addCommand(COMMAND_UPDATE, PERMISSION_ADMIN, 0, 1, handleUpdate, listHandleUpdate); + addCommand(COMMAND_UPDATE, PERMISSION_ADMIN, 0, 1, handleUpdate, NULL); addCommand(COMMAND_NEXT, PERMISSION_CONTROL, 0, 0, handleNext, NULL); addCommand(COMMAND_PREVIOUS, PERMISSION_CONTROL, 0, 0, handlePrevious, NULL); addCommand(COMMAND_LISTALL, PERMISSION_READ, 0, 1, handleListAll, NULL); @@ -1420,24 +1395,6 @@ static CommandEntry *getCommandEntryAndCheckArgcAndPermission(struct client *cli return cmd; } -static CommandEntry *getCommandEntryFromString(char *string, int permission) -{ - CommandEntry *cmd = NULL; - char *argv[COMMAND_ARGV_MAX] = { NULL }; - char *duplicated = xstrdup(string); - int argc = buffer2array(duplicated, argv, COMMAND_ARGV_MAX); - - if (0 == argc) - goto out; - - cmd = getCommandEntryAndCheckArgcAndPermission(0, permission, - argc, argv); - -out: - free(duplicated); - return cmd; -} - static int processCommandInternal(struct client *client, char *commandString, struct strnode *cmdnode) { diff --git a/src/directory.c b/src/directory.c index 82ee0854d..cc0027d96 100644 --- a/src/directory.c +++ b/src/directory.c @@ -53,13 +53,18 @@ enum update_progress { 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 Directory *music_root; static time_t directory_dbModTime; static pthread_t update_thr; -static int directory_updateJobId; +static const int update_task_id_max = 1 << 15; +static int update_task_id; static enum update_return addToDirectory(Directory * directory, const char *name); @@ -99,74 +104,84 @@ static char *getDbFile(void) int isUpdatingDB(void) { - return (progress != UPDATE_PROGRESS_IDLE) ? directory_updateJobId : 0; + return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0; } -void reap_update_task(void) +static void * update_task(void *_path) { - enum update_return ret; - - 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(); - progress = UPDATE_PROGRESS_IDLE; -} - -static void * update_task(void *arg) -{ - List *path_list = (List *)arg; enum update_return ret = UPDATE_RETURN_NOUPDATE; - if (path_list) { - ListNode *node = path_list->firstNode; - - while (node) { - switch (updatePath(node->key)) { - case UPDATE_RETURN_ERROR: - ret = UPDATE_RETURN_ERROR; - goto out; - case UPDATE_RETURN_NOUPDATE: - break; - case UPDATE_RETURN_UPDATED: - ret = UPDATE_RETURN_UPDATED; - } - node = node->nextNode; - } - freeList(path_list); + if (_path) { + ret = updatePath((char *)_path); + free(_path); } else { ret = updateDirectory(music_root); } if (ret == UPDATE_RETURN_UPDATED && writeDirectoryDB() < 0) ret = UPDATE_RETURN_ERROR; -out: progress = UPDATE_PROGRESS_DONE; wakeup_main_task(); return (void *)ret; } -int updateInit(List * path_list) +static void spawn_update_task(char *path) { pthread_attr_t attr; - if (progress != UPDATE_PROGRESS_IDLE) - return -1; + assert(pthread_equal(pthread_self(), main_task)); progress = UPDATE_PROGRESS_RUNNING; - pthread_attr_init(&attr); - if (pthread_create(&update_thr, &attr, update_task, path_list)) + if (pthread_create(&update_thr, &attr, update_task, path)) FATAL("Failed to spawn update task: %s\n", strerror(errno)); - directory_updateJobId++; - if (directory_updateJobId > 1 << 15) - directory_updateJobId = 1; - DEBUG("updateInit: spawned update thread for update job id %i\n", - (int)directory_updateJobId); + if (++update_task_id > update_task_id_max) + update_task_id = 1; + DEBUG("spawned thread for update job id %i\n", update_task_id); +} + +void reap_update_task(void) +{ + enum update_return ret; + + assert(pthread_equal(pthread_self(), main_task)); - return (int)directory_updateJobId; + 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; + } +} + +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; } static void directory_set_stat(Directory * dir, const struct stat *st) diff --git a/src/directory.h b/src/directory.h index 42d0e2bb6..764902071 100644 --- a/src/directory.h +++ b/src/directory.h @@ -42,12 +42,12 @@ void reap_update_task(void); int isUpdatingDB(void); -/** - * Starts the tag cache update in the specified location(s). Returns - * the job id on success, -1 on error or 0 if an update is already - * running. +/* + * returns the non-negative update job ID on success, + * returns -1 if busy + * @path will be freed by this function and should not be reused */ -int updateInit(List * pathList); +int directory_update_init(char *path); void directory_init(void); |