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) 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; return;
data_file_writef(&db->db_file, "%u\n", db_actual_size(db)); 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; 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) static bool __file_open(struct file *file, enum open_mode mode)
{ {
gchar *cmode, *path; gchar *cmode, *path;
@ -51,9 +45,10 @@ static bool __file_open(struct file *file, enum open_mode mode)
return file->f_file != NULL; 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); int ret = g_mkdir_with_parents(dir, 0755);
if (ret != 0) if (ret != 0)
@ -62,9 +57,9 @@ static bool __file_mkdir(const gchar *basedir, const gchar *subdir)
return ret == 0; 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; bool ret = true;
if (g_access(path, F_OK) == 0 && g_access(path, W_OK) < 0) 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; 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; return false;
if (!__file_can_write(data)) if (!__file_can_write(file))
return false; return false;
if (!__file_open(data, OPEN_WRITE)) if (!__file_open(file, OPEN_WRITE))
return false; return false;
data->f_mode = OPEN_WRITE; file->f_mode = mode;
return data_file_writef(data, "%d\n", data->f_version) > 0; if (mode == OPEN_WRITE_BINARY)
} return true;
return data_file_writef(file, "%d\n", file->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;
} }
bool file_open(struct file *file, enum open_mode mode) 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) if (mode == OPEN_READ || mode == OPEN_READ_BINARY)
return __file_open_read(file, mode); return __file_open_read(file, mode);
return false; return __file_open_write(file, mode);
} }
void file_close(struct file *file) void file_close(struct file *file)
@ -206,7 +179,7 @@ void file_close(struct file *file)
if (file->f_file) { if (file->f_file) {
fclose(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); g_rename(tmp, path);
} }

View File

@ -70,7 +70,7 @@ static void pl_artist_save(void)
struct db_entry *dbe, *next; struct db_entry *dbe, *next;
struct playlist *playlist; struct playlist *playlist;
if (!data_file_open(&artist_file, OPEN_WRITE)) if (!file_open(&artist_file, OPEN_WRITE))
return; return;
data_file_writef(&artist_file, "%u\n", artist_db_get()->db_size); 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 db_entry *dbe, *next;
struct playlist *playlist; struct playlist *playlist;
if (!data_file_open(&lib_file, OPEN_WRITE)) if (!file_open(&lib_file, OPEN_WRITE))
return; return;
data_file_writef(&lib_file, "%u\n", library_db_get()->db_size); 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; struct playlist *playlist;
unsigned int i, save; unsigned int i, save;
if (!data_file_open(&sys_pl_file, OPEN_WRITE)) if (!file_open(&sys_pl_file, OPEN_WRITE))
return; return;
data_file_writef(&sys_pl_file, "%u\n", SYS_PL_NUM_PLAYLISTS); 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() 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)); data_file_writef(&gui_settings_file, "%u\n", g_hash_table_size(gui_settings));
g_hash_table_foreach(gui_settings, __settings_save_item, NULL); 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); 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), cache_file_write(&file->ac_file, caa_imagedata_data(image),
caa_imagedata_size(image)); caa_imagedata_size(image));
file_close(&file->ac_file); file_close(&file->ac_file);
@ -391,7 +391,7 @@ bool album_artwork_import(struct album *album, gchar *path)
bool ret = false; bool ret = false;
file = __album_alloc_file(album); 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); ret = cache_file_import(&file->ac_file, path);
file_close(&file->ac_file); file_close(&file->ac_file);
} }

View File

