I initially hoped to resolve bug 152993 [1] with this patch, but the issue was actually another subtile metadata issue. This patch is not very well tested, it's meant to resolve one of the metadata FIXMES: +/* if a move/copy operation is in progress and metadata on the target is set during the + * async operation, we have to keep the metadata sets around until the copy/move operation + * is finished */ It may not be a good idea to include it in the 2.14 release unless it is well tested. [1] http://bugzilla.gnome.org/show_bug.cgi?id=152993 -- Christian Neumair <chris gnome-de org>
Index: libnautilus-private/nautilus-metafile.c =================================================================== RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-metafile.c,v retrieving revision 1.44 diff -u -p -r1.44 nautilus-metafile.c --- libnautilus-private/nautilus-metafile.c 12 Dec 2005 16:59:10 -0000 1.44 +++ libnautilus-private/nautilus-metafile.c 29 Jan 2006 21:29:40 -0000 @@ -52,14 +52,13 @@ /* TODO asynchronous copying/moving of metadata * - * - potential metadata loss when a deletion is scheduled, and new metadata is copied to - * this location before the old deletion is consumed - * * - if metafile read fails, and a file from that metafile is scheduled for a copy/move operation, * its associated operations are not removed from pending_copies * * */ +typedef struct _MetadataValue MetadataValue; + static char *get_file_metadata (NautilusMetafile *metafile, const char *file_name, const char *key, @@ -105,6 +104,14 @@ static void async_read_cancel static void set_metafile_contents (NautilusMetafile *metafile, xmlDocPtr metafile_contents); +static MetadataValue *metadata_value_dup (const MetadataValue *value); +static void metadata_value_destroy (MetadataValue *value); + +static gboolean nautilus_metadata_has_scheduled_copy_as_source (NautilusMetafile *metafile, + const char *file_name); +static gboolean nautilus_metadata_has_scheduled_copy_as_destination (NautilusMetafile *metafile, + const char *file_name); + BONOBO_CLASS_BOILERPLATE_FULL (NautilusMetafile, nautilus_metafile, Nautilus_Metafile, BonoboObject, BONOBO_OBJECT_TYPE) @@ -140,6 +147,15 @@ struct NautilusMetafileDetails { GnomeVFSURI *directory_vfs_uri; }; +struct _MetadataValue { + gboolean is_list; + union { + char *string; + GList *string_list; + } value; + char *default_value; +}; + static GHashTable *metafiles; static void @@ -281,6 +297,127 @@ nautilus_metafile_get (const char *direc return metafile; } +/* if a move/copy operation is in progress and metadata on the target is set during the + * async operation, we have to keep the metadata sets around until the copy/move operation + * is finished */ +static GList *pending_sets; + +typedef struct { + NautilusMetafile *metafile; + char *file_name; + char *key; + char *subkey; + MetadataValue *value; +} NautilusMetadataSet; + +static void +nautilus_metadata_set_destroy (NautilusMetadataSet *set) +{ + bonobo_object_unref (set->metafile); + g_free (set->file_name); + g_free (set->key); + g_free (set->subkey); + metadata_value_destroy (set->value); + g_free (set); +} + +static void +nautilus_metadata_schedule_set (NautilusMetafile *metafile, + const char *file_name, + const char *key, + const char *subkey, + MetadataValue *value) +{ + GList *l; + NautilusMetadataSet *set; + + g_assert (metafile != NULL); + + set = NULL; + + for (l = pending_sets; l != NULL; l = l->next) { + set = l->data; + if (set->metafile == metafile) { + break; + } + } + + if (set == NULL) { + set = g_new (NautilusMetadataSet, 1); + set->metafile = bonobo_object_ref (metafile); + set->file_name = g_strdup (file_name); + set->key = g_strdup (key); + set->subkey = g_strdup (subkey); + set->value = metadata_value_dup (value); + pending_sets = g_list_prepend (pending_sets, set); + } else { + metadata_value_destroy (set->value); + set->value = metadata_value_dup (value); + } +} + +static int +changed_set_compare (gconstpointer a, + gconstpointer b) +{ + const NautilusMetadataSet *a_set = a; + const NautilusMetadataSet *b_set = b; + + if (a_set == b_set) { + return 0; + } + + if (a_set->metafile == b_set->metafile) { + return 0; + } + + return strcmp (a_set->file_name, b_set->file_name); +} + +static void +nautilus_metadata_process_ready_sets (void) +{ + NautilusMetadataSet *set; + GList *l, *next; + GList *changed_sets; + gboolean success; + + changed_sets = NULL; + + l = pending_sets; + while (l != NULL) { + set = l->data; + + next = l->next; + + if (!nautilus_metadata_has_scheduled_copy_as_destination (set->metafile, set->file_name)) { + if (set->value->is_list) { + success = set_file_metadata_list (set->metafile, set->file_name, set->key, set->subkey, set->value->value.string_list); + } else { + success = set_file_metadata (set->metafile, set->file_name, set->key, set->value->default_value, set->value->value.string); + } + + if (!success) { + nautilus_metadata_set_destroy (set); + } else if (!g_list_find_custom (changed_sets, set, changed_set_compare)) { + changed_sets = g_list_prepend (changed_sets, set); + } + + pending_sets = g_list_delete_link (pending_sets, l); + } + + l = next; + } + + for (l = changed_sets; l != NULL; l = l->next) { + set = l->data; + call_metafile_changed_for_one_file (set->metafile, set->file_name); + nautilus_metadata_set_destroy (set); + } + + g_list_free (changed_sets); +} + static GList *pending_copies; typedef struct { @@ -326,8 +463,27 @@ nautilus_metadata_get_scheduled_copy (Na } static gboolean -nautilus_metadata_has_scheduled_copy (NautilusMetafile *source_metafile, - const char *source_file_name) +nautilus_metadata_has_scheduled_copy_as_source (NautilusMetafile *metafile, + const char *file_name) +{ + NautilusMetadataCopy *copy; + GList *l; + + for (l = pending_copies; l != NULL; l = l->next) { + copy = l->data; + + if ((copy->source_metafile == metafile) + && (strcmp (copy->source_file_name, file_name) == 0)) { + return TRUE; + } + } + + return FALSE; +} + +static gboolean +nautilus_metadata_has_scheduled_copy_as_destination (NautilusMetafile *metafile, + const char *file_name) { NautilusMetadataCopy *copy; GList *l; @@ -335,8 +491,8 @@ nautilus_metadata_has_scheduled_copy (Na for (l = pending_copies; l != NULL; l = l->next) { copy = l->data; - if ((copy->source_metafile == source_metafile) - && (strcmp (copy->source_file_name, source_file_name) == 0)) { + if ((copy->destination_metafile == metafile) + && (strcmp (copy->destination_file_name, file_name) == 0)) { return TRUE; } } @@ -444,7 +600,7 @@ nautilus_metadata_schedule_removal (Naut { NautilusMetadataRemoval *removal; - g_assert (nautilus_metadata_has_scheduled_copy (metafile, file_name)); + g_assert (nautilus_metadata_has_scheduled_copy_as_source (metafile, file_name)); removal = nautilus_metadata_get_scheduled_removal (metafile, file_name); if (removal == NULL) { @@ -468,7 +624,7 @@ nautilus_metadata_process_ready_removals next = l->next; - if (!nautilus_metadata_has_scheduled_copy (removal->metafile, removal->file_name)) { + if (!nautilus_metadata_has_scheduled_copy_as_source (removal->metafile, removal->file_name)) { real_remove_file_metadata (removal->metafile, removal->file_name); pending_removals = g_list_delete_link (pending_removals, l); @@ -897,15 +1053,6 @@ call_metafile_changed_for_one_file (Naut call_metafile_changed (metafile, &file_names); } -typedef struct { - gboolean is_list; - union { - char *string; - GList *string_list; - } value; - char *default_value; -} MetadataValue; - static char * get_metadata_from_node (xmlNode *node, const char *key, @@ -1154,6 +1303,18 @@ metadata_value_new_list (GList *metadata return value; } +static MetadataValue * +metadata_value_dup (const MetadataValue *value) +{ + if (value == NULL) { + return NULL; + } else if (value->is_list) { + return metadata_value_new_list (value->value.string_list); + } else { + return metadata_value_new (value->default_value, value->value.string); + } +} + static void metadata_value_destroy (MetadataValue *value) { @@ -1454,7 +1615,14 @@ set_file_metadata (NautilusMetafile *met g_return_val_if_fail (!eel_str_is_empty (file_name), FALSE); g_return_val_if_fail (!eel_str_is_empty (key), FALSE); - if (metafile->details->is_read) { + + if (nautilus_metadata_has_scheduled_copy_as_destination (metafile, file_name)) { + value = metadata_value_new (default_metadata, metadata); + nautilus_metadata_schedule_set (metafile, file_name, + key, NULL, value); + metadata_value_destroy (value); + return FALSE; + } else if (metafile->details->is_read) { return set_metadata_string_in_metafile (metafile, file_name, key, default_metadata, metadata); } else { @@ -1478,7 +1646,14 @@ set_file_metadata_list (NautilusMetafile g_return_val_if_fail (!eel_str_is_empty (list_key), FALSE); g_return_val_if_fail (!eel_str_is_empty (list_subkey), FALSE); - if (metafile->details->is_read) { + + if (nautilus_metadata_has_scheduled_copy_as_destination (metafile, file_name)) { + value = metadata_value_new_list (list); + nautilus_metadata_schedule_set (metafile, file_name, + list_key, list_subkey, value); + metadata_value_destroy (value); + return FALSE; + } else if (metafile->details->is_read) { return set_metadata_list_in_metafile (metafile, file_name, list_key, list_subkey, list); } else { @@ -1753,7 +1930,7 @@ remove_file_metadata (NautilusMetafile * g_return_if_fail (NAUTILUS_IS_METAFILE (metafile)); g_return_if_fail (file_name != NULL); - if (nautilus_metadata_has_scheduled_copy (metafile, file_name)) { + if (nautilus_metadata_has_scheduled_copy_as_source (metafile, file_name)) { nautilus_metadata_schedule_removal (metafile, file_name); } else { real_remove_file_metadata (metafile, file_name); @@ -1836,6 +2013,7 @@ metafile_read_done (NautilusMetafile *me metafile_read_mark_done (metafile); nautilus_metadata_process_ready_copies (); + nautilus_metadata_process_ready_sets (); nautilus_metadata_process_ready_removals (); }
Attachment:
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil