diff options
Diffstat (limited to 'src/directory.c')
-rw-r--r-- | src/directory.c | 165 |
1 files changed, 85 insertions, 80 deletions
diff --git a/src/directory.c b/src/directory.c index fc9c6b41d..773b16db6 100644 --- a/src/directory.c +++ b/src/directory.c @@ -52,13 +52,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 int addToDirectory(Directory * directory, const char *name); @@ -70,8 +75,7 @@ static enum update_return updateDirectory(Directory * directory); static void deleteEmptyDirectoriesInDirectory(Directory * directory); -static void removeSongFromDirectory(Directory * directory, - const char *shortname); +static void delete_song(Directory *dir, Song *del); static enum update_return addSubDirectoryToDirectory(Directory * directory, const char *name, struct stat *st); @@ -98,87 +102,84 @@ static char *getDbFile(void) int isUpdatingDB(void) { - return (progress != UPDATE_PROGRESS_IDLE) ? directory_updateJobId : 0; -} - -void reap_update_task(void) -{ - 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; + return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0; } -/* @argv represents a null-terminated array of (null-terminated) strings */ -static void * update_task(void *argv) +static void * update_task(void *_path) { enum update_return ret = UPDATE_RETURN_NOUPDATE; - if (argv) { - char **pathv; - for (pathv = (char **)argv; *pathv; pathv++) { - switch (updatePath(*pathv)) { - case UPDATE_RETURN_ERROR: - ret = UPDATE_RETURN_ERROR; - goto out; - case UPDATE_RETURN_NOUPDATE: - break; - case UPDATE_RETURN_UPDATED: - ret = UPDATE_RETURN_UPDATED; - } - free(*pathv); - } - free(argv); + 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(int argc, char *argv[]) +static void spawn_update_task(char *path) { pthread_attr_t attr; - char **pathv = NULL; - int i; - - 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; - } + assert(pthread_equal(pthread_self(), main_task)); 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, pathv)) + 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); - return 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)); + + 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) @@ -212,16 +213,12 @@ static void freeDirectory(Directory * directory) /*getDirectoryPath(NULL); */ } -static void removeSongFromDirectory(Directory * directory, const char *shortname) +static void delete_song(Directory *dir, Song *del) { - Song *song = songvec_find(&directory->songs, shortname); - - if (song) { - char path_max_tmp[MPD_PATH_MAX]; /* wasteful */ - LOG("removing: %s\n", get_song_url(path_max_tmp, song)); - songvec_delete(&directory->songs, song); - freeSong(song); /* FIXME racy */ - } + char path_max_tmp[MPD_PATH_MAX]; /* wasteful */ + LOG("removing: %s\n", get_song_url(path_max_tmp, del)); + songvec_delete(&dir->songs, del); + freeSong(del); /* FIXME racy */ } static void deleteEmptyDirectoriesInDirectory(Directory * directory) @@ -256,7 +253,7 @@ updateInDirectory(Directory * directory, const char *name) } else if (st.st_mtime != song->mtime) { LOG("updating %s\n", name); if (updateSongInfo(song) < 0) - removeSongFromDirectory(directory, shortname); + delete_song(directory, song); return UPDATE_RETURN_UPDATED; } } else if (S_ISDIR(st.st_mode)) { @@ -308,7 +305,7 @@ removeDeletedFromDirectory(char *path_max_tmp, Directory * directory) strcpy(path_max_tmp, song->url); if (!isFile(path_max_tmp, NULL)) { - removeSongFromDirectory(directory, song->url); + delete_song(directory, song); ret = UPDATE_RETURN_UPDATED; } } @@ -322,6 +319,7 @@ static Directory *addDirectoryPathToDB(const char *utf8path) char *parent; Directory *parentDirectory; Directory *directory; + Song *conflicting; parent = parent_path(path_max_tmp, utf8path); @@ -348,7 +346,10 @@ static Directory *addDirectoryPathToDB(const char *utf8path) /* if we're adding directory paths, make sure to delete filenames with potentially the same name */ - removeSongFromDirectory(parentDirectory, mpd_basename(directory->path)); + conflicting = songvec_find(&parentDirectory->songs, + mpd_basename(directory->path)); + if (conflicting) + delete_song(parentDirectory, conflicting); return directory; } @@ -419,14 +420,13 @@ static enum update_return updatePath(const char *utf8path) else if (updateSongInfo(song) == 0) return UPDATE_RETURN_UPDATED; else { - removeSongFromDirectory(parentDirectory, - song->url); + delete_song(parentDirectory, song); return UPDATE_RETURN_UPDATED; } } /* if updateDirectory fails, means we should delete it */ else { - removeSongFromDirectory(parentDirectory, song->url); + delete_song(parentDirectory, song); ret = UPDATE_RETURN_UPDATED; /* don't return, path maybe a directory now */ } @@ -723,12 +723,13 @@ static void readDirectoryInfo(FILE * fp, Directory * directory) char buffer[MPD_PATH_MAX * 2]; int bufferSize = MPD_PATH_MAX * 2; char key[MPD_PATH_MAX * 2]; - Directory *subDirectory; char *name; while (myFgets(buffer, bufferSize, fp) && prefixcmp(buffer, DIRECTORY_END)) { if (!prefixcmp(buffer, DIRECTORY_DIR)) { + Directory *subdir; + strcpy(key, &(buffer[strlen(DIRECTORY_DIR)])); if (!myFgets(buffer, bufferSize, fp)) FATAL("Error reading db, fgets\n"); @@ -740,9 +741,13 @@ static void readDirectoryInfo(FILE * fp, Directory * directory) if (prefixcmp(buffer, DIRECTORY_BEGIN)) FATAL("Error reading db at line: %s\n", buffer); name = &(buffer[strlen(DIRECTORY_BEGIN)]); - subDirectory = newDirectory(name, directory); - dirvec_add(&directory->children, subDirectory); - readDirectoryInfo(fp, subDirectory); + if ((subdir = getDirectory(name))) { + assert(subdir->parent == directory); + } else { + subdir = newDirectory(name, directory); + dirvec_add(&directory->children, subdir); + } + readDirectoryInfo(fp, subdir); } else if (!prefixcmp(buffer, SONG_BEGIN)) { readSongInfoIntoList(fp, directory); } else { |