diff options
author | Eric Wong <normalperson@yhbt.net> | 2008-09-29 02:48:09 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2008-09-29 03:04:29 -0700 |
commit | 659a543da853bcb28c22df300a93bd22dc9ae877 (patch) | |
tree | 7b3651df4ec404fe7041b5a9b698e7ac17307b7e | |
parent | 887f97b868886a66d7bb2fcd0e1fd6810297299d (diff) | |
download | mpd-659a543da853bcb28c22df300a93bd22dc9ae877.tar.gz mpd-659a543da853bcb28c22df300a93bd22dc9ae877.tar.xz mpd-659a543da853bcb28c22df300a93bd22dc9ae877.zip |
update: move path sanitation up the stack to avoid extra copies
Remove yet another use of our old malloc-happy linked list
implementation and replace it with a simple array of strings.
This also implements more eager error handling of invalid
paths (still centralized in updateInit) so we can filter out
bad paths before we spawn a thread.
This also does its part to fix the "update" command inside list mode
which lost its static variable in
ada24f9a921ff95d874195acf253b5a9dd12213d (although it was broken and
requires the fix in 769939b62f7557f8e7c483223d68a8b39af43e37, too).
Diffstat (limited to '')
-rw-r--r-- | src/command.c | 40 | ||||
-rw-r--r-- | src/directory.c | 38 | ||||
-rw-r--r-- | src/directory.h | 10 |
3 files changed, 58 insertions, 30 deletions
diff --git a/src/command.c b/src/command.c index ce41abb64..70bfa78b5 100644 --- a/src/command.c +++ b/src/command.c @@ -36,6 +36,7 @@ #include "os_compat.h" #include "player_error.h" #include "outputBuffer.h" +#include "path.h" #define COMMAND_PLAY "play" #define COMMAND_PLAYID "playid" @@ -805,7 +806,10 @@ static int print_update_result(int fd, int ret) fdprintf(fd, "updating_db: %i\n", ret); return 0; } - commandError(fd, ACK_ERROR_UPDATE_ALREADY, "already updating"); + if (ret == -2) + commandError(fd, ACK_ERROR_ARG, "invalid path"); + else + commandError(fd, ACK_ERROR_UPDATE_ALREADY, "already updating"); return -1; } @@ -815,20 +819,28 @@ static int listHandleUpdate(int fd, char *argv[], struct strnode *cmdnode, CommandEntry * cmd) { - List *pathList = makeList(NULL, 1); + static char **pathv; + static int pathc; CommandEntry *nextCmd = NULL; struct strnode *next = cmdnode->next; + int last = pathc++; - if (argc == 2) - insertInList(pathList, argv[1], NULL); - else - insertInList(pathList, "", NULL); + pathv = xrealloc(pathv, pathc * sizeof(char *)); + pathv[last] = sanitizePathDup(argc == 2 ? argv[1] : ""); if (next) nextCmd = getCommandEntryFromString(next->data, permission); - if (cmd != nextCmd) - return print_update_result(fd, updateInit(pathList)); + if (cmd != nextCmd) { + int ret = print_update_result(fd, updateInit(pathc, pathv)); + if (pathc) { + assert(pathv); + free(pathv); + pathv = NULL; + pathc = 0; + } + return ret; + } return 0; } @@ -836,14 +848,12 @@ static int listHandleUpdate(int fd, static int handleUpdate(int fd, mpd_unused int *permission, mpd_unused int argc, char *argv[]) { - List *pathList = NULL; + char *pathv[1]; - if (argc == 2) { - pathList = makeList(NULL, 1); - insertInList(pathList, argv[1], NULL); - } - - return print_update_result(fd, updateInit(pathList)); + assert(argc <= 2); + if (argc == 2) + pathv[0] = sanitizePathDup(argv[1]); + return print_update_result(fd, updateInit(argc - 1, pathv)); } static int handleNext(mpd_unused int fd, mpd_unused int *permission, diff --git a/src/directory.c b/src/directory.c index a332316ff..8d36985dc 100644 --- a/src/directory.c +++ b/src/directory.c @@ -114,16 +114,15 @@ void reap_update_task(void) progress = UPDATE_PROGRESS_IDLE; } -static void * update_task(void *arg) +/* @argv represents a null-terminated array of (null-terminated) strings */ +static void * update_task(void *argv) { - 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)) { + if (argv) { + char **pathv; + for (pathv = (char **)argv; *pathv; pathv++) { + switch (updatePath(*pathv)) { case UPDATE_RETURN_ERROR: ret = UPDATE_RETURN_ERROR; goto out; @@ -132,9 +131,9 @@ static void * update_task(void *arg) case UPDATE_RETURN_UPDATED: ret = UPDATE_RETURN_UPDATED; } - node = node->nextNode; + free(*pathv); } - freeList(path_list); + free(argv); } else { ret = updateDirectory(music_root); } @@ -147,17 +146,32 @@ out: return (void *)ret; } -int updateInit(List * path_list) +int updateInit(int argc, char *argv[]) { pthread_attr_t attr; + char **pathv = NULL; + int i; - if (progress != UPDATE_PROGRESS_IDLE) + if (progress != UPDATE_PROGRESS_IDLE) { + for (i = argc; --i >= 0; ) + free(argv[i]); return -1; + } + + for (i = argc; --i >= 0; ) { + if (!argv[i]) + return -2; + } progress = UPDATE_PROGRESS_RUNNING; + if (argc > 0) { + pathv = xmalloc((argc + 1) * sizeof(char *)); + memcpy(pathv, argv, argc * sizeof(char *)); + pathv[argc] = NULL; + } pthread_attr_init(&attr); - if (pthread_create(&update_thr, &attr, update_task, path_list)) + if (pthread_create(&update_thr, &attr, update_task, pathv)) FATAL("Failed to spawn update task: %s\n", strerror(errno)); directory_updateJobId++; if (directory_updateJobId > 1 << 15) diff --git a/src/directory.h b/src/directory.h index 9161efc38..eb1b35aa7 100644 --- a/src/directory.h +++ b/src/directory.h @@ -21,7 +21,6 @@ #include "song.h" #include "songvec.h" -#include "list.h" struct dirvec { struct _Directory **base; @@ -42,8 +41,13 @@ void reap_update_task(void); int isUpdatingDB(void); -/* returns the non-negative update job ID on success, -1 on error */ -int updateInit(List * pathList); +/* + * returns the non-negative update job ID on success, + * -1 if busy, -2 if invalid argument + * @argv itself is safe to free once updateInit returns, but the + * string values contained by @argv MUST NOT be freed manually + */ +int updateInit(int argc, char *argv[]); void directory_init(void); |