summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-01-04 17:02:39 -0500
committerColin Walters <walters@verbum.org>2013-01-04 17:02:39 -0500
commit660aa3e43f53d272508fc8fcd3eef62b426c59ae (patch)
tree09e069ebb6e4028af60d6ce7671b6b4a79efb52d
parentb11ad335f459e3c61b317308da57de441660efd0 (diff)
downloadlibgsystem-660aa3e43f53d272508fc8fcd3eef62b426c59ae.tar.gz
fileutils: Add gs_file_sync_data()
It often occurs that I want to ensure file data is on disk so that updates can be atomic.
-rw-r--r--gsystem-file-utils.c65
-rw-r--r--gsystem-file-utils.h4
2 files changed, 69 insertions, 0 deletions
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c
index 546ff99..5e70c34 100644
--- a/gsystem-file-utils.c
+++ b/gsystem-file-utils.c
@@ -159,6 +159,71 @@ gs_file_map_readonly (GFile *file,
return ret;
}
+static int
+close_nointr (int fd)
+{
+ int res;
+ do
+ res = close (fd);
+ while (G_UNLIKELY (res != 0 && errno == EINTR));
+ return res;
+}
+
+/**
+ * gs_file_sync_data:
+ * @file: a #GFile
+ * @cancellable:
+ * @error:
+ *
+ * Wraps the UNIX fdatasync() function, which ensures that the data in
+ * @file is on non-volatile storage.
+ */
+gboolean
+gs_file_sync_data (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ int res;
+ int fd = -1;
+
+ fd = _open_fd_noatime (gs_file_get_path_cached (file));
+ if (fd < 0)
+ {
+ int errsv = errno;
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ g_strerror (errsv));
+ goto out;
+ }
+
+ do
+ res = fdatasync (fd);
+ while (G_UNLIKELY (res != 0 && errno == EINTR));
+ if (res != 0)
+ {
+ int errsv = errno;
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ g_strerror (errsv));
+ goto out;
+ }
+
+ res = close_nointr (fd);
+ if (res != 0)
+ {
+ int errsv = errno;
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ g_strerror (errsv));
+ goto out;
+ }
+ fd = -1;
+
+ ret = TRUE;
+ out:
+ if (fd != -1)
+ (void) close_nointr (fd);
+ return ret;
+}
+
/**
* gs_file_get_path_cached:
*
diff --git a/gsystem-file-utils.h b/gsystem-file-utils.h
index bf07b3a..768cc0c 100644
--- a/gsystem-file-utils.h
+++ b/gsystem-file-utils.h
@@ -40,6 +40,10 @@ GBytes *gs_file_map_readonly (GFile *file,
GCancellable *cancellable,
GError **error);
+gboolean gs_file_sync_data (GFile *file,
+ GCancellable *cancellable,
+ GError **error);
+
gboolean gs_file_rename (GFile *from,
GFile *to,
GCancellable *cancellable,