aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/command.c79
-rw-r--r--src/directory.c105
-rw-r--r--src/directory.h10
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);