Blob Blame History Raw
From a56e545824e0cdce4bbfbdf9fc54aa7405194cd9 Mon Sep 17 00:00:00 2001
From: Alexander Larsson <alexl@redhat.com>
Date: Thu, 21 Aug 2014 12:17:31 +0200
Subject: [PATCH] Fix crash when changing owner of file

Cherry picked commits from git master:
ab6aa9aca1c25c34e3f1aece63efbe05a2984397
bfa2d63249a1f5de986f7f1ad21d79920fa4947f
f7d1394a03e6d02cd5c67f9c85a142e33f14566f

https://bugzilla.redhat.com/show_bug.cgi?id=1090999
---
 libnautilus-private/nautilus-file.c |   3 +-
 src/nautilus-properties-window.c    | 354 +++++++++++++++++-------------------
 2 files changed, 164 insertions(+), 193 deletions(-)

diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c
index 5e837f6..efef296 100644
--- a/libnautilus-private/nautilus-file.c
+++ b/libnautilus-private/nautilus-file.c
@@ -5670,7 +5670,8 @@ nautilus_file_get_owner_as_string (NautilusFile *file, gboolean include_real_nam
 		return NULL;
 	}
 
-	if (file->details->uid == getuid ()) {
+	if (include_real_name &&
+	    file->details->uid == getuid ()) {
 		/* Translators: "Me" is used to indicate the file is owned by me (the current user) */
 		user_name = g_strdup (_("Me"));
 	} else if (file->details->owner_real == NULL) {
diff --git a/src/nautilus-properties-window.c b/src/nautilus-properties-window.c
index 6793b7a..7a81ddd 100644
--- a/src/nautilus-properties-window.c
+++ b/src/nautilus-properties-window.c
@@ -89,6 +89,22 @@
 static GHashTable *windows;
 static GHashTable *pending_lists;
 
+typedef struct {
+	NautilusFile *file;
+	char         *owner;
+	GtkWindow    *window;
+	unsigned int  timeout;
+	gboolean      cancelled;
+} OwnerChange;
+
+typedef struct {
+	NautilusFile *file;
+	char         *group;
+	GtkWindow    *window;
+	unsigned int  timeout;
+	gboolean      cancelled;
+} GroupChange;
+
 struct NautilusPropertiesWindowDetails {	
 	GList *original_files;
 	GList *target_files;
@@ -112,12 +128,8 @@ struct NautilusPropertiesWindowDetails {
 	guint update_directory_contents_timeout_id;
 	guint update_files_timeout_id;
 
-	NautilusFile *group_change_file;
-	char         *group_change_group;
-	unsigned int  group_change_timeout;
-	NautilusFile *owner_change_file;
-	char         *owner_change_owner;
-	unsigned int  owner_change_timeout;
+	GroupChange  *group_change;
+	OwnerChange  *owner_change;
 
 	GList *permission_buttons;
 	GList *permission_combos;
@@ -208,8 +220,8 @@ static void properties_window_update              (NautilusPropertiesWindow *win
 						   GList              *files);
 static void is_directory_ready_callback           (NautilusFile       *file,
 						   gpointer            data);
-static void cancel_group_change_callback          (NautilusPropertiesWindow *window);
-static void cancel_owner_change_callback          (NautilusPropertiesWindow *window);
+static void cancel_group_change_callback          (GroupChange        *change);
+static void cancel_owner_change_callback          (OwnerChange        *change);
 static void parent_widget_destroyed_callback      (GtkWidget          *widget,
 						   gpointer            callback_data);
 static void select_image_button_callback          (GtkWidget          *widget,
@@ -1363,78 +1375,70 @@ attach_ellipsizing_value_field (NautilusPropertiesWindow *window,
 }
 
 static void
+group_change_free (GroupChange *change)
+{
+	nautilus_file_unref (change->file);
+	g_free (change->group);
+	g_object_unref (change->window);
+
+	g_free (change);
+}
+
+static void
 group_change_callback (NautilusFile *file,
 		       GFile *res_loc,
 		       GError *error,
-		       NautilusPropertiesWindow *window)
+		       GroupChange *change)
 {
-	char *group;
-
-	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
-	g_assert (window->details->group_change_file == file);
+	NautilusPropertiesWindow *window;
 
-	group = window->details->group_change_group;
-	g_assert (group != NULL);
+	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (change->window));
+	g_assert (NAUTILUS_IS_FILE (change->file));
+	g_assert (change->group != NULL);
 
-	/* Report the error if it's an error. */
-	eel_timed_wait_stop ((EelCancelCallback) cancel_group_change_callback, window);
-	nautilus_report_error_setting_group (file, error, GTK_WINDOW (window));
+	if (!change->cancelled) {
+		/* Report the error if it's an error. */
+		eel_timed_wait_stop ((EelCancelCallback) cancel_group_change_callback, change);
+		nautilus_report_error_setting_group (change->file, error, change->window);
+	}
 
-	nautilus_file_unref (file);
-	g_free (group);
+	window = NAUTILUS_PROPERTIES_WINDOW(change->window);
+	if (window->details->group_change == change) {
+		window->details->group_change = NULL;
+	}
 
-	window->details->group_change_file = NULL;
-	window->details->group_change_group = NULL;
-	g_object_unref (G_OBJECT (window));
+	group_change_free (change);
 }
 
 static void
-cancel_group_change_callback (NautilusPropertiesWindow *window)
+cancel_group_change_callback (GroupChange *change)
 {
-	NautilusFile *file;
-	char *group;
+	g_assert (NAUTILUS_IS_FILE (change->file));
+	g_assert (change->group != NULL);
 
-	file = window->details->group_change_file;
-	g_assert (NAUTILUS_IS_FILE (file));
-
-	group = window->details->group_change_group;
-	g_assert (group != NULL);
-
-	nautilus_file_cancel (file, (NautilusFileOperationCallback) group_change_callback, window);
-
-	g_free (group);
-	nautilus_file_unref (file);
-
-	window->details->group_change_file = NULL;
-	window->details->group_change_group = NULL;
-	g_object_unref (window);
+	change->cancelled = TRUE;
+	nautilus_file_cancel (change->file, (NautilusFileOperationCallback) group_change_callback, change);
 }
 
 static gboolean
-schedule_group_change_timeout (NautilusPropertiesWindow *window)
+schedule_group_change_timeout (GroupChange *change)
 {
-	NautilusFile *file;
-	char *group;
+	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (change->window));
+	g_assert (NAUTILUS_IS_FILE (change->file));
+	g_assert (change->group != NULL);
 
-	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
-
-	file = window->details->group_change_file;
-	g_assert (NAUTILUS_IS_FILE (file));
-
-	group = window->details->group_change_group;
-	g_assert (group != NULL);
+	change->timeout = 0;
 
 	eel_timed_wait_start
 		((EelCancelCallback) cancel_group_change_callback,
-		 window,
+		 change,
 		 _("Cancel Group Change?"),
-		 GTK_WINDOW (window));
+		 change->window);
 
 	nautilus_file_set_group
-		(file,  group,
-		 (NautilusFileOperationCallback) group_change_callback, window);
+		(change->file, change->group,
+		 (NautilusFileOperationCallback) group_change_callback, change);
 
-	window->details->group_change_timeout = 0;
 	return FALSE;
 }
 
@@ -1443,55 +1447,45 @@ schedule_group_change (NautilusPropertiesWindow *window,
 		       NautilusFile       *file,
 		       const char         *group)
 {
+	GroupChange *change;
+
 	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
-	g_assert (window->details->group_change_group == NULL);
-	g_assert (window->details->group_change_file == NULL);
+	g_assert (window->details->group_change == NULL);
 	g_assert (NAUTILUS_IS_FILE (file));
 
-	window->details->group_change_file = nautilus_file_ref (file);
-	window->details->group_change_group = g_strdup (group);
-	g_object_ref (G_OBJECT (window));
-	window->details->group_change_timeout =
+	change = g_new0 (GroupChange, 1);
+
+	change->file = nautilus_file_ref (file);
+	change->group = g_strdup (group);
+	change->window = g_object_ref (G_OBJECT (window));
+	change->timeout =
 		g_timeout_add (CHOWN_CHGRP_TIMEOUT,
 			       (GSourceFunc) schedule_group_change_timeout,
-			       window);
+			       change);
+
+	window->details->group_change = change;
 }
 
 static void
 unschedule_or_cancel_group_change (NautilusPropertiesWindow *window)
 {
-	NautilusFile *file;
-	char *group;
+	GroupChange *change;
 
 	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
 
-	file = window->details->group_change_file;
-	group = window->details->group_change_group;
-
-	g_assert ((file == NULL && group == NULL) ||
-		  (file != NULL && group != NULL));
+	change = window->details->group_change;
 
-	if (file != NULL) {
-		g_assert (NAUTILUS_IS_FILE (file));
-
-		if (window->details->group_change_timeout == 0) {
-			nautilus_file_cancel (file,
-					      (NautilusFileOperationCallback) group_change_callback, window);
-			eel_timed_wait_stop ((EelCancelCallback) cancel_group_change_callback, window);
+	if (change != NULL) {
+		if (change->timeout == 0) {
+			/* The operation was started, cancel it and let the operation callback free the change */
+			cancel_group_change_callback (change);
+			eel_timed_wait_stop ((EelCancelCallback) cancel_group_change_callback, change);
+		} else {
+			g_source_remove (change->timeout);
+			group_change_free (change);
 		}
 
-		nautilus_file_unref (file);
-		g_free (group);
-
-		window->details->group_change_file = NULL;
-		window->details->group_change_group = NULL;
-		g_object_unref (G_OBJECT (window));
-	}
-
-	if (window->details->group_change_timeout > 0) {
-		g_assert (file != NULL);
-		g_source_remove (window->details->group_change_timeout);
-		window->details->group_change_timeout = 0;
+		window->details->group_change = NULL;
 	}
 }
 
@@ -1713,18 +1707,18 @@ combo_box_row_separator_func (GtkTreeModel *model,
 static GtkComboBox *
 attach_combo_box (GtkGrid *grid,
 		  GtkWidget *sibling,
-		  gboolean two_columns)
+		  gboolean three_columns)
 {
 	GtkWidget *combo_box;
 	GtkWidget *aligner;
 
-	if (!two_columns) {
+	if (!three_columns) {
 		combo_box = gtk_combo_box_text_new ();
 	} else {
 		GtkTreeModel *model;
 		GtkCellRenderer *renderer;
 
-		model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
+		model = GTK_TREE_MODEL (gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
 		combo_box = gtk_combo_box_new_with_model (model);
 		g_object_unref (G_OBJECT (model));
 
@@ -1778,78 +1772,70 @@ attach_group_combo_box (GtkGrid *grid,
 }	
 
 static void
+owner_change_free (OwnerChange *change)
+{
+	nautilus_file_unref (change->file);
+	g_free (change->owner);
+	g_object_unref (change->window);
+
+	g_free (change);
+}
+
+static void
 owner_change_callback (NautilusFile *file,
                        GFile 	    *result_location,
 		       GError        *error,
-		       NautilusPropertiesWindow *window)
+		       OwnerChange *change)
 {
-	char *owner;
-
-	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
-	g_assert (window->details->owner_change_file == file);
+	NautilusPropertiesWindow *window;
 
-	owner = window->details->owner_change_owner;
-	g_assert (owner != NULL);
+	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (change->window));
+	g_assert (NAUTILUS_IS_FILE (change->file));
+	g_assert (change->owner != NULL);
 
-	/* Report the error if it's an error. */
-	eel_timed_wait_stop ((EelCancelCallback) cancel_owner_change_callback, window);
-	nautilus_report_error_setting_owner (file, error, GTK_WINDOW (window));
+	if (!change->cancelled) {
+		/* Report the error if it's an error. */
+		eel_timed_wait_stop ((EelCancelCallback) cancel_owner_change_callback, change);
+		nautilus_report_error_setting_owner (file, error, change->window);
+	}
 
-	nautilus_file_unref (file);
-	g_free (owner);
+	window = NAUTILUS_PROPERTIES_WINDOW(change->window);
+	if (window->details->owner_change == change) {
+		window->details->owner_change = NULL;
+	}
 
-	window->details->owner_change_file = NULL;
-	window->details->owner_change_owner = NULL;
-	g_object_unref (G_OBJECT (window));
+	owner_change_free (change);
 }
 
 static void
-cancel_owner_change_callback (NautilusPropertiesWindow *window)
+cancel_owner_change_callback (OwnerChange *change)
 {
-	NautilusFile *file;
-	char *owner;
-
-	file = window->details->owner_change_file;
-	g_assert (NAUTILUS_IS_FILE (file));
-
-	owner = window->details->owner_change_owner;
-	g_assert (owner != NULL);
-
-	nautilus_file_cancel (file, (NautilusFileOperationCallback) owner_change_callback, window);
-
-	nautilus_file_unref (file);
-	g_free (owner);
+	g_assert (NAUTILUS_IS_FILE (change->file));
+	g_assert (change->owner != NULL);
 
-	window->details->owner_change_file = NULL;
-	window->details->owner_change_owner = NULL;
-	g_object_unref (window);
+	change->cancelled = TRUE;
+	nautilus_file_cancel (change->file, (NautilusFileOperationCallback) owner_change_callback, change);
 }
 
 static gboolean
-schedule_owner_change_timeout (NautilusPropertiesWindow *window)
+schedule_owner_change_timeout (OwnerChange *change)
 {
-	NautilusFile *file;
-	char *owner;
-
-	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
-
-	file = window->details->owner_change_file;
-	g_assert (NAUTILUS_IS_FILE (file));
+	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (change->window));
+	g_assert (NAUTILUS_IS_FILE (change->file));
+	g_assert (change->owner != NULL);
 
-	owner = window->details->owner_change_owner;
-	g_assert (owner != NULL);
+	change->timeout = 0;
 
 	eel_timed_wait_start
 		((EelCancelCallback) cancel_owner_change_callback,
-		 window,
+		 change,
 		 _("Cancel Owner Change?"),
-		 GTK_WINDOW (window));
+		 change->window);
 
 	nautilus_file_set_owner
-		(file,  owner,
-		 (NautilusFileOperationCallback) owner_change_callback, window);
+		(change->file, change->owner,
+		 (NautilusFileOperationCallback) owner_change_callback, change);
 
-	window->details->owner_change_timeout = 0;
 	return FALSE;
 }
 
@@ -1858,55 +1844,47 @@ schedule_owner_change (NautilusPropertiesWindow *window,
 		       NautilusFile       *file,
 		       const char         *owner)
 {
+	OwnerChange *change;
+
 	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
-	g_assert (window->details->owner_change_owner == NULL);
-	g_assert (window->details->owner_change_file == NULL);
+	g_assert (window->details->owner_change == NULL);
 	g_assert (NAUTILUS_IS_FILE (file));
 
-	window->details->owner_change_file = nautilus_file_ref (file);
-	window->details->owner_change_owner = g_strdup (owner);
-	g_object_ref (G_OBJECT (window));
-	window->details->owner_change_timeout =
+	change = g_new0 (OwnerChange, 1);
+
+	change->file = nautilus_file_ref (file);
+	change->owner = g_strdup (owner);
+	change->window = g_object_ref (G_OBJECT (window));
+	change->timeout =
 		g_timeout_add (CHOWN_CHGRP_TIMEOUT,
 			       (GSourceFunc) schedule_owner_change_timeout,
-			       window);
+			       change);
+
+	window->details->owner_change = change;
 }
 
 static void
 unschedule_or_cancel_owner_change (NautilusPropertiesWindow *window)
 {
-	NautilusFile *file;
-	char *owner;
+	OwnerChange *change;
 
 	g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (window));
 
-	file = window->details->owner_change_file;
-	owner = window->details->owner_change_owner;
+	change = window->details->owner_change;
 
-	g_assert ((file == NULL && owner == NULL) ||
-		  (file != NULL && owner != NULL));
+	if (change != NULL) {
+		g_assert (NAUTILUS_IS_FILE (change->file));
 
-	if (file != NULL) {
-		g_assert (NAUTILUS_IS_FILE (file));
-
-		if (window->details->owner_change_timeout == 0) {
-			nautilus_file_cancel (file,
-					      (NautilusFileOperationCallback) owner_change_callback, window);
-			eel_timed_wait_stop ((EelCancelCallback) cancel_owner_change_callback, window);
+		if (change->timeout == 0) {
+			/* The operation was started, cancel it and let the operation callback free the change */
+			cancel_owner_change_callback (change);
+			eel_timed_wait_stop ((EelCancelCallback) cancel_owner_change_callback, change);
+		} else {
+			g_source_remove (change->timeout);
+			owner_change_free (change);
 		}
 
-		nautilus_file_unref (file);
-		g_free (owner);
-
-		window->details->owner_change_file = NULL;
-		window->details->owner_change_owner = NULL;
-		g_object_unref (G_OBJECT (window));
-	}
-
-	if (window->details->owner_change_timeout > 0) {
-		g_assert (file != NULL);
-		g_source_remove (window->details->owner_change_timeout);
-		window->details->owner_change_timeout = 0;
+		window->details->owner_change = NULL;
 	}
 }
 
@@ -1914,20 +1892,15 @@ static void
 changed_owner_callback (GtkComboBox *combo_box, NautilusFile* file)
 {
 	NautilusPropertiesWindow *window;
-	char *owner_text;
-	char **name_array;
 	char *new_owner;
 	char *cur_owner;
 
 	g_assert (GTK_IS_COMBO_BOX (combo_box));
 	g_assert (NAUTILUS_IS_FILE (file));
 
-	owner_text = combo_box_get_active_entry (combo_box, 0);
-        if (! owner_text)
+	new_owner = combo_box_get_active_entry (combo_box, 2);
+        if (! new_owner)
 	    return;
-    	name_array = g_strsplit (owner_text, " - ", 2);
-	new_owner = name_array[0];
-	g_free (owner_text);
 	cur_owner = nautilus_file_get_owner_name (file);
 
 	if (strcmp (new_owner, cur_owner) != 0) {
@@ -1937,7 +1910,7 @@ changed_owner_callback (GtkComboBox *combo_box, NautilusFile* file)
 		unschedule_or_cancel_owner_change (window);
 		schedule_owner_change (window, file, new_owner);
 	}
-	g_strfreev (name_array);
+	g_free (new_owner);
 	g_free (cur_owner);
 }
 
@@ -1951,6 +1924,7 @@ synch_user_menu (GtkComboBox *combo_box, NautilusFile *file)
 	GtkTreeIter iter;
 	char *user_name;
 	char *owner_name;
+	char *nice_owner_name;
 	int user_index;
 	int owner_index;
 	char **name_array;
@@ -1980,7 +1954,7 @@ synch_user_menu (GtkComboBox *combo_box, NautilusFile *file)
 			user_name = (char *)node->data;
 
 			name_array = g_strsplit (user_name, "\n", 2);
-			if (name_array[1] != NULL) {
+			if (name_array[1] != NULL && *name_array[1] != 0) {
 				combo_text = g_strdup_printf ("%s - %s", name_array[0], name_array[1]);
 			} else {
 				combo_text = g_strdup (name_array[0]);
@@ -1990,6 +1964,7 @@ synch_user_menu (GtkComboBox *combo_box, NautilusFile *file)
 			gtk_list_store_set (store, &iter,
 					    0, combo_text,
 					    1, user_name,
+					    2, name_array[0],
 					    -1);
 
 			g_strfreev (name_array);
@@ -1997,8 +1972,9 @@ synch_user_menu (GtkComboBox *combo_box, NautilusFile *file)
 		}
 	}
 
-	owner_name = nautilus_file_get_string_attribute (file, "owner");
-	owner_index = tree_model_get_entry_index (model, 0, owner_name);
+	owner_name = nautilus_file_get_owner_name (file);
+	owner_index = tree_model_get_entry_index (model, 2, owner_name);
+	nice_owner_name = nautilus_file_get_string_attribute (file, "owner");
 
 	/* If owner wasn't in list, we prepend it (with a separator). 
 	 * This can happen if the owner is an id with no matching
@@ -2011,30 +1987,24 @@ synch_user_menu (GtkComboBox *combo_box, NautilusFile *file)
 			gtk_list_store_set (store, &iter,
 					    0, "-",
 					    1, NULL,
+					    2, NULL,
 					    -1);
 		}
 
-		name_array = g_strsplit (owner_name, " - ", 2);
-		if (name_array[1] != NULL) {
-			user_name = g_strdup_printf ("%s\n%s", name_array[0], name_array[1]);
-		} else {
-			user_name = g_strdup (name_array[0]);
-		}
 		owner_index = 0;
 
 		gtk_list_store_prepend (store, &iter);
 		gtk_list_store_set (store, &iter,
-				    0, owner_name,
-				    1, user_name,
+				    0, nice_owner_name,
+				    1, owner_name,
+				    2, owner_name,
 				    -1);
-
-		g_free (user_name);
-		g_strfreev (name_array);
 	}
 
 	gtk_combo_box_set_active (combo_box, owner_index);
 
 	g_free (owner_name);
+	g_free (nice_owner_name);
 	g_list_free_full (users, g_free);
 }	
 
-- 
2.0.4