[geany/geany] daf4dd: Don't mix POSIX/GIO operations when opening/saving/stat()ing files

Jiří Techet git-noreply at xxxxx
Thu Oct 1 10:09:45 UTC 2015


Branch:      refs/heads/master
Author:      Jiří Techet <techet at gmail.com>
Committer:   Jiří Techet <techet at gmail.com>
Date:        Thu, 01 Oct 2015 10:09:45 UTC
Commit:      daf4dd45b874f7d29e30f8eddd4fbb6cae40e687
             https://github.com/geany/geany/commit/daf4dd45b874f7d29e30f8eddd4fbb6cae40e687

Log Message:
-----------
Don't mix POSIX/GIO operations when opening/saving/stat()ing files

GVFS uses different backends for "native" GIO operations and POSIX
operations which use the FUSE backend. If the two kinds of operations are
mixed, we may get races.

The patch checks the value of file_prefs.use_gio_unsafe_file_saving and
based on it either uses GIO operations or POSIX operations for file loading,
saving and checking modification time.


Modified Paths:
--------------
    src/document.c

Modified: src/document.c
101 lines changed, 72 insertions(+), 29 deletions(-)
===================================================================
@@ -80,6 +80,10 @@
 
 #include <gdk/gdkkeysyms.h>
 
+
+#define USE_GIO_FILE_OPERATIONS (!file_prefs.use_safe_file_saving && file_prefs.use_gio_unsafe_file_saving)
+
+
 GeanyFilePrefs file_prefs;
 
 
@@ -930,12 +934,60 @@ typedef struct
 } FileData;
 
 
+static gboolean get_mtime(const gchar *locale_filename, time_t *time)
+{
+	GError *error = NULL;
+	const gchar *err_msg = NULL;
+
+	if (USE_GIO_FILE_OPERATIONS)
+	{
+		GFile *file = g_file_new_for_path(locale_filename);
+		GFileInfo *info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, &error);
+
+		if (info)
+		{
+			GTimeVal timeval;
+
+			g_file_info_get_modification_time(info, &timeval);
+			g_object_unref(info);
+			*time = timeval.tv_sec;
+		}
+		else if (error)
+			err_msg = error->message;
+
+		g_object_unref(file);
+	}
+	else
+	{
+		GStatBuf st;
+
+		if (g_stat(locale_filename, &st) == 0)
+			*time = st.st_mtime;
+		else
+			err_msg = g_strerror(errno);
+	}
+
+	if (err_msg)
+	{
+		gchar *utf8_filename = utils_get_utf8_from_locale(locale_filename);
+
+		ui_set_statusbar(TRUE, _("Could not open file %s (%s)"),
+			utf8_filename, err_msg);
+		g_free(utf8_filename);
+	}
+
+	if (error)
+		g_error_free(error);
+
+	return err_msg == NULL;
+}
+
+
 /* loads textfile data, verifies and converts to forced_enc or UTF-8. Also handles BOM. */
 static gboolean load_text_file(const gchar *locale_filename, const gchar *display_filename,
 	FileData *filedata, const gchar *forced_enc)
 {
 	GError *err = NULL;
-	struct stat st;
 
 	filedata->data = NULL;
 	filedata->len = 0;
@@ -943,23 +995,26 @@ static gboolean load_text_file(const gchar *locale_filename, const gchar *displa
 	filedata->bom = FALSE;
 	filedata->readonly = FALSE;
 
-	if (g_stat(locale_filename, &st) != 0)
-	{
-		ui_set_statusbar(TRUE, _("Could not open file %s (%s)"),
-			display_filename, g_strerror(errno));
+	if (!get_mtime(locale_filename, &filedata->mtime))
 		return FALSE;
-	}
 
-	filedata->mtime = st.st_mtime;
+	if (USE_GIO_FILE_OPERATIONS)
+	{
+		GFile *file = g_file_new_for_path(locale_filename);
+
+		g_file_load_contents(file, NULL, &filedata->data, &filedata->len, NULL, &err);
+		g_object_unref(file);
+	}
+	else
+		g_file_get_contents(locale_filename, &filedata->data, &filedata->len, &err);
 
-	if (! g_file_get_contents(locale_filename, &filedata->data, NULL, &err))
+	if (err)
 	{
 		ui_set_statusbar(TRUE, "%s", err->message);
 		g_error_free(err);
 		return FALSE;
 	}
 
-	filedata->len = (gsize) st.st_size;
 	if (! encodings_convert_to_utf8_auto(&filedata->data, &filedata->len, forced_enc,
 				&filedata->enc, &filedata->bom, &filedata->readonly))
 	{
@@ -1583,25 +1638,13 @@ gboolean document_reload_prompt(GeanyDocument *doc, const gchar *forced_enc)
 }
 
 
-static gboolean document_update_timestamp(GeanyDocument *doc, const gchar *locale_filename)
+static void document_update_timestamp(GeanyDocument *doc, const gchar *locale_filename)
 {
 #ifndef USE_GIO_FILEMON
-	struct stat st;
-
-	g_return_val_if_fail(doc != NULL, FALSE);
-
-	/* stat the file to get the timestamp, otherwise on Windows the actual
-	 * timestamp can be ahead of time(NULL) */
-	if (g_stat(locale_filename, &st) != 0)
-	{
-		ui_set_statusbar(TRUE, _("Could not open file %s (%s)"), doc->file_name,
-			g_strerror(errno));
-		return FALSE;
-	}
+	g_return_if_fail(doc != NULL);
 
-	doc->priv->mtime = st.st_mtime; /* get the modification time from file and keep it */
+	get_mtime(locale_filename, &doc->priv->mtime); /* get the modification time from file and keep it */
 #endif
-	return TRUE;
 }
 
 
@@ -1867,7 +1910,7 @@ static gchar *write_data_to_disk(const gchar *locale_filename,
 		if (g_file_set_contents(locale_filename, data, len, &error))
 			geany_debug("Wrote %s with g_file_set_contents().", locale_filename);
 	}
-	else if (file_prefs.use_gio_unsafe_file_saving)
+	else if (USE_GIO_FILE_OPERATIONS)
 	{
 		GFile *fp;
 
@@ -3583,7 +3626,7 @@ gboolean document_check_disk_status(GeanyDocument *doc, gboolean force)
 	gboolean ret = FALSE;
 	gboolean use_gio_filemon;
 	time_t cur_time = 0;
-	struct stat st;
+	time_t mtime;
 	gchar *locale_filename;
 	FileDiskStatus old_status;
 
@@ -3611,16 +3654,16 @@ gboolean document_check_disk_status(GeanyDocument *doc, gboolean force)
 	}
 
 	locale_filename = utils_get_locale_from_utf8(doc->file_name);
-	if (g_stat(locale_filename, &st) != 0)
+	if (!get_mtime(locale_filename, &mtime))
 	{
 		monitor_resave_missing_file(doc);
 		/* doc may be closed now */
 		ret = TRUE;
 	}
-	else if (doc->priv->mtime < st.st_mtime)
+	else if (doc->priv->mtime < mtime)
 	{
 		/* make sure the user is not prompted again after he cancelled the "reload file?" message */
-		doc->priv->mtime = st.st_mtime;
+		doc->priv->mtime = mtime;
 		monitor_reload_file(doc);
 		/* doc may be closed now */
 		ret = TRUE;



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list