diff options
Diffstat (limited to 'src/database.c')
-rw-r--r-- | src/database.c | 355 |
1 files changed, 60 insertions, 295 deletions
diff --git a/src/database.c b/src/database.c index 9f29f95e1..9c4d90a2b 100644 --- a/src/database.c +++ b/src/database.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,14 +19,16 @@ #include "config.h" #include "database.h" +#include "db_error.h" +#include "db_save.h" +#include "db_selection.h" +#include "db_visitor.h" +#include "db_plugin.h" +#include "db/simple_db_plugin.h" #include "directory.h" -#include "directory_save.h" -#include "song.h" -#include "path.h" #include "stats.h" -#include "text_file.h" -#include "tag.h" -#include "tag_internal.h" +#include "conf.h" +#include "glib_compat.h" #include <glib.h> @@ -35,81 +37,58 @@ #include <unistd.h> #include <assert.h> #include <string.h> -#include <stdlib.h> #include <errno.h> #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "database" -#define DIRECTORY_INFO_BEGIN "info_begin" -#define DIRECTORY_INFO_END "info_end" -#define DB_FORMAT_PREFIX "format: " -#define DIRECTORY_MPD_VERSION "mpd_version: " -#define DIRECTORY_FS_CHARSET "fs_charset: " -#define DB_TAG_PREFIX "tag: " +static struct db *db; +static bool db_is_open; -enum { - DB_FORMAT = 1, -}; - -static char *database_path; - -static struct directory *music_root; - -static time_t database_mtime; - -/** - * The quark used for GError.domain. - */ -static inline GQuark -db_quark(void) +bool +db_init(const struct config_param *path, GError **error_r) { - return g_quark_from_static_string("database"); -} + assert(db == NULL); + assert(!db_is_open); -void -db_init(const char *path) -{ - database_path = g_strdup(path); + if (path == NULL) + return true; - if (path != NULL) - music_root = directory_new("", NULL); -} + struct config_param *param = config_new_param("database", path->line); + config_add_block_param(param, "path", path->value, path->line); -void -db_finish(void) -{ - assert((database_path == NULL) == (music_root == NULL)); + db = db_plugin_new(&simple_db_plugin, param, error_r); - if (music_root != NULL) - directory_free(music_root); + config_param_free(param); - g_free(database_path); + return db != NULL; } void -db_clear(void) +db_finish(void) { - assert(music_root != NULL); + if (db_is_open) + db_plugin_close(db); - directory_free(music_root); - music_root = directory_new("", NULL); + if (db != NULL) + db_plugin_free(db); } struct directory * db_get_root(void) { - assert(music_root != NULL); + assert(db != NULL); - return music_root; + return simple_db_get_root(db); } struct directory * db_get_directory(const char *name) { - if (music_root == NULL) + if (db == NULL) return NULL; + struct directory *music_root = db_get_root(); if (name == NULL) return music_root; @@ -123,281 +102,67 @@ db_get_song(const char *file) g_debug("get song: %s", file); - if (music_root == NULL) + if (db == NULL) return NULL; - return directory_lookup_song(music_root, file); + return db_plugin_get_song(db, file, NULL); } -int -db_walk(const char *name, - int (*forEachSong)(struct song *, void *), - int (*forEachDir)(struct directory *, void *), void *data) +bool +db_visit(const struct db_selection *selection, + const struct db_visitor *visitor, void *ctx, + GError **error_r) { - struct directory *directory; - - if (music_root == NULL) - return -1; - - if ((directory = db_get_directory(name)) == NULL) { - struct song *song; - if ((song = db_get_song(name)) && forEachSong) { - return forEachSong(song, data); - } - return -1; + if (db == NULL) { + g_set_error_literal(error_r, db_quark(), DB_DISABLED, + "No database"); + return false; } - return directory_walk(directory, forEachSong, forEachDir, data); + return db_plugin_visit(db, selection, visitor, ctx, error_r); } bool -db_check(void) +db_walk(const char *uri, + const struct db_visitor *visitor, void *ctx, + GError **error_r) { - struct stat st; - - assert(database_path != NULL); - - /* Check if the file exists */ - if (access(database_path, 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 = g_path_get_dirname(database_path); - - /* Check that the parent part of the path is a directory */ - if (stat(dirPath, &st) < 0) { - g_free(dirPath); - g_warning("Couldn't stat parent directory of db file " - "\"%s\": %s", database_path, strerror(errno)); - return false; - } - - if (!S_ISDIR(st.st_mode)) { - g_free(dirPath); - g_warning("Couldn't create db file \"%s\" because the " - "parent path is not a directory", database_path); - return false; - } - - /* Check if we can write to the directory */ - if (access(dirPath, X_OK | W_OK)) { - g_warning("Can't create db file in \"%s\": %s", - dirPath, strerror(errno)); - g_free(dirPath); - return false; - } - - g_free(dirPath); - - return true; - } - - /* Path exists, now check if it's a regular file */ - if (stat(database_path, &st) < 0) { - g_warning("Couldn't stat db file \"%s\": %s", - database_path, strerror(errno)); - return false; - } + struct db_selection selection; + db_selection_init(&selection, uri, true); - if (!S_ISREG(st.st_mode)) { - g_warning("db file \"%s\" is not a regular file", database_path); - return false; - } - - /* And check that we can write to it */ - if (access(database_path, R_OK | W_OK)) { - g_warning("Can't open db file \"%s\" for reading/writing: %s", - database_path, strerror(errno)); - return false; - } - - return true; + return db_visit(&selection, visitor, ctx, error_r); } bool -db_save(void) +db_save(GError **error_r) { - FILE *fp; - struct stat st; - - assert(database_path != NULL); - assert(music_root != NULL); + assert(db != NULL); + assert(db_is_open); - g_debug("removing empty directories from DB"); - directory_prune_empty(music_root); - - g_debug("sorting DB"); - - directory_sort(music_root); - - g_debug("writing DB"); - - fp = fopen(database_path, "w"); - if (!fp) { - g_warning("unable to write to db file \"%s\": %s", - database_path, strerror(errno)); - return false; - } - - fprintf(fp, "%s\n", DIRECTORY_INFO_BEGIN); - fprintf(fp, DB_FORMAT_PREFIX "%u\n", DB_FORMAT); - fprintf(fp, "%s%s\n", DIRECTORY_MPD_VERSION, VERSION); - fprintf(fp, "%s%s\n", DIRECTORY_FS_CHARSET, path_get_fs_charset()); - - for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) - if (!ignore_tag_items[i]) - fprintf(fp, DB_TAG_PREFIX "%s\n", tag_item_names[i]); - - fprintf(fp, "%s\n", DIRECTORY_INFO_END); - - directory_save(fp, music_root); - - if (ferror(fp)) { - g_warning("Failed to write to database file: %s", - strerror(errno)); - fclose(fp); - return false; - } - - fclose(fp); - - if (stat(database_path, &st) == 0) - database_mtime = st.st_mtime; - - return true; + return simple_db_save(db, error_r); } bool db_load(GError **error) { - FILE *fp = NULL; - struct stat st; - GString *buffer = g_string_sized_new(1024); - char *line; - int format = 0; - bool found_charset = false, found_version = false; - bool success; - bool tags[TAG_NUM_OF_ITEM_TYPES]; - - assert(database_path != NULL); - assert(music_root != NULL); - - fp = fopen(database_path, "r"); - if (fp == NULL) { - g_set_error(error, db_quark(), errno, - "Failed to open database file \"%s\": %s", - database_path, strerror(errno)); - g_string_free(buffer, true); - return false; - } - - /* get initial info */ - line = read_text_line(fp, buffer); - if (line == NULL || strcmp(DIRECTORY_INFO_BEGIN, line) != 0) { - fclose(fp); - g_set_error(error, db_quark(), 0, "Database corrupted"); - g_string_free(buffer, true); - return false; - } - - memset(tags, false, sizeof(tags)); - - while ((line = read_text_line(fp, buffer)) != NULL && - strcmp(line, DIRECTORY_INFO_END) != 0) { - if (g_str_has_prefix(line, DB_FORMAT_PREFIX)) { - format = atoi(line + sizeof(DB_FORMAT_PREFIX) - 1); - } else if (g_str_has_prefix(line, DIRECTORY_MPD_VERSION)) { - if (found_version) { - fclose(fp); - g_set_error(error, db_quark(), 0, - "Duplicate version line"); - g_string_free(buffer, true); - return false; - } - - found_version = true; - } else if (g_str_has_prefix(line, DIRECTORY_FS_CHARSET)) { - const char *new_charset, *old_charset; - - if (found_charset) { - fclose(fp); - g_set_error(error, db_quark(), 0, - "Duplicate charset line"); - g_string_free(buffer, true); - return false; - } - - found_charset = true; - - new_charset = line + sizeof(DIRECTORY_FS_CHARSET) - 1; - old_charset = path_get_fs_charset(); - if (old_charset != NULL - && strcmp(new_charset, old_charset)) { - fclose(fp); - g_set_error(error, db_quark(), 0, - "Existing database has charset " - "\"%s\" instead of \"%s\"; " - "discarding database file", - new_charset, old_charset); - g_string_free(buffer, true); - return false; - } - } else if (g_str_has_prefix(line, DB_TAG_PREFIX)) { - const char *name = line + sizeof(DB_TAG_PREFIX) - 1; - enum tag_type tag = tag_name_parse(name); - if (tag == TAG_NUM_OF_ITEM_TYPES) { - g_set_error(error, db_quark(), 0, - "Unrecognized tag '%s', " - "discarding database file", - name); - return false; - } - - tags[tag] = true; - } else { - fclose(fp); - g_set_error(error, db_quark(), 0, - "Malformed line: %s", line); - g_string_free(buffer, true); - return false; - } - } + assert(db != NULL); + assert(!db_is_open); - if (format != DB_FORMAT) { - g_set_error(error, db_quark(), 0, - "Database format mismatch, " - "discarding database file"); + if (!db_plugin_open(db, error)) return false; - } - - for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { - if (!ignore_tag_items[i] && !tags[i]) { - g_set_error(error, db_quark(), 0, - "Tag list mismatch, " - "discarding database file"); - return false; - } - } - - g_debug("reading DB"); - success = directory_load(fp, music_root, buffer, error); - g_string_free(buffer, true); - fclose(fp); - - if (!success) - return false; + db_is_open = true; stats_update(); - if (stat(database_path, &st) == 0) - database_mtime = st.st_mtime; - return true; } time_t db_get_mtime(void) { - return database_mtime; + assert(db != NULL); + assert(db_is_open); + + return simple_db_get_mtime(db); } |