directory: require the caller to lock the db_mutex
Reduce the number of lock/unlock cycles, and make database handling safer.
This commit is contained in:
parent
837bd79b20
commit
ef5cf40fa6
@ -45,6 +45,7 @@
|
|||||||
#include "db_error.h"
|
#include "db_error.h"
|
||||||
#include "db_print.h"
|
#include "db_print.h"
|
||||||
#include "db_selection.h"
|
#include "db_selection.h"
|
||||||
|
#include "db_lock.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "client_idle.h"
|
#include "client_idle.h"
|
||||||
@ -1892,8 +1893,10 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
|
|||||||
.name = argv[4],
|
.name = argv[4],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
db_lock();
|
||||||
directory = db_get_directory(argv[3]);
|
directory = db_get_directory(argv[3]);
|
||||||
if (directory == NULL) {
|
if (directory == NULL) {
|
||||||
|
db_unlock();
|
||||||
command_error(client, ACK_ERROR_NO_EXIST,
|
command_error(client, ACK_ERROR_NO_EXIST,
|
||||||
"no such directory");
|
"no such directory");
|
||||||
return COMMAND_RETURN_ERROR;
|
return COMMAND_RETURN_ERROR;
|
||||||
@ -1901,6 +1904,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
|
|||||||
|
|
||||||
success = sticker_song_find(directory, data.name,
|
success = sticker_song_find(directory, data.name,
|
||||||
sticker_song_find_print_cb, &data);
|
sticker_song_find_print_cb, &data);
|
||||||
|
db_unlock();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
command_error(client, ACK_ERROR_SYSTEM,
|
command_error(client, ACK_ERROR_SYSTEM,
|
||||||
"failed to set search sticker database");
|
"failed to set search sticker database");
|
||||||
|
@ -92,7 +92,9 @@ db_get_directory(const char *name)
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return music_root;
|
return music_root;
|
||||||
|
|
||||||
return directory_lookup_directory(music_root, name);
|
struct directory *directory =
|
||||||
|
directory_lookup_directory(music_root, name);
|
||||||
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct song *
|
struct song *
|
||||||
|
@ -50,6 +50,9 @@ db_finish(void);
|
|||||||
struct directory *
|
struct directory *
|
||||||
db_get_root(void);
|
db_get_root(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*/
|
||||||
gcc_nonnull(1)
|
gcc_nonnull(1)
|
||||||
struct directory *
|
struct directory *
|
||||||
db_get_directory(const char *name);
|
db_get_directory(const char *name);
|
||||||
|
@ -59,7 +59,11 @@ simple_db_lookup_directory(const struct simple_db *db, const char *uri)
|
|||||||
assert(db->root != NULL);
|
assert(db->root != NULL);
|
||||||
assert(uri != NULL);
|
assert(uri != NULL);
|
||||||
|
|
||||||
return directory_lookup_directory(db->root, uri);
|
db_lock();
|
||||||
|
struct directory *directory =
|
||||||
|
directory_lookup_directory(db->root, uri);
|
||||||
|
db_unlock();
|
||||||
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct db *
|
static struct db *
|
||||||
@ -236,7 +240,9 @@ simple_db_get_song(struct db *_db, const char *uri, GError **error_r)
|
|||||||
|
|
||||||
assert(db->root != NULL);
|
assert(db->root != NULL);
|
||||||
|
|
||||||
|
db_lock();
|
||||||
struct song *song = directory_lookup_song(db->root, uri);
|
struct song *song = directory_lookup_song(db->root, uri);
|
||||||
|
db_unlock();
|
||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
g_set_error(error_r, db_quark(), DB_NOT_FOUND,
|
g_set_error(error_r, db_quark(), DB_NOT_FOUND,
|
||||||
"No such song: %s", uri);
|
"No such song: %s", uri);
|
||||||
@ -301,13 +307,16 @@ simple_db_save(struct db *_db, GError **error_r)
|
|||||||
struct simple_db *db = (struct simple_db *)_db;
|
struct simple_db *db = (struct simple_db *)_db;
|
||||||
struct directory *music_root = db->root;
|
struct directory *music_root = db->root;
|
||||||
|
|
||||||
|
db_lock();
|
||||||
|
|
||||||
g_debug("removing empty directories from DB");
|
g_debug("removing empty directories from DB");
|
||||||
directory_prune_empty(music_root);
|
directory_prune_empty(music_root);
|
||||||
|
|
||||||
g_debug("sorting DB");
|
g_debug("sorting DB");
|
||||||
|
|
||||||
directory_sort(music_root);
|
directory_sort(music_root);
|
||||||
|
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
g_debug("writing DB");
|
g_debug("writing DB");
|
||||||
|
|
||||||
FILE *fp = fopen(db->path, "w");
|
FILE *fp = fopen(db->path, "w");
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "db_save.h"
|
#include "db_save.h"
|
||||||
|
#include "db_lock.h"
|
||||||
#include "directory.h"
|
#include "directory.h"
|
||||||
#include "directory_save.h"
|
#include "directory_save.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
@ -169,7 +170,9 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
|
|||||||
|
|
||||||
g_debug("reading DB");
|
g_debug("reading DB");
|
||||||
|
|
||||||
|
db_lock();
|
||||||
success = directory_load(fp, music_root, buffer, error);
|
success = directory_load(fp, music_root, buffer, error);
|
||||||
|
db_unlock();
|
||||||
g_string_free(buffer, true);
|
g_string_free(buffer, true);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
@ -74,13 +74,11 @@ directory_free(struct directory *directory)
|
|||||||
void
|
void
|
||||||
directory_delete(struct directory *directory)
|
directory_delete(struct directory *directory)
|
||||||
{
|
{
|
||||||
|
assert(holding_db_lock());
|
||||||
assert(directory != NULL);
|
assert(directory != NULL);
|
||||||
assert(directory->parent != NULL);
|
assert(directory->parent != NULL);
|
||||||
|
|
||||||
db_lock();
|
|
||||||
list_del(&directory->siblings);
|
list_del(&directory->siblings);
|
||||||
db_unlock();
|
|
||||||
|
|
||||||
directory_free(directory);
|
directory_free(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +91,7 @@ directory_get_name(const struct directory *directory)
|
|||||||
struct directory *
|
struct directory *
|
||||||
directory_new_child(struct directory *parent, const char *name_utf8)
|
directory_new_child(struct directory *parent, const char *name_utf8)
|
||||||
{
|
{
|
||||||
|
assert(holding_db_lock());
|
||||||
assert(parent != NULL);
|
assert(parent != NULL);
|
||||||
assert(name_utf8 != NULL);
|
assert(name_utf8 != NULL);
|
||||||
assert(*name_utf8 != 0);
|
assert(*name_utf8 != 0);
|
||||||
@ -111,32 +110,28 @@ directory_new_child(struct directory *parent, const char *name_utf8)
|
|||||||
struct directory *directory = directory_new(path_utf8, parent);
|
struct directory *directory = directory_new(path_utf8, parent);
|
||||||
g_free(allocated);
|
g_free(allocated);
|
||||||
|
|
||||||
db_lock();
|
list_add(&directory->siblings, &parent->children);
|
||||||
list_add_tail(&directory->siblings, &parent->children);
|
|
||||||
db_unlock();
|
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct directory *
|
struct directory *
|
||||||
directory_get_child(const struct directory *directory, const char *name)
|
directory_get_child(const struct directory *directory, const char *name)
|
||||||
{
|
{
|
||||||
db_lock();
|
assert(holding_db_lock());
|
||||||
|
|
||||||
struct directory *child;
|
struct directory *child;
|
||||||
directory_for_each_child(child, directory) {
|
directory_for_each_child(child, directory)
|
||||||
if (strcmp(directory_get_name(child), name) == 0) {
|
if (strcmp(directory_get_name(child), name) == 0)
|
||||||
db_unlock();
|
|
||||||
return child;
|
return child;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db_unlock();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
directory_prune_empty(struct directory *directory)
|
directory_prune_empty(struct directory *directory)
|
||||||
{
|
{
|
||||||
|
assert(holding_db_lock());
|
||||||
|
|
||||||
struct directory *child, *n;
|
struct directory *child, *n;
|
||||||
directory_for_each_child_safe(child, n, directory) {
|
directory_for_each_child_safe(child, n, directory) {
|
||||||
directory_prune_empty(child);
|
directory_prune_empty(child);
|
||||||
@ -149,12 +144,14 @@ directory_prune_empty(struct directory *directory)
|
|||||||
struct directory *
|
struct directory *
|
||||||
directory_lookup_directory(struct directory *directory, const char *uri)
|
directory_lookup_directory(struct directory *directory, const char *uri)
|
||||||
{
|
{
|
||||||
|
assert(holding_db_lock());
|
||||||
assert(uri != NULL);
|
assert(uri != NULL);
|
||||||
|
|
||||||
if (isRootDirectory(uri))
|
if (isRootDirectory(uri))
|
||||||
return directory;
|
return directory;
|
||||||
|
|
||||||
char *duplicated = g_strdup(uri), *name = duplicated;
|
char *duplicated = g_strdup(uri), *name = duplicated;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
char *slash = strchr(name, '/');
|
char *slash = strchr(name, '/');
|
||||||
if (slash == name) {
|
if (slash == name) {
|
||||||
@ -201,21 +198,18 @@ directory_remove_song(G_GNUC_UNUSED struct directory *directory,
|
|||||||
struct song *
|
struct song *
|
||||||
directory_get_song(const struct directory *directory, const char *name_utf8)
|
directory_get_song(const struct directory *directory, const char *name_utf8)
|
||||||
{
|
{
|
||||||
|
assert(holding_db_lock());
|
||||||
assert(directory != NULL);
|
assert(directory != NULL);
|
||||||
assert(name_utf8 != NULL);
|
assert(name_utf8 != NULL);
|
||||||
|
|
||||||
db_lock();
|
|
||||||
struct song *song;
|
struct song *song;
|
||||||
directory_for_each_song(song, directory) {
|
directory_for_each_song(song, directory) {
|
||||||
assert(song->parent == directory);
|
assert(song->parent == directory);
|
||||||
|
|
||||||
if (strcmp(song->uri, name_utf8) == 0) {
|
if (strcmp(song->uri, name_utf8) == 0)
|
||||||
db_unlock();
|
|
||||||
return song;
|
return song;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db_unlock();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,6 +218,7 @@ directory_lookup_song(struct directory *directory, const char *uri)
|
|||||||
{
|
{
|
||||||
char *duplicated, *base;
|
char *duplicated, *base;
|
||||||
|
|
||||||
|
assert(holding_db_lock());
|
||||||
assert(directory != NULL);
|
assert(directory != NULL);
|
||||||
assert(uri != NULL);
|
assert(uri != NULL);
|
||||||
|
|
||||||
@ -260,10 +255,10 @@ directory_cmp(G_GNUC_UNUSED void *priv,
|
|||||||
void
|
void
|
||||||
directory_sort(struct directory *directory)
|
directory_sort(struct directory *directory)
|
||||||
{
|
{
|
||||||
db_lock();
|
assert(holding_db_lock());
|
||||||
|
|
||||||
list_sort(NULL, &directory->children, directory_cmp);
|
list_sort(NULL, &directory->children, directory_cmp);
|
||||||
song_list_sort(&directory->songs);
|
song_list_sort(&directory->songs);
|
||||||
db_unlock();
|
|
||||||
|
|
||||||
struct directory *child;
|
struct directory *child;
|
||||||
directory_for_each_child(child, directory)
|
directory_for_each_child(child, directory)
|
||||||
|
@ -118,6 +118,8 @@ directory_free(struct directory *directory);
|
|||||||
/**
|
/**
|
||||||
* Remove this #directory object from its parent and free it. This
|
* Remove this #directory object from its parent and free it. This
|
||||||
* must not be called with the root directory.
|
* must not be called with the root directory.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
directory_delete(struct directory *directory);
|
directory_delete(struct directory *directory);
|
||||||
@ -152,6 +154,9 @@ G_GNUC_PURE
|
|||||||
const char *
|
const char *
|
||||||
directory_get_name(const struct directory *directory);
|
directory_get_name(const struct directory *directory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*/
|
||||||
G_GNUC_PURE
|
G_GNUC_PURE
|
||||||
struct directory *
|
struct directory *
|
||||||
directory_get_child(const struct directory *directory, const char *name);
|
directory_get_child(const struct directory *directory, const char *name);
|
||||||
@ -159,6 +164,8 @@ directory_get_child(const struct directory *directory, const char *name);
|
|||||||
/**
|
/**
|
||||||
* Create a new #directory object as a child of the given one.
|
* Create a new #directory object as a child of the given one.
|
||||||
*
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*
|
||||||
* @param parent the parent directory the new one will be added to
|
* @param parent the parent directory the new one will be added to
|
||||||
* @param name_utf8 the UTF-8 encoded name of the new sub directory
|
* @param name_utf8 the UTF-8 encoded name of the new sub directory
|
||||||
*/
|
*/
|
||||||
@ -169,6 +176,8 @@ directory_new_child(struct directory *parent, const char *name_utf8);
|
|||||||
/**
|
/**
|
||||||
* Look up a sub directory, and create the object if it does not
|
* Look up a sub directory, and create the object if it does not
|
||||||
* exist.
|
* exist.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
static inline struct directory *
|
static inline struct directory *
|
||||||
directory_make_child(struct directory *directory, const char *name_utf8)
|
directory_make_child(struct directory *directory, const char *name_utf8)
|
||||||
@ -179,6 +188,9 @@ directory_make_child(struct directory *directory, const char *name_utf8)
|
|||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
directory_prune_empty(struct directory *directory);
|
directory_prune_empty(struct directory *directory);
|
||||||
|
|
||||||
@ -209,6 +221,8 @@ directory_remove_song(struct directory *directory, struct song *song);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up a song in this directory by its name.
|
* Look up a song in this directory by its name.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
G_GNUC_PURE
|
G_GNUC_PURE
|
||||||
struct song *
|
struct song *
|
||||||
@ -217,6 +231,8 @@ directory_get_song(const struct directory *directory, const char *name_utf8);
|
|||||||
/**
|
/**
|
||||||
* Looks up a song by its relative URI.
|
* Looks up a song by its relative URI.
|
||||||
*
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*
|
||||||
* @param directory the parent (or grandparent, ...) directory
|
* @param directory the parent (or grandparent, ...) directory
|
||||||
* @param uri the relative URI
|
* @param uri the relative URI
|
||||||
* @return the song, or NULL if none was found
|
* @return the song, or NULL if none was found
|
||||||
@ -224,6 +240,11 @@ directory_get_song(const struct directory *directory, const char *name_utf8);
|
|||||||
struct song *
|
struct song *
|
||||||
directory_lookup_song(struct directory *directory, const char *uri);
|
directory_lookup_song(struct directory *directory, const char *uri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort all directory entries recursively.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
directory_sort(struct directory *directory);
|
directory_sort(struct directory *directory);
|
||||||
|
|
||||||
|
@ -68,6 +68,8 @@ sticker_song_get(const struct song *song);
|
|||||||
* Finds stickers with the specified name below the specified
|
* Finds stickers with the specified name below the specified
|
||||||
* directory.
|
* directory.
|
||||||
*
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*
|
||||||
* @param directory the base directory to search in
|
* @param directory the base directory to search in
|
||||||
* @param name the name of the sticker
|
* @param name the name of the sticker
|
||||||
* @return true on success (even if no sticker was found), false on
|
* @return true on success (even if no sticker was found), false on
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "config.h" /* must be first for large file support */
|
#include "config.h" /* must be first for large file support */
|
||||||
#include "update_internal.h"
|
#include "update_internal.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "db_lock.h"
|
||||||
#include "exclude.h"
|
#include "exclude.h"
|
||||||
#include "directory.h"
|
#include "directory.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
@ -89,6 +90,9 @@ directory_set_stat(struct directory *dir, const struct stat *st)
|
|||||||
dir->have_stat = true;
|
dir->have_stat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
delete_song(struct directory *dir, struct song *del)
|
delete_song(struct directory *dir, struct song *del)
|
||||||
{
|
{
|
||||||
@ -97,11 +101,15 @@ delete_song(struct directory *dir, struct song *del)
|
|||||||
/* first, prevent traversers in main task from getting this */
|
/* first, prevent traversers in main task from getting this */
|
||||||
directory_remove_song(dir, del);
|
directory_remove_song(dir, del);
|
||||||
|
|
||||||
|
db_unlock(); /* temporary unlock, because update_remove_song() blocks */
|
||||||
|
|
||||||
/* now take it out of the playlist (in the main_task) */
|
/* now take it out of the playlist (in the main_task) */
|
||||||
update_remove_song(del);
|
update_remove_song(del);
|
||||||
|
|
||||||
/* finally, all possible references gone, free it */
|
/* finally, all possible references gone, free it */
|
||||||
song_free(del);
|
song_free(del);
|
||||||
|
|
||||||
|
db_lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -110,6 +118,8 @@ delete_directory(struct directory *directory);
|
|||||||
/**
|
/**
|
||||||
* Recursively remove all sub directories and songs from a directory,
|
* Recursively remove all sub directories and songs from a directory,
|
||||||
* leaving an empty directory.
|
* leaving an empty directory.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
clear_directory(struct directory *directory)
|
clear_directory(struct directory *directory)
|
||||||
@ -127,6 +137,8 @@ clear_directory(struct directory *directory)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively free a directory and all its contents.
|
* Recursively free a directory and all its contents.
|
||||||
|
*
|
||||||
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
delete_directory(struct directory *directory)
|
delete_directory(struct directory *directory)
|
||||||
@ -134,12 +146,14 @@ delete_directory(struct directory *directory)
|
|||||||
assert(directory->parent != NULL);
|
assert(directory->parent != NULL);
|
||||||
|
|
||||||
clear_directory(directory);
|
clear_directory(directory);
|
||||||
|
|
||||||
directory_delete(directory);
|
directory_delete(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
delete_name_in(struct directory *parent, const char *name)
|
delete_name_in(struct directory *parent, const char *name)
|
||||||
{
|
{
|
||||||
|
db_lock();
|
||||||
struct directory *directory = directory_get_child(parent, name);
|
struct directory *directory = directory_get_child(parent, name);
|
||||||
|
|
||||||
if (directory != NULL) {
|
if (directory != NULL) {
|
||||||
@ -153,6 +167,8 @@ delete_name_in(struct directory *parent, const char *name)
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
playlist_vector_remove(&parent->playlists, name);
|
playlist_vector_remove(&parent->playlists, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +176,8 @@ static void
|
|||||||
remove_excluded_from_directory(struct directory *directory,
|
remove_excluded_from_directory(struct directory *directory,
|
||||||
GSList *exclude_list)
|
GSList *exclude_list)
|
||||||
{
|
{
|
||||||
|
db_lock();
|
||||||
|
|
||||||
struct directory *child, *n;
|
struct directory *child, *n;
|
||||||
directory_for_each_child_safe(child, n, directory) {
|
directory_for_each_child_safe(child, n, directory) {
|
||||||
char *name_fs = utf8_to_fs_charset(directory_get_name(child));
|
char *name_fs = utf8_to_fs_charset(directory_get_name(child));
|
||||||
@ -184,6 +202,8 @@ remove_excluded_from_directory(struct directory *directory,
|
|||||||
|
|
||||||
g_free(name_fs);
|
g_free(name_fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -232,7 +252,10 @@ removeDeletedFromDirectory(struct directory *directory)
|
|||||||
if (directory_exists(child))
|
if (directory_exists(child))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
db_lock();
|
||||||
delete_directory(child);
|
delete_directory(child);
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +265,10 @@ removeDeletedFromDirectory(struct directory *directory)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if ((path = map_song_fs(song)) == NULL ||
|
if ((path = map_song_fs(song)) == NULL ||
|
||||||
stat(path, &st) < 0 || !S_ISREG(st.st_mode)) {
|
stat(path, &st) < 0 || !S_ISREG(st.st_mode)) {
|
||||||
|
db_lock();
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,8 +370,10 @@ update_archive_tree(struct directory *directory, char *name)
|
|||||||
if (tmp) {
|
if (tmp) {
|
||||||
*tmp = 0;
|
*tmp = 0;
|
||||||
//add dir is not there already
|
//add dir is not there already
|
||||||
|
db_lock();
|
||||||
subdir = directory_make_child(directory, name);
|
subdir = directory_make_child(directory, name);
|
||||||
subdir->device = DEVICE_INARCHIVE;
|
subdir->device = DEVICE_INARCHIVE;
|
||||||
|
db_unlock();
|
||||||
//create directories first
|
//create directories first
|
||||||
update_archive_tree(subdir, tmp+1);
|
update_archive_tree(subdir, tmp+1);
|
||||||
} else {
|
} else {
|
||||||
@ -354,7 +382,9 @@ update_archive_tree(struct directory *directory, char *name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//add file
|
//add file
|
||||||
|
db_lock();
|
||||||
struct song *song = directory_get_song(directory, name);
|
struct song *song = directory_get_song(directory, name);
|
||||||
|
db_unlock();
|
||||||
if (song == NULL) {
|
if (song == NULL) {
|
||||||
song = song_file_load(name, directory);
|
song = song_file_load(name, directory);
|
||||||
if (song != NULL) {
|
if (song != NULL) {
|
||||||
@ -386,7 +416,9 @@ update_archive_file(struct directory *parent, const char *name,
|
|||||||
struct directory *directory;
|
struct directory *directory;
|
||||||
char *filepath;
|
char *filepath;
|
||||||
|
|
||||||
|
db_lock();
|
||||||
directory = directory_get_child(parent, name);
|
directory = directory_get_child(parent, name);
|
||||||
|
db_unlock();
|
||||||
if (directory != NULL && directory->mtime == st->st_mtime &&
|
if (directory != NULL && directory->mtime == st->st_mtime &&
|
||||||
!walk_discard)
|
!walk_discard)
|
||||||
/* MPD has already scanned the archive, and it hasn't
|
/* MPD has already scanned the archive, and it hasn't
|
||||||
@ -409,10 +441,12 @@ update_archive_file(struct directory *parent, const char *name,
|
|||||||
|
|
||||||
if (directory == NULL) {
|
if (directory == NULL) {
|
||||||
g_debug("creating archive directory: %s", name);
|
g_debug("creating archive directory: %s", name);
|
||||||
|
db_lock();
|
||||||
directory = directory_new_child(parent, name);
|
directory = directory_new_child(parent, name);
|
||||||
/* mark this directory as archive (we use device for
|
/* mark this directory as archive (we use device for
|
||||||
this) */
|
this) */
|
||||||
directory->device = DEVICE_INARCHIVE;
|
directory->device = DEVICE_INARCHIVE;
|
||||||
|
db_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
directory->mtime = st->st_mtime;
|
directory->mtime = st->st_mtime;
|
||||||
@ -438,6 +472,8 @@ update_container_file( struct directory* directory,
|
|||||||
char* vtrack = NULL;
|
char* vtrack = NULL;
|
||||||
unsigned int tnum = 0;
|
unsigned int tnum = 0;
|
||||||
char* pathname = map_directory_child_fs(directory, name);
|
char* pathname = map_directory_child_fs(directory, name);
|
||||||
|
|
||||||
|
db_lock();
|
||||||
struct directory *contdir = directory_get_child(directory, name);
|
struct directory *contdir = directory_get_child(directory, name);
|
||||||
|
|
||||||
// directory exists already
|
// directory exists already
|
||||||
@ -454,6 +490,7 @@ update_container_file( struct directory* directory,
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
db_unlock();
|
||||||
g_free(pathname);
|
g_free(pathname);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -462,6 +499,7 @@ update_container_file( struct directory* directory,
|
|||||||
contdir = directory_make_child(directory, name);
|
contdir = directory_make_child(directory, name);
|
||||||
contdir->mtime = st->st_mtime;
|
contdir->mtime = st->st_mtime;
|
||||||
contdir->device = DEVICE_CONTAINER;
|
contdir->device = DEVICE_CONTAINER;
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL)
|
while ((vtrack = plugin->container_scan(pathname, ++tnum)) != NULL)
|
||||||
{
|
{
|
||||||
@ -489,7 +527,9 @@ update_container_file( struct directory* directory,
|
|||||||
|
|
||||||
if (tnum == 1)
|
if (tnum == 1)
|
||||||
{
|
{
|
||||||
|
db_lock();
|
||||||
delete_directory(contdir);
|
delete_directory(contdir);
|
||||||
|
db_unlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -536,13 +576,19 @@ update_regular_file(struct directory *directory,
|
|||||||
|
|
||||||
if ((plugin = decoder_plugin_from_suffix(suffix, false)) != NULL)
|
if ((plugin = decoder_plugin_from_suffix(suffix, false)) != NULL)
|
||||||
{
|
{
|
||||||
|
db_lock();
|
||||||
struct song *song = directory_get_song(directory, name);
|
struct song *song = directory_get_song(directory, name);
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
if (!directory_child_access(directory, name, R_OK)) {
|
if (!directory_child_access(directory, name, R_OK)) {
|
||||||
g_warning("no read permissions on %s/%s",
|
g_warning("no read permissions on %s/%s",
|
||||||
directory_get_path(directory), name);
|
directory_get_path(directory), name);
|
||||||
if (song != NULL)
|
if (song != NULL) {
|
||||||
|
db_lock();
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
|
db_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,8 +598,11 @@ update_regular_file(struct directory *directory,
|
|||||||
{
|
{
|
||||||
if (update_container_file(directory, name, st, plugin))
|
if (update_container_file(directory, name, st, plugin))
|
||||||
{
|
{
|
||||||
if (song != NULL)
|
if (song != NULL) {
|
||||||
|
db_lock();
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
|
db_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -579,7 +628,9 @@ update_regular_file(struct directory *directory,
|
|||||||
if (!song_file_update(song)) {
|
if (!song_file_update(song)) {
|
||||||
g_debug("deleting unrecognized file %s/%s",
|
g_debug("deleting unrecognized file %s/%s",
|
||||||
directory_get_path(directory), name);
|
directory_get_path(directory), name);
|
||||||
|
db_lock();
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
|
db_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
modified = true;
|
modified = true;
|
||||||
@ -614,12 +665,18 @@ updateInDirectory(struct directory *directory,
|
|||||||
if (inodeFoundInParent(directory, st->st_ino, st->st_dev))
|
if (inodeFoundInParent(directory, st->st_ino, st->st_dev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
db_lock();
|
||||||
subdir = directory_make_child(directory, name);
|
subdir = directory_make_child(directory, name);
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
assert(directory == subdir->parent);
|
assert(directory == subdir->parent);
|
||||||
|
|
||||||
ret = updateDirectory(subdir, st);
|
ret = updateDirectory(subdir, st);
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
|
db_lock();
|
||||||
delete_directory(subdir);
|
delete_directory(subdir);
|
||||||
|
db_unlock();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g_debug("update: %s is not a directory, archive or music", name);
|
g_debug("update: %s is not a directory, archive or music", name);
|
||||||
}
|
}
|
||||||
@ -778,7 +835,9 @@ directory_make_child_checked(struct directory *parent, const char *name_utf8)
|
|||||||
struct directory *directory;
|
struct directory *directory;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
db_lock();
|
||||||
directory = directory_get_child(parent, name_utf8);
|
directory = directory_get_child(parent, name_utf8);
|
||||||
|
db_unlock();
|
||||||
if (directory != NULL)
|
if (directory != NULL)
|
||||||
return directory;
|
return directory;
|
||||||
|
|
||||||
@ -788,11 +847,14 @@ directory_make_child_checked(struct directory *parent, const char *name_utf8)
|
|||||||
|
|
||||||
/* if we're adding directory paths, make sure to delete filenames
|
/* if we're adding directory paths, make sure to delete filenames
|
||||||
with potentially the same name */
|
with potentially the same name */
|
||||||
|
db_lock();
|
||||||
struct song *conflicting = directory_get_song(parent, name_utf8);
|
struct song *conflicting = directory_get_song(parent, name_utf8);
|
||||||
if (conflicting)
|
if (conflicting)
|
||||||
delete_song(parent, conflicting);
|
delete_song(parent, conflicting);
|
||||||
|
|
||||||
directory = directory_new_child(parent, name_utf8);
|
directory = directory_new_child(parent, name_utf8);
|
||||||
|
db_unlock();
|
||||||
|
|
||||||
directory_set_stat(directory, &st);
|
directory_set_stat(directory, &st);
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user