core/file: Build in minimum version checks
I don't think it makes sense that callers of file_open() are expected to check the file version after opening. This should be something handled by the file code so we can print a consistent error message. Implements issue #5: Better file versioning Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
fe6f31b1e5
commit
9e0f017e61
|
@ -7,7 +7,7 @@
|
|||
#include <core/idle.h>
|
||||
#include <core/tempq.h>
|
||||
|
||||
static struct file audio_file = FILE_INIT("cur_track", 0);
|
||||
static struct file audio_file = FILE_INIT("cur_track", 0, 0);
|
||||
static struct track *audio_track = NULL;
|
||||
static GstElement *audio_player = NULL;
|
||||
static struct audio_ops *audio_ops = NULL;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
|
||||
static struct file c_file = FILE_INIT("library.q", 0);
|
||||
static struct file c_file = FILE_INIT("library.q", 0, 0);
|
||||
static struct queue c_queue;
|
||||
|
||||
struct scan_data {
|
||||
|
|
|
@ -78,7 +78,7 @@ void db_init(struct database *db, const char *filepath, bool autosave,
|
|||
db->db_autosave = autosave;
|
||||
db->db_entries = g_ptr_array_new();
|
||||
db->db_keys = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
file_init(&db->db_file, filepath, 0);
|
||||
file_init(&db->db_file, filepath, 0, 0);
|
||||
}
|
||||
|
||||
void db_deinit(struct database *db)
|
||||
|
|
13
core/file.c
13
core/file.c
|
@ -61,11 +61,13 @@ static void __file_rename_tmp(struct file *file)
|
|||
}
|
||||
|
||||
|
||||
void file_init(struct file *file, const gchar *name, unsigned int version)
|
||||
void file_init(struct file *file, const gchar *name,
|
||||
unsigned int version, unsigned int min)
|
||||
{
|
||||
file->f_mode = OPEN_READ;
|
||||
file->f_version = version;
|
||||
file->f_prev = 0;
|
||||
file->f_min = 0;
|
||||
file->f_file = NULL;
|
||||
file->f_name = name;
|
||||
}
|
||||
|
@ -117,7 +119,14 @@ static bool __file_open_read(struct file *file)
|
|||
return false;
|
||||
|
||||
file->f_mode = OPEN_READ;
|
||||
return file_readf(file, "%u\n", &file->f_prev) == 1;
|
||||
if (file_readf(file, "%u\n", &file->f_prev) != 1)
|
||||
return false;
|
||||
if (file->f_prev < file->f_min) {
|
||||
REPORT_ERROR(file->f_name, "File too old to be upgraded.");
|
||||
file_close(file);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __file_open_write(struct file *file)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <core/tempq.h>
|
||||
#include <glib.h>
|
||||
|
||||
static struct file tempq_file = FILE_INIT("deck", 1);
|
||||
static struct file tempq_file = FILE_INIT("deck", 1, 1);
|
||||
static struct queue_ops *tempq_ops = NULL;
|
||||
static GSList *tempq_list;
|
||||
static struct file tempq_file;
|
||||
|
@ -63,13 +63,10 @@ static void __tempq_init_idle(void *data)
|
|||
|
||||
if (!file_open(&tempq_file, OPEN_READ))
|
||||
return;
|
||||
if (file_version(&tempq_file) < 1)
|
||||
goto out;
|
||||
|
||||
file_readf(&tempq_file, "%u", &num);
|
||||
for (i = 0; i < num; i++)
|
||||
__tempq_read_queue();
|
||||
out:
|
||||
file_close(&tempq_file);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <gui/settings.h>
|
||||
|
||||
static GHashTable *gui_settings = NULL;
|
||||
static struct file gui_settings_file = FILE_INIT("settings", 0);
|
||||
static struct file gui_settings_file = FILE_INIT("settings", 0, 0);
|
||||
|
||||
|
||||
static void __settings_save_item(gpointer key, gpointer value, gpointer data)
|
||||
|
|
|
@ -81,7 +81,7 @@ struct database {
|
|||
{ \
|
||||
.db_size = 0, \
|
||||
.db_autosave = autosave, \
|
||||
.db_file = FILE_INIT(fname, 0), \
|
||||
.db_file = FILE_INIT(fname, 0, 0), \
|
||||
.db_entries = g_ptr_array_new(), \
|
||||
.db_keys = g_hash_table_new(g_str_hash, g_str_equal), \
|
||||
.db_ops = ops, \
|
||||
|
|
|
@ -37,21 +37,24 @@ struct file {
|
|||
enum open_mode f_mode; /* The file's current open mode. */
|
||||
unsigned int f_version; /* The file's current data version. */
|
||||
unsigned int f_prev; /* The file's on-disk data version. */
|
||||
unsigned int f_min; /* The file's minimum data version. */
|
||||
FILE *f_file; /* The file's IO stream. */
|
||||
const gchar *f_name; /* The file's basename. */
|
||||
};
|
||||
|
||||
#define FILE_INIT(fname, version) \
|
||||
{ \
|
||||
.f_mode = OPEN_READ, \
|
||||
.f_version = version, \
|
||||
.f_prev = 0, .f_file = NULL, \
|
||||
.f_name = fname, \
|
||||
#define FILE_INIT(fname, version, min) \
|
||||
{ \
|
||||
.f_mode = OPEN_READ, \
|
||||
.f_version = version, \
|
||||
.f_prev = 0, \
|
||||
.f_min = min, \
|
||||
.f_file = NULL, \
|
||||
.f_name = fname, \
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a new file object. */
|
||||
void file_init(struct file *, const gchar *, unsigned int);
|
||||
void file_init(struct file *, const gchar *, unsigned int, unsigned int);
|
||||
|
||||
/*
|
||||
* Returns the full path of the file or an empty string if filename is not set.
|
||||
|
|
|
@ -83,7 +83,7 @@ static void test_db_entry()
|
|||
test_equal(ent->ie_val, 1);
|
||||
test_str_equal(int_ops.dbe_key(&ent->ie_dbe), "1");
|
||||
|
||||
file_init(&f, "test_db_entry", 0);
|
||||
file_init(&f, "test_db_entry", 0, 0);
|
||||
file_open(&f, OPEN_WRITE);
|
||||
int_ops.dbe_write(&f, &ent->ie_dbe);
|
||||
file_close(&f);
|
||||
|
|
|
@ -26,7 +26,7 @@ static void test_entry()
|
|||
i++;
|
||||
} test_loop_passed();
|
||||
|
||||
file_init(&f, "index_entry", 0);
|
||||
file_init(&f, "index_entry", 0, 0);
|
||||
file_open(&f, OPEN_WRITE);
|
||||
file_writef(&f, "Zelda\n0 \n");
|
||||
index_ops->dbe_write(&f, &ie->ie_dbe);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
void test_set()
|
||||
{
|
||||
struct file f = FILE_INIT("set", 0);
|
||||
struct file f = FILE_INIT("set", 0, 0);
|
||||
struct set set = SET_INIT();
|
||||
unsigned int i, N = 10;
|
||||
struct set_iter it;
|
||||
|
|
|
@ -17,7 +17,7 @@ void test_date()
|
|||
.d_month = 0,
|
||||
.d_day = 0,
|
||||
};
|
||||
struct file f = FILE_INIT("date", 0);
|
||||
struct file f = FILE_INIT("date", 0, 0);
|
||||
gchar *str;
|
||||
|
||||
date_today(NULL);
|
||||
|
|
|
@ -33,20 +33,20 @@ static void test_invalid_file(struct file *file)
|
|||
static void test_null()
|
||||
{
|
||||
struct file fnull;
|
||||
file_init(&fnull, NULL, 0);
|
||||
file_init(&fnull, NULL, 0, 0);
|
||||
test_invalid_file(&fnull);
|
||||
}
|
||||
|
||||
static void test_empty()
|
||||
{
|
||||
struct file fempty;
|
||||
file_init(&fempty, "", 0);
|
||||
file_init(&fempty, "", 0, 0);
|
||||
test_invalid_file(&fempty);
|
||||
}
|
||||
|
||||
static void test_file()
|
||||
{
|
||||
struct file file = FILE_INIT("file.txt", 0);
|
||||
struct file file = FILE_INIT("file.txt", 0, 0);
|
||||
gchar *basepath, *filepath, *realpath;
|
||||
|
||||
basepath = g_strjoin("/", g_get_user_data_dir(), OCARINA_NAME, NULL);
|
||||
|
@ -88,8 +88,8 @@ static void test_file()
|
|||
|
||||
static void test_io()
|
||||
{
|
||||
struct file fout = FILE_INIT("file.txt", 1);
|
||||
struct file fin = FILE_INIT("file.txt", 0);
|
||||
struct file fout = FILE_INIT("file.txt", 1, 1);
|
||||
struct file fin = FILE_INIT("file.txt", 0, 0);
|
||||
char *res = NULL;
|
||||
unsigned int i;
|
||||
|
||||
|
@ -129,9 +129,24 @@ static void test_io()
|
|||
test_equal(file_version(&fin), 0);
|
||||
}
|
||||
|
||||
static void test_versioning()
|
||||
{
|
||||
struct file fout = FILE_INIT("file.txt", 0, 0);
|
||||
struct file fin = FILE_INIT("file.txt", 2, 1);
|
||||
|
||||
test_equal(file_open(&fout, OPEN_WRITE), (bool)true);
|
||||
file_writef(&fout, "abcdefghijklmnopqrstuvwxyz");
|
||||
file_close(&fout);
|
||||
test_equal(file_exists(&fout), (bool)true);
|
||||
|
||||
test_equal(file_open(&fin, OPEN_READ), (bool)false);
|
||||
test_equal((void *)fin.f_file, NULL);
|
||||
}
|
||||
|
||||
DECLARE_UNIT_TESTS(
|
||||
UNIT_TEST("File (Path = NULL)", test_null),
|
||||
UNIT_TEST("File (Path = \"\")", test_empty),
|
||||
UNIT_TEST("File (Path = \"file.txt\")", test_file),
|
||||
UNIT_TEST("File I/O", test_io),
|
||||
UNIT_TEST("File Versioning", test_versioning),
|
||||
);
|
||||
|
|
|
@ -31,7 +31,7 @@ static void test_album()
|
|||
album = ALBUM(album_ops->dbe_alloc("1998/Hyrule Symphony"));
|
||||
test_verify_hyrule(album);
|
||||
|
||||
file_init(&f, "album_tag", 0);
|
||||
file_init(&f, "album_tag", 0, 0);
|
||||
file_open(&f, OPEN_WRITE);
|
||||
file_writef(&f, "0 \n");
|
||||
album_ops->dbe_write(&f, &album->al_dbe);
|
||||
|
|
|
@ -30,7 +30,7 @@ static void test_artist()
|
|||
artist = ARTIST(artist_ops->dbe_alloc("Koji Kondo"));
|
||||
test_verify_koji(artist);
|
||||
|
||||
file_init(&f, "artist_tag", 0);
|
||||
file_init(&f, "artist_tag", 0, 0);
|
||||
file_open(&f, OPEN_WRITE);
|
||||
file_writef(&f, "1 \n2 ");
|
||||
artist_ops->dbe_write(&f, &artist->ar_dbe);
|
||||
|
|
|
@ -30,7 +30,7 @@ static void test_genre()
|
|||
genre = GENRE(genre_ops->dbe_alloc("Video Game Music"));
|
||||
test_verify_vg(genre);
|
||||
|
||||
file_init(&f, "genre_tag", 0);
|
||||
file_init(&f, "genre_tag", 0, 0);
|
||||
file_open(&f, OPEN_WRITE);
|
||||
file_writef(&f, "1 \n1 ");
|
||||
genre_ops->dbe_write(&f, &genre->ge_dbe);
|
||||
|
|
|
@ -36,7 +36,7 @@ static void test_library()
|
|||
link->li_size = 21;
|
||||
zelda->li_size = 42;
|
||||
|
||||
file_init(&f, "library_tag", 0);
|
||||
file_init(&f, "library_tag", 0, 0);
|
||||
file_open(&f, OPEN_WRITE);
|
||||
library_ops->dbe_write(&f, &link->li_dbe);
|
||||
file_writef(&f, "\n");
|
||||
|
|
|
@ -74,7 +74,7 @@ static void test_track()
|
|||
setlocale(LC_TIME, "C");
|
||||
filter_init();
|
||||
tags_init();
|
||||
file_init(&f, "track_tag", 0);
|
||||
file_init(&f, "track_tag", 0, 0);
|
||||
while (idle_run_task()) {}
|
||||
|
||||
date = string_tm2str(now);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
static void test_settings()
|
||||
{
|
||||
struct file f = FILE_INIT("settings", 0);
|
||||
struct file f = FILE_INIT("settings", 0, 0);
|
||||
|
||||
test_equal((void *)test_get_gui_settings(), NULL);
|
||||
gui_settings_set("test.value1", 42);
|
||||
|
|
Loading…
Reference in New Issue