From 3858601ea2cba734ebccce6b9a38ee90e38f90ac Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: May 20 2007 02:29:55 +0000 Subject: 2.19.2 --- diff --git a/.cvsignore b/.cvsignore index 34a31cf..4b5d815 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -nautilus-2.18.1.tar.bz2 +nautilus-2.19.2.tar.bz2 diff --git a/nautilus-2.16.2-selinux.patch b/nautilus-2.16.2-selinux.patch deleted file mode 100644 index d6658dd..0000000 --- a/nautilus-2.16.2-selinux.patch +++ /dev/null @@ -1,1665 +0,0 @@ ---- nautilus-2.16.2/libnautilus-private/nautilus-file.c.selinux 2006-11-06 13:57:32.000000000 +0100 -+++ nautilus-2.16.2/libnautilus-private/nautilus-file.c 2006-11-07 16:31:36.000000000 +0100 -@@ -3569,7 +3569,7 @@ - * context - * @file: NautilusFile representing the file in question. - * -- * Returns: Newly allocated string ready to display to the user. -+ * Returns: Newly allocated string ready to display to the user, or NULL. - * - **/ - char * -@@ -3602,6 +3602,133 @@ - return translated; - } - -+/** -+ * nautilus_file_get_selinux_matchpathcon: -+ * -+ * Get a user-displayable string representing a file's default selinux -+ * context (as from matchpathcon). Only works on local files. -+ * @file: NautilusFile representing the file in question. -+ * -+ * Returns: Newly allocated string ready to display to the user, or NULL. -+ * -+ **/ -+char * -+nautilus_file_get_selinux_matchpathcon (NautilusFile *file) -+{ -+ char *translated; -+ char *raw; -+ char *uri; -+ char *fname; -+ -+ g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); -+ -+ translated = NULL; -+#ifdef HAVE_SELINUX -+ uri = nautilus_file_get_uri (file); -+ fname = gnome_vfs_get_local_path_from_uri (uri); -+ -+ if (!fname) { -+ return NULL; -+ } -+ -+ raw = NULL; -+ if (matchpathcon (fname, file->details->info->permissions, &raw) == 0) { -+ if (selinux_raw_to_trans_context (raw, &translated) == 0) { -+ char *tmp; -+ tmp = g_strdup (translated); -+ freecon (translated); -+ translated = tmp; -+ } -+ freecon (raw); -+ } -+ -+ g_free (fname); -+ g_free (uri); -+#endif -+ -+ return translated; -+} -+ -+static void -+set_selinux_context_callback (GnomeVFSAsyncHandle *handle, -+ GnomeVFSResult result, -+ GnomeVFSFileInfo *new_info, -+ gpointer callback_data) -+{ -+ set_permissions_callback (handle, result, new_info, callback_data); -+} -+ -+void -+nautilus_file_set_selinux_context (NautilusFile *file, -+ const char *selinux_context, -+ NautilusFileOperationCallback callback, -+ gpointer callback_data) -+{ -+ Operation *op; -+ GnomeVFSURI *vfs_uri; -+ GnomeVFSFileInfo *partial_file_info; -+ GnomeVFSFileInfoOptions options; -+ char *rcontext; -+ -+ rcontext = NULL; -+ -+ /* this is probably mostly right... */ -+ if (!nautilus_file_can_set_permissions (file)) { -+ /* Claim that something changed even if the permission change failed. -+ * This makes it easier for some clients who see the "reverting" -+ * to the old permissions as "changing back". -+ */ -+ nautilus_file_changed (file); -+ (* callback) (file, GNOME_VFS_ERROR_ACCESS_DENIED, callback_data); -+ return; -+ } -+ -+ /* Test the permissions-haven't-changed case explicitly -+ * because we don't want to send the file-changed signal if -+ * nothing changed. -+ */ -+ if (!strcmp(selinux_context, file->details->info->selinux_context)) { -+ (* callback) (file, GNOME_VFS_OK, callback_data); -+ return; -+ } -+ -+#ifdef HAVE_SELINUX -+ /* this is really const, but prototype is wrong, *sigh* */ -+ if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) { -+ (* callback) (file, GNOME_VFS_ERROR_NO_MEMORY, callback_data); -+ return; -+ } -+ selinux_context = rcontext; -+#endif -+ -+ /* Set up a context change operation. */ -+ op = operation_new (file, callback, callback_data); -+ op->use_slow_mime = file->details->got_slow_mime_type; -+ -+ options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS; -+ if (op->use_slow_mime) { -+ options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE; -+ } -+ /* Change the file-on-disk context. */ -+ partial_file_info = gnome_vfs_file_info_new (); -+ g_free (partial_file_info->selinux_context); -+ partial_file_info->selinux_context = g_strdup (selinux_context); -+ vfs_uri = nautilus_file_get_gnome_vfs_uri (file); -+ gnome_vfs_async_set_file_info (&op->handle, -+ vfs_uri, partial_file_info, -+ GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT, -+ options, -+ GNOME_VFS_PRIORITY_DEFAULT, -+ set_selinux_context_callback, op); -+ gnome_vfs_file_info_unref (partial_file_info); -+ gnome_vfs_uri_unref (vfs_uri); -+ -+#ifdef HAVE_SELINUX -+ freecon (rcontext); -+#endif -+} -+ -+ - static char * - get_real_name (const char *name, const char *gecos) - { -@@ -3804,7 +3931,7 @@ - GnomeVFSResult result, - GnomeVFSFileInfo *new_info, - gpointer callback_data) --{ -+{ /* FIXME: this is identical to set_permissions_callback */ - Operation *op; - - op = callback_data; ---- nautilus-2.16.2/libnautilus-private/nautilus-file.h.selinux 2006-10-02 12:46:28.000000000 +0200 -+++ nautilus-2.16.2/libnautilus-private/nautilus-file.h 2006-11-07 16:31:36.000000000 +0100 -@@ -200,6 +200,7 @@ - GList * nautilus_file_get_settable_group_names (NautilusFile *file); - gboolean nautilus_file_can_get_selinux_context (NautilusFile *file); - char * nautilus_file_get_selinux_context (NautilusFile *file); -+char * nautilus_file_get_selinux_matchpathcon (NautilusFile *file); - - /* "Capabilities". */ - gboolean nautilus_file_can_read (NautilusFile *file); -@@ -226,6 +227,10 @@ - GnomeVFSFilePermissions permissions, - NautilusFileOperationCallback callback, - gpointer callback_data); -+void nautilus_file_set_selinux_context (NautilusFile *file, -+ const char *selinux_context, -+ NautilusFileOperationCallback callback, -+ gpointer callback_data); - void nautilus_file_rename (NautilusFile *file, - const char *new_name, - NautilusFileOperationCallback callback, ---- nautilus-2.16.2/libnautilus-private/nautilus-file-operations.c.selinux 2006-11-06 13:21:46.000000000 +0100 -+++ nautilus-2.16.2/libnautilus-private/nautilus-file-operations.c 2006-11-07 16:31:36.000000000 +0100 -@@ -62,6 +62,10 @@ - #include "nautilus-trash-monitor.h" - #include "nautilus-file-utilities.h" - -+#ifdef HAVE_SELINUX -+#include -+#endif -+ - typedef enum TransferKind TransferKind; - typedef struct TransferInfo TransferInfo; - typedef struct IconPositionIterator IconPositionIterator; -@@ -2908,6 +2912,7 @@ - GnomeVFSFilePermissions file_mask; - GnomeVFSFilePermissions dir_permissions; - GnomeVFSFilePermissions dir_mask; -+ char *context; - NautilusSetPermissionsCallback callback; - gpointer callback_data; - }; -@@ -2935,6 +2940,8 @@ - GnomeVFSURI *uri; - char *uri_str; - struct FileInfo *file_info; -+ int flags; -+ int options; - - info = callback_data; - -@@ -2965,10 +2972,18 @@ - vfs_info->permissions = - (file_info->permissions & ~info->file_mask) | - info->file_permissions; -+ flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; -+ options = GNOME_VFS_FILE_INFO_DEFAULT; -+ if (info->context) { -+ flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; -+ vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; -+ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; -+ g_free (vfs_info->selinux_context); -+ vfs_info->selinux_context = g_strdup (info->context); -+ } - - gnome_vfs_async_set_file_info (&info->handle, uri, vfs_info, -- GNOME_VFS_SET_FILE_INFO_PERMISSIONS, -- GNOME_VFS_FILE_INFO_DEFAULT, -+ flags, options, - GNOME_VFS_PRIORITY_DEFAULT, - set_permissions_set_file_info, - info); -@@ -2976,7 +2991,6 @@ - gnome_vfs_file_info_unref (vfs_info); - g_free (file_info->name); - g_free (file_info); -- - } - - static void -@@ -3021,13 +3035,11 @@ - } - } - -- - if (result != GNOME_VFS_OK) { - /* Finished with this dir, work on the files */ - info->current_file = NULL; - set_permissions_set_file_info (NULL, GNOME_VFS_OK, NULL, info); - } -- - } - - /* Also called for the toplevel dir */ -@@ -3039,7 +3051,8 @@ - { - struct RecursivePermissionsInfo *info; - char *uri_str; -- -+ int options; -+ - info = callback_data; - - if (result == GNOME_VFS_OK && handle != NULL) { -@@ -3048,9 +3061,13 @@ - g_free (uri_str); - } - -+ options = GNOME_VFS_FILE_INFO_DEFAULT; -+ if (info->context) { -+ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; -+ } - gnome_vfs_async_load_directory_uri (&info->handle, - info->current_dir, -- GNOME_VFS_FILE_INFO_DEFAULT, -+ options, - 50, - GNOME_VFS_PRIORITY_DEFAULT, - set_permissions_got_files, -@@ -3062,6 +3079,8 @@ - { - struct DirInfo *dir_info; - GnomeVFSFileInfo *vfs_info; -+ int flags; -+ int options; - - gnome_vfs_uri_unref (info->current_dir); - -@@ -3069,6 +3088,7 @@ - /* No more directories, finished! */ - info->callback (info->callback_data); - /* All parts of info should be freed now */ -+ g_free (info->context); - g_free (info); - return; - } -@@ -3083,12 +3103,18 @@ - vfs_info->permissions = - (dir_info->permissions & ~info->dir_mask) | - info->dir_permissions; -- -- gnome_vfs_async_set_file_info (&info->handle, -- info->current_dir, -- vfs_info, -- GNOME_VFS_SET_FILE_INFO_PERMISSIONS, -- GNOME_VFS_FILE_INFO_DEFAULT, -+ flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; -+ options = GNOME_VFS_FILE_INFO_DEFAULT; -+ if (info->context) { -+ flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; -+ vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; -+ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; -+ g_free (vfs_info->selinux_context); -+ vfs_info->selinux_context = g_strdup (info->context); -+ } -+ -+ gnome_vfs_async_set_file_info (&info->handle, info->current_dir, -+ vfs_info, flags, options, - GNOME_VFS_PRIORITY_DEFAULT, - set_permissions_load_dir, - info); -@@ -3103,6 +3129,7 @@ - GnomeVFSFilePermissions file_mask, - GnomeVFSFilePermissions dir_permissions, - GnomeVFSFilePermissions dir_mask, -+ const char *context, - NautilusSetPermissionsCallback callback, - gpointer callback_data) - { -@@ -3116,6 +3143,22 @@ - info->file_mask = file_mask; - info->dir_permissions = dir_permissions; - info->dir_mask = dir_mask; -+ if (context) { -+ char *rcontext; -+ -+ rcontext = info->context = NULL; -+#ifdef HAVE_SELINUX -+ /* this is really const, but prototype is wrong, *sigh* */ -+ if (selinux_trans_to_raw_context((char *)context, &rcontext)) { -+ g_error ("selinux_trans_to_raw_context: failed to allocate bytes"); -+ return; -+ } -+ info->context = g_strdup (rcontext); -+ freecon (rcontext); -+#endif -+ } else { -+ info->context = NULL; -+ } - info->callback = callback; - info->callback_data = callback_data; - -@@ -3123,6 +3166,8 @@ - - if (info->current_dir == NULL) { - info->callback (info->callback_data); -+ /* All parts of info should be freed now */ -+ g_free (info->context); - g_free (info); - return; - } ---- nautilus-2.16.2/libnautilus-private/nautilus-file-operations.h.selinux 2006-10-02 12:46:28.000000000 +0200 -+++ nautilus-2.16.2/libnautilus-private/nautilus-file-operations.h 2006-11-07 16:31:36.000000000 +0100 -@@ -76,6 +76,7 @@ - GnomeVFSFilePermissions file_mask, - GnomeVFSFilePermissions folder_permissions, - GnomeVFSFilePermissions folder_mask, -+ const char *context, - NautilusSetPermissionsCallback callback, - gpointer callback_data); - ---- nautilus-2.16.2/src/file-manager/fm-error-reporting.c.selinux 2006-10-02 12:46:28.000000000 +0200 -+++ nautilus-2.16.2/src/file-manager/fm-error-reporting.c 2006-11-07 16:31:36.000000000 +0100 -@@ -251,6 +251,38 @@ - g_free (message); - } - -+void -+fm_report_error_setting_selinux (NautilusFile *file, -+ GnomeVFSResult error, -+ GtkWindow *parent_window) -+{ -+ char *file_name; -+ char *message; -+ -+ if (error == GNOME_VFS_OK) { -+ return; -+ } -+ -+ file_name = nautilus_file_get_display_name (file); -+ -+ switch (error) { -+ case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM: -+ message = g_strdup_printf (_("Couldn't change the SELinux security context of \"%s\" because it is on a read-only disk"), -+ file_name); -+ break; -+ default: -+ /* We should invent decent error messages for every case we actually experience. */ -+ g_warning ("Hit unhandled case %d (%s) in fm_report_error_setting_permissions", -+ error, gnome_vfs_result_to_string (error)); -+ message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\"."), file_name); -+ } -+ -+ eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window); -+ -+ g_free (file_name); -+ g_free (message); -+} -+ - typedef struct _FMRenameData { - char *name; - NautilusFileOperationCallback callback; ---- nautilus-2.16.2/src/file-manager/fm-error-reporting.h.selinux 2006-10-02 12:46:28.000000000 +0200 -+++ nautilus-2.16.2/src/file-manager/fm-error-reporting.h 2006-11-07 16:31:36.000000000 +0100 -@@ -39,7 +39,10 @@ - GnomeVFSResult error_code, - GtkWindow *parent_window); - void fm_report_error_setting_permissions (NautilusFile *file, -- GnomeVFSResult error_code, -+ GnomeVFSResult error_code, -+ GtkWindow *parent_window); -+void fm_report_error_setting_selinux (NautilusFile *file, -+ GnomeVFSResult error_code, - GtkWindow *parent_window); - void fm_report_error_setting_owner (NautilusFile *file, - GnomeVFSResult error_code, ---- nautilus-2.16.2/src/file-manager/fm-properties-window.c.selinux 2006-10-31 10:21:41.000000000 +0100 -+++ nautilus-2.16.2/src/file-manager/fm-properties-window.c 2006-11-07 16:41:59.000000000 +0100 -@@ -83,6 +83,10 @@ - #include - #include - -+#ifdef HAVE_SELINUX -+# include -+#endif -+ - #define PREVIEW_IMAGE_WIDTH 96 - - #define ROW_PAD 6 -@@ -102,7 +106,7 @@ - - GtkWidget *icon_button; - GtkWidget *icon_image; -- GtkWidget *icon_chooser; -+ GtkWidget *icon_chooser; - - GtkWidget *name_label; - GtkWidget *name_field; -@@ -124,12 +128,15 @@ - unsigned int owner_change_timeout; - - GList *permission_buttons; -- GList *permission_combos; -+ GList *permission_combos; /* how is this deallocated???? */ -+ GList *selinux_combo; - GHashTable *initial_permissions; - gboolean has_recursive_apply; - - GList *value_fields; - -+ GList *edit_fields; -+ - GList *mime_list; - - gboolean deep_count_finished; -@@ -208,6 +215,10 @@ - GtkComboBox *combo); - static void value_field_update (FMPropertiesWindow *window, - GtkLabel *field); -+static void edit_field_update (FMPropertiesWindow *window, -+ GtkEntry *field); -+static void popup_field_update (FMPropertiesWindow *window, -+ GtkComboBox *entry); - static void properties_window_update (FMPropertiesWindow *window, - GList *files); - static void is_directory_ready_callback (NautilusFile *file, -@@ -235,10 +246,32 @@ - int row, - int column, - const char *initial_text); -+static void attach_selinux_data_edit_field (GtkEntry *entry, -+ char *attr_value, -+ char *def_attr_value); -+static void attach_selinux_data_popup_field (GtkComboBox *comb, -+ char *attr_val, -+ char *def_attr_val); -+ - - G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_WINDOW); - #define parent_class fm_properties_window_parent_class - -+static void -+maybe_gtk_entry_set_text (GtkEntry *entry, const char *val) -+{ -+ char *old_val; -+ -+ g_assert (GTK_IS_ENTRY (entry)); -+ -+ old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); -+ -+ if (strcmp (old_val, val) != 0) { -+ gtk_entry_set_text (entry, val); -+ } -+ g_free(old_val); -+} -+ - static gboolean - is_multi_file_window (FMPropertiesWindow *window) - { -@@ -259,6 +292,39 @@ - return FALSE; - } - -+static gboolean -+multi_have_same_selinux_context (FMPropertiesWindow *window) -+{ -+ GList *l; -+ char *cntx; -+ -+ cntx = NULL; -+ for (l = window->details->original_files; l != NULL; l = l->next) { -+ NautilusFile *file; -+ -+ file = NAUTILUS_FILE (l->data); -+ if (!nautilus_file_is_gone (file)) { -+ char *tmp; -+ -+ tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context"); -+ if (!cntx) { -+ cntx = tmp; -+ } else if (strcmp (cntx, tmp)) { -+ g_free (tmp); -+ g_free (cntx); -+ return FALSE; -+ } -+ else { -+ g_free (tmp); -+ } -+ } -+ } -+ -+ g_free (cntx); -+ -+ return TRUE; -+} -+ - static int - get_not_gone_original_file_count (FMPropertiesWindow *window) - { -@@ -494,7 +560,7 @@ - return; - } - -- uris = g_strsplit (selection_data->data, "\r\n", 0); -+ uris = g_strsplit ((char *) selection_data->data, "\r\n", 0); - exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); - - -@@ -575,7 +641,7 @@ - - static void - set_name_field (FMPropertiesWindow *window, const gchar *original_name, -- const gchar *name) -+ const gchar *name) - { - gboolean new_widget; - gboolean use_label; -@@ -641,11 +707,7 @@ - * currently showing. This causes minimal ripples (e.g. - * selection change). - */ -- gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1); -- if (strcmp (displayed_name, name) != 0) { -- gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); -- } -- g_free (displayed_name); -+ maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); - } - } - } -@@ -721,7 +783,6 @@ - name_field_restore_original_name (NautilusEntry *name_field) - { - const char *original_name; -- char *displayed_name; - - original_name = (const char *) g_object_get_data (G_OBJECT (name_field), - "original_name"); -@@ -730,14 +791,8 @@ - return; - } - -- displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1); -- -- if (strcmp (original_name, displayed_name) != 0) { -- gtk_entry_set_text (GTK_ENTRY (name_field), original_name); -- } -+ maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name); - nautilus_entry_select_all (name_field); -- -- g_free (displayed_name); - } - - static void -@@ -850,7 +905,7 @@ - word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp); - eel_g_list_free_deep (keywords); - -- return (word != NULL); -+ return word != NULL; - } - - static void -@@ -1117,7 +1172,7 @@ - b = b->next; - } - -- return (a == b); -+ return a == b; - } - - static GList * -@@ -1199,6 +1254,14 @@ - for (l = window->details->value_fields; l != NULL; l = l->next) { - value_field_update (window, GTK_LABEL (l->data)); - } -+ -+ for (l = window->details->edit_fields; l != NULL; l = l->next) { -+ edit_field_update (window, GTK_ENTRY (l->data)); -+ } -+ -+ for (l = window->details->selinux_combo; l != NULL; l = l->next) { -+ popup_field_update (window, GTK_COMBO_BOX (l->data)); -+ } - } - - mime_list = get_mime_list (window); -@@ -1379,6 +1442,111 @@ - ellipsize_text); - } - -+static void -+edit_field_update_internal (GtkEntry *entry, -+ GList *file_list) -+{ -+ const char *attr_name; -+ char *attr_value; -+ char *def_attr_value; -+ char *inconsistent_string; -+ -+ g_assert (GTK_IS_ENTRY (entry)); -+ -+ attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute"); -+ inconsistent_string = g_object_get_data (G_OBJECT (entry), -+ "inconsistent_string"); -+ def_attr_value = g_object_get_data (G_OBJECT (entry), -+ "matchpathcon_cntx"); -+ -+ attr_value = file_list_get_string_attribute (file_list, attr_name, -+ inconsistent_string); -+ -+ maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value); -+ -+ /* JFIXME: this isn't generic, *sigh* ... */ -+ attach_selinux_data_edit_field (entry, attr_value, def_attr_value); -+ g_free (attr_value); -+} -+ -+static void -+edit_field_update (FMPropertiesWindow *window, GtkEntry *entry) -+{ -+ gboolean use_original; -+ -+ if (gtk_widget_is_focus (GTK_WIDGET (entry))) { -+ return; -+ } -+ -+ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original")); -+ -+ edit_field_update_internal (entry, -+ (use_original ? -+ window->details->original_files : -+ window->details->target_files)); -+} -+ -+static void -+popup_field_update_internal (GtkComboBox *combo, -+ GList *file_list) -+{ -+ const char *attr_name; -+ char *attr_value; -+ char *def_attr_value; -+ char *inconsistent_string; -+ char *cntx_type; -+ GtkTreeIter iter; -+ -+ g_assert (GTK_IS_COMBO_BOX (combo)); -+ -+ if (gtk_widget_is_focus (GTK_WIDGET (combo))) { -+ return; -+ } -+ -+ attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute"); -+ inconsistent_string = g_object_get_data (G_OBJECT (combo), -+ "inconsistent_string"); -+ def_attr_value = g_object_get_data (G_OBJECT (combo), -+ "matchpathcon_cntx"); -+ -+ attr_value = file_list_get_string_attribute (file_list, attr_name, -+ inconsistent_string); -+ -+ /* JFIXME: this isn't generic, *sigh* ... */ -+ -+ if (gtk_combo_box_get_active_iter (combo, &iter)) { -+ GtkTreeModel *model = gtk_combo_box_get_model (combo); -+ -+ /* don't update, if it's identical */ -+ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); -+ if (cntx_type && strcmp (cntx_type, attr_value) == 0) { -+ g_free (attr_value); -+ return; -+ } -+ } -+ -+ attach_selinux_data_popup_field (combo, attr_value, def_attr_value); -+ -+ g_free (attr_value); -+} -+ -+static void -+popup_field_update (FMPropertiesWindow *window, GtkComboBox *combo) -+{ -+ gboolean use_original; -+ -+ if (window->details->selinux_combo) { -+ return; /* FIXME: must be true: horrible UI, if working */ -+ } -+ -+ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original")); -+ -+ popup_field_update_internal (combo, -+ (use_original ? -+ window->details->original_files : -+ window->details->target_files)); -+} -+ - static GtkLabel * - attach_label (GtkTable *table, - int row, -@@ -1430,6 +1598,45 @@ - return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); - } - -+static GtkEntry * -+attach_edit (GtkTable *table, -+ int row, -+ int column, -+ const char *initial_text, -+ gboolean right_aligned, -+ gboolean bold, -+ gboolean ellipsize_text, -+ gboolean selectable, -+ gboolean mnemonic) -+{ -+ GtkWidget *entry_field; -+ -+ entry_field = nautilus_entry_new (); -+ gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text); -+ -+ gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0); -+ gtk_widget_show (entry_field); -+ gtk_table_attach (table, entry_field, -+ column, column + 1, -+ row, row + 1, -+ ellipsize_text -+ ? GTK_FILL | GTK_EXPAND -+ : GTK_FILL, -+ 0, -+ 0, 0); -+ -+ return GTK_ENTRY (entry_field); -+} -+ -+static GtkEntry * -+attach_edit_label (GtkTable *table, -+ int row, -+ int column, -+ const char *initial_text) -+{ -+ return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); -+} -+ - static GtkLabel * - attach_ellipsizing_value_label (GtkTable *table, - int row, -@@ -1489,6 +1696,672 @@ - FALSE); - } - -+static void -+start_long_operation (FMPropertiesWindow *window) -+{ -+ if (window->details->long_operation_underway == 0) { -+ /* start long operation */ -+ GdkCursor * cursor; -+ -+ cursor = gdk_cursor_new (GDK_WATCH); -+ gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); -+ gdk_cursor_unref (cursor); -+ } -+ window->details->long_operation_underway ++; -+} -+ -+static void -+end_long_operation (FMPropertiesWindow *window) -+{ -+ if (GTK_WIDGET (window)->window != NULL && -+ window->details->long_operation_underway == 1) { -+ /* finished !! */ -+ gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); -+ } -+ window->details->long_operation_underway--; -+} -+ -+static void -+selinux_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) -+{ -+ FMPropertiesWindow *window; -+ g_assert (callback_data != NULL); -+ -+ window = FM_PROPERTIES_WINDOW (callback_data); -+ end_long_operation (window); -+ -+ /* Report the error if it's an error. */ -+ fm_report_error_setting_selinux (file, result, NULL); -+ -+ g_object_unref (window); -+} -+ -+static void -+selinux_done_editing (FMPropertiesWindow *window, char *selinux_context) -+{ -+ GList *l; -+ -+ /* Accept changes. */ -+ for (l = window->details->target_files; l != NULL; l = l->next) { -+ NautilusFile *file; -+ -+ file = NAUTILUS_FILE (l->data); -+ -+ start_long_operation (window); -+ g_object_ref (window); -+ nautilus_file_set_selinux_context (file, selinux_context, -+ selinux_change_callback, -+ window); -+ } -+} -+ -+static gboolean -+selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data) -+{ -+ g_assert (NAUTILUS_IS_ENTRY (entry)); -+ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); -+ -+ if (GTK_WIDGET_SENSITIVE (entry)) { -+ char *tmp; -+ -+ tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); -+ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); -+ g_free (tmp); -+ } -+ -+ return FALSE; -+} -+ -+static void -+selinux_entry_activate (NautilusEntry *entry, gpointer cb_data) -+{ -+ char *tmp; -+ -+ g_assert (NAUTILUS_IS_ENTRY (entry)); -+ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); -+ -+ tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); -+ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); -+ g_free (tmp); -+ -+ nautilus_entry_select_all_at_idle (entry); -+} -+ -+/* NOTE: This modifies cntx */ -+static void -+selinux_split_cntx (char *cntx, -+ const char **ret_attr_u, -+ const char **ret_attr_r, -+ const char **ret_attr_t, -+ const char **ret_attr_s) -+{ -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ -+ attr_u = cntx; -+ if (!(attr_r = strchr (attr_u, ':'))) { -+ attr_r = "object_r"; /* shouldn't happen */ -+ } else { -+ *((char *)attr_r++) = 0; -+ } -+ -+ if (!(attr_t = strchr (attr_r, ':'))) { -+ attr_t = "file_t"; /* shouldn't happen */ -+ } else { -+ *((char *)attr_t++) = 0; -+ } -+ -+ if ((attr_s = strchr (attr_t, ':'))) { -+ *((char *)attr_s++) = 0; -+ } -+ -+ *ret_attr_u = attr_u; -+ *ret_attr_r = attr_r; -+ *ret_attr_t = attr_t; -+ *ret_attr_s = attr_s; -+} -+ -+static void -+selinux_popup_activate (GtkComboBox *comb, gpointer cb_data) -+{ -+ char *cntx_type; -+ char *orig_type; -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ char *tmp; -+ GtkTreeIter iter; -+ -+ g_assert (GTK_IS_COMBO_BOX (comb)); -+ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); -+ -+ if (!gtk_combo_box_get_active_iter (comb, &iter)) { -+ return; -+ } else { -+ -+ GtkTreeModel *model = gtk_combo_box_get_model (comb); -+ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); -+ } -+ -+ if (!(orig_type = g_object_get_data (G_OBJECT (comb), -+ "original_cntx"))) { -+ return; -+ } -+ orig_type = g_strdup (orig_type); -+ -+ selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s); -+ tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL); -+ g_free (orig_type); -+ -+ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); -+ g_free (tmp); -+} -+ -+static char * -+cust_type_next_line (GIOChannel *ioc_ctypes) -+{ -+ char *data; -+ gsize term; -+ GError *errc; -+ -+ data = NULL; -+ term = 0; -+ errc = NULL; -+ -+ if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data, -+ NULL, &term, &errc)) { -+ data[term] = 0; -+ return data; -+ } -+ -+ return NULL; -+} -+ -+static GSList * -+selinux__type_list (void) -+{ -+ static GSList *cust_types; -+ static time_t file_mtime; -+ const char *fname_ctypes; -+ struct stat buf; -+ GIOChannel *ioc_ctypes; -+ GError *errc; -+ GSList *scan; -+ int fd; -+ -+#ifndef HAVE_SELINUX -+ if (cust_types) { -+ return cust_types; -+ } -+#else -+ fname_ctypes = selinux_customizable_types_path (); -+ if (cust_types && file_mtime && !stat (fname_ctypes, &buf) && -+ (file_mtime == buf.st_mtime)) { -+ return cust_types; -+ } -+#endif -+ -+ if (cust_types) { -+ for (scan = cust_types; scan; scan = scan->next) { -+ g_free (scan->data); -+ } -+ g_slist_free (cust_types); -+ cust_types = NULL; -+ } -+ -+ cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t")); -+ cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t")); -+ /* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */ -+ -+#ifdef HAVE_SELINUX -+ /* read types, one per line... */ -+ fname_ctypes = selinux_customizable_types_path (); -+ errc = NULL; -+ if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) { -+ char *data = NULL; -+ -+ while ((data = cust_type_next_line (ioc_ctypes))) { -+ cust_types = g_slist_prepend (cust_types, data); -+ } -+ -+ fd = g_io_channel_unix_get_fd (ioc_ctypes); -+ if (!fstat (fd, &buf)) { -+ file_mtime = buf.st_mtime; -+ } -+ -+ g_io_channel_unref (ioc_ctypes); -+ } -+#endif -+ -+ return cust_types; -+} -+ -+static void -+attach_selinux_data_edit_field (GtkEntry *entry, -+ char *attr_val, char *def_attr_val) -+{ -+ GtkEntryCompletion *comp; -+ GtkCellRenderer *cell; -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ const char *dattr_u; -+ const char *dattr_r; -+ const char *dattr_t; -+ const char *dattr_s; -+ GtkListStore *store; -+ GtkTreeIter iter; -+ GSList *scan; -+ int width; -+ int owidth; -+ int twidth; -+ -+ attr_val = g_strdup (attr_val); /* so we can alter it... */ -+ def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */ -+ -+ /* do completion, so you don't have to type everything... */ -+ comp = gtk_entry_completion_new (); -+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); -+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), -+ 0, GTK_SORT_ASCENDING); -+ -+ gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store)); -+ cell = gtk_cell_renderer_pixbuf_new (); -+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, FALSE); -+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell, -+ "stock-id", 1, NULL); -+ gtk_entry_completion_set_text_column (comp, 0); -+ gtk_entry_set_completion (entry, comp); -+ -+ /* FIXME: default doesn't do the right thing, should it? */ -+ owidth = gtk_entry_get_width_chars (entry); -+ width = owidth; -+ -+ selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); -+ dattr_u = dattr_r = dattr_t = dattr_s = NULL; -+ if (def_attr_val) { -+ selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, -+ &dattr_t, &dattr_s); -+ } -+ -+ /* don't do it twice... */ -+ if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { -+ dattr_t = NULL; -+ } -+ -+ if (attr_t) { -+ /* highlight just the type to the end, so we can easily change it -+ * FIXME: we also highlight any Sensitivity/MCS but completion will -+ * let people put it back, and that's the only way we get completion -+ * at all -- This sucks and we need to remove Sensitivity/MCS from -+ * the edit box. Yah, more UI. */ -+ int beg = attr_t - attr_u; -+ gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1); -+ } -+ -+ for (scan = selinux__type_list(); scan; scan = scan->next) { -+ char *tmp; -+ -+ if (attr_t && !strcmp (attr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ if (dattr_t && !strcmp (dattr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ gtk_list_store_append (store, &iter); -+ tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL); -+ gtk_list_store_set (store, &iter, 0, tmp, -1); -+ -+ twidth = strlen (tmp); -+ width = MAX (twidth, width); -+ -+ g_free (tmp); -+ } -+ -+ if (dattr_t) { -+ char *tmp; -+ -+ gtk_list_store_append (store, &iter); -+ tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL); -+ gtk_list_store_set (store, &iter, 0, tmp, -+ 1, GTK_STOCK_HOME, -1); -+ -+ twidth = strlen (tmp); -+ width = MAX (twidth, width); -+ -+ g_free (tmp); -+ } -+ -+ if (attr_t) { -+ char *tmp; -+ -+ gtk_list_store_append (store, &iter); -+ tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL); -+ gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1); -+ -+ twidth = strlen (tmp); -+ width = MAX (twidth, width); -+ -+ g_free (tmp); -+ } -+ -+ g_free (attr_val); -+ g_free (def_attr_val); -+ g_object_unref (G_OBJECT (store)); -+ g_object_unref (G_OBJECT (comp)); -+ -+ if (width != owidth) { -+ gtk_entry_set_width_chars (entry, width + 2); -+ } -+} -+ -+# define HACK_TYPE(x, y) \ -+ else if (!strcmp (nice_type, x)) nice_type = y -+ -+/* hack to convert a selinux_context type into a readable string for the -+ user */ -+static const char * -+selinux__hack_conv_type (const char *type) -+{ /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon -+ * here now probably want a bunch of other types? */ -+ const char *nice_type; -+ -+ nice_type = type; -+ -+ if (0) { } -+ -+ HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration")); -+ HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)")); -+ HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data")); -+ HACK_TYPE("dhcp_etc_t", _("DHCP configuration")); -+ HACK_TYPE("dictd_etc_t", _("Dictd configuration")); -+ HACK_TYPE("dnssec_t", _("DNS secret")); -+ HACK_TYPE("etc_t", _("System configuration")); -+ HACK_TYPE("etc_aliases_t", _("Email aliases configuration")); -+ HACK_TYPE("etc_runtime_t", _("System configuration (rw)")); -+ HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon")); -+ HACK_TYPE("httpd_config_t", _("Apache-httpd configuration")); -+ HACK_TYPE("httpd_php_tmp_t", -+ _("Apache-httpd PHP module temporary data")); -+ HACK_TYPE("httpd_sys_content_t", -+ _("Read from all httpd scripts and the daemon")); -+ HACK_TYPE("httpd_sys_htaccess_t", -+ _("Apache-httpd .htaccess configuration")); -+ HACK_TYPE("httpd_sys_script_exec_t", -+ _("CGI programs with default access")); -+ HACK_TYPE("httpd_sys_script_ra_t", -+ _("CGI programs can read and append")); -+ HACK_TYPE("httpd_sys_script_ro_t", -+ _("CGI programs can read")); -+ HACK_TYPE("httpd_sys_script_rw_t", -+ _("CGI programs can read and write")); -+ HACK_TYPE("httpd_unconfined_script_exec_t", -+ _("CGI programs without any SELinux protection")); -+ HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data")); -+ HACK_TYPE("ice_tmp_t", _("ICE temporary data")); -+ HACK_TYPE("locale_t", _("Locale data")); -+ HACK_TYPE("mysql_tmp_t", _("MySQL temporary data")); -+ HACK_TYPE("named_conf_t", _("Nameserver configuration")); -+ HACK_TYPE("net_conf_t", _("Network configuration")); -+ HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data")); -+ HACK_TYPE("public_content_rw_t", -+ _("Read and write from CIFS/ftp/http/nfs/rsync")); -+ HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync")); -+ HACK_TYPE("samba_etc_t", _("Samba configuration")); -+ HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)")); -+ HACK_TYPE("staff_home_t", _("Staff user data")); -+ HACK_TYPE("staff_home_dir_t", _("Staff user home directory")); -+ HACK_TYPE("swapfile_t", _("System swapfile")); -+ HACK_TYPE("sysadm_home_t", _("Sysadmin user data")); -+ HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory")); -+ HACK_TYPE("system_cron_spool_t", _("Cron data")); -+ HACK_TYPE("tmp_t", _("Temporary data")); -+ HACK_TYPE("user_tmp_t", _("User temporary data")); -+ HACK_TYPE("user_home_t", _("User data")); -+ HACK_TYPE("user_home_dir_t", _("User home directory")); -+ HACK_TYPE("var_log_t", _("Logfile")); -+ HACK_TYPE("xen_image_t", _("Xen image")); -+ -+ return nice_type; -+} -+#undef HACK_TYPE -+ -+static void -+attach_selinux_data_popup_field (GtkComboBox *comb, -+ char *attr_val, -+ char *def_attr_val) -+{ -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ const char *dattr_u; -+ const char *dattr_r; -+ const char *dattr_t; -+ const char *dattr_s; -+ GtkListStore *store; -+ GtkTreeIter iter; -+ GSList *scan; -+ -+ attr_val = g_strdup (attr_val); /* so we can alter it... */ -+ def_attr_val = g_strdup (def_attr_val); -+ -+ /* do completion, so you don't have to type everything... */ -+ store = gtk_list_store_new (3, G_TYPE_STRING, -+ G_TYPE_STRING, G_TYPE_STRING); -+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), -+ 1, GTK_SORT_ASCENDING); -+ -+ gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store)); -+ -+ selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); -+ dattr_u = dattr_r = dattr_t = dattr_s = NULL; -+ if (def_attr_val) { -+ selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, -+ &dattr_t, &dattr_s); -+ } -+ /* don't do it twice... */ -+ if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { -+ dattr_t = NULL; -+ } -+ -+ for (scan = selinux__type_list(); scan; scan = scan->next) { -+ const char *nice_type; -+ -+ if (attr_t && !strcmp (attr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ if (dattr_t && !strcmp (dattr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ nice_type = selinux__hack_conv_type(scan->data); -+ -+ gtk_list_store_append (store, &iter); -+ gtk_list_store_set (store, &iter, 0, scan->data, -+ 1, nice_type, -1); -+ } -+ -+ if (dattr_t) { -+ const char *nice_type; -+ -+ gtk_list_store_append (store, &iter); -+ nice_type = selinux__hack_conv_type(dattr_t); -+ gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type, -+ 2, GTK_STOCK_HOME, -1); -+ } -+ -+ if (attr_t) { -+ const char *nice_type; -+ -+ gtk_list_store_append (store, &iter); -+ nice_type = selinux__hack_conv_type(attr_t); -+ gtk_list_store_set (store, &iter, 0, attr_t, 1, nice_type, -+ 2, GTK_STOCK_OK, -1); -+ gtk_combo_box_set_active_iter (comb, &iter); -+ } -+ -+ g_free (attr_val); -+ g_free (def_attr_val); -+ g_object_unref (G_OBJECT (store)); -+} -+ -+static char * -+selinux__matchpathcon (GList *file_list) -+{ -+ GList *scan; -+ -+ for (scan = file_list; scan != NULL; scan = scan->next) { -+ NautilusFile *file; -+ -+ file = NAUTILUS_FILE (scan->data); -+ if (!nautilus_file_is_gone (file)) { -+ return nautilus_file_get_selinux_matchpathcon (file); -+ } -+ } -+ -+ return NULL; -+} -+ -+static void -+attach_selinux_edit_field (FMPropertiesWindow *window, -+ GtkTable *table, -+ int row, -+ int column, -+ const char *file_attribute_name, -+ const char *inconsistent_string, -+ gboolean show_original, -+ GtkLabel *lab_title) -+{ -+ GtkEntry *entry; -+ GList *file_list; -+ char *attr_value; -+ char *def_attr_value; -+ -+ if (show_original) { -+ file_list = window->details->original_files; -+ } else { -+ file_list = window->details->target_files; -+ } -+ -+ attr_value = file_list_get_string_attribute (file_list, -+ file_attribute_name, -+ inconsistent_string); -+ if ( strcmp (attr_value, inconsistent_string) && -+ !strcmp (file_attribute_name, "selinux_context")) { -+ def_attr_value = selinux__matchpathcon (file_list); -+ } else { -+ def_attr_value = NULL; -+ } -+ -+ entry = attach_edit_label (table, row, column, attr_value); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), -+ GTK_WIDGET (entry)); -+ -+ /* Stash a copy of the file attribute name in this field for the callback's sake. */ -+ g_object_set_data_full (G_OBJECT (entry), "file_attribute", -+ g_strdup (file_attribute_name), g_free); -+ -+ g_object_set_data_full (G_OBJECT (entry), "inconsistent_string", -+ g_strdup (inconsistent_string), g_free); -+ -+ g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original)); -+ g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE)); -+ -+ g_signal_connect_object (entry, "focus_out_event", -+ G_CALLBACK (selinux_focus_out), window, 0); -+ g_signal_connect_object (entry, "activate", -+ G_CALLBACK (selinux_entry_activate), window,0); -+ -+ attach_selinux_data_edit_field (entry, attr_value, def_attr_value); -+ -+ g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value, -+ g_free); -+ -+ g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx", -+ def_attr_value, g_free); -+ -+ window->details->edit_fields = g_list_prepend (window->details->edit_fields, -+ entry); -+} -+ -+static void -+attach_selinux_popup_field (FMPropertiesWindow *window, -+ GtkTable *table, -+ int row, -+ int column, -+ const char *file_attribute_name, -+ const char *inconsistent_string, -+ gboolean show_original, -+ GtkLabel *lab_title) -+{ -+ GtkWidget *comb; -+ GtkCellRenderer *cell; -+ GList *file_list; -+ char *attr_value; -+ char *def_attr_value; -+ -+ if (show_original) { -+ file_list = window->details->original_files; -+ } else { -+ file_list = window->details->target_files; -+ } -+ -+ attr_value = file_list_get_string_attribute (file_list, -+ file_attribute_name, -+ inconsistent_string); -+ if ( strcmp (attr_value, inconsistent_string) && -+ !strcmp (file_attribute_name, "selinux_context")) { -+ def_attr_value = selinux__matchpathcon (file_list); -+ } else { -+ def_attr_value = NULL; -+ } -+ -+ comb = gtk_combo_box_new (); -+ -+ gtk_table_attach (table, comb, column, column + 1, row, row + 1, -+ GTK_FILL, 0, 0, 0); -+ -+ -+ gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb); -+ -+ /* Stash a copy of the file attribute name in this field for the callback's sake. */ -+ g_object_set_data_full (G_OBJECT (comb), "file_attribute", -+ g_strdup (file_attribute_name), g_free); -+ -+ g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original)); -+ -+ attach_selinux_data_popup_field (GTK_COMBO_BOX (comb), -+ attr_value, def_attr_value); -+ -+ g_signal_connect_object (comb, "changed", -+ G_CALLBACK (selinux_popup_activate), window, 0); -+ -+ g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value, -+ g_free); -+ -+ g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx", -+ def_attr_value, g_free); -+ -+ cell = gtk_cell_renderer_pixbuf_new (); -+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE); -+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, -+ "stock-id", 2, NULL); -+ cell = gtk_cell_renderer_text_new (); -+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE); -+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, -+ "text", 1, NULL); -+ gtk_widget_show (comb); -+ -+ g_assert (! window->details->selinux_combo); -+ -+ window->details->selinux_combo = -+ g_list_prepend (window->details->selinux_combo, comb); -+} -+ - static GtkWidget* - attach_ellipsizing_value_field (FMPropertiesWindow *window, - GtkTable *table, -@@ -2439,6 +3312,36 @@ - } - - static guint -+append_title_selinux_edit_pair (FMPropertiesWindow *window, -+ GtkTable *table, -+ const char *title, -+ const char *file_attribute_name, -+ const char *inconsistent_state, -+ gboolean show_original) -+{ -+ guint last_row; -+ GtkLabel *lab_title; -+ -+ lab_title = NULL; -+ last_row = append_title_field (table, title, &lab_title); -+ -+ if (window->details->advanced_permissions) { -+ attach_selinux_edit_field (window, table, last_row, -+ VALUE_COLUMN, file_attribute_name, -+ inconsistent_state, -+ show_original, lab_title); -+ } else { -+ -+ attach_selinux_popup_field (window, table, last_row, -+ VALUE_COLUMN, file_attribute_name, -+ inconsistent_state, -+ show_original, lab_title); -+ } -+ -+ return last_row; -+} -+ -+static guint - append_title_and_ellipsizing_value (FMPropertiesWindow *window, - GtkTable *table, - const char *title, -@@ -2900,31 +3803,6 @@ - } - - static void --start_long_operation (FMPropertiesWindow *window) --{ -- if (window->details->long_operation_underway == 0) { -- /* start long operation */ -- GdkCursor * cursor; -- -- cursor = gdk_cursor_new (GDK_WATCH); -- gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); -- gdk_cursor_unref (cursor); -- } -- window->details->long_operation_underway ++; --} -- --static void --end_long_operation (FMPropertiesWindow *window) --{ -- if (GTK_WIDGET (window)->window != NULL && -- window->details->long_operation_underway == 1) { -- /* finished !! */ -- gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); -- } -- window->details->long_operation_underway--; --} -- --static void - permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) - { - FMPropertiesWindow *window; -@@ -4051,14 +4929,16 @@ - GnomeVFSFilePermissions file_permission, file_permission_mask; - GnomeVFSFilePermissions dir_permission, dir_permission_mask; - GnomeVFSFilePermissions vfs_mask, vfs_new_perm, p; -- GtkWidget *button, *combo; -+ char *context; -+ GtkWidget *button; -+ GtkComboBox *combo; - gboolean active, is_folder, is_special, use_original; - GList *l; - GtkTreeModel *model; - GtkTreeIter iter; - PermissionType type; - int new_perm, mask; -- -+ - file_permission = 0; - file_permission_mask = 0; - dir_permission = 0; -@@ -4095,9 +4975,9 @@ - } - /* Simple mode, minus exec checkbox */ - for (l = window->details->permission_combos; l != NULL; l = l->next) { -- combo = l->data; -+ combo = GTK_COMBO_BOX (l->data); - -- if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { -+ if (!gtk_combo_box_get_active_iter (combo, &iter)) { - continue; - } - -@@ -4105,7 +4985,7 @@ - is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), - "is-folder")); - -- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); -+ model = gtk_combo_box_get_model (combo); - gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1); - if (use_original) { - continue; -@@ -4128,12 +5008,53 @@ - } - } - -+ /* get the SELinux context... */ -+ context = NULL; -+ if (window->details->advanced_permissions && -+ window->details->edit_fields) { /* advanced mode */ -+ GtkEditable *efield; -+ -+ efield = window->details->edit_fields->data; -+ context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1); -+ } else if (!window->details->advanced_permissions && -+ window->details->selinux_combo) { /* simple mode */ -+ char *cntx_type; -+ char *orig_type; -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ -+ combo = GTK_COMBO_BOX (window->details->selinux_combo->data); -+ -+ if (!gtk_combo_box_get_active_iter (combo, &iter)) { -+ return; -+ } else { -+ GtkTreeModel *model = gtk_combo_box_get_model (combo); -+ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); -+ } -+ if (!(orig_type = g_object_get_data (G_OBJECT (combo), -+ "original_cntx"))) { -+ return; -+ } -+ -+ orig_type = g_strdup (orig_type); -+ -+ selinux_split_cntx (orig_type, -+ &attr_u, &attr_r, &attr_t, &attr_s); -+ context = g_strjoin (":", -+ attr_u, attr_r, cntx_type, attr_s, NULL); -+ g_free (orig_type); -+ } -+ - for (l = window->details->target_files; l != NULL; l = l->next) { - NautilusFile *file; - char *uri; - - file = NAUTILUS_FILE (l->data); - -+ /* assume permissions setting allows context setting... -+ * we can't really do much else due to race conditions anyway */ - if (nautilus_file_is_directory (file) && - nautilus_file_can_set_permissions (file)) { - uri = nautilus_file_get_uri (file); -@@ -4144,11 +5065,13 @@ - file_permission_mask, - dir_permission, - dir_permission_mask, -+ context, - set_recursive_permissions_done, - window); - g_free (uri); - } - } -+ g_free (context); - } - - static void -@@ -4195,11 +5118,20 @@ - } - - gtk_table_set_row_spacing (page_table, page_table->nrows - 1, 18); -- -- append_title_value_pair -- (window, page_table, _("SELinux Context:"), -- "selinux_context", _("--"), -- FALSE); -+ -+ if (!is_multi_file_window (window) || -+ multi_have_same_selinux_context (window)) -+ append_title_selinux_edit_pair -+ (window, page_table, _("_SELinux Context:"), -+ "selinux_context", _("--"), -+ FALSE); -+ else /* Static text in this case. */ -+ append_title_value_pair (window, page_table, -+ _("_SELinux Context:"), -+ "selinux_context", _("--"), -+ FALSE); -+ -+ - append_title_value_pair - (window, page_table, _("Last changed:"), - "date_permissions", _("--"), diff --git a/nautilus-2.17.90-selinux.patch b/nautilus-2.17.90-selinux.patch deleted file mode 100644 index fbee9df..0000000 --- a/nautilus-2.17.90-selinux.patch +++ /dev/null @@ -1,1666 +0,0 @@ ---- nautilus-2.17.90/libnautilus-private/nautilus-file.c.selinux 2007-01-22 10:10:45.000000000 +0100 -+++ nautilus-2.17.90/libnautilus-private/nautilus-file.c 2007-01-23 10:04:29.000000000 +0100 -@@ -3569,7 +3569,7 @@ - * context - * @file: NautilusFile representing the file in question. - * -- * Returns: Newly allocated string ready to display to the user. -+ * Returns: Newly allocated string ready to display to the user, or NULL. - * - **/ - char * -@@ -3602,6 +3602,134 @@ - return translated; - } - -+/** -+ * nautilus_file_get_selinux_matchpathcon: -+ * -+ * Get a user-displayable string representing a file's default selinux -+ * context (as from matchpathcon). Only works on local files. -+ * @file: NautilusFile representing the file in question. -+ * -+ * Returns: Newly allocated string ready to display to the user, or NULL. -+ * -+ **/ -+char * -+nautilus_file_get_selinux_matchpathcon (NautilusFile *file) -+{ -+ char *translated; -+ char *raw; -+ char *uri; -+ char *fname; -+ -+ g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); -+ -+ translated = NULL; -+#ifdef HAVE_SELINUX -+ uri = nautilus_file_get_uri (file); -+ fname = gnome_vfs_get_local_path_from_uri (uri); -+ -+ if (!fname) { -+ return NULL; -+ } -+ -+ raw = NULL; -+ if (matchpathcon (fname, file->details->info->permissions, &raw) == 0) { -+ if (selinux_raw_to_trans_context (raw, &translated) == 0) { -+ char *tmp; -+ tmp = g_strdup (translated); -+ freecon (translated); -+ translated = tmp; -+ } -+ freecon (raw); -+ } -+ -+ g_free (fname); -+ g_free (uri); -+#endif -+ -+ return translated; -+} -+ -+static void -+set_selinux_context_callback (GnomeVFSAsyncHandle *handle, -+ GnomeVFSResult result, -+ GnomeVFSFileInfo *new_info, -+ gpointer callback_data) -+{ -+ set_permissions_callback (handle, result, new_info, callback_data); -+} -+ -+void -+nautilus_file_set_selinux_context (NautilusFile *file, -+ const char *selinux_context, -+ NautilusFileOperationCallback callback, -+ gpointer callback_data) -+{ -+ Operation *op; -+ GnomeVFSURI *vfs_uri; -+ GnomeVFSFileInfo *partial_file_info; -+ GnomeVFSFileInfoOptions options; -+ char *rcontext; -+ -+ rcontext = NULL; -+ -+ /* this is probably mostly right... */ -+ if (!nautilus_file_can_set_permissions (file)) { -+ /* Claim that something changed even if the permission change failed. -+ * This makes it easier for some clients who see the "reverting" -+ * to the old permissions as "changing back". -+ */ -+ nautilus_file_changed (file); -+ (* callback) (file, GNOME_VFS_ERROR_ACCESS_DENIED, callback_data); -+ return; -+ } -+ -+ /* Test the permissions-haven't-changed case explicitly -+ * because we don't want to send the file-changed signal if -+ * nothing changed. -+ */ -+ if (file->details->info->selinux_context != NULL && -+ strcmp(selinux_context, file->details->info->selinux_context) == 0) { -+ (* callback) (file, GNOME_VFS_OK, callback_data); -+ return; -+ } -+ -+#ifdef HAVE_SELINUX -+ /* this is really const, but prototype is wrong, *sigh* */ -+ if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) { -+ (* callback) (file, GNOME_VFS_ERROR_NO_MEMORY, callback_data); -+ return; -+ } -+ selinux_context = rcontext; -+#endif -+ -+ /* Set up a context change operation. */ -+ op = operation_new (file, callback, callback_data); -+ op->use_slow_mime = file->details->got_slow_mime_type; -+ -+ options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS; -+ if (op->use_slow_mime) { -+ options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE; -+ } -+ /* Change the file-on-disk context. */ -+ partial_file_info = gnome_vfs_file_info_new (); -+ g_free (partial_file_info->selinux_context); -+ partial_file_info->selinux_context = g_strdup (selinux_context); -+ vfs_uri = nautilus_file_get_gnome_vfs_uri (file); -+ gnome_vfs_async_set_file_info (&op->handle, -+ vfs_uri, partial_file_info, -+ GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT, -+ options, -+ GNOME_VFS_PRIORITY_DEFAULT, -+ set_selinux_context_callback, op); -+ gnome_vfs_file_info_unref (partial_file_info); -+ gnome_vfs_uri_unref (vfs_uri); -+ -+#ifdef HAVE_SELINUX -+ freecon (rcontext); -+#endif -+} -+ -+ - static char * - get_real_name (const char *name, const char *gecos) - { -@@ -3804,7 +3932,7 @@ - GnomeVFSResult result, - GnomeVFSFileInfo *new_info, - gpointer callback_data) --{ -+{ /* FIXME: this is identical to set_permissions_callback */ - Operation *op; - - op = callback_data; ---- nautilus-2.17.90/libnautilus-private/nautilus-file.h.selinux 2007-01-11 10:58:31.000000000 +0100 -+++ nautilus-2.17.90/libnautilus-private/nautilus-file.h 2007-01-23 09:15:44.000000000 +0100 -@@ -200,6 +200,7 @@ - GList * nautilus_file_get_settable_group_names (NautilusFile *file); - gboolean nautilus_file_can_get_selinux_context (NautilusFile *file); - char * nautilus_file_get_selinux_context (NautilusFile *file); -+char * nautilus_file_get_selinux_matchpathcon (NautilusFile *file); - - /* "Capabilities". */ - gboolean nautilus_file_can_read (NautilusFile *file); -@@ -226,6 +227,10 @@ - GnomeVFSFilePermissions permissions, - NautilusFileOperationCallback callback, - gpointer callback_data); -+void nautilus_file_set_selinux_context (NautilusFile *file, -+ const char *selinux_context, -+ NautilusFileOperationCallback callback, -+ gpointer callback_data); - void nautilus_file_rename (NautilusFile *file, - const char *new_name, - NautilusFileOperationCallback callback, ---- nautilus-2.17.90/libnautilus-private/nautilus-file-operations.c.selinux 2007-01-11 12:36:02.000000000 +0100 -+++ nautilus-2.17.90/libnautilus-private/nautilus-file-operations.c 2007-01-23 09:15:44.000000000 +0100 -@@ -63,6 +63,10 @@ - #include "nautilus-trash-monitor.h" - #include "nautilus-file-utilities.h" - -+#ifdef HAVE_SELINUX -+#include -+#endif -+ - typedef enum TransferKind TransferKind; - typedef struct TransferInfo TransferInfo; - typedef struct IconPositionIterator IconPositionIterator; -@@ -2953,6 +2957,7 @@ - GnomeVFSFilePermissions file_mask; - GnomeVFSFilePermissions dir_permissions; - GnomeVFSFilePermissions dir_mask; -+ char *context; - NautilusSetPermissionsCallback callback; - gpointer callback_data; - }; -@@ -2980,6 +2985,8 @@ - GnomeVFSURI *uri; - char *uri_str; - struct FileInfo *file_info; -+ int flags; -+ int options; - - info = callback_data; - -@@ -3010,10 +3017,18 @@ - vfs_info->permissions = - (file_info->permissions & ~info->file_mask) | - info->file_permissions; -+ flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; -+ options = GNOME_VFS_FILE_INFO_DEFAULT; -+ if (info->context) { -+ flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; -+ vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; -+ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; -+ g_free (vfs_info->selinux_context); -+ vfs_info->selinux_context = g_strdup (info->context); -+ } - - gnome_vfs_async_set_file_info (&info->handle, uri, vfs_info, -- GNOME_VFS_SET_FILE_INFO_PERMISSIONS, -- GNOME_VFS_FILE_INFO_DEFAULT, -+ flags, options, - GNOME_VFS_PRIORITY_DEFAULT, - set_permissions_set_file_info, - info); -@@ -3021,7 +3036,6 @@ - gnome_vfs_file_info_unref (vfs_info); - g_free (file_info->name); - g_free (file_info); -- - } - - static void -@@ -3066,13 +3080,11 @@ - } - } - -- - if (result != GNOME_VFS_OK) { - /* Finished with this dir, work on the files */ - info->current_file = NULL; - set_permissions_set_file_info (NULL, GNOME_VFS_OK, NULL, info); - } -- - } - - /* Also called for the toplevel dir */ -@@ -3084,7 +3096,8 @@ - { - struct RecursivePermissionsInfo *info; - char *uri_str; -- -+ int options; -+ - info = callback_data; - - if (result == GNOME_VFS_OK && handle != NULL) { -@@ -3093,9 +3106,13 @@ - g_free (uri_str); - } - -+ options = GNOME_VFS_FILE_INFO_DEFAULT; -+ if (info->context) { -+ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; -+ } - gnome_vfs_async_load_directory_uri (&info->handle, - info->current_dir, -- GNOME_VFS_FILE_INFO_DEFAULT, -+ options, - 50, - GNOME_VFS_PRIORITY_DEFAULT, - set_permissions_got_files, -@@ -3107,6 +3124,8 @@ - { - struct DirInfo *dir_info; - GnomeVFSFileInfo *vfs_info; -+ int flags; -+ int options; - - gnome_vfs_uri_unref (info->current_dir); - -@@ -3114,6 +3133,7 @@ - /* No more directories, finished! */ - info->callback (info->callback_data); - /* All parts of info should be freed now */ -+ g_free (info->context); - g_free (info); - return; - } -@@ -3128,12 +3148,18 @@ - vfs_info->permissions = - (dir_info->permissions & ~info->dir_mask) | - info->dir_permissions; -- -- gnome_vfs_async_set_file_info (&info->handle, -- info->current_dir, -- vfs_info, -- GNOME_VFS_SET_FILE_INFO_PERMISSIONS, -- GNOME_VFS_FILE_INFO_DEFAULT, -+ flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; -+ options = GNOME_VFS_FILE_INFO_DEFAULT; -+ if (info->context) { -+ flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; -+ vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; -+ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; -+ g_free (vfs_info->selinux_context); -+ vfs_info->selinux_context = g_strdup (info->context); -+ } -+ -+ gnome_vfs_async_set_file_info (&info->handle, info->current_dir, -+ vfs_info, flags, options, - GNOME_VFS_PRIORITY_DEFAULT, - set_permissions_load_dir, - info); -@@ -3148,6 +3174,7 @@ - GnomeVFSFilePermissions file_mask, - GnomeVFSFilePermissions dir_permissions, - GnomeVFSFilePermissions dir_mask, -+ const char *context, - NautilusSetPermissionsCallback callback, - gpointer callback_data) - { -@@ -3161,6 +3188,22 @@ - info->file_mask = file_mask; - info->dir_permissions = dir_permissions; - info->dir_mask = dir_mask; -+ if (context) { -+ char *rcontext; -+ -+ rcontext = info->context = NULL; -+#ifdef HAVE_SELINUX -+ /* this is really const, but prototype is wrong, *sigh* */ -+ if (selinux_trans_to_raw_context((char *)context, &rcontext)) { -+ g_error ("selinux_trans_to_raw_context: failed to allocate bytes"); -+ return; -+ } -+ info->context = g_strdup (rcontext); -+ freecon (rcontext); -+#endif -+ } else { -+ info->context = NULL; -+ } - info->callback = callback; - info->callback_data = callback_data; - -@@ -3168,6 +3211,8 @@ - - if (info->current_dir == NULL) { - info->callback (info->callback_data); -+ /* All parts of info should be freed now */ -+ g_free (info->context); - g_free (info); - return; - } ---- nautilus-2.17.90/libnautilus-private/nautilus-file-operations.h.selinux 2007-01-03 09:52:25.000000000 +0100 -+++ nautilus-2.17.90/libnautilus-private/nautilus-file-operations.h 2007-01-23 09:15:44.000000000 +0100 -@@ -76,6 +76,7 @@ - GnomeVFSFilePermissions file_mask, - GnomeVFSFilePermissions folder_permissions, - GnomeVFSFilePermissions folder_mask, -+ const char *context, - NautilusSetPermissionsCallback callback, - gpointer callback_data); - ---- nautilus-2.17.90/src/file-manager/fm-error-reporting.c.selinux 2007-01-03 09:52:12.000000000 +0100 -+++ nautilus-2.17.90/src/file-manager/fm-error-reporting.c 2007-01-23 09:15:44.000000000 +0100 -@@ -252,6 +252,38 @@ - g_free (message); - } - -+void -+fm_report_error_setting_selinux (NautilusFile *file, -+ GnomeVFSResult error, -+ GtkWindow *parent_window) -+{ -+ char *file_name; -+ char *message; -+ -+ if (error == GNOME_VFS_OK) { -+ return; -+ } -+ -+ file_name = nautilus_file_get_display_name (file); -+ -+ switch (error) { -+ case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM: -+ message = g_strdup_printf (_("Couldn't change the SELinux security context of \"%s\" because it is on a read-only disk"), -+ file_name); -+ break; -+ default: -+ /* We should invent decent error messages for every case we actually experience. */ -+ g_warning ("Hit unhandled case %d (%s) in fm_report_error_setting_permissions", -+ error, gnome_vfs_result_to_string (error)); -+ message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\"."), file_name); -+ } -+ -+ eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window); -+ -+ g_free (file_name); -+ g_free (message); -+} -+ - typedef struct _FMRenameData { - char *name; - NautilusFileOperationCallback callback; ---- nautilus-2.17.90/src/file-manager/fm-error-reporting.h.selinux 2007-01-03 09:52:12.000000000 +0100 -+++ nautilus-2.17.90/src/file-manager/fm-error-reporting.h 2007-01-23 09:15:44.000000000 +0100 -@@ -39,7 +39,10 @@ - GnomeVFSResult error_code, - GtkWindow *parent_window); - void fm_report_error_setting_permissions (NautilusFile *file, -- GnomeVFSResult error_code, -+ GnomeVFSResult error_code, -+ GtkWindow *parent_window); -+void fm_report_error_setting_selinux (NautilusFile *file, -+ GnomeVFSResult error_code, - GtkWindow *parent_window); - void fm_report_error_setting_owner (NautilusFile *file, - GnomeVFSResult error_code, ---- nautilus-2.17.90/src/file-manager/fm-properties-window.c.selinux 2007-01-11 11:53:01.000000000 +0100 -+++ nautilus-2.17.90/src/file-manager/fm-properties-window.c 2007-01-23 09:15:44.000000000 +0100 -@@ -83,6 +83,10 @@ - #include - #include - -+#ifdef HAVE_SELINUX -+# include -+#endif -+ - #define PREVIEW_IMAGE_WIDTH 96 - - #define ROW_PAD 6 -@@ -102,7 +106,7 @@ - - GtkWidget *icon_button; - GtkWidget *icon_image; -- GtkWidget *icon_chooser; -+ GtkWidget *icon_chooser; - - GtkWidget *name_label; - GtkWidget *name_field; -@@ -124,12 +128,15 @@ - unsigned int owner_change_timeout; - - GList *permission_buttons; -- GList *permission_combos; -+ GList *permission_combos; /* how is this deallocated???? */ -+ GList *selinux_combo; - GHashTable *initial_permissions; - gboolean has_recursive_apply; - - GList *value_fields; - -+ GList *edit_fields; -+ - GList *mime_list; - - gboolean deep_count_finished; -@@ -208,6 +215,10 @@ - GtkComboBox *combo); - static void value_field_update (FMPropertiesWindow *window, - GtkLabel *field); -+static void edit_field_update (FMPropertiesWindow *window, -+ GtkEntry *field); -+static void popup_field_update (FMPropertiesWindow *window, -+ GtkComboBox *entry); - static void properties_window_update (FMPropertiesWindow *window, - GList *files); - static void is_directory_ready_callback (NautilusFile *file, -@@ -235,10 +246,32 @@ - int row, - int column, - const char *initial_text); -+static void attach_selinux_data_edit_field (GtkEntry *entry, -+ char *attr_value, -+ char *def_attr_value); -+static void attach_selinux_data_popup_field (GtkComboBox *comb, -+ char *attr_val, -+ char *def_attr_val); -+ - - G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_WINDOW); - #define parent_class fm_properties_window_parent_class - -+static void -+maybe_gtk_entry_set_text (GtkEntry *entry, const char *val) -+{ -+ char *old_val; -+ -+ g_assert (GTK_IS_ENTRY (entry)); -+ -+ old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); -+ -+ if (strcmp (old_val, val) != 0) { -+ gtk_entry_set_text (entry, val); -+ } -+ g_free(old_val); -+} -+ - static gboolean - is_multi_file_window (FMPropertiesWindow *window) - { -@@ -259,6 +292,39 @@ - return FALSE; - } - -+static gboolean -+multi_have_same_selinux_context (FMPropertiesWindow *window) -+{ -+ GList *l; -+ char *cntx; -+ -+ cntx = NULL; -+ for (l = window->details->original_files; l != NULL; l = l->next) { -+ NautilusFile *file; -+ -+ file = NAUTILUS_FILE (l->data); -+ if (!nautilus_file_is_gone (file)) { -+ char *tmp; -+ -+ tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context"); -+ if (!cntx) { -+ cntx = tmp; -+ } else if (strcmp (cntx, tmp)) { -+ g_free (tmp); -+ g_free (cntx); -+ return FALSE; -+ } -+ else { -+ g_free (tmp); -+ } -+ } -+ } -+ -+ g_free (cntx); -+ -+ return TRUE; -+} -+ - static int - get_not_gone_original_file_count (FMPropertiesWindow *window) - { -@@ -496,7 +562,7 @@ - return; - } - -- uris = g_strsplit (selection_data->data, "\r\n", 0); -+ uris = g_strsplit ((char *) selection_data->data, "\r\n", 0); - exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); - - -@@ -577,7 +643,7 @@ - - static void - set_name_field (FMPropertiesWindow *window, const gchar *original_name, -- const gchar *name) -+ const gchar *name) - { - gboolean new_widget; - gboolean use_label; -@@ -643,11 +709,7 @@ - * currently showing. This causes minimal ripples (e.g. - * selection change). - */ -- gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1); -- if (strcmp (displayed_name, name) != 0) { -- gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); -- } -- g_free (displayed_name); -+ maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); - } - } - } -@@ -723,7 +785,6 @@ - name_field_restore_original_name (NautilusEntry *name_field) - { - const char *original_name; -- char *displayed_name; - - original_name = (const char *) g_object_get_data (G_OBJECT (name_field), - "original_name"); -@@ -732,14 +793,8 @@ - return; - } - -- displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1); -- -- if (strcmp (original_name, displayed_name) != 0) { -- gtk_entry_set_text (GTK_ENTRY (name_field), original_name); -- } -+ maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name); - nautilus_entry_select_all (name_field); -- -- g_free (displayed_name); - } - - static void -@@ -852,7 +907,7 @@ - word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp); - eel_g_list_free_deep (keywords); - -- return (word != NULL); -+ return word != NULL; - } - - static void -@@ -1119,7 +1174,7 @@ - b = b->next; - } - -- return (a == b); -+ return a == b; - } - - static GList * -@@ -1201,6 +1256,14 @@ - for (l = window->details->value_fields; l != NULL; l = l->next) { - value_field_update (window, GTK_LABEL (l->data)); - } -+ -+ for (l = window->details->edit_fields; l != NULL; l = l->next) { -+ edit_field_update (window, GTK_ENTRY (l->data)); -+ } -+ -+ for (l = window->details->selinux_combo; l != NULL; l = l->next) { -+ popup_field_update (window, GTK_COMBO_BOX (l->data)); -+ } - } - - mime_list = get_mime_list (window); -@@ -1381,6 +1444,111 @@ - ellipsize_text); - } - -+static void -+edit_field_update_internal (GtkEntry *entry, -+ GList *file_list) -+{ -+ const char *attr_name; -+ char *attr_value; -+ char *def_attr_value; -+ char *inconsistent_string; -+ -+ g_assert (GTK_IS_ENTRY (entry)); -+ -+ attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute"); -+ inconsistent_string = g_object_get_data (G_OBJECT (entry), -+ "inconsistent_string"); -+ def_attr_value = g_object_get_data (G_OBJECT (entry), -+ "matchpathcon_cntx"); -+ -+ attr_value = file_list_get_string_attribute (file_list, attr_name, -+ inconsistent_string); -+ -+ maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value); -+ -+ /* JFIXME: this isn't generic, *sigh* ... */ -+ attach_selinux_data_edit_field (entry, attr_value, def_attr_value); -+ g_free (attr_value); -+} -+ -+static void -+edit_field_update (FMPropertiesWindow *window, GtkEntry *entry) -+{ -+ gboolean use_original; -+ -+ if (gtk_widget_is_focus (GTK_WIDGET (entry))) { -+ return; -+ } -+ -+ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original")); -+ -+ edit_field_update_internal (entry, -+ (use_original ? -+ window->details->original_files : -+ window->details->target_files)); -+} -+ -+static void -+popup_field_update_internal (GtkComboBox *combo, -+ GList *file_list) -+{ -+ const char *attr_name; -+ char *attr_value; -+ char *def_attr_value; -+ char *inconsistent_string; -+ char *cntx_type; -+ GtkTreeIter iter; -+ -+ g_assert (GTK_IS_COMBO_BOX (combo)); -+ -+ if (gtk_widget_is_focus (GTK_WIDGET (combo))) { -+ return; -+ } -+ -+ attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute"); -+ inconsistent_string = g_object_get_data (G_OBJECT (combo), -+ "inconsistent_string"); -+ def_attr_value = g_object_get_data (G_OBJECT (combo), -+ "matchpathcon_cntx"); -+ -+ attr_value = file_list_get_string_attribute (file_list, attr_name, -+ inconsistent_string); -+ -+ /* JFIXME: this isn't generic, *sigh* ... */ -+ -+ if (gtk_combo_box_get_active_iter (combo, &iter)) { -+ GtkTreeModel *model = gtk_combo_box_get_model (combo); -+ -+ /* don't update, if it's identical */ -+ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); -+ if (cntx_type && strcmp (cntx_type, attr_value) == 0) { -+ g_free (attr_value); -+ return; -+ } -+ } -+ -+ attach_selinux_data_popup_field (combo, attr_value, def_attr_value); -+ -+ g_free (attr_value); -+} -+ -+static void -+popup_field_update (FMPropertiesWindow *window, GtkComboBox *combo) -+{ -+ gboolean use_original; -+ -+ if (window->details->selinux_combo) { -+ return; /* FIXME: must be true: horrible UI, if working */ -+ } -+ -+ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original")); -+ -+ popup_field_update_internal (combo, -+ (use_original ? -+ window->details->original_files : -+ window->details->target_files)); -+} -+ - static GtkLabel * - attach_label (GtkTable *table, - int row, -@@ -1432,6 +1600,45 @@ - return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); - } - -+static GtkEntry * -+attach_edit (GtkTable *table, -+ int row, -+ int column, -+ const char *initial_text, -+ gboolean right_aligned, -+ gboolean bold, -+ gboolean ellipsize_text, -+ gboolean selectable, -+ gboolean mnemonic) -+{ -+ GtkWidget *entry_field; -+ -+ entry_field = nautilus_entry_new (); -+ gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text); -+ -+ gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0); -+ gtk_widget_show (entry_field); -+ gtk_table_attach (table, entry_field, -+ column, column + 1, -+ row, row + 1, -+ ellipsize_text -+ ? GTK_FILL | GTK_EXPAND -+ : GTK_FILL, -+ 0, -+ 0, 0); -+ -+ return GTK_ENTRY (entry_field); -+} -+ -+static GtkEntry * -+attach_edit_label (GtkTable *table, -+ int row, -+ int column, -+ const char *initial_text) -+{ -+ return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); -+} -+ - static GtkLabel * - attach_ellipsizing_value_label (GtkTable *table, - int row, -@@ -1491,6 +1698,672 @@ - FALSE); - } - -+static void -+start_long_operation (FMPropertiesWindow *window) -+{ -+ if (window->details->long_operation_underway == 0) { -+ /* start long operation */ -+ GdkCursor * cursor; -+ -+ cursor = gdk_cursor_new (GDK_WATCH); -+ gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); -+ gdk_cursor_unref (cursor); -+ } -+ window->details->long_operation_underway ++; -+} -+ -+static void -+end_long_operation (FMPropertiesWindow *window) -+{ -+ if (GTK_WIDGET (window)->window != NULL && -+ window->details->long_operation_underway == 1) { -+ /* finished !! */ -+ gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); -+ } -+ window->details->long_operation_underway--; -+} -+ -+static void -+selinux_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) -+{ -+ FMPropertiesWindow *window; -+ g_assert (callback_data != NULL); -+ -+ window = FM_PROPERTIES_WINDOW (callback_data); -+ end_long_operation (window); -+ -+ /* Report the error if it's an error. */ -+ fm_report_error_setting_selinux (file, result, NULL); -+ -+ g_object_unref (window); -+} -+ -+static void -+selinux_done_editing (FMPropertiesWindow *window, char *selinux_context) -+{ -+ GList *l; -+ -+ /* Accept changes. */ -+ for (l = window->details->target_files; l != NULL; l = l->next) { -+ NautilusFile *file; -+ -+ file = NAUTILUS_FILE (l->data); -+ -+ start_long_operation (window); -+ g_object_ref (window); -+ nautilus_file_set_selinux_context (file, selinux_context, -+ selinux_change_callback, -+ window); -+ } -+} -+ -+static gboolean -+selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data) -+{ -+ g_assert (NAUTILUS_IS_ENTRY (entry)); -+ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); -+ -+ if (GTK_WIDGET_SENSITIVE (entry)) { -+ char *tmp; -+ -+ tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); -+ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); -+ g_free (tmp); -+ } -+ -+ return FALSE; -+} -+ -+static void -+selinux_entry_activate (NautilusEntry *entry, gpointer cb_data) -+{ -+ char *tmp; -+ -+ g_assert (NAUTILUS_IS_ENTRY (entry)); -+ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); -+ -+ tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); -+ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); -+ g_free (tmp); -+ -+ nautilus_entry_select_all_at_idle (entry); -+} -+ -+/* NOTE: This modifies cntx */ -+static void -+selinux_split_cntx (char *cntx, -+ const char **ret_attr_u, -+ const char **ret_attr_r, -+ const char **ret_attr_t, -+ const char **ret_attr_s) -+{ -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ -+ attr_u = cntx; -+ if (!(attr_r = strchr (attr_u, ':'))) { -+ attr_r = "object_r"; /* shouldn't happen */ -+ } else { -+ *((char *)attr_r++) = 0; -+ } -+ -+ if (!(attr_t = strchr (attr_r, ':'))) { -+ attr_t = "file_t"; /* shouldn't happen */ -+ } else { -+ *((char *)attr_t++) = 0; -+ } -+ -+ if ((attr_s = strchr (attr_t, ':'))) { -+ *((char *)attr_s++) = 0; -+ } -+ -+ *ret_attr_u = attr_u; -+ *ret_attr_r = attr_r; -+ *ret_attr_t = attr_t; -+ *ret_attr_s = attr_s; -+} -+ -+static void -+selinux_popup_activate (GtkComboBox *comb, gpointer cb_data) -+{ -+ char *cntx_type; -+ char *orig_type; -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ char *tmp; -+ GtkTreeIter iter; -+ -+ g_assert (GTK_IS_COMBO_BOX (comb)); -+ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); -+ -+ if (!gtk_combo_box_get_active_iter (comb, &iter)) { -+ return; -+ } else { -+ -+ GtkTreeModel *model = gtk_combo_box_get_model (comb); -+ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); -+ } -+ -+ if (!(orig_type = g_object_get_data (G_OBJECT (comb), -+ "original_cntx"))) { -+ return; -+ } -+ orig_type = g_strdup (orig_type); -+ -+ selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s); -+ tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL); -+ g_free (orig_type); -+ -+ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); -+ g_free (tmp); -+} -+ -+static char * -+cust_type_next_line (GIOChannel *ioc_ctypes) -+{ -+ char *data; -+ gsize term; -+ GError *errc; -+ -+ data = NULL; -+ term = 0; -+ errc = NULL; -+ -+ if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data, -+ NULL, &term, &errc)) { -+ data[term] = 0; -+ return data; -+ } -+ -+ return NULL; -+} -+ -+static GSList * -+selinux__type_list (void) -+{ -+ static GSList *cust_types; -+ static time_t file_mtime; -+ const char *fname_ctypes; -+ struct stat buf; -+ GIOChannel *ioc_ctypes; -+ GError *errc; -+ GSList *scan; -+ int fd; -+ -+#ifndef HAVE_SELINUX -+ if (cust_types) { -+ return cust_types; -+ } -+#else -+ fname_ctypes = selinux_customizable_types_path (); -+ if (cust_types && file_mtime && !stat (fname_ctypes, &buf) && -+ (file_mtime == buf.st_mtime)) { -+ return cust_types; -+ } -+#endif -+ -+ if (cust_types) { -+ for (scan = cust_types; scan; scan = scan->next) { -+ g_free (scan->data); -+ } -+ g_slist_free (cust_types); -+ cust_types = NULL; -+ } -+ -+ cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t")); -+ cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t")); -+ /* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */ -+ -+#ifdef HAVE_SELINUX -+ /* read types, one per line... */ -+ fname_ctypes = selinux_customizable_types_path (); -+ errc = NULL; -+ if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) { -+ char *data = NULL; -+ -+ while ((data = cust_type_next_line (ioc_ctypes))) { -+ cust_types = g_slist_prepend (cust_types, data); -+ } -+ -+ fd = g_io_channel_unix_get_fd (ioc_ctypes); -+ if (!fstat (fd, &buf)) { -+ file_mtime = buf.st_mtime; -+ } -+ -+ g_io_channel_unref (ioc_ctypes); -+ } -+#endif -+ -+ return cust_types; -+} -+ -+static void -+attach_selinux_data_edit_field (GtkEntry *entry, -+ char *attr_val, char *def_attr_val) -+{ -+ GtkEntryCompletion *comp; -+ GtkCellRenderer *cell; -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ const char *dattr_u; -+ const char *dattr_r; -+ const char *dattr_t; -+ const char *dattr_s; -+ GtkListStore *store; -+ GtkTreeIter iter; -+ GSList *scan; -+ int width; -+ int owidth; -+ int twidth; -+ -+ attr_val = g_strdup (attr_val); /* so we can alter it... */ -+ def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */ -+ -+ /* do completion, so you don't have to type everything... */ -+ comp = gtk_entry_completion_new (); -+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); -+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), -+ 0, GTK_SORT_ASCENDING); -+ -+ gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store)); -+ cell = gtk_cell_renderer_pixbuf_new (); -+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, FALSE); -+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell, -+ "stock-id", 1, NULL); -+ gtk_entry_completion_set_text_column (comp, 0); -+ gtk_entry_set_completion (entry, comp); -+ -+ /* FIXME: default doesn't do the right thing, should it? */ -+ owidth = gtk_entry_get_width_chars (entry); -+ width = owidth; -+ -+ selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); -+ dattr_u = dattr_r = dattr_t = dattr_s = NULL; -+ if (def_attr_val) { -+ selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, -+ &dattr_t, &dattr_s); -+ } -+ -+ /* don't do it twice... */ -+ if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { -+ dattr_t = NULL; -+ } -+ -+ if (attr_t) { -+ /* highlight just the type to the end, so we can easily change it -+ * FIXME: we also highlight any Sensitivity/MCS but completion will -+ * let people put it back, and that's the only way we get completion -+ * at all -- This sucks and we need to remove Sensitivity/MCS from -+ * the edit box. Yah, more UI. */ -+ int beg = attr_t - attr_u; -+ gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1); -+ } -+ -+ for (scan = selinux__type_list(); scan; scan = scan->next) { -+ char *tmp; -+ -+ if (attr_t && !strcmp (attr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ if (dattr_t && !strcmp (dattr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ gtk_list_store_append (store, &iter); -+ tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL); -+ gtk_list_store_set (store, &iter, 0, tmp, -1); -+ -+ twidth = strlen (tmp); -+ width = MAX (twidth, width); -+ -+ g_free (tmp); -+ } -+ -+ if (dattr_t) { -+ char *tmp; -+ -+ gtk_list_store_append (store, &iter); -+ tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL); -+ gtk_list_store_set (store, &iter, 0, tmp, -+ 1, GTK_STOCK_HOME, -1); -+ -+ twidth = strlen (tmp); -+ width = MAX (twidth, width); -+ -+ g_free (tmp); -+ } -+ -+ if (attr_t) { -+ char *tmp; -+ -+ gtk_list_store_append (store, &iter); -+ tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL); -+ gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1); -+ -+ twidth = strlen (tmp); -+ width = MAX (twidth, width); -+ -+ g_free (tmp); -+ } -+ -+ g_free (attr_val); -+ g_free (def_attr_val); -+ g_object_unref (G_OBJECT (store)); -+ g_object_unref (G_OBJECT (comp)); -+ -+ if (width != owidth) { -+ gtk_entry_set_width_chars (entry, width + 2); -+ } -+} -+ -+# define HACK_TYPE(x, y) \ -+ else if (!strcmp (nice_type, x)) nice_type = y -+ -+/* hack to convert a selinux_context type into a readable string for the -+ user */ -+static const char * -+selinux__hack_conv_type (const char *type) -+{ /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon -+ * here now probably want a bunch of other types? */ -+ const char *nice_type; -+ -+ nice_type = type; -+ -+ if (0) { } -+ -+ HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration")); -+ HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)")); -+ HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data")); -+ HACK_TYPE("dhcp_etc_t", _("DHCP configuration")); -+ HACK_TYPE("dictd_etc_t", _("Dictd configuration")); -+ HACK_TYPE("dnssec_t", _("DNS secret")); -+ HACK_TYPE("etc_t", _("System configuration")); -+ HACK_TYPE("etc_aliases_t", _("Email aliases configuration")); -+ HACK_TYPE("etc_runtime_t", _("System configuration (rw)")); -+ HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon")); -+ HACK_TYPE("httpd_config_t", _("Apache-httpd configuration")); -+ HACK_TYPE("httpd_php_tmp_t", -+ _("Apache-httpd PHP module temporary data")); -+ HACK_TYPE("httpd_sys_content_t", -+ _("Read from all httpd scripts and the daemon")); -+ HACK_TYPE("httpd_sys_htaccess_t", -+ _("Apache-httpd .htaccess configuration")); -+ HACK_TYPE("httpd_sys_script_exec_t", -+ _("CGI programs with default access")); -+ HACK_TYPE("httpd_sys_script_ra_t", -+ _("CGI programs can read and append")); -+ HACK_TYPE("httpd_sys_script_ro_t", -+ _("CGI programs can read")); -+ HACK_TYPE("httpd_sys_script_rw_t", -+ _("CGI programs can read and write")); -+ HACK_TYPE("httpd_unconfined_script_exec_t", -+ _("CGI programs without any SELinux protection")); -+ HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data")); -+ HACK_TYPE("ice_tmp_t", _("ICE temporary data")); -+ HACK_TYPE("locale_t", _("Locale data")); -+ HACK_TYPE("mysql_tmp_t", _("MySQL temporary data")); -+ HACK_TYPE("named_conf_t", _("Nameserver configuration")); -+ HACK_TYPE("net_conf_t", _("Network configuration")); -+ HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data")); -+ HACK_TYPE("public_content_rw_t", -+ _("Read and write from CIFS/ftp/http/nfs/rsync")); -+ HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync")); -+ HACK_TYPE("samba_etc_t", _("Samba configuration")); -+ HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)")); -+ HACK_TYPE("staff_home_t", _("Staff user data")); -+ HACK_TYPE("staff_home_dir_t", _("Staff user home directory")); -+ HACK_TYPE("swapfile_t", _("System swapfile")); -+ HACK_TYPE("sysadm_home_t", _("Sysadmin user data")); -+ HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory")); -+ HACK_TYPE("system_cron_spool_t", _("Cron data")); -+ HACK_TYPE("tmp_t", _("Temporary data")); -+ HACK_TYPE("user_tmp_t", _("User temporary data")); -+ HACK_TYPE("user_home_t", _("User data")); -+ HACK_TYPE("user_home_dir_t", _("User home directory")); -+ HACK_TYPE("var_log_t", _("Logfile")); -+ HACK_TYPE("xen_image_t", _("Xen image")); -+ -+ return nice_type; -+} -+#undef HACK_TYPE -+ -+static void -+attach_selinux_data_popup_field (GtkComboBox *comb, -+ char *attr_val, -+ char *def_attr_val) -+{ -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ const char *dattr_u; -+ const char *dattr_r; -+ const char *dattr_t; -+ const char *dattr_s; -+ GtkListStore *store; -+ GtkTreeIter iter; -+ GSList *scan; -+ -+ attr_val = g_strdup (attr_val); /* so we can alter it... */ -+ def_attr_val = g_strdup (def_attr_val); -+ -+ /* do completion, so you don't have to type everything... */ -+ store = gtk_list_store_new (3, G_TYPE_STRING, -+ G_TYPE_STRING, G_TYPE_STRING); -+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), -+ 1, GTK_SORT_ASCENDING); -+ -+ gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store)); -+ -+ selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); -+ dattr_u = dattr_r = dattr_t = dattr_s = NULL; -+ if (def_attr_val) { -+ selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, -+ &dattr_t, &dattr_s); -+ } -+ /* don't do it twice... */ -+ if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { -+ dattr_t = NULL; -+ } -+ -+ for (scan = selinux__type_list(); scan; scan = scan->next) { -+ const char *nice_type; -+ -+ if (attr_t && !strcmp (attr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ if (dattr_t && !strcmp (dattr_t, scan->data)) -+ continue; /* don't have two entries */ -+ -+ nice_type = selinux__hack_conv_type(scan->data); -+ -+ gtk_list_store_append (store, &iter); -+ gtk_list_store_set (store, &iter, 0, scan->data, -+ 1, nice_type, -1); -+ } -+ -+ if (dattr_t) { -+ const char *nice_type; -+ -+ gtk_list_store_append (store, &iter); -+ nice_type = selinux__hack_conv_type(dattr_t); -+ gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type, -+ 2, GTK_STOCK_HOME, -1); -+ } -+ -+ if (attr_t) { -+ const char *nice_type; -+ -+ gtk_list_store_append (store, &iter); -+ nice_type = selinux__hack_conv_type(attr_t); -+ gtk_list_store_set (store, &iter, 0, attr_t, 1, nice_type, -+ 2, GTK_STOCK_OK, -1); -+ gtk_combo_box_set_active_iter (comb, &iter); -+ } -+ -+ g_free (attr_val); -+ g_free (def_attr_val); -+ g_object_unref (G_OBJECT (store)); -+} -+ -+static char * -+selinux__matchpathcon (GList *file_list) -+{ -+ GList *scan; -+ -+ for (scan = file_list; scan != NULL; scan = scan->next) { -+ NautilusFile *file; -+ -+ file = NAUTILUS_FILE (scan->data); -+ if (!nautilus_file_is_gone (file)) { -+ return nautilus_file_get_selinux_matchpathcon (file); -+ } -+ } -+ -+ return NULL; -+} -+ -+static void -+attach_selinux_edit_field (FMPropertiesWindow *window, -+ GtkTable *table, -+ int row, -+ int column, -+ const char *file_attribute_name, -+ const char *inconsistent_string, -+ gboolean show_original, -+ GtkLabel *lab_title) -+{ -+ GtkEntry *entry; -+ GList *file_list; -+ char *attr_value; -+ char *def_attr_value; -+ -+ if (show_original) { -+ file_list = window->details->original_files; -+ } else { -+ file_list = window->details->target_files; -+ } -+ -+ attr_value = file_list_get_string_attribute (file_list, -+ file_attribute_name, -+ inconsistent_string); -+ if ( strcmp (attr_value, inconsistent_string) && -+ !strcmp (file_attribute_name, "selinux_context")) { -+ def_attr_value = selinux__matchpathcon (file_list); -+ } else { -+ def_attr_value = NULL; -+ } -+ -+ entry = attach_edit_label (table, row, column, attr_value); -+ gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), -+ GTK_WIDGET (entry)); -+ -+ /* Stash a copy of the file attribute name in this field for the callback's sake. */ -+ g_object_set_data_full (G_OBJECT (entry), "file_attribute", -+ g_strdup (file_attribute_name), g_free); -+ -+ g_object_set_data_full (G_OBJECT (entry), "inconsistent_string", -+ g_strdup (inconsistent_string), g_free); -+ -+ g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original)); -+ g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE)); -+ -+ g_signal_connect_object (entry, "focus_out_event", -+ G_CALLBACK (selinux_focus_out), window, 0); -+ g_signal_connect_object (entry, "activate", -+ G_CALLBACK (selinux_entry_activate), window,0); -+ -+ attach_selinux_data_edit_field (entry, attr_value, def_attr_value); -+ -+ g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value, -+ g_free); -+ -+ g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx", -+ def_attr_value, g_free); -+ -+ window->details->edit_fields = g_list_prepend (window->details->edit_fields, -+ entry); -+} -+ -+static void -+attach_selinux_popup_field (FMPropertiesWindow *window, -+ GtkTable *table, -+ int row, -+ int column, -+ const char *file_attribute_name, -+ const char *inconsistent_string, -+ gboolean show_original, -+ GtkLabel *lab_title) -+{ -+ GtkWidget *comb; -+ GtkCellRenderer *cell; -+ GList *file_list; -+ char *attr_value; -+ char *def_attr_value; -+ -+ if (show_original) { -+ file_list = window->details->original_files; -+ } else { -+ file_list = window->details->target_files; -+ } -+ -+ attr_value = file_list_get_string_attribute (file_list, -+ file_attribute_name, -+ inconsistent_string); -+ if ( strcmp (attr_value, inconsistent_string) && -+ !strcmp (file_attribute_name, "selinux_context")) { -+ def_attr_value = selinux__matchpathcon (file_list); -+ } else { -+ def_attr_value = NULL; -+ } -+ -+ comb = gtk_combo_box_new (); -+ -+ gtk_table_attach (table, comb, column, column + 1, row, row + 1, -+ GTK_FILL, 0, 0, 0); -+ -+ -+ gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb); -+ -+ /* Stash a copy of the file attribute name in this field for the callback's sake. */ -+ g_object_set_data_full (G_OBJECT (comb), "file_attribute", -+ g_strdup (file_attribute_name), g_free); -+ -+ g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original)); -+ -+ attach_selinux_data_popup_field (GTK_COMBO_BOX (comb), -+ attr_value, def_attr_value); -+ -+ g_signal_connect_object (comb, "changed", -+ G_CALLBACK (selinux_popup_activate), window, 0); -+ -+ g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value, -+ g_free); -+ -+ g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx", -+ def_attr_value, g_free); -+ -+ cell = gtk_cell_renderer_pixbuf_new (); -+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE); -+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, -+ "stock-id", 2, NULL); -+ cell = gtk_cell_renderer_text_new (); -+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE); -+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, -+ "text", 1, NULL); -+ gtk_widget_show (comb); -+ -+ g_assert (! window->details->selinux_combo); -+ -+ window->details->selinux_combo = -+ g_list_prepend (window->details->selinux_combo, comb); -+} -+ - static GtkWidget* - attach_ellipsizing_value_field (FMPropertiesWindow *window, - GtkTable *table, -@@ -2441,6 +3314,36 @@ - } - - static guint -+append_title_selinux_edit_pair (FMPropertiesWindow *window, -+ GtkTable *table, -+ const char *title, -+ const char *file_attribute_name, -+ const char *inconsistent_state, -+ gboolean show_original) -+{ -+ guint last_row; -+ GtkLabel *lab_title; -+ -+ lab_title = NULL; -+ last_row = append_title_field (table, title, &lab_title); -+ -+ if (window->details->advanced_permissions) { -+ attach_selinux_edit_field (window, table, last_row, -+ VALUE_COLUMN, file_attribute_name, -+ inconsistent_state, -+ show_original, lab_title); -+ } else { -+ -+ attach_selinux_popup_field (window, table, last_row, -+ VALUE_COLUMN, file_attribute_name, -+ inconsistent_state, -+ show_original, lab_title); -+ } -+ -+ return last_row; -+} -+ -+static guint - append_title_and_ellipsizing_value (FMPropertiesWindow *window, - GtkTable *table, - const char *title, -@@ -2902,31 +3805,6 @@ - } - - static void --start_long_operation (FMPropertiesWindow *window) --{ -- if (window->details->long_operation_underway == 0) { -- /* start long operation */ -- GdkCursor * cursor; -- -- cursor = gdk_cursor_new (GDK_WATCH); -- gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); -- gdk_cursor_unref (cursor); -- } -- window->details->long_operation_underway ++; --} -- --static void --end_long_operation (FMPropertiesWindow *window) --{ -- if (GTK_WIDGET (window)->window != NULL && -- window->details->long_operation_underway == 1) { -- /* finished !! */ -- gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); -- } -- window->details->long_operation_underway--; --} -- --static void - permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) - { - FMPropertiesWindow *window; -@@ -4053,14 +4931,16 @@ - GnomeVFSFilePermissions file_permission, file_permission_mask; - GnomeVFSFilePermissions dir_permission, dir_permission_mask; - GnomeVFSFilePermissions vfs_mask, vfs_new_perm, p; -- GtkWidget *button, *combo; -+ char *context; -+ GtkWidget *button; -+ GtkComboBox *combo; - gboolean active, is_folder, is_special, use_original; - GList *l; - GtkTreeModel *model; - GtkTreeIter iter; - PermissionType type; - int new_perm, mask; -- -+ - file_permission = 0; - file_permission_mask = 0; - dir_permission = 0; -@@ -4097,9 +4977,9 @@ - } - /* Simple mode, minus exec checkbox */ - for (l = window->details->permission_combos; l != NULL; l = l->next) { -- combo = l->data; -+ combo = GTK_COMBO_BOX (l->data); - -- if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { -+ if (!gtk_combo_box_get_active_iter (combo, &iter)) { - continue; - } - -@@ -4107,7 +4987,7 @@ - is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), - "is-folder")); - -- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); -+ model = gtk_combo_box_get_model (combo); - gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1); - if (use_original) { - continue; -@@ -4130,12 +5010,53 @@ - } - } - -+ /* get the SELinux context... */ -+ context = NULL; -+ if (window->details->advanced_permissions && -+ window->details->edit_fields) { /* advanced mode */ -+ GtkEditable *efield; -+ -+ efield = window->details->edit_fields->data; -+ context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1); -+ } else if (!window->details->advanced_permissions && -+ window->details->selinux_combo) { /* simple mode */ -+ char *cntx_type; -+ char *orig_type; -+ const char *attr_u; -+ const char *attr_r; -+ const char *attr_t; -+ const char *attr_s; -+ -+ combo = GTK_COMBO_BOX (window->details->selinux_combo->data); -+ -+ if (!gtk_combo_box_get_active_iter (combo, &iter)) { -+ return; -+ } else { -+ GtkTreeModel *model = gtk_combo_box_get_model (combo); -+ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); -+ } -+ if (!(orig_type = g_object_get_data (G_OBJECT (combo), -+ "original_cntx"))) { -+ return; -+ } -+ -+ orig_type = g_strdup (orig_type); -+ -+ selinux_split_cntx (orig_type, -+ &attr_u, &attr_r, &attr_t, &attr_s); -+ context = g_strjoin (":", -+ attr_u, attr_r, cntx_type, attr_s, NULL); -+ g_free (orig_type); -+ } -+ - for (l = window->details->target_files; l != NULL; l = l->next) { - NautilusFile *file; - char *uri; - - file = NAUTILUS_FILE (l->data); - -+ /* assume permissions setting allows context setting... -+ * we can't really do much else due to race conditions anyway */ - if (nautilus_file_is_directory (file) && - nautilus_file_can_set_permissions (file)) { - uri = nautilus_file_get_uri (file); -@@ -4146,11 +5067,13 @@ - file_permission_mask, - dir_permission, - dir_permission_mask, -+ context, - set_recursive_permissions_done, - window); - g_free (uri); - } - } -+ g_free (context); - } - - static void -@@ -4197,11 +5120,20 @@ - } - - gtk_table_set_row_spacing (page_table, page_table->nrows - 1, 18); -- -- append_title_value_pair -- (window, page_table, _("SELinux Context:"), -- "selinux_context", _("--"), -- FALSE); -+ -+ if (!is_multi_file_window (window) || -+ multi_have_same_selinux_context (window)) -+ append_title_selinux_edit_pair -+ (window, page_table, _("_SELinux Context:"), -+ "selinux_context", _("--"), -+ FALSE); -+ else /* Static text in this case. */ -+ append_title_value_pair (window, page_table, -+ _("_SELinux Context:"), -+ "selinux_context", _("--"), -+ FALSE); -+ -+ - append_title_value_pair - (window, page_table, _("Last changed:"), - "date_permissions", _("--"), diff --git a/nautilus-2.18.0.1-file-and-directory-list-leak.patch b/nautilus-2.18.0.1-file-and-directory-list-leak.patch deleted file mode 100644 index fc66af8..0000000 --- a/nautilus-2.18.0.1-file-and-directory-list-leak.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- nautilus-2.18.0.1/src/file-manager/fm-directory-view.c.file-and-directory-list-leak 2007-04-09 19:28:53.000000000 +0200 -+++ nautilus-2.18.0.1/src/file-manager/fm-directory-view.c 2007-04-09 19:29:04.000000000 +0200 -@@ -519,6 +519,8 @@ - for (l = list; l != NULL; l = l->next) { - file_and_directory_free (l->data); - } -+ -+ g_list_free (list); - } - - static gboolean diff --git a/nautilus-2.19.2-selinux.patch b/nautilus-2.19.2-selinux.patch new file mode 100644 index 0000000..49089ed --- /dev/null +++ b/nautilus-2.19.2-selinux.patch @@ -0,0 +1,1665 @@ +--- nautilus-2.19.2/src/file-manager/fm-error-reporting.c.selinux 2007-04-03 06:08:04.000000000 -0400 ++++ nautilus-2.19.2/src/file-manager/fm-error-reporting.c 2007-05-19 22:20:22.000000000 -0400 +@@ -252,6 +252,38 @@ fm_report_error_setting_permissions (Nau + g_free (message); + } + ++void ++fm_report_error_setting_selinux (NautilusFile *file, ++ GnomeVFSResult error, ++ GtkWindow *parent_window) ++{ ++ char *file_name; ++ char *message; ++ ++ if (error == GNOME_VFS_OK) { ++ return; ++ } ++ ++ file_name = nautilus_file_get_display_name (file); ++ ++ switch (error) { ++ case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM: ++ message = g_strdup_printf (_("Couldn't change the SELinux security context of \"%s\" because it is on a read-only disk"), ++ file_name); ++ break; ++ default: ++ /* We should invent decent error messages for every case we actually experience. */ ++ g_warning ("Hit unhandled case %d (%s) in fm_report_error_setting_permissions", ++ error, gnome_vfs_result_to_string (error)); ++ message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\"."), file_name); ++ } ++ ++ eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window); ++ ++ g_free (file_name); ++ g_free (message); ++} ++ + typedef struct _FMRenameData { + char *name; + NautilusFileOperationCallback callback; +--- nautilus-2.19.2/src/file-manager/fm-error-reporting.h.selinux 2007-04-03 06:08:04.000000000 -0400 ++++ nautilus-2.19.2/src/file-manager/fm-error-reporting.h 2007-05-19 22:20:22.000000000 -0400 +@@ -39,7 +39,10 @@ void fm_report_error_renaming_file + GnomeVFSResult error_code, + GtkWindow *parent_window); + void fm_report_error_setting_permissions (NautilusFile *file, +- GnomeVFSResult error_code, ++ GnomeVFSResult error_code, ++ GtkWindow *parent_window); ++void fm_report_error_setting_selinux (NautilusFile *file, ++ GnomeVFSResult error_code, + GtkWindow *parent_window); + void fm_report_error_setting_owner (NautilusFile *file, + GnomeVFSResult error_code, +--- nautilus-2.19.2/src/file-manager/fm-properties-window.c.selinux 2007-05-02 08:40:07.000000000 -0400 ++++ nautilus-2.19.2/src/file-manager/fm-properties-window.c 2007-05-19 22:22:52.000000000 -0400 +@@ -111,6 +111,10 @@ + #define FREE_STROKE_G 0.396078431 + #define FREE_STROKE_B 0.643137255 + ++#ifdef HAVE_SELINUX ++# include ++#endif ++ + #define PREVIEW_IMAGE_WIDTH 96 + + #define ROW_PAD 6 +@@ -130,7 +134,7 @@ struct FMPropertiesWindowDetails { + + GtkWidget *icon_button; + GtkWidget *icon_image; +- GtkWidget *icon_chooser; ++ GtkWidget *icon_chooser; + + GtkWidget *name_label; + GtkWidget *name_field; +@@ -152,12 +156,15 @@ struct FMPropertiesWindowDetails { + unsigned int owner_change_timeout; + + GList *permission_buttons; +- GList *permission_combos; ++ GList *permission_combos; /* how is this deallocated???? */ ++ GList *selinux_combo; + GHashTable *initial_permissions; + gboolean has_recursive_apply; + + GList *value_fields; + ++ GList *edit_fields; ++ + GList *mime_list; + + gboolean deep_count_finished; +@@ -239,6 +246,10 @@ static void permission_combo_update + GtkComboBox *combo); + static void value_field_update (FMPropertiesWindow *window, + GtkLabel *field); ++static void edit_field_update (FMPropertiesWindow *window, ++ GtkEntry *field); ++static void popup_field_update (FMPropertiesWindow *window, ++ GtkComboBox *entry); + static void properties_window_update (FMPropertiesWindow *window, + GList *files); + static void is_directory_ready_callback (NautilusFile *file, +@@ -269,9 +280,31 @@ static GtkLabel *attach_ellipsizing_valu + + static GtkWidget* create_pie_widget (FMPropertiesWindow *window); + ++static void attach_selinux_data_edit_field (GtkEntry *entry, ++ char *attr_value, ++ char *def_attr_value); ++static void attach_selinux_data_popup_field (GtkComboBox *comb, ++ char *attr_val, ++ char *def_attr_val); ++ + G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_WINDOW); + #define parent_class fm_properties_window_parent_class + ++static void ++maybe_gtk_entry_set_text (GtkEntry *entry, const char *val) ++{ ++ char *old_val; ++ ++ g_assert (GTK_IS_ENTRY (entry)); ++ ++ old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); ++ ++ if (strcmp (old_val, val) != 0) { ++ gtk_entry_set_text (entry, val); ++ } ++ g_free(old_val); ++} ++ + static gboolean + is_multi_file_window (FMPropertiesWindow *window) + { +@@ -292,6 +325,39 @@ is_multi_file_window (FMPropertiesWindow + return FALSE; + } + ++static gboolean ++multi_have_same_selinux_context (FMPropertiesWindow *window) ++{ ++ GList *l; ++ char *cntx; ++ ++ cntx = NULL; ++ for (l = window->details->original_files; l != NULL; l = l->next) { ++ NautilusFile *file; ++ ++ file = NAUTILUS_FILE (l->data); ++ if (!nautilus_file_is_gone (file)) { ++ char *tmp; ++ ++ tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context"); ++ if (!cntx) { ++ cntx = tmp; ++ } else if (strcmp (cntx, tmp)) { ++ g_free (tmp); ++ g_free (cntx); ++ return FALSE; ++ } ++ else { ++ g_free (tmp); ++ } ++ } ++ } ++ ++ g_free (cntx); ++ ++ return TRUE; ++} ++ + static int + get_not_gone_original_file_count (FMPropertiesWindow *window) + { +@@ -529,7 +595,7 @@ fm_properties_window_drag_data_received + return; + } + +- uris = g_strsplit (selection_data->data, "\r\n", 0); ++ uris = g_strsplit ((char *) selection_data->data, "\r\n", 0); + exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); + + +@@ -610,7 +676,7 @@ create_image_widget (FMPropertiesWindow + + static void + set_name_field (FMPropertiesWindow *window, const gchar *original_name, +- const gchar *name) ++ const gchar *name) + { + gboolean new_widget; + gboolean use_label; +@@ -676,11 +742,7 @@ set_name_field (FMPropertiesWindow *wind + * currently showing. This causes minimal ripples (e.g. + * selection change). + */ +- gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1); +- if (strcmp (displayed_name, name) != 0) { +- gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); +- } +- g_free (displayed_name); ++ maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); + } + } + } +@@ -756,7 +818,6 @@ static void + name_field_restore_original_name (NautilusEntry *name_field) + { + const char *original_name; +- char *displayed_name; + + original_name = (const char *) g_object_get_data (G_OBJECT (name_field), + "original_name"); +@@ -765,14 +826,8 @@ name_field_restore_original_name (Nautil + return; + } + +- displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1); +- +- if (strcmp (original_name, displayed_name) != 0) { +- gtk_entry_set_text (GTK_ENTRY (name_field), original_name); +- } ++ maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name); + nautilus_entry_select_all (name_field); +- +- g_free (displayed_name); + } + + static void +@@ -885,7 +940,7 @@ file_has_keyword (NautilusFile *file, co + word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp); + eel_g_list_free_deep (keywords); + +- return (word != NULL); ++ return word != NULL; + } + + static void +@@ -1152,7 +1207,7 @@ mime_list_equal (GList *a, GList *b) + b = b->next; + } + +- return (a == b); ++ return a == b; + } + + static GList * +@@ -1234,6 +1289,14 @@ properties_window_update (FMPropertiesWi + for (l = window->details->value_fields; l != NULL; l = l->next) { + value_field_update (window, GTK_LABEL (l->data)); + } ++ ++ for (l = window->details->edit_fields; l != NULL; l = l->next) { ++ edit_field_update (window, GTK_ENTRY (l->data)); ++ } ++ ++ for (l = window->details->selinux_combo; l != NULL; l = l->next) { ++ popup_field_update (window, GTK_COMBO_BOX (l->data)); ++ } + } + + mime_list = get_mime_list (window); +@@ -1403,6 +1466,111 @@ value_field_update (FMPropertiesWindow * + window->details->target_files)); + } + ++static void ++edit_field_update_internal (GtkEntry *entry, ++ GList *file_list) ++{ ++ const char *attr_name; ++ char *attr_value; ++ char *def_attr_value; ++ char *inconsistent_string; ++ ++ g_assert (GTK_IS_ENTRY (entry)); ++ ++ attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute"); ++ inconsistent_string = g_object_get_data (G_OBJECT (entry), ++ "inconsistent_string"); ++ def_attr_value = g_object_get_data (G_OBJECT (entry), ++ "matchpathcon_cntx"); ++ ++ attr_value = file_list_get_string_attribute (file_list, attr_name, ++ inconsistent_string); ++ ++ maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value); ++ ++ /* JFIXME: this isn't generic, *sigh* ... */ ++ attach_selinux_data_edit_field (entry, attr_value, def_attr_value); ++ g_free (attr_value); ++} ++ ++static void ++edit_field_update (FMPropertiesWindow *window, GtkEntry *entry) ++{ ++ gboolean use_original; ++ ++ if (gtk_widget_is_focus (GTK_WIDGET (entry))) { ++ return; ++ } ++ ++ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original")); ++ ++ edit_field_update_internal (entry, ++ (use_original ? ++ window->details->original_files : ++ window->details->target_files)); ++} ++ ++static void ++popup_field_update_internal (GtkComboBox *combo, ++ GList *file_list) ++{ ++ const char *attr_name; ++ char *attr_value; ++ char *def_attr_value; ++ char *inconsistent_string; ++ char *cntx_type; ++ GtkTreeIter iter; ++ ++ g_assert (GTK_IS_COMBO_BOX (combo)); ++ ++ if (gtk_widget_is_focus (GTK_WIDGET (combo))) { ++ return; ++ } ++ ++ attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute"); ++ inconsistent_string = g_object_get_data (G_OBJECT (combo), ++ "inconsistent_string"); ++ def_attr_value = g_object_get_data (G_OBJECT (combo), ++ "matchpathcon_cntx"); ++ ++ attr_value = file_list_get_string_attribute (file_list, attr_name, ++ inconsistent_string); ++ ++ /* JFIXME: this isn't generic, *sigh* ... */ ++ ++ if (gtk_combo_box_get_active_iter (combo, &iter)) { ++ GtkTreeModel *model = gtk_combo_box_get_model (combo); ++ ++ /* don't update, if it's identical */ ++ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); ++ if (cntx_type && strcmp (cntx_type, attr_value) == 0) { ++ g_free (attr_value); ++ return; ++ } ++ } ++ ++ attach_selinux_data_popup_field (combo, attr_value, def_attr_value); ++ ++ g_free (attr_value); ++} ++ ++static void ++popup_field_update (FMPropertiesWindow *window, GtkComboBox *combo) ++{ ++ gboolean use_original; ++ ++ if (window->details->selinux_combo) { ++ return; /* FIXME: must be true: horrible UI, if working */ ++ } ++ ++ use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original")); ++ ++ popup_field_update_internal (combo, ++ (use_original ? ++ window->details->original_files : ++ window->details->target_files)); ++} ++ + static GtkLabel * + attach_label (GtkTable *table, + int row, +@@ -1457,6 +1625,45 @@ attach_value_label (GtkTable *table, + return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); + } + ++static GtkEntry * ++attach_edit (GtkTable *table, ++ int row, ++ int column, ++ const char *initial_text, ++ gboolean right_aligned, ++ gboolean bold, ++ gboolean ellipsize_text, ++ gboolean selectable, ++ gboolean mnemonic) ++{ ++ GtkWidget *entry_field; ++ ++ entry_field = nautilus_entry_new (); ++ gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text); ++ ++ gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0); ++ gtk_widget_show (entry_field); ++ gtk_table_attach (table, entry_field, ++ column, column + 1, ++ row, row + 1, ++ ellipsize_text ++ ? GTK_FILL | GTK_EXPAND ++ : GTK_FILL, ++ 0, ++ 0, 0); ++ ++ return GTK_ENTRY (entry_field); ++} ++ ++static GtkEntry * ++attach_edit_label (GtkTable *table, ++ int row, ++ int column, ++ const char *initial_text) ++{ ++ return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); ++} ++ + static GtkLabel * + attach_ellipsizing_value_label (GtkTable *table, + int row, +@@ -1515,6 +1722,672 @@ attach_value_field (FMPropertiesWindow * + FALSE); + } + ++static void ++start_long_operation (FMPropertiesWindow *window) ++{ ++ if (window->details->long_operation_underway == 0) { ++ /* start long operation */ ++ GdkCursor * cursor; ++ ++ cursor = gdk_cursor_new (GDK_WATCH); ++ gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); ++ gdk_cursor_unref (cursor); ++ } ++ window->details->long_operation_underway ++; ++} ++ ++static void ++end_long_operation (FMPropertiesWindow *window) ++{ ++ if (GTK_WIDGET (window)->window != NULL && ++ window->details->long_operation_underway == 1) { ++ /* finished !! */ ++ gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); ++ } ++ window->details->long_operation_underway--; ++} ++ ++static void ++selinux_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) ++{ ++ FMPropertiesWindow *window; ++ g_assert (callback_data != NULL); ++ ++ window = FM_PROPERTIES_WINDOW (callback_data); ++ end_long_operation (window); ++ ++ /* Report the error if it's an error. */ ++ fm_report_error_setting_selinux (file, result, NULL); ++ ++ g_object_unref (window); ++} ++ ++static void ++selinux_done_editing (FMPropertiesWindow *window, char *selinux_context) ++{ ++ GList *l; ++ ++ /* Accept changes. */ ++ for (l = window->details->target_files; l != NULL; l = l->next) { ++ NautilusFile *file; ++ ++ file = NAUTILUS_FILE (l->data); ++ ++ start_long_operation (window); ++ g_object_ref (window); ++ nautilus_file_set_selinux_context (file, selinux_context, ++ selinux_change_callback, ++ window); ++ } ++} ++ ++static gboolean ++selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data) ++{ ++ g_assert (NAUTILUS_IS_ENTRY (entry)); ++ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); ++ ++ if (GTK_WIDGET_SENSITIVE (entry)) { ++ char *tmp; ++ ++ tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); ++ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); ++ g_free (tmp); ++ } ++ ++ return FALSE; ++} ++ ++static void ++selinux_entry_activate (NautilusEntry *entry, gpointer cb_data) ++{ ++ char *tmp; ++ ++ g_assert (NAUTILUS_IS_ENTRY (entry)); ++ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); ++ ++ tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); ++ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); ++ g_free (tmp); ++ ++ nautilus_entry_select_all_at_idle (entry); ++} ++ ++/* NOTE: This modifies cntx */ ++static void ++selinux_split_cntx (char *cntx, ++ const char **ret_attr_u, ++ const char **ret_attr_r, ++ const char **ret_attr_t, ++ const char **ret_attr_s) ++{ ++ const char *attr_u; ++ const char *attr_r; ++ const char *attr_t; ++ const char *attr_s; ++ ++ attr_u = cntx; ++ if (!(attr_r = strchr (attr_u, ':'))) { ++ attr_r = "object_r"; /* shouldn't happen */ ++ } else { ++ *((char *)attr_r++) = 0; ++ } ++ ++ if (!(attr_t = strchr (attr_r, ':'))) { ++ attr_t = "file_t"; /* shouldn't happen */ ++ } else { ++ *((char *)attr_t++) = 0; ++ } ++ ++ if ((attr_s = strchr (attr_t, ':'))) { ++ *((char *)attr_s++) = 0; ++ } ++ ++ *ret_attr_u = attr_u; ++ *ret_attr_r = attr_r; ++ *ret_attr_t = attr_t; ++ *ret_attr_s = attr_s; ++} ++ ++static void ++selinux_popup_activate (GtkComboBox *comb, gpointer cb_data) ++{ ++ char *cntx_type; ++ char *orig_type; ++ const char *attr_u; ++ const char *attr_r; ++ const char *attr_t; ++ const char *attr_s; ++ char *tmp; ++ GtkTreeIter iter; ++ ++ g_assert (GTK_IS_COMBO_BOX (comb)); ++ g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); ++ ++ if (!gtk_combo_box_get_active_iter (comb, &iter)) { ++ return; ++ } else { ++ ++ GtkTreeModel *model = gtk_combo_box_get_model (comb); ++ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); ++ } ++ ++ if (!(orig_type = g_object_get_data (G_OBJECT (comb), ++ "original_cntx"))) { ++ return; ++ } ++ orig_type = g_strdup (orig_type); ++ ++ selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s); ++ tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL); ++ g_free (orig_type); ++ ++ selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); ++ g_free (tmp); ++} ++ ++static char * ++cust_type_next_line (GIOChannel *ioc_ctypes) ++{ ++ char *data; ++ gsize term; ++ GError *errc; ++ ++ data = NULL; ++ term = 0; ++ errc = NULL; ++ ++ if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data, ++ NULL, &term, &errc)) { ++ data[term] = 0; ++ return data; ++ } ++ ++ return NULL; ++} ++ ++static GSList * ++selinux__type_list (void) ++{ ++ static GSList *cust_types; ++ static time_t file_mtime; ++ const char *fname_ctypes; ++ struct stat buf; ++ GIOChannel *ioc_ctypes; ++ GError *errc; ++ GSList *scan; ++ int fd; ++ ++#ifndef HAVE_SELINUX ++ if (cust_types) { ++ return cust_types; ++ } ++#else ++ fname_ctypes = selinux_customizable_types_path (); ++ if (cust_types && file_mtime && !stat (fname_ctypes, &buf) && ++ (file_mtime == buf.st_mtime)) { ++ return cust_types; ++ } ++#endif ++ ++ if (cust_types) { ++ for (scan = cust_types; scan; scan = scan->next) { ++ g_free (scan->data); ++ } ++ g_slist_free (cust_types); ++ cust_types = NULL; ++ } ++ ++ cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t")); ++ cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t")); ++ /* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */ ++ ++#ifdef HAVE_SELINUX ++ /* read types, one per line... */ ++ fname_ctypes = selinux_customizable_types_path (); ++ errc = NULL; ++ if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) { ++ char *data = NULL; ++ ++ while ((data = cust_type_next_line (ioc_ctypes))) { ++ cust_types = g_slist_prepend (cust_types, data); ++ } ++ ++ fd = g_io_channel_unix_get_fd (ioc_ctypes); ++ if (!fstat (fd, &buf)) { ++ file_mtime = buf.st_mtime; ++ } ++ ++ g_io_channel_unref (ioc_ctypes); ++ } ++#endif ++ ++ return cust_types; ++} ++ ++static void ++attach_selinux_data_edit_field (GtkEntry *entry, ++ char *attr_val, char *def_attr_val) ++{ ++ GtkEntryCompletion *comp; ++ GtkCellRenderer *cell; ++ const char *attr_u; ++ const char *attr_r; ++ const char *attr_t; ++ const char *attr_s; ++ const char *dattr_u; ++ const char *dattr_r; ++ const char *dattr_t; ++ const char *dattr_s; ++ GtkListStore *store; ++ GtkTreeIter iter; ++ GSList *scan; ++ int width; ++ int owidth; ++ int twidth; ++ ++ attr_val = g_strdup (attr_val); /* so we can alter it... */ ++ def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */ ++ ++ /* do completion, so you don't have to type everything... */ ++ comp = gtk_entry_completion_new (); ++ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); ++ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), ++ 0, GTK_SORT_ASCENDING); ++ ++ gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store)); ++ cell = gtk_cell_renderer_pixbuf_new (); ++ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, FALSE); ++ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell, ++ "stock-id", 1, NULL); ++ gtk_entry_completion_set_text_column (comp, 0); ++ gtk_entry_set_completion (entry, comp); ++ ++ /* FIXME: default doesn't do the right thing, should it? */ ++ owidth = gtk_entry_get_width_chars (entry); ++ width = owidth; ++ ++ selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); ++ dattr_u = dattr_r = dattr_t = dattr_s = NULL; ++ if (def_attr_val) { ++ selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, ++ &dattr_t, &dattr_s); ++ } ++ ++ /* don't do it twice... */ ++ if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { ++ dattr_t = NULL; ++ } ++ ++ if (attr_t) { ++ /* highlight just the type to the end, so we can easily change it ++ * FIXME: we also highlight any Sensitivity/MCS but completion will ++ * let people put it back, and that's the only way we get completion ++ * at all -- This sucks and we need to remove Sensitivity/MCS from ++ * the edit box. Yah, more UI. */ ++ int beg = attr_t - attr_u; ++ gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1); ++ } ++ ++ for (scan = selinux__type_list(); scan; scan = scan->next) { ++ char *tmp; ++ ++ if (attr_t && !strcmp (attr_t, scan->data)) ++ continue; /* don't have two entries */ ++ ++ if (dattr_t && !strcmp (dattr_t, scan->data)) ++ continue; /* don't have two entries */ ++ ++ gtk_list_store_append (store, &iter); ++ tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL); ++ gtk_list_store_set (store, &iter, 0, tmp, -1); ++ ++ twidth = strlen (tmp); ++ width = MAX (twidth, width); ++ ++ g_free (tmp); ++ } ++ ++ if (dattr_t) { ++ char *tmp; ++ ++ gtk_list_store_append (store, &iter); ++ tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL); ++ gtk_list_store_set (store, &iter, 0, tmp, ++ 1, GTK_STOCK_HOME, -1); ++ ++ twidth = strlen (tmp); ++ width = MAX (twidth, width); ++ ++ g_free (tmp); ++ } ++ ++ if (attr_t) { ++ char *tmp; ++ ++ gtk_list_store_append (store, &iter); ++ tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL); ++ gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1); ++ ++ twidth = strlen (tmp); ++ width = MAX (twidth, width); ++ ++ g_free (tmp); ++ } ++ ++ g_free (attr_val); ++ g_free (def_attr_val); ++ g_object_unref (G_OBJECT (store)); ++ g_object_unref (G_OBJECT (comp)); ++ ++ if (width != owidth) { ++ gtk_entry_set_width_chars (entry, width + 2); ++ } ++} ++ ++# define HACK_TYPE(x, y) \ ++ else if (!strcmp (nice_type, x)) nice_type = y ++ ++/* hack to convert a selinux_context type into a readable string for the ++ user */ ++static const char * ++selinux__hack_conv_type (const char *type) ++{ /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon ++ * here now probably want a bunch of other types? */ ++ const char *nice_type; ++ ++ nice_type = type; ++ ++ if (0) { } ++ ++ HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration")); ++ HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)")); ++ HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data")); ++ HACK_TYPE("dhcp_etc_t", _("DHCP configuration")); ++ HACK_TYPE("dictd_etc_t", _("Dictd configuration")); ++ HACK_TYPE("dnssec_t", _("DNS secret")); ++ HACK_TYPE("etc_t", _("System configuration")); ++ HACK_TYPE("etc_aliases_t", _("Email aliases configuration")); ++ HACK_TYPE("etc_runtime_t", _("System configuration (rw)")); ++ HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon")); ++ HACK_TYPE("httpd_config_t", _("Apache-httpd configuration")); ++ HACK_TYPE("httpd_php_tmp_t", ++ _("Apache-httpd PHP module temporary data")); ++ HACK_TYPE("httpd_sys_content_t", ++ _("Read from all httpd scripts and the daemon")); ++ HACK_TYPE("httpd_sys_htaccess_t", ++ _("Apache-httpd .htaccess configuration")); ++ HACK_TYPE("httpd_sys_script_exec_t", ++ _("CGI programs with default access")); ++ HACK_TYPE("httpd_sys_script_ra_t", ++ _("CGI programs can read and append")); ++ HACK_TYPE("httpd_sys_script_ro_t", ++ _("CGI programs can read")); ++ HACK_TYPE("httpd_sys_script_rw_t", ++ _("CGI programs can read and write")); ++ HACK_TYPE("httpd_unconfined_script_exec_t", ++ _("CGI programs without any SELinux protection")); ++ HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data")); ++ HACK_TYPE("ice_tmp_t", _("ICE temporary data")); ++ HACK_TYPE("locale_t", _("Locale data")); ++ HACK_TYPE("mysql_tmp_t", _("MySQL temporary data")); ++ HACK_TYPE("named_conf_t", _("Nameserver configuration")); ++ HACK_TYPE("net_conf_t", _("Network configuration")); ++ HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data")); ++ HACK_TYPE("public_content_rw_t", ++ _("Read and write from CIFS/ftp/http/nfs/rsync")); ++ HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync")); ++ HACK_TYPE("samba_etc_t", _("Samba configuration")); ++ HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)")); ++ HACK_TYPE("staff_home_t", _("Staff user data")); ++ HACK_TYPE("staff_home_dir_t", _("Staff user home directory")); ++ HACK_TYPE("swapfile_t", _("System swapfile")); ++ HACK_TYPE("sysadm_home_t", _("Sysadmin user data")); ++ HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory")); ++ HACK_TYPE("system_cron_spool_t", _("Cron data")); ++ HACK_TYPE("tmp_t", _("Temporary data")); ++ HACK_TYPE("user_tmp_t", _("User temporary data")); ++ HACK_TYPE("user_home_t", _("User data")); ++ HACK_TYPE("user_home_dir_t", _("User home directory")); ++ HACK_TYPE("var_log_t", _("Logfile")); ++ HACK_TYPE("xen_image_t", _("Xen image")); ++ ++ return nice_type; ++} ++#undef HACK_TYPE ++ ++static void ++attach_selinux_data_popup_field (GtkComboBox *comb, ++ char *attr_val, ++ char *def_attr_val) ++{ ++ const char *attr_u; ++ const char *attr_r; ++ const char *attr_t; ++ const char *attr_s; ++ const char *dattr_u; ++ const char *dattr_r; ++ const char *dattr_t; ++ const char *dattr_s; ++ GtkListStore *store; ++ GtkTreeIter iter; ++ GSList *scan; ++ ++ attr_val = g_strdup (attr_val); /* so we can alter it... */ ++ def_attr_val = g_strdup (def_attr_val); ++ ++ /* do completion, so you don't have to type everything... */ ++ store = gtk_list_store_new (3, G_TYPE_STRING, ++ G_TYPE_STRING, G_TYPE_STRING); ++ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), ++ 1, GTK_SORT_ASCENDING); ++ ++ gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store)); ++ ++ selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); ++ dattr_u = dattr_r = dattr_t = dattr_s = NULL; ++ if (def_attr_val) { ++ selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, ++ &dattr_t, &dattr_s); ++ } ++ /* don't do it twice... */ ++ if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { ++ dattr_t = NULL; ++ } ++ ++ for (scan = selinux__type_list(); scan; scan = scan->next) { ++ const char *nice_type; ++ ++ if (attr_t && !strcmp (attr_t, scan->data)) ++ continue; /* don't have two entries */ ++ ++ if (dattr_t && !strcmp (dattr_t, scan->data)) ++ continue; /* don't have two entries */ ++ ++ nice_type = selinux__hack_conv_type(scan->data); ++ ++ gtk_list_store_append (store, &iter); ++ gtk_list_store_set (store, &iter, 0, scan->data, ++ 1, nice_type, -1); ++ } ++ ++ if (dattr_t) { ++ const char *nice_type; ++ ++ gtk_list_store_append (store, &iter); ++ nice_type = selinux__hack_conv_type(dattr_t); ++ gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type, ++ 2, GTK_STOCK_HOME, -1); ++ } ++ ++ if (attr_t) { ++ const char *nice_type; ++ ++ gtk_list_store_append (store, &iter); ++ nice_type = selinux__hack_conv_type(attr_t); ++ gtk_list_store_set (store, &iter, 0, attr_t, 1, nice_type, ++ 2, GTK_STOCK_OK, -1); ++ gtk_combo_box_set_active_iter (comb, &iter); ++ } ++ ++ g_free (attr_val); ++ g_free (def_attr_val); ++ g_object_unref (G_OBJECT (store)); ++} ++ ++static char * ++selinux__matchpathcon (GList *file_list) ++{ ++ GList *scan; ++ ++ for (scan = file_list; scan != NULL; scan = scan->next) { ++ NautilusFile *file; ++ ++ file = NAUTILUS_FILE (scan->data); ++ if (!nautilus_file_is_gone (file)) { ++ return nautilus_file_get_selinux_matchpathcon (file); ++ } ++ } ++ ++ return NULL; ++} ++ ++static void ++attach_selinux_edit_field (FMPropertiesWindow *window, ++ GtkTable *table, ++ int row, ++ int column, ++ const char *file_attribute_name, ++ const char *inconsistent_string, ++ gboolean show_original, ++ GtkLabel *lab_title) ++{ ++ GtkEntry *entry; ++ GList *file_list; ++ char *attr_value; ++ char *def_attr_value; ++ ++ if (show_original) { ++ file_list = window->details->original_files; ++ } else { ++ file_list = window->details->target_files; ++ } ++ ++ attr_value = file_list_get_string_attribute (file_list, ++ file_attribute_name, ++ inconsistent_string); ++ if ( strcmp (attr_value, inconsistent_string) && ++ !strcmp (file_attribute_name, "selinux_context")) { ++ def_attr_value = selinux__matchpathcon (file_list); ++ } else { ++ def_attr_value = NULL; ++ } ++ ++ entry = attach_edit_label (table, row, column, attr_value); ++ gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), ++ GTK_WIDGET (entry)); ++ ++ /* Stash a copy of the file attribute name in this field for the callback's sake. */ ++ g_object_set_data_full (G_OBJECT (entry), "file_attribute", ++ g_strdup (file_attribute_name), g_free); ++ ++ g_object_set_data_full (G_OBJECT (entry), "inconsistent_string", ++ g_strdup (inconsistent_string), g_free); ++ ++ g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original)); ++ g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE)); ++ ++ g_signal_connect_object (entry, "focus_out_event", ++ G_CALLBACK (selinux_focus_out), window, 0); ++ g_signal_connect_object (entry, "activate", ++ G_CALLBACK (selinux_entry_activate), window,0); ++ ++ attach_selinux_data_edit_field (entry, attr_value, def_attr_value); ++ ++ g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value, ++ g_free); ++ ++ g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx", ++ def_attr_value, g_free); ++ ++ window->details->edit_fields = g_list_prepend (window->details->edit_fields, ++ entry); ++} ++ ++static void ++attach_selinux_popup_field (FMPropertiesWindow *window, ++ GtkTable *table, ++ int row, ++ int column, ++ const char *file_attribute_name, ++ const char *inconsistent_string, ++ gboolean show_original, ++ GtkLabel *lab_title) ++{ ++ GtkWidget *comb; ++ GtkCellRenderer *cell; ++ GList *file_list; ++ char *attr_value; ++ char *def_attr_value; ++ ++ if (show_original) { ++ file_list = window->details->original_files; ++ } else { ++ file_list = window->details->target_files; ++ } ++ ++ attr_value = file_list_get_string_attribute (file_list, ++ file_attribute_name, ++ inconsistent_string); ++ if ( strcmp (attr_value, inconsistent_string) && ++ !strcmp (file_attribute_name, "selinux_context")) { ++ def_attr_value = selinux__matchpathcon (file_list); ++ } else { ++ def_attr_value = NULL; ++ } ++ ++ comb = gtk_combo_box_new (); ++ ++ gtk_table_attach (table, comb, column, column + 1, row, row + 1, ++ GTK_FILL, 0, 0, 0); ++ ++ ++ gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb); ++ ++ /* Stash a copy of the file attribute name in this field for the callback's sake. */ ++ g_object_set_data_full (G_OBJECT (comb), "file_attribute", ++ g_strdup (file_attribute_name), g_free); ++ ++ g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original)); ++ ++ attach_selinux_data_popup_field (GTK_COMBO_BOX (comb), ++ attr_value, def_attr_value); ++ ++ g_signal_connect_object (comb, "changed", ++ G_CALLBACK (selinux_popup_activate), window, 0); ++ ++ g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value, ++ g_free); ++ ++ g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx", ++ def_attr_value, g_free); ++ ++ cell = gtk_cell_renderer_pixbuf_new (); ++ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE); ++ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, ++ "stock-id", 2, NULL); ++ cell = gtk_cell_renderer_text_new (); ++ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE); ++ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, ++ "text", 1, NULL); ++ gtk_widget_show (comb); ++ ++ g_assert (! window->details->selinux_combo); ++ ++ window->details->selinux_combo = ++ g_list_prepend (window->details->selinux_combo, comb); ++} ++ + static GtkWidget* + attach_ellipsizing_value_field (FMPropertiesWindow *window, + GtkTable *table, +@@ -2465,6 +3338,36 @@ append_title_value_pair (FMPropertiesWin + } + + static guint ++append_title_selinux_edit_pair (FMPropertiesWindow *window, ++ GtkTable *table, ++ const char *title, ++ const char *file_attribute_name, ++ const char *inconsistent_state, ++ gboolean show_original) ++{ ++ guint last_row; ++ GtkLabel *lab_title; ++ ++ lab_title = NULL; ++ last_row = append_title_field (table, title, &lab_title); ++ ++ if (window->details->advanced_permissions) { ++ attach_selinux_edit_field (window, table, last_row, ++ VALUE_COLUMN, file_attribute_name, ++ inconsistent_state, ++ show_original, lab_title); ++ } else { ++ ++ attach_selinux_popup_field (window, table, last_row, ++ VALUE_COLUMN, file_attribute_name, ++ inconsistent_state, ++ show_original, lab_title); ++ } ++ ++ return last_row; ++} ++ ++static guint + append_title_and_ellipsizing_value (FMPropertiesWindow *window, + GtkTable *table, + const char *title, +@@ -3263,31 +4166,6 @@ create_emblems_page (FMPropertiesWindow + } + + static void +-start_long_operation (FMPropertiesWindow *window) +-{ +- if (window->details->long_operation_underway == 0) { +- /* start long operation */ +- GdkCursor * cursor; +- +- cursor = gdk_cursor_new (GDK_WATCH); +- gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); +- gdk_cursor_unref (cursor); +- } +- window->details->long_operation_underway ++; +-} +- +-static void +-end_long_operation (FMPropertiesWindow *window) +-{ +- if (GTK_WIDGET (window)->window != NULL && +- window->details->long_operation_underway == 1) { +- /* finished !! */ +- gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); +- } +- window->details->long_operation_underway--; +-} +- +-static void + permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) + { + FMPropertiesWindow *window; +@@ -4414,14 +5292,16 @@ apply_recursive_clicked (GtkWidget *recu + GnomeVFSFilePermissions file_permission, file_permission_mask; + GnomeVFSFilePermissions dir_permission, dir_permission_mask; + GnomeVFSFilePermissions vfs_mask, vfs_new_perm, p; +- GtkWidget *button, *combo; ++ char *context; ++ GtkWidget *button; ++ GtkComboBox *combo; + gboolean active, is_folder, is_special, use_original; + GList *l; + GtkTreeModel *model; + GtkTreeIter iter; + PermissionType type; + int new_perm, mask; +- ++ + file_permission = 0; + file_permission_mask = 0; + dir_permission = 0; +@@ -4458,9 +5338,9 @@ apply_recursive_clicked (GtkWidget *recu + } + /* Simple mode, minus exec checkbox */ + for (l = window->details->permission_combos; l != NULL; l = l->next) { +- combo = l->data; ++ combo = GTK_COMBO_BOX (l->data); + +- if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { ++ if (!gtk_combo_box_get_active_iter (combo, &iter)) { + continue; + } + +@@ -4468,7 +5348,7 @@ apply_recursive_clicked (GtkWidget *recu + is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), + "is-folder")); + +- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); ++ model = gtk_combo_box_get_model (combo); + gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1); + if (use_original) { + continue; +@@ -4491,12 +5371,53 @@ apply_recursive_clicked (GtkWidget *recu + } + } + ++ /* get the SELinux context... */ ++ context = NULL; ++ if (window->details->advanced_permissions && ++ window->details->edit_fields) { /* advanced mode */ ++ GtkEditable *efield; ++ ++ efield = window->details->edit_fields->data; ++ context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1); ++ } else if (!window->details->advanced_permissions && ++ window->details->selinux_combo) { /* simple mode */ ++ char *cntx_type; ++ char *orig_type; ++ const char *attr_u; ++ const char *attr_r; ++ const char *attr_t; ++ const char *attr_s; ++ ++ combo = GTK_COMBO_BOX (window->details->selinux_combo->data); ++ ++ if (!gtk_combo_box_get_active_iter (combo, &iter)) { ++ return; ++ } else { ++ GtkTreeModel *model = gtk_combo_box_get_model (combo); ++ gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); ++ } ++ if (!(orig_type = g_object_get_data (G_OBJECT (combo), ++ "original_cntx"))) { ++ return; ++ } ++ ++ orig_type = g_strdup (orig_type); ++ ++ selinux_split_cntx (orig_type, ++ &attr_u, &attr_r, &attr_t, &attr_s); ++ context = g_strjoin (":", ++ attr_u, attr_r, cntx_type, attr_s, NULL); ++ g_free (orig_type); ++ } ++ + for (l = window->details->target_files; l != NULL; l = l->next) { + NautilusFile *file; + char *uri; + + file = NAUTILUS_FILE (l->data); + ++ /* assume permissions setting allows context setting... ++ * we can't really do much else due to race conditions anyway */ + if (nautilus_file_is_directory (file) && + nautilus_file_can_set_permissions (file)) { + uri = nautilus_file_get_uri (file); +@@ -4507,11 +5428,13 @@ apply_recursive_clicked (GtkWidget *recu + file_permission_mask, + dir_permission, + dir_permission_mask, ++ context, + set_recursive_permissions_done, + window); + g_free (uri); + } + } ++ g_free (context); + } + + static void +@@ -4558,11 +5481,20 @@ create_permissions_page (FMPropertiesWin + } + + gtk_table_set_row_spacing (page_table, page_table->nrows - 1, 18); +- +- append_title_value_pair +- (window, page_table, _("SELinux Context:"), +- "selinux_context", _("--"), +- FALSE); ++ ++ if (!is_multi_file_window (window) || ++ multi_have_same_selinux_context (window)) ++ append_title_selinux_edit_pair ++ (window, page_table, _("_SELinux Context:"), ++ "selinux_context", _("--"), ++ FALSE); ++ else /* Static text in this case. */ ++ append_title_value_pair (window, page_table, ++ _("_SELinux Context:"), ++ "selinux_context", _("--"), ++ FALSE); ++ ++ + append_title_value_pair + (window, page_table, _("Last changed:"), + "date_permissions", _("--"), +--- nautilus-2.19.2/libnautilus-private/nautilus-file-operations.c.selinux 2007-04-03 06:08:46.000000000 -0400 ++++ nautilus-2.19.2/libnautilus-private/nautilus-file-operations.c 2007-05-19 22:20:22.000000000 -0400 +@@ -63,6 +63,10 @@ + #include "nautilus-trash-monitor.h" + #include "nautilus-file-utilities.h" + ++#ifdef HAVE_SELINUX ++#include ++#endif ++ + typedef enum TransferKind TransferKind; + typedef struct TransferInfo TransferInfo; + typedef struct IconPositionIterator IconPositionIterator; +@@ -3181,6 +3185,7 @@ struct RecursivePermissionsInfo { + GnomeVFSFilePermissions file_mask; + GnomeVFSFilePermissions dir_permissions; + GnomeVFSFilePermissions dir_mask; ++ char *context; + NautilusSetPermissionsCallback callback; + gpointer callback_data; + }; +@@ -3208,6 +3213,8 @@ set_permissions_set_file_info (GnomeVFSA + GnomeVFSURI *uri; + char *uri_str; + struct FileInfo *file_info; ++ int flags; ++ int options; + + info = callback_data; + +@@ -3238,10 +3245,18 @@ set_permissions_set_file_info (GnomeVFSA + vfs_info->permissions = + (file_info->permissions & ~info->file_mask) | + info->file_permissions; ++ flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; ++ options = GNOME_VFS_FILE_INFO_DEFAULT; ++ if (info->context) { ++ flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; ++ vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; ++ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; ++ g_free (vfs_info->selinux_context); ++ vfs_info->selinux_context = g_strdup (info->context); ++ } + + gnome_vfs_async_set_file_info (&info->handle, uri, vfs_info, +- GNOME_VFS_SET_FILE_INFO_PERMISSIONS, +- GNOME_VFS_FILE_INFO_DEFAULT, ++ flags, options, + GNOME_VFS_PRIORITY_DEFAULT, + set_permissions_set_file_info, + info); +@@ -3249,7 +3264,6 @@ set_permissions_set_file_info (GnomeVFSA + gnome_vfs_file_info_unref (vfs_info); + g_free (file_info->name); + g_free (file_info); +- + } + + static void +@@ -3294,13 +3308,11 @@ set_permissions_got_files (GnomeVFSAsync + } + } + +- + if (result != GNOME_VFS_OK) { + /* Finished with this dir, work on the files */ + info->current_file = NULL; + set_permissions_set_file_info (NULL, GNOME_VFS_OK, NULL, info); + } +- + } + + /* Also called for the toplevel dir */ +@@ -3312,7 +3324,8 @@ set_permissions_load_dir (GnomeVFSAsyncH + { + struct RecursivePermissionsInfo *info; + char *uri_str; +- ++ int options; ++ + info = callback_data; + + if (result == GNOME_VFS_OK && handle != NULL) { +@@ -3321,9 +3334,13 @@ set_permissions_load_dir (GnomeVFSAsyncH + g_free (uri_str); + } + ++ options = GNOME_VFS_FILE_INFO_DEFAULT; ++ if (info->context) { ++ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; ++ } + gnome_vfs_async_load_directory_uri (&info->handle, + info->current_dir, +- GNOME_VFS_FILE_INFO_DEFAULT, ++ options, + 50, + GNOME_VFS_PRIORITY_DEFAULT, + set_permissions_got_files, +@@ -3335,6 +3352,8 @@ set_permissions_run (struct RecursivePer + { + struct DirInfo *dir_info; + GnomeVFSFileInfo *vfs_info; ++ int flags; ++ int options; + + gnome_vfs_uri_unref (info->current_dir); + +@@ -3342,6 +3361,7 @@ set_permissions_run (struct RecursivePer + /* No more directories, finished! */ + info->callback (info->callback_data); + /* All parts of info should be freed now */ ++ g_free (info->context); + g_free (info); + return; + } +@@ -3356,12 +3376,18 @@ set_permissions_run (struct RecursivePer + vfs_info->permissions = + (dir_info->permissions & ~info->dir_mask) | + info->dir_permissions; +- +- gnome_vfs_async_set_file_info (&info->handle, +- info->current_dir, +- vfs_info, +- GNOME_VFS_SET_FILE_INFO_PERMISSIONS, +- GNOME_VFS_FILE_INFO_DEFAULT, ++ flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; ++ options = GNOME_VFS_FILE_INFO_DEFAULT; ++ if (info->context) { ++ flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; ++ vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; ++ options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; ++ g_free (vfs_info->selinux_context); ++ vfs_info->selinux_context = g_strdup (info->context); ++ } ++ ++ gnome_vfs_async_set_file_info (&info->handle, info->current_dir, ++ vfs_info, flags, options, + GNOME_VFS_PRIORITY_DEFAULT, + set_permissions_load_dir, + info); +@@ -3376,6 +3402,7 @@ nautilus_file_set_permissions_recursive + GnomeVFSFilePermissions file_mask, + GnomeVFSFilePermissions dir_permissions, + GnomeVFSFilePermissions dir_mask, ++ const char *context, + NautilusSetPermissionsCallback callback, + gpointer callback_data) + { +@@ -3389,6 +3416,22 @@ nautilus_file_set_permissions_recursive + info->file_mask = file_mask; + info->dir_permissions = dir_permissions; + info->dir_mask = dir_mask; ++ if (context) { ++ char *rcontext; ++ ++ rcontext = info->context = NULL; ++#ifdef HAVE_SELINUX ++ /* this is really const, but prototype is wrong, *sigh* */ ++ if (selinux_trans_to_raw_context((char *)context, &rcontext)) { ++ g_error ("selinux_trans_to_raw_context: failed to allocate bytes"); ++ return; ++ } ++ info->context = g_strdup (rcontext); ++ freecon (rcontext); ++#endif ++ } else { ++ info->context = NULL; ++ } + info->callback = callback; + info->callback_data = callback_data; + +@@ -3396,6 +3439,8 @@ nautilus_file_set_permissions_recursive + + if (info->current_dir == NULL) { + info->callback (info->callback_data); ++ /* All parts of info should be freed now */ ++ g_free (info->context); + g_free (info); + return; + } +--- nautilus-2.19.2/libnautilus-private/nautilus-file-operations.h.selinux 2007-04-03 06:08:46.000000000 -0400 ++++ nautilus-2.19.2/libnautilus-private/nautilus-file-operations.h 2007-05-19 22:20:22.000000000 -0400 +@@ -82,6 +82,7 @@ void nautilus_file_set_permissions_recur + GnomeVFSFilePermissions file_mask, + GnomeVFSFilePermissions folder_permissions, + GnomeVFSFilePermissions folder_mask, ++ const char *context, + NautilusSetPermissionsCallback callback, + gpointer callback_data); + +--- nautilus-2.19.2/libnautilus-private/nautilus-file.c.selinux 2007-05-09 04:32:15.000000000 -0400 ++++ nautilus-2.19.2/libnautilus-private/nautilus-file.c 2007-05-19 22:20:22.000000000 -0400 +@@ -3589,7 +3589,7 @@ nautilus_file_can_get_selinux_context (N + * context + * @file: NautilusFile representing the file in question. + * +- * Returns: Newly allocated string ready to display to the user. ++ * Returns: Newly allocated string ready to display to the user, or NULL. + * + **/ + char * +@@ -3622,6 +3622,134 @@ nautilus_file_get_selinux_context (Nauti + return translated; + } + ++/** ++ * nautilus_file_get_selinux_matchpathcon: ++ * ++ * Get a user-displayable string representing a file's default selinux ++ * context (as from matchpathcon). Only works on local files. ++ * @file: NautilusFile representing the file in question. ++ * ++ * Returns: Newly allocated string ready to display to the user, or NULL. ++ * ++ **/ ++char * ++nautilus_file_get_selinux_matchpathcon (NautilusFile *file) ++{ ++ char *translated; ++ char *raw; ++ char *uri; ++ char *fname; ++ ++ g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); ++ ++ translated = NULL; ++#ifdef HAVE_SELINUX ++ uri = nautilus_file_get_uri (file); ++ fname = gnome_vfs_get_local_path_from_uri (uri); ++ ++ if (!fname) { ++ return NULL; ++ } ++ ++ raw = NULL; ++ if (matchpathcon (fname, file->details->info->permissions, &raw) == 0) { ++ if (selinux_raw_to_trans_context (raw, &translated) == 0) { ++ char *tmp; ++ tmp = g_strdup (translated); ++ freecon (translated); ++ translated = tmp; ++ } ++ freecon (raw); ++ } ++ ++ g_free (fname); ++ g_free (uri); ++#endif ++ ++ return translated; ++} ++ ++static void ++set_selinux_context_callback (GnomeVFSAsyncHandle *handle, ++ GnomeVFSResult result, ++ GnomeVFSFileInfo *new_info, ++ gpointer callback_data) ++{ ++ set_permissions_callback (handle, result, new_info, callback_data); ++} ++ ++void ++nautilus_file_set_selinux_context (NautilusFile *file, ++ const char *selinux_context, ++ NautilusFileOperationCallback callback, ++ gpointer callback_data) ++{ ++ Operation *op; ++ GnomeVFSURI *vfs_uri; ++ GnomeVFSFileInfo *partial_file_info; ++ GnomeVFSFileInfoOptions options; ++ char *rcontext; ++ ++ rcontext = NULL; ++ ++ /* this is probably mostly right... */ ++ if (!nautilus_file_can_set_permissions (file)) { ++ /* Claim that something changed even if the permission change failed. ++ * This makes it easier for some clients who see the "reverting" ++ * to the old permissions as "changing back". ++ */ ++ nautilus_file_changed (file); ++ (* callback) (file, GNOME_VFS_ERROR_ACCESS_DENIED, callback_data); ++ return; ++ } ++ ++ /* Test the permissions-haven't-changed case explicitly ++ * because we don't want to send the file-changed signal if ++ * nothing changed. ++ */ ++ if (file->details->info->selinux_context != NULL && ++ strcmp(selinux_context, file->details->info->selinux_context) == 0) { ++ (* callback) (file, GNOME_VFS_OK, callback_data); ++ return; ++ } ++ ++#ifdef HAVE_SELINUX ++ /* this is really const, but prototype is wrong, *sigh* */ ++ if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) { ++ (* callback) (file, GNOME_VFS_ERROR_NO_MEMORY, callback_data); ++ return; ++ } ++ selinux_context = rcontext; ++#endif ++ ++ /* Set up a context change operation. */ ++ op = operation_new (file, callback, callback_data); ++ op->use_slow_mime = file->details->got_slow_mime_type; ++ ++ options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS; ++ if (op->use_slow_mime) { ++ options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE; ++ } ++ /* Change the file-on-disk context. */ ++ partial_file_info = gnome_vfs_file_info_new (); ++ g_free (partial_file_info->selinux_context); ++ partial_file_info->selinux_context = g_strdup (selinux_context); ++ vfs_uri = nautilus_file_get_gnome_vfs_uri (file); ++ gnome_vfs_async_set_file_info (&op->handle, ++ vfs_uri, partial_file_info, ++ GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT, ++ options, ++ GNOME_VFS_PRIORITY_DEFAULT, ++ set_selinux_context_callback, op); ++ gnome_vfs_file_info_unref (partial_file_info); ++ gnome_vfs_uri_unref (vfs_uri); ++ ++#ifdef HAVE_SELINUX ++ freecon (rcontext); ++#endif ++} ++ ++ + static char * + get_real_name (const char *name, const char *gecos) + { +@@ -3824,7 +3952,7 @@ set_owner_and_group_callback (GnomeVFSAs + GnomeVFSResult result, + GnomeVFSFileInfo *new_info, + gpointer callback_data) +-{ ++{ /* FIXME: this is identical to set_permissions_callback */ + Operation *op; + + op = callback_data; +--- nautilus-2.19.2/libnautilus-private/nautilus-file.h.selinux 2007-04-03 06:08:46.000000000 -0400 ++++ nautilus-2.19.2/libnautilus-private/nautilus-file.h 2007-05-19 22:20:22.000000000 -0400 +@@ -200,6 +200,7 @@ GList * nautilus_get_all + GList * nautilus_file_get_settable_group_names (NautilusFile *file); + gboolean nautilus_file_can_get_selinux_context (NautilusFile *file); + char * nautilus_file_get_selinux_context (NautilusFile *file); ++char * nautilus_file_get_selinux_matchpathcon (NautilusFile *file); + + /* "Capabilities". */ + gboolean nautilus_file_can_read (NautilusFile *file); +@@ -226,6 +227,10 @@ void nautilus_file_se + GnomeVFSFilePermissions permissions, + NautilusFileOperationCallback callback, + gpointer callback_data); ++void nautilus_file_set_selinux_context (NautilusFile *file, ++ const char *selinux_context, ++ NautilusFileOperationCallback callback, ++ gpointer callback_data); + void nautilus_file_rename (NautilusFile *file, + const char *new_name, + NautilusFileOperationCallback callback, diff --git a/nautilus.spec b/nautilus.spec index 066048d..2bccbeb 100644 --- a/nautilus.spec +++ b/nautilus.spec @@ -18,11 +18,11 @@ Name: nautilus Summary: Nautilus is a file manager for GNOME -Version: 2.18.1 -Release: 2%{?dist} +Version: 2.19.2 +Release: 1%{?dist} License: GPL Group: User Interface/Desktops -Source: ftp://ftp.gnome.org/pub/GNOME/sources/%{name}/2.17/%{name}-%{version}.tar.bz2 +Source: http://download.gnome.org/sources/%{name}/2.19/%{name}-%{version}.tar.bz2 URL: http://www.gnome.org/projects/nautilus/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -77,14 +77,10 @@ Obsoletes: nautilus-media Patch1: nautilus-2.5.7-rhconfig.patch Patch2: nautilus-2.15.2-format.patch Patch3: background-no-delay.patch -Patch5: nautilus-2.17.90-selinux.patch +Patch5: nautilus-2.19.2-selinux.patch Patch6: nautilus-2.16.2-dynamic-search.patch - Patch7: nautilus-xdg-user-dirs.patch -#backport from svn -Patch8: nautilus-2.18.0.1-file-and-directory-list-leak.patch - %description Nautilus integrates access to files, applications, media, Internet-based resources and the Web. Nautilus delivers a dynamic and @@ -118,7 +114,6 @@ for writing nautilus extensions. %patch5 -p1 -b .selinux %patch6 -p1 -b .dynamic-search %patch7 -p0 -b .xdg-user-dirs -%patch8 -p1 -b .xdg-user-dirs %build @@ -225,6 +220,9 @@ fi %{_libdir}/*.so %changelog +* Sat May 19 2007 Matthias Clasen - 2.19.2-1 +- Update to 2.19.2 + * Wed Apr 11 2007 Alexander Larsson - 2.18.1-2 - Fix memleak (#235696) diff --git a/sources b/sources index e362d87..b0eeefb 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -e4718f37080b7d98cd5707e617d43ae6 nautilus-2.18.1.tar.bz2 +9cfca01a91c12e447c7db3418c3acd2b nautilus-2.19.2.tar.bz2