core/collection: Handle -EIO errors coming from the filesystem
One of my disks frequently returns this error, and has wiped out my track database on more than one occasion. Let's handle this error by disabling the library until the user tells us it is safe to use again. Fixes #33: Handle music directories disappearing better Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
2dd4f93bd0
commit
5979d1dcaf
|
@ -5,8 +5,10 @@
|
|||
#include <core/idle.h>
|
||||
#include <core/playlist.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static struct file c_file = FILE_INIT("library.q", 0);
|
||||
|
@ -20,6 +22,29 @@ struct scan_data {
|
|||
static void __scan_dir(void *);
|
||||
|
||||
|
||||
#ifdef CONFIG_TESTING
|
||||
bool test_collection_eio = false;
|
||||
static inline int __g_access(const gchar *path, int mode)
|
||||
{
|
||||
if (test_collection_eio) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return g_access(path, F_OK);
|
||||
}
|
||||
#else
|
||||
#define __g_access g_access
|
||||
#endif /* CONFIG_TESTING */
|
||||
|
||||
|
||||
static inline int __check_access(const gchar *path)
|
||||
{
|
||||
int ret = __g_access(path, F_OK);
|
||||
if (ret == -1)
|
||||
return -errno;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __scan_dir_later(struct library *library, const gchar *dir)
|
||||
{
|
||||
struct scan_data *data = g_malloc(sizeof(struct scan_data));
|
||||
|
@ -77,6 +102,7 @@ static void __validate_library(void *data)
|
|||
struct library *library = data;
|
||||
struct db_entry *dbe, *next;
|
||||
struct track *track;
|
||||
int access;
|
||||
gchar *path;
|
||||
|
||||
db_for_each(dbe, next, track_db_get()) {
|
||||
|
@ -84,12 +110,18 @@ static void __validate_library(void *data)
|
|||
if (track->tr_library != library)
|
||||
continue;
|
||||
|
||||
path = track_path(track);
|
||||
if (g_file_test(path, G_FILE_TEST_EXISTS) == false) {
|
||||
path = track_path(track);
|
||||
access = __check_access(path);
|
||||
g_free(path);
|
||||
|
||||
if (access == -EIO) {
|
||||
if (collection_check_library(library) == -EIO)
|
||||
return;
|
||||
}
|
||||
if (access < 0) {
|
||||
queue_remove_all(&c_queue, track);
|
||||
track_remove(track);
|
||||
}
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,6 +255,8 @@ void collection_set_enabled(struct library *library, bool enabled)
|
|||
|
||||
if (!library || (library->li_enabled == enabled))
|
||||
return;
|
||||
if (enabled && (collection_check_library(library) == -EIO))
|
||||
return;
|
||||
|
||||
library_set_enabled(library, enabled);
|
||||
queue_set_flag(&c_queue, Q_ADD_FRONT);
|
||||
|
@ -242,6 +276,16 @@ void collection_set_enabled(struct library *library, bool enabled)
|
|||
queue_resort(&c_queue);
|
||||
}
|
||||
|
||||
int collection_check_library(struct library *library)
|
||||
{
|
||||
int ret = __check_access(library->li_path);
|
||||
if (ret == -EIO) {
|
||||
g_warning("Can't access library at %s/\n", library->li_path);
|
||||
collection_set_enabled(library, false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct queue *collection_get_queue()
|
||||
{
|
||||
return &c_queue;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
#include <core/audio.h>
|
||||
extern "C" {
|
||||
#include <core/collection.h>
|
||||
#include <core/string.h>
|
||||
}
|
||||
#include <gui/ocarina.h>
|
||||
|
@ -154,6 +155,7 @@ static void parse_gst_error(GstMessage *error)
|
|||
if (track) {
|
||||
path = track_path(track);
|
||||
g_print("Error playing file: %s\n", path);
|
||||
collection_check_library(track->tr_library);
|
||||
g_free(path);
|
||||
}
|
||||
g_print("Error: %s\n", err->message);
|
||||
|
|
|
@ -48,7 +48,15 @@ bool collection_unban(struct track *);
|
|||
/* Called to enable or disable a library directory. */
|
||||
void collection_set_enabled(struct library *, bool);
|
||||
|
||||
/* Called to check if the library path is good. */
|
||||
int collection_check_library(struct library *);
|
||||
|
||||
/* Called to access the collection queue. */
|
||||
struct queue *collection_get_queue();
|
||||
|
||||
|
||||
#ifdef CONFIG_TESTING
|
||||
extern bool test_collection_eio;
|
||||
#endif /* CONFIG_TESTING */
|
||||
|
||||
#endif /* OCARINA_CORE_COLLECTION_H */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <core/playlist.h>
|
||||
#include <core/tags/tags.h>
|
||||
#include <tests/test.h>
|
||||
#include <errno.h>
|
||||
|
||||
static void test_init()
|
||||
{
|
||||
|
@ -225,6 +226,42 @@ static void test_save_load()
|
|||
test_equal(GPOINTER_TO_INT(list->data), COMPARE_GENRE);
|
||||
}
|
||||
|
||||
static void test_eio()
|
||||
{
|
||||
struct queue *q = collection_get_queue();
|
||||
struct library *lib = library_get(0);
|
||||
|
||||
test_equal(queue_size(q), 48);
|
||||
test_equal(collection_check_library(lib), 0);
|
||||
test_equal(lib->li_enabled, (bool)true);
|
||||
test_equal(queue_size(q), 48);
|
||||
|
||||
test_collection_eio = true;
|
||||
test_equal(collection_check_library(lib), -EIO);
|
||||
test_equal(lib->li_enabled, (bool)false);
|
||||
test_equal(queue_size(q), 0);
|
||||
|
||||
collection_set_enabled(lib, true);
|
||||
test_equal(lib->li_enabled, (bool)false);
|
||||
test_equal(queue_size(q), 0);
|
||||
|
||||
test_collection_eio = false;
|
||||
collection_set_enabled(lib, true);
|
||||
test_equal(lib->li_enabled, (bool)true);
|
||||
test_equal(queue_size(q), 48);
|
||||
|
||||
test_collection_eio = true;
|
||||
collection_update_all();
|
||||
test_equal(idle_run_task(), (bool)true);
|
||||
test_equal(lib->li_enabled, (bool)false);
|
||||
test_equal(queue_size(q), 0);
|
||||
|
||||
test_collection_eio = false;
|
||||
collection_set_enabled(lib, true);
|
||||
test_equal(lib->li_enabled, (bool)true);
|
||||
test_equal(queue_size(q), 48);
|
||||
}
|
||||
|
||||
static void test_remove()
|
||||
{
|
||||
struct queue *q = collection_get_queue();
|
||||
|
@ -250,5 +287,6 @@ DECLARE_UNIT_TESTS(
|
|||
UNIT_TEST("Collection Ban and Unban", test_ban),
|
||||
UNIT_TEST("Collection Enable and Disable", test_enable),
|
||||
UNIT_TEST("Collection Save and Load", test_save_load),
|
||||
UNIT_TEST("Colleciton -EIO Handling", test_eio),
|
||||
UNIT_TEST("Collection Remove Path", test_remove),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue