core/file: Add write support to file_open()

I also take this opportunity to add a OPEN_WRITE_BINARY mode to support
writing binary data to files.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2018-02-20 15:38:28 -05:00
parent a848d5d03c
commit 35d53855f5
17 changed files with 45 additions and 74 deletions

View File

@ -94,7 +94,7 @@ void db_deinit(struct database *db)
void db_save(struct database *db)
{
if (data_file_open(&db->db_file, OPEN_WRITE) == false)
if (file_open(&db->db_file, OPEN_WRITE) == false)
return;
data_file_writef(&db->db_file, "%u\n", db_actual_size(db));

View File

@ -26,12 +26,6 @@ static void __file_init_common(struct file *file, const gchar *subdir,
file->f_user_dir = user_dir;
}
static gchar *__file_path(const gchar *base, const gchar *dir,
const gchar *name)
{
return g_build_filename(base, OCARINA_NAME, dir ? dir : "", name, NULL);
}
static bool __file_open(struct file *file, enum open_mode mode)
{
gchar *cmode, *path;
@ -51,9 +45,10 @@ static bool __file_open(struct file *file, enum open_mode mode)
return file->f_file != NULL;
}
static bool __file_mkdir(const gchar *basedir, const gchar *subdir)
static bool __file_mkdir(struct file *file)
{
gchar *dir = __file_path(basedir, subdir, NULL);
gchar *dir = g_build_filename(file->f_user_dir(), OCARINA_NAME,
file->f_subdir, NULL);
int ret = g_mkdir_with_parents(dir, 0755);
if (ret != 0)
@ -62,9 +57,9 @@ static bool __file_mkdir(const gchar *basedir, const gchar *subdir)
return ret == 0;
}
static bool __file_can_write(struct file *data)
static bool __file_can_write(struct file *file)
{
gchar *path = file_path(data);
gchar *path = file_path(file);
bool ret = true;
if (g_access(path, F_OK) == 0 && g_access(path, W_OK) < 0)
@ -150,41 +145,19 @@ static bool __file_open_read(struct file *file, enum open_mode mode)
return true;
}
static bool __file_open_write(struct file *data)
static bool __file_open_write(struct file *file, enum open_mode mode)
{
if (!__file_mkdir(g_get_user_data_dir(), NULL))
if (!__file_mkdir(file))
return false;
if (!__file_can_write(data))
if (!__file_can_write(file))
return false;
if (!__file_open(data, OPEN_WRITE))
if (!__file_open(file, OPEN_WRITE))
return false;
data->f_mode = OPEN_WRITE;
return data_file_writef(data, "%d\n", data->f_version) > 0;
}
bool data_file_open(struct file *data, enum open_mode mode)
{
if ((string_length(data->f_name) == 0) || (data->f_file != NULL))
return false;
if (mode == CLOSED || mode == OPEN_READ)
return false;
return __file_open_write(data);
}
bool cache_file_open(struct file *cache, enum open_mode mode)
{
if ((string_length(cache->f_name) == 0) || (cache->f_file != NULL))
return false;
if (mode == OPEN_READ || mode == CLOSED)
return false;
if (!__file_mkdir(g_get_user_cache_dir(), cache->f_subdir))
return false;
if (!__file_open(cache, OPEN_WRITE))
return false;
cache->f_mode = mode;
return cache->f_file != NULL;
file->f_mode = mode;
if (mode == OPEN_WRITE_BINARY)
return true;
return data_file_writef(file, "%d\n", file->f_version) > 0;
}
bool file_open(struct file *file, enum open_mode mode)
@ -196,7 +169,7 @@ bool file_open(struct file *file, enum open_mode mode)
if (mode == OPEN_READ || mode == OPEN_READ_BINARY)
return __file_open_read(file, mode);
return false;
return __file_open_write(file, mode);
}
void file_close(struct file *file)
@ -206,7 +179,7 @@ void file_close(struct file *file)
if (file->f_file) {
fclose(file->f_file);
if (file->f_mode == OPEN_WRITE)
if (file->f_mode == OPEN_WRITE || file->f_mode == OPEN_WRITE_BINARY)
g_rename(tmp, path);
}

View File

@ -70,7 +70,7 @@ static void pl_artist_save(void)
struct db_entry *dbe, *next;
struct playlist *playlist;
if (!data_file_open(&artist_file, OPEN_WRITE))
if (!file_open(&artist_file, OPEN_WRITE))
return;
data_file_writef(&artist_file, "%u\n", artist_db_get()->db_size);

View File

@ -187,7 +187,7 @@ static void pl_library_save(void)
struct db_entry *dbe, *next;
struct playlist *playlist;
if (!data_file_open(&lib_file, OPEN_WRITE))
if (!file_open(&lib_file, OPEN_WRITE))
return;
data_file_writef(&lib_file, "%u\n", library_db_get()->db_size);

View File

@ -330,7 +330,7 @@ static void pl_system_save(void)
struct playlist *playlist;
unsigned int i, save;
if (!data_file_open(&sys_pl_file, OPEN_WRITE))
if (!file_open(&sys_pl_file, OPEN_WRITE))
return;
data_file_writef(&sys_pl_file, "%u\n", SYS_PL_NUM_PLAYLISTS);

View File

@ -16,7 +16,7 @@ static void __settings_save_item(gpointer key, gpointer value, gpointer data)
static void __settings_save()
{
data_file_open(&gui_settings_file, OPEN_WRITE);
file_open(&gui_settings_file, OPEN_WRITE);
data_file_writef(&gui_settings_file, "%u\n", g_hash_table_size(gui_settings));
g_hash_table_foreach(gui_settings, __settings_save_item, NULL);

View File

@ -64,7 +64,7 @@ static bool __album_fetch_cover(struct album *album, gchar *releaseid)
}
file = __album_alloc_file(album);
if (cache_file_open(&file->ac_file, OPEN_WRITE)) {
if (file_open(&file->ac_file, OPEN_WRITE_BINARY)) {
cache_file_write(&file->ac_file, caa_imagedata_data(image),
caa_imagedata_size(image));
file_close(&file->ac_file);
@ -391,7 +391,7 @@ bool album_artwork_import(struct album *album, gchar *path)
bool ret = false;
file = __album_alloc_file(album);
if (path && cache_file_open(&file->ac_file, OPEN_WRITE)) {
if (path && file_open(&file->ac_file, OPEN_WRITE_BINARY)) {
ret = cache_file_import(&file->ac_file, path);
file_close(&file->ac_file);
}

View File

@ -34,6 +34,7 @@ enum open_mode {
OPEN_READ, /* File is open for reading text. */
OPEN_READ_BINARY, /* File is open for reading binary data. */
OPEN_WRITE, /* File is open for writing text. */
OPEN_WRITE_BINARY, /* File is open for writing binary data. */
};
struct file {
@ -92,15 +93,14 @@ bool file_exists(struct file *);
* - If open for reading text (OPEN_READ):
* - Read in file->_prev_version from the start of the file.
*
* When opening a file for writing (OPEN_WRITE):
* When opening a file for writing (OPEN_WRITE / OPEN_WRITE_BINARY):
* - Create missing directories as needed.
* - Open a temporary file to protect data if Ocarina crashes.
* - Write file->_version to the start of the file (data files only).
* - If open for writing text (OPEN_WRITE):
* - Write file->_version to the start of the file (data files only).
*
* Returns true if the open was successful and false otherwise.
*/
bool data_file_open(struct file *, enum open_mode);
bool cache_file_open(struct file *, enum open_mode);
bool file_open(struct file *, enum open_mode);
/*

View File

@ -76,7 +76,7 @@ static void test_db_entry()
g_assert_cmpuint(ent->ie_val, ==, 1);
g_assert_cmpstr_free(int_ops.dbe_key(&ent->ie_dbe), ==, "1");
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
int_ops.dbe_write(&f, &ent->ie_dbe);
file_close(&f);

View File

@ -20,7 +20,7 @@ void test_date()
date_today(NULL);
date_set(NULL, 0, 0, 0);
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
date_set(&date, 1988, 6, 17);
g_assert_cmpuint(date.d_year, ==, 1988);

View File

@ -25,7 +25,7 @@ static void test_invalid_file(gconstpointer path)
g_assert_false(file_open(&file, OPEN_READ));
g_assert_null(file.f_file);
g_assert_false(data_file_open(&file, OPEN_WRITE));
g_assert_false(file_open(&file, OPEN_WRITE));
g_assert_null(file.f_file);
g_assert_cmpuint(file.f_mode, ==, CLOSED);
@ -46,10 +46,10 @@ static void __test_file_subprocess()
g_assert_false(file_open(&file, OPEN_READ));
g_assert_false(file_open(&file, CLOSED));
g_assert_true(data_file_open(&file, OPEN_WRITE));
g_assert_true( file_open(&file, OPEN_WRITE));
g_assert_nonnull(file.f_file);
g_assert_cmpuint(file.f_mode, ==, OPEN_WRITE);
g_assert_false(data_file_open(&file, OPEN_WRITE));
g_assert_false(file_open(&file, OPEN_WRITE));
g_assert_false(file_exists(&file));
file_close(&file);
@ -58,7 +58,7 @@ static void __test_file_subprocess()
g_assert_true(file_exists(&file));
g_chmod(filepath, 0444);
g_assert_false(data_file_open(&file, OPEN_WRITE));
g_assert_false(file_open(&file, OPEN_WRITE));
g_chmod(filepath, 0200);
g_assert_false(file_open(&file, OPEN_READ));
g_chmod(filepath, 0644);
@ -99,7 +99,7 @@ static void test_io()
unsigned int i;
fout.f_version = 1;
g_assert_true(data_file_open(&fout, OPEN_WRITE));
g_assert_true(file_open(&fout, OPEN_WRITE));
data_file_writef(&fout, "1 ABCDE\n");
data_file_writef(&fout, "2 FGHIJ KLMNO\n");
data_file_writef(&fout, "3 \n");
@ -139,7 +139,7 @@ static void __test_versioning_subprocess(unsigned int out, unsigned int in)
fout.f_version = out;
fin.f_version = in;
g_assert_true(data_file_open(&fout, OPEN_WRITE));
g_assert_true(file_open(&fout, OPEN_WRITE));
data_file_writef(&fout, "abcdefghijklmnopqrstuvwxyz");
file_close(&fout);
g_assert_true(file_exists(&fout));
@ -195,12 +195,11 @@ static void test_cache()
/* Test writing data to a cache file. */
g_assert_false(file_exists(&file));
g_assert_false(file_open(&file, OPEN_READ_BINARY));
g_assert_false(cache_file_open(&file, OPEN_READ));
g_assert_false(cache_file_open(&file, CLOSED));
g_assert_true(cache_file_open(&file, OPEN_WRITE));
g_assert_false(file_open(&file, CLOSED));
g_assert_true( file_open(&file, OPEN_WRITE_BINARY));
g_assert_nonnull(file.f_file);
g_assert_cmpuint(file.f_mode, ==, OPEN_WRITE);
g_assert_false(cache_file_open(&file, OPEN_WRITE));
g_assert_cmpuint(file.f_mode, ==, OPEN_WRITE_BINARY);
g_assert_false(file_open(&file, OPEN_WRITE_BINARY));
g_assert_false(file_exists(&file));
g_assert_cmpuint(cache_file_write(&file, "abcde", 5), ==, 5);
@ -208,7 +207,6 @@ static void test_cache()
g_assert_null(file.f_file);
g_assert_cmpuint(file.f_mode, ==, CLOSED);
g_assert_true(file_exists(&file));
g_assert_false(cache_file_open(&file, OPEN_READ));
g_assert_true(file_open(&file, OPEN_READ_BINARY));
g_assert_cmpuint(file.f_mode, ==, OPEN_READ_BINARY);
@ -220,7 +218,7 @@ static void test_cache()
g_assert_false(file_exists(&copy));
g_assert_false(cache_file_import(&copy, filepath));
g_assert_false(file_exists(&copy));
g_assert_true(cache_file_open(&copy, OPEN_WRITE));
g_assert_true(file_open(&copy, OPEN_WRITE_BINARY));
g_assert_false(cache_file_import(&copy, NULL));
g_assert_true(cache_file_import(&copy, filepath));
g_assert_false(file_exists(&copy));

View File

@ -344,7 +344,7 @@ static void test_save_load()
playlist_current_set(&q, 4);
g_assert_false(file_exists(&f));
g_assert_true( data_file_open(&f, OPEN_WRITE));
g_assert_true( file_open(&f, OPEN_WRITE));
playlist_generic_save(&p, &f, PL_SAVE_METADATA);
playlist_generic_save(&q, &f, PL_SAVE_ALL);
file_close(&f);

View File

@ -58,7 +58,7 @@ static void test_album()
g_assert_true( album_match_token(album, "symphony"));
g_assert_false(album_match_token(album, "skyward"));
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
data_file_writef(&f, "0 0 0 \n");
album_ops->dbe_write(&f, &album->al_dbe);
file_close(&f);

View File

@ -40,7 +40,7 @@ static void test_artist()
g_assert_true( artist_match_token(artist, "kondo"));
g_assert_false(artist_match_token(artist, "hajime"));
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
data_file_writef(&f, "1 \n2 ");
artist_ops->dbe_write(&f, &artist->ar_dbe);
file_close(&f);

View File

@ -38,7 +38,7 @@ static void test_genre()
g_assert_true( genre_match_token(genre, "music"));
g_assert_false(genre_match_token(genre, "rock"));
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
data_file_writef(&f, "1 \n1 ");
genre_ops->dbe_write(&f, &genre->ge_dbe);
file_close(&f);

View File

@ -30,7 +30,7 @@ static void test_library()
test_verify_link(link);
test_verify_zelda(zelda);
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
library_ops->dbe_write(&f, &link->li_dbe);
data_file_writef(&f, "\n");
library_ops->dbe_write(&f, &zelda->li_dbe);

View File

@ -98,7 +98,7 @@ static void test_track()
g_assert_true( track_match_token(track, "theme"));
g_assert_false(track_match_token(track, "hyrule"));
data_file_open(&f, OPEN_WRITE);
file_open(&f, OPEN_WRITE);
data_file_writef(&f, "0 0 0 0 0 0 \n");
data_file_writef(&f, "Hyrule Symphony/00 - No Track.ogg\n");
track_ops->dbe_write(&f, &track->tr_dbe);