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