@ -34,6 +34,7 @@ enum open_mode {
OPEN_READ, /* File is open for reading text. */ OPEN_READ, /* File is open for reading text. */
OPEN_READ_BINARY, /* File is open for reading binary data. */ OPEN_READ_BINARY, /* File is open for reading binary data. */
OPEN_WRITE, /* File is open for writing text. */ OPEN_WRITE, /* File is open for writing text. */
OPEN_WRITE_BINARY, /* File is open for writing binary data. */
}; };
struct file { struct file {
@ -92,15 +93,14 @@ bool file_exists(struct file *);
* - If open for reading text (OPEN_READ): * - If open for reading text (OPEN_READ):
* - Read in file->_prev_version from the start of the file. * - 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. * - Create missing directories as needed.
* - Open a temporary file to protect data if Ocarina crashes. * - 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. * 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); 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_cmpuint(ent->ie_val, ==, 1);
g_assert_cmpstr_free(int_ops.dbe_key(&ent->ie_dbe), ==, "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); int_ops.dbe_write(&f, &ent->ie_dbe);
file_close(&f); file_close(&f);

View File

@ -20,7 +20,7 @@ void test_date()
date_today(NULL); date_today(NULL);
date_set(NULL, 0, 0, 0); date_set(NULL, 0, 0, 0);
data_file_open(&f, OPEN_WRITE); file_open(&f, OPEN_WRITE);
date_set(&date, 1988, 6, 17); date_set(&date, 1988, 6, 17);
g_assert_cmpuint(date.d_year, ==, 1988); 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_false(file_open(&file, OPEN_READ));
g_assert_null(file.f_file); 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_null(file.f_file);
g_assert_cmpuint(file.f_mode, ==, CLOSED); 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, OPEN_READ));
g_assert_false(file_open(&file, CLOSED)); 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_nonnull(file.f_file);
g_assert_cmpuint(file.f_mode, ==, OPEN_WRITE); 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)); g_assert_false(file_exists(&file));
file_close(&file); file_close(&file);
@ -58,7 +58,7 @@ static void __test_file_subprocess()
g_assert_true(file_exists(&file)); g_assert_true(file_exists(&file));
g_chmod(filepath, 0444); 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_chmod(filepath, 0200);
g_assert_false(file_open(&file, OPEN_READ)); g_assert_false(file_open(&file, OPEN_READ));
g_chmod(filepath, 0644); g_chmod(filepath, 0644);
@ -99,7 +99,7 @@ static void test_io()
unsigned int i; unsigned int i;
fout.f_version = 1; 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, "1 ABCDE\n");
data_file_writef(&fout, "2 FGHIJ KLMNO\n"); data_file_writef(&fout, "2 FGHIJ KLMNO\n");
data_file_writef(&fout, "3 \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; fout.f_version = out;
fin.f_version = in; 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"); data_file_writef(&fout, "abcdefghijklmnopqrstuvwxyz");
file_close(&fout); file_close(&fout);
g_assert_true(file_exists(&fout)); g_assert_true(file_exists(&fout));
@ -195,12 +195,11 @@ static void test_cache()
/* Test writing data to a cache file. */ /* Test writing data to a cache file. */
g_assert_false(file_exists(&file)); g_assert_false(file_exists(&file));
g_assert_false(file_open(&file, OPEN_READ_BINARY)); g_assert_false(file_open(&file, OPEN_READ_BINARY));
g_assert_false(cache_file_open(&file, OPEN_READ)); g_assert_false(file_open(&file, CLOSED));
g_assert_false(cache_file_open(&file, CLOSED)); g_assert_true( file_open(&file, OPEN_WRITE_BINARY));
g_assert_true(cache_file_open(&file, OPEN_WRITE));
g_assert_nonnull(file.f_file); g_assert_nonnull(file.f_file);
g_assert_cmpuint(file.f_mode, ==, OPEN_WRITE); g_assert_cmpuint(file.f_mode, ==, OPEN_WRITE_BINARY);
g_assert_false(cache_file_open(&file, OPEN_WRITE)); g_assert_false(file_open(&file, OPEN_WRITE_BINARY));
g_assert_false(file_exists(&file)); g_assert_false(file_exists(&file));
g_assert_cmpuint(cache_file_write(&file, "abcde", 5), ==, 5); 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_null(file.f_file);
g_assert_cmpuint(file.f_mode, ==, CLOSED); g_assert_cmpuint(file.f_mode, ==, CLOSED);
g_assert_true(file_exists(&file)); 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_true(file_open(&file, OPEN_READ_BINARY));
g_assert_cmpuint(file.f_mode, ==, 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(file_exists(&copy));
g_assert_false(cache_file_import(&copy, filepath)); g_assert_false(cache_file_import(&copy, filepath));
g_assert_false(file_exists(&copy)); 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_false(cache_file_import(&copy, NULL));
g_assert_true(cache_file_import(&copy, filepath)); g_assert_true(cache_file_import(&copy, filepath));
g_assert_false(file_exists(&copy)); g_assert_false(file_exists(&copy));

View File

@ -344,7 +344,7 @@ static void test_save_load()
playlist_current_set(&q, 4); playlist_current_set(&q, 4);
g_assert_false(file_exists(&f)); 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(&p, &f, PL_SAVE_METADATA);
playlist_generic_save(&q, &f, PL_SAVE_ALL); playlist_generic_save(&q, &f, PL_SAVE_ALL);
file_close(&f); file_close(&f);

View File

@ -58,7 +58,7 @@ static void test_album()
g_assert_true( album_match_token(album, "symphony")); g_assert_true( album_match_token(album, "symphony"));
g_assert_false(album_match_token(album, "skyward")); 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"); data_file_writef(&f, "0 0 0 \n");
album_ops->dbe_write(&f, &album->al_dbe); album_ops->dbe_write(&f, &album->al_dbe);
file_close(&f); file_close(&f);

View File

@ -40,7 +40,7 @@ static void test_artist()
g_assert_true( artist_match_token(artist, "kondo")); g_assert_true( artist_match_token(artist, "kondo"));
g_assert_false(artist_match_token(artist, "hajime")); 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 "); data_file_writef(&f, "1 \n2 ");
artist_ops->dbe_write(&f, &artist->ar_dbe); artist_ops->dbe_write(&f, &artist->ar_dbe);
file_close(&f); file_close(&f);

View File

@ -38,7 +38,7 @@ static void test_genre()
g_assert_true( genre_match_token(genre, "music")); g_assert_true( genre_match_token(genre, "music"));
g_assert_false(genre_match_token(genre, "rock")); 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 "); data_file_writef(&f, "1 \n1 ");
genre_ops->dbe_write(&f, &genre->ge_dbe); genre_ops->dbe_write(&f, &genre->ge_dbe);
file_close(&f); file_close(&f);

View File

@ -30,7 +30,7 @@ static void test_library()
test_verify_link(link); test_verify_link(link);
test_verify_zelda(zelda); test_verify_zelda(zelda);
data_file_open(&f, OPEN_WRITE); file_open(&f, OPEN_WRITE);
library_ops->dbe_write(&f, &link->li_dbe); library_ops->dbe_write(&f, &link->li_dbe);
data_file_writef(&f, "\n"); data_file_writef(&f, "\n");
library_ops->dbe_write(&f, &zelda->li_dbe); 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_true( track_match_token(track, "theme"));
g_assert_false(track_match_token(track, "hyrule")); 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, "0 0 0 0 0 0 \n");
data_file_writef(&f, "Hyrule Symphony/00 - No Track.ogg\n"); data_file_writef(&f, "Hyrule Symphony/00 - No Track.ogg\n");
track_ops->dbe_write(&f, &track->tr_dbe); track_ops->dbe_write(&f, &track->tr_dbe);