gfileutils: Add g_file_set_contents_full() and GFileSetContentsFlags

This is a new version of the g_file_set_contents() API which will allow
its safety to be controlled by some flags, allowing the user to choose
their preferred tradeoff between safety (`fsync()` calls) and speed.

Currently, the flags do nothing and the new API behaves like the old
API. This will change in the following commits.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #1302
This commit is contained in:
Philip Withnall 2020-05-27 13:54:47 +01:00
parent 5b49df3b9f
commit 554107c23c
3 changed files with 77 additions and 5 deletions

View File

@ -1613,7 +1613,9 @@ G_FILE_ERROR
GFileTest
g_file_error_from_errno
g_file_get_contents
GFileSetContentsFlags
g_file_set_contents
g_file_set_contents_full
g_file_test
g_mkstemp
g_mkstemp_full

View File

@ -1179,6 +1179,34 @@ write_to_temp_file (const gchar *contents,
* @length: length of @contents, or -1 if @contents is a nul-terminated string
* @error: return location for a #GError, or %NULL
*
* Writes all of @contents to a file named @filename. This is a convenience
* wrapper around calling g_file_set_contents() with `flags` set to
* `G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING`.
*
* Returns: %TRUE on success, %FALSE if an error occurred
*
* Since: 2.8
*/
gboolean
g_file_set_contents (const gchar *filename,
const gchar *contents,
gssize length,
GError **error)
{
return g_file_set_contents_full (filename, contents, length,
G_FILE_SET_CONTENTS_CONSISTENT |
G_FILE_SET_CONTENTS_ONLY_EXISTING, error);
}
/**
* g_file_set_contents_full:
* @filename: (type filename): name of a file to write @contents to, in the GLib file name
* encoding
* @contents: (array length=length) (element-type guint8): string to write to the file
* @length: length of @contents, or -1 if @contents is a nul-terminated string
* @flags: flags controlling the safety vs speed of the operation
* @error: return location for a #GError, or %NULL
*
* Writes all of @contents to a file named @filename, with good error checking.
* If a file called @filename already exists it will be overwritten.
*
@ -1218,13 +1246,14 @@ write_to_temp_file (const gchar *contents,
*
* Returns: %TRUE on success, %FALSE if an error occurred
*
* Since: 2.8
* Since: 2.66
*/
gboolean
g_file_set_contents (const gchar *filename,
const gchar *contents,
gssize length,
GError **error)
g_file_set_contents_full (const gchar *filename,
const gchar *contents,
gssize length,
GFileSetContentsFlags flags,
GError **error)
{
gchar *tmp_filename;
gboolean retval;

View File

@ -72,6 +72,39 @@ typedef enum
G_FILE_TEST_EXISTS = 1 << 4
} GFileTest;
/**
* GFileSetContentsFlags:
* @G_FILE_SET_CONTENTS_NONE: No guarantees about file consistency or durability.
* The most dangerous setting, which is slightly faster than other settings.
* @G_FILE_SET_CONTENTS_CONSISTENT: Guarantee file consistency: after a crash,
* either the old version of the file or the new version of the file will be
* available, but not a mixture. On Unix systems this equates to an `fsync()`
* on the file and use of an atomic `rename()` of the new version of the file
* over the old.
* @G_FILE_SET_CONTENTS_DURABLE: Guarantee file durability: after a crash, the
* new version of the file will be available. On Unix systems this equates to
* an `fsync()` on the file (if %G_FILE_SET_CONTENTS_CONSISTENT is unset), or
* the effects of %G_FILE_SET_CONTENTS_CONSISTENT plus an `fsync()` on the
* directory containing the file after calling `rename()`.
* @G_FILE_SET_CONTENTS_ONLY_EXISTING: Only apply consistency and durability
* guarantees if the file already exists. This may speed up file operations
* if the file doesnt currently exist, but may result in a corrupted version
* of the new file if the system crashes while writing it.
*
* Flags to pass to g_file_set_contents_full() to affect its safety and
* performance.
*
* Since: 2.66
*/
typedef enum
{
G_FILE_SET_CONTENTS_NONE = 0,
G_FILE_SET_CONTENTS_CONSISTENT = 1 << 0,
G_FILE_SET_CONTENTS_DURABLE = 1 << 1,
G_FILE_SET_CONTENTS_ONLY_EXISTING = 1 << 2
} GFileSetContentsFlags
GLIB_AVAILABLE_ENUMERATOR_IN_2_66;
GLIB_AVAILABLE_IN_ALL
GQuark g_file_error_quark (void);
/* So other code can generate a GFileError */
@ -91,6 +124,14 @@ gboolean g_file_set_contents (const gchar *filename,
const gchar *contents,
gssize length,
GError **error);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_2_66
gboolean g_file_set_contents_full (const gchar *filename,
const gchar *contents,
gssize length,
GFileSetContentsFlags flags,
GError **error);
G_GNUC_END_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_IN_ALL
gchar *g_file_read_link (const gchar *filename,
GError **error);