Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: Jiří Techet techet@gmail.com Date: Thu, 01 Oct 2015 10:09:45 UTC Commit: daf4dd45b874f7d29e30f8eddd4fbb6cae40e687 https://github.com/geany/geany/commit/daf4dd45b874f7d29e30f8eddd4fbb6cae40e6...
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).