mpd/src/directory.c

1059 lines
25 KiB
C
Raw Normal View History

/* the Music Player Daemon (MPD)
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "directory.h"
#include "conf.h"
#include "log.h"
#include "ls.h"
#include "path.h"
#include "playlist.h"
#include "stats.h"
#include "utils.h"
2008-09-29 12:16:57 +02:00
#include "client.h"
#include "dbUtils.h"
#include "song_print.h"
#include "song_save.h"
#include "main_notify.h"
#include "dirvec.h"
#define DIRECTORY_DIR "directory: "
#define DIRECTORY_MTIME "mtime: " /* DEPRECATED, noop-read-only */
#define DIRECTORY_BEGIN "begin: "
#define DIRECTORY_END "end: "
#define DIRECTORY_INFO_BEGIN "info_begin"
#define DIRECTORY_INFO_END "info_end"
#define DIRECTORY_MPD_VERSION "mpd_version: "
#define DIRECTORY_FS_CHARSET "fs_charset: "
enum update_return {
UPDATE_RETURN_ERROR = -1,
UPDATE_RETURN_NOUPDATE = 0,
UPDATE_RETURN_UPDATED = 1
};
enum update_progress {
UPDATE_PROGRESS_IDLE = 0,
UPDATE_PROGRESS_RUNNING = 1,
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 const int update_task_id_max = 1 << 15;
static int update_task_id;
static enum update_return
addToDirectory(Directory * directory, const char *name);
static void freeDirectory(Directory * directory);
static enum update_return exploreDirectory(Directory * directory);
static enum update_return updateDirectory(Directory * directory);
static void deleteEmptyDirectoriesInDirectory(Directory * directory);
static void delete_song(Directory *dir, Song *del);
static enum update_return addSubDirectoryToDirectory(Directory * directory,
const char *name, struct stat *st);
static Directory *getDirectory(const char *name);
static enum update_return updatePath(const char *utf8path);
static void sortDirectory(Directory * directory);
static int inodeFoundInParent(Directory * parent, ino_t inode, dev_t device);
static int statDirectory(Directory * dir);
static char *getDbFile(void)
{
ConfigParam *param = parseConfigFilePath(CONF_DB_FILE, 1);
assert(param);
assert(param->value);
return param->value;
}
int isUpdatingDB(void)
{
return (progress != UPDATE_PROGRESS_IDLE) ? update_task_id : 0;
}
static void * update_task(void *_path)
{
enum update_return ret = UPDATE_RETURN_NOUPDATE;
if (_path) {
ret = updatePath((char *)_path);
free(_path);
} else {
ret = updateDirectory(music_root);
}
if (ret == UPDATE_RETURN_UPDATED && writeDirectoryDB() < 0)
ret = UPDATE_RETURN_ERROR;
progress = UPDATE_PROGRESS_DONE;
wakeup_main_task();
return (void *)ret;
}
static void spawn_update_task(char *path)
{
pthread_attr_t attr;
assert(pthread_equal(pthread_self(), main_task));
progress = UPDATE_PROGRESS_RUNNING;
pthread_attr_init(&attr);
if (pthread_create(&update_thr, &attr, update_task, path))
FATAL("Failed to spawn update task: %s\n", strerror(errno));
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)
{
dir->inode = st->st_ino;
dir->device = st->st_dev;
dir->stat = 1;
}
static Directory *newDirectory(const char *dirname, Directory * parent)
{
Directory *directory;
directory = xcalloc(1, sizeof(Directory));
if (dirname && strlen(dirname))
directory->path = xstrdup(dirname);
directory->parent = parent;
return directory;
}
static void freeDirectory(Directory * directory)
{
dirvec_destroy(&directory->children);
songvec_destroy(&directory->songs);
if (directory->path)
free(directory->path);
free(directory);
/* this resets last dir returned */
/*getDirectoryPath(NULL); */
}
static void delete_song(Directory *dir, Song *del)
{
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)
{
int i;
struct dirvec *dv = &directory->children;
for (i = dv->nr; --i >= 0; ) {
deleteEmptyDirectoriesInDirectory(dv->base[i]);
if (!dv->base[i]->children.nr && !dv->base[i]->songs.nr)
dirvec_delete(dv, dv->base[i]);
}
if (!dv->nr)
dirvec_destroy(dv);
}
static enum update_return
updateInDirectory(Directory * directory, const char *name)
{
Song *song;
struct stat st;
if (myStat(name, &st))
return UPDATE_RETURN_ERROR;
if (S_ISREG(st.st_mode) && hasMusicSuffix(name, 0)) {
const char *shortname = mpd_basename(name);
if (!(song = songvec_find(&directory->songs, shortname))) {
addToDirectory(directory, name);
return UPDATE_RETURN_UPDATED;
} else if (st.st_mtime != song->mtime) {
LOG("updating %s\n", name);
if (updateSongInfo(song) < 0)
delete_song(directory, song);
return UPDATE_RETURN_UPDATED;
}
} else if (S_ISDIR(st.st_mode)) {
Directory *subdir = dirvec_find(&directory->children, name);
if (subdir) {
assert(directory == subdir->parent);
directory_set_stat(subdir, &st);
return updateDirectory(subdir);
} else {
return addSubDirectoryToDirectory(directory, name, &st);
}
}
return UPDATE_RETURN_NOUPDATE;
}
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
/* we don't look at hidden files nor files with newlines in them */
static int skip_path(const char *path)
{
return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0;
}
static enum update_return
removeDeletedFromDirectory(char *path_max_tmp, Directory * directory)
{
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
const char *dirname = (directory && directory->path) ?
directory->path : NULL;
enum update_return ret = UPDATE_RETURN_NOUPDATE;
int i;
struct songvec *sv = &directory->songs;
struct dirvec *dv = &directory->children;
for (i = dv->nr; --i >= 0; ) {
if (isDir(dv->base[i]->path))
continue;
LOG("removing directory: %s\n", dv->base[i]->path);
dirvec_delete(dv, dv->base[i]);
ret = UPDATE_RETURN_UPDATED;
}
for (i = sv->nr; --i >= 0; ) { /* cleaner deletes if we go backwards */
Song *song = sv->base[i];
if (!song || !song->url)
continue; /* does this happen?, perhaps assert() */
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (dirname)
sprintf(path_max_tmp, "%s/%s", dirname, song->url);
else
strcpy(path_max_tmp, song->url);
if (!isFile(path_max_tmp, NULL)) {
delete_song(directory, song);
ret = UPDATE_RETURN_UPDATED;
}
}
return ret;
}
static Directory *addDirectoryPathToDB(const char *utf8path)
{
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
char path_max_tmp[MPD_PATH_MAX];
char *parent;
Directory *parentDirectory;
Directory *directory;
Song *conflicting;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
parent = parent_path(path_max_tmp, utf8path);
if (strlen(parent) == 0)
parentDirectory = music_root;
else
parentDirectory = addDirectoryPathToDB(parent);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (!parentDirectory)
return NULL;
if ((directory = dirvec_find(&parentDirectory->children, utf8path))) {
assert(parentDirectory == directory->parent);
} else {
struct stat st;
if (myStat(utf8path, &st) < 0 ||
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev))
return NULL;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
else {
directory = newDirectory(utf8path, parentDirectory);
dirvec_add(&parentDirectory->children, directory);
}
}
/* if we're adding directory paths, make sure to delete filenames
with potentially the same name */
conflicting = songvec_find(&parentDirectory->songs,
mpd_basename(directory->path));
if (conflicting)
delete_song(parentDirectory, conflicting);
return directory;
}
static Directory *addParentPathToDB(const char *utf8path)
{
char *parent;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
char path_max_tmp[MPD_PATH_MAX];
Directory *parentDirectory;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
parent = parent_path(path_max_tmp, utf8path);
if (strlen(parent) == 0)
parentDirectory = music_root;
else
parentDirectory = addDirectoryPathToDB(parent);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (!parentDirectory)
return NULL;
return (Directory *) parentDirectory;
}
static enum update_return updatePath(const char *utf8path)
{
Directory *directory;
Directory *parentDirectory;
Song *song;
char *path = sanitizePathDup(utf8path);
time_t mtime;
enum update_return ret = UPDATE_RETURN_NOUPDATE;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
char path_max_tmp[MPD_PATH_MAX];
if (NULL == path)
return UPDATE_RETURN_ERROR;
/* if path is in the DB try to update it, or else delete it */
if ((directory = getDirectory(path))) {
parentDirectory = directory->parent;
/* if this update directory is successfull, we are done */
ret = updateDirectory(directory);
if (ret != UPDATE_RETURN_ERROR) {
free(path);
sortDirectory(directory);
return ret;
}
/* we don't want to delete the root directory */
else if (directory == music_root) {
free(path);
return UPDATE_RETURN_NOUPDATE;
}
/* if updateDirectory fails, means we should delete it */
else {
LOG("removing directory: %s\n", path);
dirvec_delete(&parentDirectory->children, directory);
ret = UPDATE_RETURN_UPDATED;
/* don't return, path maybe a song now */
}
} else if ((song = getSongFromDB(path))) {
parentDirectory = song->parentDir;
if (!parentDirectory->stat
&& statDirectory(parentDirectory) < 0) {
free(path);
return UPDATE_RETURN_NOUPDATE;
}
/* if this song update is successful, we are done */
else if (!inodeFoundInParent(parentDirectory->parent,
parentDirectory->inode,
parentDirectory->device) &&
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
isMusic(get_song_url(path_max_tmp, song), &mtime, 0)) {
free(path);
if (song->mtime == mtime)
return UPDATE_RETURN_NOUPDATE;
else if (updateSongInfo(song) == 0)
return UPDATE_RETURN_UPDATED;
else {
delete_song(parentDirectory, song);
return UPDATE_RETURN_UPDATED;
}
}
/* if updateDirectory fails, means we should delete it */
else {
delete_song(parentDirectory, song);
ret = UPDATE_RETURN_UPDATED;
/* don't return, path maybe a directory now */
}
}
/* path not found in the db, see if it actually exists on the fs.
* Also, if by chance a directory was replaced by a file of the same
* name or vice versa, we need to add it to the db
*/
if (isDir(path) || isMusic(path, NULL, 0)) {
parentDirectory = addParentPathToDB(path);
if (!parentDirectory || (!parentDirectory->stat &&
statDirectory(parentDirectory) < 0)) {
} else if (0 == inodeFoundInParent(parentDirectory->parent,
parentDirectory->inode,
parentDirectory->device)
&& addToDirectory(parentDirectory, path)
== UPDATE_RETURN_UPDATED) {
ret = UPDATE_RETURN_UPDATED;
}
}
free(path);
return ret;
}
static const char *opendir_path(char *path_max_tmp, const char *dirname)
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
{
if (*dirname != '\0')
return rmp2amp_r(path_max_tmp,
utf8_to_fs_charset(path_max_tmp, dirname));
return musicDir;
}
static enum update_return updateDirectory(Directory * directory)
{
DIR *dir;
const char *dirname = getDirectoryPath(directory);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
struct dirent *ent;
char path_max_tmp[MPD_PATH_MAX];
enum update_return ret = UPDATE_RETURN_NOUPDATE;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (!directory->stat && statDirectory(directory) < 0)
return UPDATE_RETURN_ERROR;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
else if (inodeFoundInParent(directory->parent,
directory->inode,
directory->device))
return UPDATE_RETURN_ERROR;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
dir = opendir(opendir_path(path_max_tmp, dirname));
if (!dir)
return UPDATE_RETURN_ERROR;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (removeDeletedFromDirectory(path_max_tmp, directory) > 0)
ret = UPDATE_RETURN_UPDATED;
while ((ent = readdir(dir))) {
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
char *utf8;
if (skip_path(ent->d_name))
continue;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name);
if (!utf8)
continue;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (directory->path)
utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8),
dirname, strlen(dirname));
if (updateInDirectory(directory, path_max_tmp) > 0)
ret = UPDATE_RETURN_UPDATED;
}
closedir(dir);
return ret;
}
static enum update_return exploreDirectory(Directory * directory)
{
DIR *dir;
const char *dirname = getDirectoryPath(directory);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
struct dirent *ent;
char path_max_tmp[MPD_PATH_MAX];
enum update_return ret = UPDATE_RETURN_NOUPDATE;
DEBUG("explore: attempting to opendir: %s\n", dirname);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
dir = opendir(opendir_path(path_max_tmp, dirname));
if (!dir)
return UPDATE_RETURN_ERROR;
DEBUG("explore: %s\n", dirname);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
while ((ent = readdir(dir))) {
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
char *utf8;
if (skip_path(ent->d_name))
continue;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name);
if (!utf8)
continue;
DEBUG("explore: found: %s (%s)\n", ent->d_name, utf8);
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (directory->path)
utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8),
dirname, strlen(dirname));
if (addToDirectory(directory, path_max_tmp) ==
UPDATE_RETURN_UPDATED)
ret = UPDATE_RETURN_UPDATED;
}
closedir(dir);
return ret;
}
static int statDirectory(Directory * dir)
{
struct stat st;
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
if (myStat(getDirectoryPath(dir), &st) < 0)
return -1;
directory_set_stat(dir, &st);
return 0;
}
static int inodeFoundInParent(Directory * parent, ino_t inode, dev_t device)
{
while (parent) {
if (!parent->stat && statDirectory(parent) < 0)
return -1;
if (parent->inode == inode && parent->device == device) {
DEBUG("recursive directory found\n");
return 1;
}
parent = parent->parent;
}
return 0;
}
static enum update_return addSubDirectoryToDirectory(Directory * directory,
const char *name, struct stat *st)
{
Directory *subDirectory;
if (inodeFoundInParent(directory, st->st_ino, st->st_dev))
return UPDATE_RETURN_NOUPDATE;
subDirectory = newDirectory(name, directory);
directory_set_stat(subDirectory, st);
if (exploreDirectory(subDirectory) != UPDATE_RETURN_UPDATED) {
freeDirectory(subDirectory);
return UPDATE_RETURN_NOUPDATE;
}
dirvec_add(&directory->children, subDirectory);
return UPDATE_RETURN_UPDATED;
}
static enum update_return
addToDirectory(Directory * directory, const char *name)
{
struct stat st;
if (myStat(name, &st)) {
DEBUG("failed to stat %s: %s\n", name, strerror(errno));
return UPDATE_RETURN_ERROR;
}
if (S_ISREG(st.st_mode) &&
hasMusicSuffix(name, 0) && isMusic(name, NULL, 0)) {
Song *song;
const char *shortname = mpd_basename(name);
if (!(song = newSong(shortname, SONG_TYPE_FILE, directory)))
return -1;
songvec_add(&directory->songs, song);
LOG("added %s\n", name);
return UPDATE_RETURN_UPDATED;
} else if (S_ISDIR(st.st_mode)) {
return addSubDirectoryToDirectory(directory, name, &st);
}
DEBUG("addToDirectory: %s is not a directory or music\n", name);
return UPDATE_RETURN_ERROR;
}
void directory_finish(void)
{
freeDirectory(music_root);
}
int isRootDirectory(const char *name)
{
return (!name || name[0] == '\0' || !strcmp(name, "/"));
}
static Directory *getSubDirectory(Directory * directory, const char *name)
{
Directory *cur = directory;
Directory *found = NULL;
char *duplicated;
char *locate;
if (isRootDirectory(name))
return directory;
duplicated = xstrdup(name);
locate = strchr(duplicated, '/');
while (1) {
if (locate)
*locate = '\0';
if (!(found = dirvec_find(&cur->children, duplicated)))
break;
assert(cur == found->parent);
cur = found;
if (!locate)
break;
*locate = '/';
locate = strchr(locate + 1, '/');
}
free(duplicated);
return found;
}
static Directory *getDirectory(const char *name)
{
return getSubDirectory(music_root, name);
}
static int printDirectoryList(struct client *client, struct dirvec *dv)
{
size_t i;
for (i = 0; i < dv->nr; ++i) {
client_printf(client, DIRECTORY_DIR "%s\n",
getDirectoryPath(dv->base[i]));
}
return 0;
}
int printDirectoryInfo(struct client *client, const char *name)
{
Directory *directory;
if ((directory = getDirectory(name)) == NULL)
return -1;
printDirectoryList(client, &directory->children);
songvec_print(client, &directory->songs);
return 0;
}
/* TODO error checking */
static int writeDirectoryInfo(FILE * fp, Directory * directory)
{
struct dirvec *children = &directory->children;
size_t i;
int retv;
if (directory->path) {
retv = fprintf(fp, "%s%s\n", DIRECTORY_BEGIN,
getDirectoryPath(directory));
if (retv < 0)
return -1;
}
for (i = 0; i < children->nr; ++i) {
Directory *cur = children->base[i];
const char *base = mpd_basename(cur->path);
retv = fprintf(fp, DIRECTORY_DIR "%s\n", base);
if (retv < 0)
return -1;
if (writeDirectoryInfo(fp, cur) < 0)
return -1;
}
songvec_save(fp, &directory->songs);
if (directory->path &&
fprintf(fp, DIRECTORY_END "%s\n",
getDirectoryPath(directory)) < 0)
return -1;
return 0;
}
static void readDirectoryInfo(FILE * fp, Directory * directory)
{
Merge branches/ew r7104 thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
2007-12-28 03:56:25 +01:00
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)) {
strcpy(key, &(buffer[strlen(DIRECTORY_DIR)]));
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
/* for compatibility with db's prior to 0.11 */
if (!prefixcmp(buffer, DIRECTORY_MTIME)) {
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
}
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);
} else if (!prefixcmp(buffer, SONG_BEGIN)) {
readSongInfoIntoList(fp, &directory->songs, directory);
} else {
FATAL("Unknown line in db: %s\n", buffer);
}
}
}
static void sortDirectory(Directory * directory)
{
int i;
struct dirvec *dv = &directory->children;
dirvec_sort(dv);
songvec_sort(&directory->songs);
for (i = dv->nr; --i >= 0; )
sortDirectory(dv->base[i]);
}
int checkDirectoryDB(void)
{
struct stat st;
char *dbFile = getDbFile();
/* Check if the file exists */
if (access(dbFile, F_OK)) {
/* If the file doesn't exist, we can't check if we can write
* it, so we are going to try to get the directory path, and
* see if we can write a file in that */
char dirPath[MPD_PATH_MAX];
parent_path(dirPath, dbFile);
if (*dirPath == '\0')
strcpy(dirPath, "/");
/* Check that the parent part of the path is a directory */
if (stat(dirPath, &st) < 0) {
ERROR("Couldn't stat parent directory of db file "
"\"%s\": %s\n", dbFile, strerror(errno));
return -1;
}
if (!S_ISDIR(st.st_mode)) {
ERROR("Couldn't create db file \"%s\" because the "
"parent path is not a directory\n", dbFile);
return -1;
}
/* Check if we can write to the directory */
if (access(dirPath, R_OK | W_OK)) {
ERROR("Can't create db file in \"%s\": %s\n", dirPath,
strerror(errno));
return -1;
}
return 0;
}
/* Path exists, now check if it's a regular file */
if (stat(dbFile, &st) < 0) {
ERROR("Couldn't stat db file \"%s\": %s\n", dbFile,
strerror(errno));
return -1;
}
if (!S_ISREG(st.st_mode)) {
ERROR("db file \"%s\" is not a regular file\n", dbFile);
return -1;
}
/* And check that we can write to it */
if (access(dbFile, R_OK | W_OK)) {
ERROR("Can't open db file \"%s\" for reading/writing: %s\n",
dbFile, strerror(errno));
return -1;
}
return 0;
}
int writeDirectoryDB(void)
{
FILE *fp;
char *dbFile = getDbFile();
struct stat st;
DEBUG("removing empty directories from DB\n");
deleteEmptyDirectoriesInDirectory(music_root);
DEBUG("sorting DB\n");
sortDirectory(music_root);
DEBUG("writing DB\n");
fp = fopen(dbFile, "w");
if (!fp) {
ERROR("unable to write to db file \"%s\": %s\n",
dbFile, strerror(errno));
return -1;
}
/* block signals when writing the db so we don't get a corrupted db */
fprintf(fp, "%s\n", DIRECTORY_INFO_BEGIN);
fprintf(fp, "%s%s\n", DIRECTORY_MPD_VERSION, VERSION);
fprintf(fp, "%s%s\n", DIRECTORY_FS_CHARSET, getFsCharset());
fprintf(fp, "%s\n", DIRECTORY_INFO_END);
if (writeDirectoryInfo(fp, music_root) < 0) {
ERROR("Failed to write to database file: %s\n",
strerror(errno));
while (fclose(fp) && errno == EINTR);
return -1;
}
while (fclose(fp) && errno == EINTR);
if (stat(dbFile, &st) == 0)
directory_dbModTime = st.st_mtime;
return 0;
}
int readDirectoryDB(void)
{
FILE *fp = NULL;
char *dbFile = getDbFile();
struct stat st;
if (!music_root)
music_root = newDirectory(NULL, NULL);
while (!(fp = fopen(dbFile, "r")) && errno == EINTR) ;
if (fp == NULL) {
ERROR("unable to open db file \"%s\": %s\n",
dbFile, strerror(errno));
return -1;
}
/* get initial info */
{
char buffer[100];
int bufferSize = 100;
int foundFsCharset = 0;
int foundVersion = 0;
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
if (0 == strcmp(DIRECTORY_INFO_BEGIN, buffer)) {
while (myFgets(buffer, bufferSize, fp) &&
0 != strcmp(DIRECTORY_INFO_END, buffer)) {
if (!prefixcmp(buffer, DIRECTORY_MPD_VERSION))
{
if (foundVersion)
FATAL("already found version in db\n");
foundVersion = 1;
} else if (!prefixcmp(buffer,
DIRECTORY_FS_CHARSET)) {
char *fsCharset;
char *tempCharset;
if (foundFsCharset)
FATAL("already found fs charset in db\n");
foundFsCharset = 1;
fsCharset = &(buffer[strlen(DIRECTORY_FS_CHARSET)]);
if ((tempCharset = getConfigParamValue(CONF_FS_CHARSET))
&& strcmp(fsCharset, tempCharset)) {
WARNING("Using \"%s\" for the "
"filesystem charset "
"instead of \"%s\"\n",
fsCharset, tempCharset);
WARNING("maybe you need to "
"recreate the db?\n");
setFsCharset(fsCharset);
}
} else {
FATAL("directory: unknown line in db info: %s\n",
buffer);
}
}
} else {
ERROR("db info not found in db file\n");
ERROR("you should recreate the db using --create-db\n");
while (fclose(fp) && errno == EINTR) ;
return -1;
}
}
DEBUG("reading DB\n");
readDirectoryInfo(fp, music_root);
while (fclose(fp) && errno == EINTR) ;
stats.numberOfSongs = countSongsIn(NULL);
stats.dbPlayTime = sumSongTimesIn(NULL);
if (stat(dbFile, &st) == 0)
directory_dbModTime = st.st_mtime;
return 0;
}
static int traverseAllInSubDirectory(Directory * directory,
int (*forEachSong) (Song *, void *),
int (*forEachDir) (Directory *, void *),
void *data)
{
struct dirvec *dv = &directory->children;
int errFlag = 0;
size_t j;
if (forEachDir) {
errFlag = forEachDir(directory, data);
if (errFlag)
return errFlag;
}
if (forEachSong) {
int i;
struct songvec *sv = &directory->songs;
Song **sp = sv->base;
for (i = sv->nr; --i >= 0; ) {
Song *song = *sp++;
if ((errFlag = forEachSong(song, data)))
return errFlag;
}
}
for (j = 0; !errFlag && j < dv->nr; ++j)
errFlag = traverseAllInSubDirectory(dv->base[j], forEachSong,
forEachDir, data);
return errFlag;
}
int traverseAllIn(const char *name,
int (*forEachSong) (Song *, void *),
int (*forEachDir) (Directory *, void *), void *data)
{
Directory *directory;
if ((directory = getDirectory(name)) == NULL) {
Song *song;
if ((song = getSongFromDB(name)) && forEachSong) {
return forEachSong(song, data);
}
return -1;
}
return traverseAllInSubDirectory(directory, forEachSong, forEachDir,
data);
}
void directory_init(void)
{
music_root = newDirectory(NULL, NULL);
exploreDirectory(music_root);
stats.numberOfSongs = countSongsIn(NULL);
stats.dbPlayTime = sumSongTimesIn(NULL);
}
Song *getSongFromDB(const char *file)
{
Song *song = NULL;
Directory *directory;
char *dir = NULL;
char *duplicated = xstrdup(file);
char *shortname = strrchr(duplicated, '/');
DEBUG("get song: %s\n", file);
if (!shortname) {
shortname = duplicated;
} else {
*shortname = '\0';
++shortname;
dir = duplicated;
}
if (!(directory = getDirectory(dir)))
goto out;
if (!(song = songvec_find(&directory->songs, shortname)))
goto out;
assert(song->parentDir == directory);
out:
free(duplicated);
return song;
}
time_t getDbModTime(void)
{
return directory_dbModTime;
}