[RFC] [PATCH] Fix copying/moving of metadata where source/dest metafile are not yet read



The attached patch tries to fix moving/copying of metadata if the source
or destination metafile are not yet read. I'd like to get some feedback
whether the overall architecture/resolution proposal looks sane. Maybe
people familiar with async APIs do see some shortcomings/issues?

One question remains, though:
What should we do if the metadata reading fails? For now, the copy
process stays in pending_copies, possibly forever.

-- 
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.42
diff -u -p -r1.42 nautilus-metafile.c
--- libnautilus-private/nautilus-metafile.c	19 Sep 2005 13:51:16 -0000	1.42
+++ libnautilus-private/nautilus-metafile.c	19 Sep 2005 14:35:29 -0000
@@ -74,8 +74,14 @@ static void     copy_file_metadata      
 						    const char       *source_file_name,
 						    NautilusMetafile *destination_metafile,
 						    const char       *destination_file_name);
+static void     real_copy_file_metadata            (NautilusMetafile *source_metafile,
+						    const char       *source_file_name,
+						    NautilusMetafile *destination_metafile,
+						    const char       *destination_file_name);
 static void     remove_file_metadata               (NautilusMetafile *metafile,
 						    const char       *file_name);
+static void     real_remove_file_metadata          (NautilusMetafile *metafile,
+						    const char       *file_name);
 static void     call_metafile_changed_for_one_file (NautilusMetafile *metafile,
 						    const CORBA_char *file_name);
 static void     metafile_read_restart              (NautilusMetafile *metafile);
@@ -259,6 +265,206 @@ nautilus_metafile_get (const char *direc
 	return metafile;
 }
 
+static GList *pending_copies;
+
+typedef struct {
+	NautilusMetafile *source_metafile;
+	char             *source_file_name;
+	NautilusMetafile *destination_metafile;
+	char             *destination_file_name;
+} NautilusMetadataCopy;
+
+static gboolean
+nautilus_metadata_copy_equal (const NautilusMetadataCopy *a,
+			      const NautilusMetadataCopy *b)
+{
+	return (b->source_metafile == a->source_metafile)
+	       && (b->destination_metafile == a->destination_metafile)
+	       && (strcmp (a->source_file_name, b->source_file_name) == 0)
+	       && (strcmp (a->destination_file_name, b->destination_file_name) == 0);
+}
+
+static NautilusMetadataCopy *
+nautilus_metadata_get_scheduled_copy (NautilusMetafile *source_metafile,
+				      const char       *source_file_name,
+				      NautilusMetafile *destination_metafile,
+				      const char       *destination_file_name)
+{
+	NautilusMetadataCopy key, *copy;
+	GList *l;
+
+	key.source_metafile = source_metafile;
+	key.source_file_name = (char *) source_file_name;
+	key.destination_metafile = destination_metafile;
+	key.destination_file_name = (char *) destination_file_name;
+
+	for (l = pending_copies; l != NULL; l = l->next) {
+		copy = l->data;
+
+		if (nautilus_metadata_copy_equal (l->data, &key)) {
+			return copy;
+		}
+	}
+
+	return NULL;
+}
+
+static gboolean
+nautilus_metadata_has_scheduled_copy (NautilusMetafile *source_metafile,
+				      const char       *source_file_name)
+{
+	NautilusMetadataCopy *copy;
+	GList *l;
+
+	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)) {
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static void
+nautilus_metadata_schedule_copy (NautilusMetafile *source_metafile,
+				 const char       *source_file_name,
+				 NautilusMetafile *destination_metafile,
+				 const char       *destination_file_name)
+{
+	NautilusMetadataCopy *copy;
+
+	g_assert (!source_metafile->details->is_read || !destination_metafile->details->is_read);
+
+	copy = nautilus_metadata_get_scheduled_copy (source_metafile,
+						     source_file_name,
+						     destination_metafile,
+						     destination_file_name);
+	if (copy == NULL) {
+		copy = g_malloc (sizeof (NautilusMetadataCopy));
+		copy->source_metafile = bonobo_object_ref (source_metafile);
+		copy->source_file_name = g_strdup (source_file_name);
+		copy->destination_metafile = bonobo_object_ref (destination_metafile);
+		copy->destination_file_name = g_strdup (destination_file_name);
+
+		pending_copies = g_list_prepend (pending_copies, copy);
+
+		metafile_read_start (source_metafile);
+		metafile_read_start (destination_metafile);
+	}
+}
+
+static void
+nautilus_metadata_process_ready_copies (void)
+{
+	NautilusMetadataCopy *copy;
+	GList *l, *next;
+
+	l = pending_copies;
+	while (l != NULL) {
+		copy = l->data;
+
+		next = l->next;
+
+		if (copy->source_metafile->details->is_read
+		    && copy->destination_metafile->details->is_read) {
+			real_copy_file_metadata (copy->source_metafile, copy->source_file_name,
+						 copy->destination_metafile, copy->destination_file_name);
+
+			bonobo_object_unref (copy->source_metafile);
+			g_free (copy->source_file_name);
+			bonobo_object_unref (copy->destination_metafile);
+			g_free (copy->destination_file_name);
+			g_free (copy);
+
+			pending_copies = g_list_delete_link (pending_copies, l);
+		}
+
+		l = next;
+	}
+}
+
+static GList *pending_removals;
+
+typedef struct {
+	NautilusMetafile *metafile;
+	char             *file_name;
+} NautilusMetadataRemoval;
+
+static gboolean
+nautilus_metadata_removal_equal (const NautilusMetadataRemoval *a,
+				 const NautilusMetadataRemoval *b)
+{
+	return ((b->metafile == a->metafile)
+		&& (strcmp (a->file_name, b->file_name) == 0));
+}
+
+static NautilusMetadataRemoval *
+nautilus_metadata_get_scheduled_removal (NautilusMetafile *metafile,
+					 const char       *file_name)
+{
+	NautilusMetadataRemoval key, *removal;
+	GList *l;
+
+	key.metafile = metafile;
+	key.file_name = (char *) file_name;
+
+	for (l = pending_removals; l != NULL; l = l->next) {
+		removal = l->data;
+
+		if (nautilus_metadata_removal_equal (l->data, &key)) {
+			return removal;
+		}
+	}
+
+	return NULL;
+}
+
+static void
+nautilus_metadata_schedule_removal (NautilusMetafile *metafile,
+				    const char       *file_name)
+{
+	NautilusMetadataRemoval *removal;
+
+	g_assert (nautilus_metadata_has_scheduled_copy (metafile, file_name));
+
+	removal = nautilus_metadata_get_scheduled_removal (metafile, file_name);
+	if (removal == NULL) {
+		removal = g_malloc (sizeof (NautilusMetadataRemoval));
+		removal->metafile = bonobo_object_ref (metafile);
+		removal->file_name = g_strdup (file_name);
+
+		pending_removals = g_list_prepend (pending_removals, removal);
+	}
+}
+
+static void
+nautilus_metadata_process_ready_removals (void)
+{
+	NautilusMetadataRemoval *removal;
+	GList *l, *next;
+
+	l = pending_removals;
+	while (l != NULL) {
+		removal = l->data;
+
+		next = l->next;
+
+		if (!nautilus_metadata_has_scheduled_copy (removal->metafile, removal->file_name)) {
+			real_remove_file_metadata (removal->metafile, removal->file_name);
+
+			pending_removals = g_list_delete_link (pending_removals, l);
+
+			bonobo_object_unref (removal->metafile);
+			g_free (removal->file_name);
+		}
+
+		l = next;
+	}
+}
+
 /* FIXME
  * Right now we only limit the number of conccurrent reads.
  * We may want to consider limiting writes as well.
@@ -1407,46 +1613,27 @@ nautilus_metafile_apply_pending_changes 
 }
 
 static void
-copy_file_metadata (NautilusMetafile *source_metafile,
-		    const char *source_file_name,
-		    NautilusMetafile *destination_metafile,
-		    const char *destination_file_name)
+real_copy_file_metadata (NautilusMetafile *source_metafile,
+			 const char *source_file_name,
+			 NautilusMetafile *destination_metafile,
+			 const char *destination_file_name)
 {
 	xmlNodePtr source_node, node, root;
 	GHashTable *hash, *changes;
-	char *source_file_uri;
-	char *destination_file_uri;
 
-	g_return_if_fail (NAUTILUS_IS_METAFILE (source_metafile));
-	g_return_if_fail (source_file_name != NULL);
-	g_return_if_fail (NAUTILUS_IS_METAFILE (destination_metafile));
-	g_return_if_fail (destination_file_name != NULL);
-
-	/* FIXME bugzilla.gnome.org 43343: This does not properly
-	 * handle the case where we don't have the source metadata yet
-	 * since it's not read in.
-	 */
-
-	remove_file_metadata
-		(destination_metafile, destination_file_name);
+	real_remove_file_metadata (destination_metafile, destination_file_name);
 	g_assert (get_file_node (destination_metafile, destination_file_name, FALSE) == NULL);
 
 	source_node = get_file_node (source_metafile, source_file_name, FALSE);
 	if (source_node != NULL) {
-		if (destination_metafile->details->is_read) {
-			node = xmlCopyNode (source_node, TRUE);
-			root = create_metafile_root (destination_metafile);
-			xmlAddChild (root, node);
-			xmlSetProp (node, "name", destination_file_name);
-			set_file_node_timestamp (node);
-			g_hash_table_insert (destination_metafile->details->node_hash,
-					     xmlMemStrdup (destination_file_name), node);
-		} else {
-			/* FIXME bugzilla.gnome.org 46526: Copying data into a destination
-			 * where the metafile was not yet read is not implemented.
-			 */
-			g_warning ("not copying metadata");
-		}
+		node = xmlCopyNode (source_node, TRUE);
+		root = create_metafile_root (destination_metafile);
+		xmlAddChild (root, node);
+		xmlSetProp (node, "name", destination_file_name);
+		set_file_node_timestamp (node);
+		g_hash_table_insert (destination_metafile->details->node_hash,
+				     xmlMemStrdup (destination_file_name), node);
+		directory_request_write_metafile (destination_metafile);
 	}
 
 	hash = source_metafile->details->changes;
@@ -1458,6 +1645,34 @@ copy_file_metadata (NautilusMetafile *so
 					    changes);
 		}
 	}
+}
+
+static void
+copy_file_metadata (NautilusMetafile *source_metafile,
+		    const char *source_file_name,
+		    NautilusMetafile *destination_metafile,
+		    const char *destination_file_name)
+{
+	char *source_file_uri;
+	char *destination_file_uri;
+
+	g_return_if_fail (NAUTILUS_IS_METAFILE (source_metafile));
+	g_return_if_fail (source_file_name != NULL);
+	g_return_if_fail (NAUTILUS_IS_METAFILE (destination_metafile));
+	g_return_if_fail (destination_file_name != NULL);
+
+	if (source_metafile->details->is_read
+	    && destination_metafile->details->is_read) {
+		real_copy_file_metadata (source_metafile,
+					 source_file_name,
+					 destination_metafile,
+					 destination_file_name);
+	} else {
+		nautilus_metadata_schedule_copy (source_metafile,
+						source_file_name,
+						destination_metafile,
+						destination_file_name);
+        }
 
 	/* Copy the thumbnail for the file, if any. */
 	source_file_uri = metafile_get_file_uri (source_metafile, source_file_name);
@@ -1468,14 +1683,13 @@ copy_file_metadata (NautilusMetafile *so
 }
 
 static void
-remove_file_metadata (NautilusMetafile *metafile,
-		      const char *file_name)
+real_remove_file_metadata (NautilusMetafile *metafile,
+			   const char *file_name)
 {
 	gboolean found;
 	gpointer key, value;
 	xmlNode *file_node;
 	GHashTable *hash;
-	char *file_uri;
 
 	g_return_if_fail (NAUTILUS_IS_METAFILE (metafile));
 	g_return_if_fail (file_name != NULL);
@@ -1512,6 +1726,22 @@ remove_file_metadata (NautilusMetafile *
 			}
 		}
 	}
+}
+
+static void
+remove_file_metadata (NautilusMetafile *metafile,
+		      const char *file_name)
+{
+	char *file_uri;
+
+	g_return_if_fail (NAUTILUS_IS_METAFILE (metafile));
+	g_return_if_fail (file_name != NULL);
+
+	if (nautilus_metadata_has_scheduled_copy (metafile, file_name)) {
+		nautilus_metadata_schedule_removal (metafile, file_name);
+	} else {
+		real_remove_file_metadata (metafile, file_name);
+	}
 
 	/* Delete the thumbnails for the file, if any. */
 	file_uri = metafile_get_file_uri (metafile, file_name);
@@ -1588,6 +1818,9 @@ static void
 metafile_read_done (NautilusMetafile *metafile)
 {
 	metafile_read_mark_done (metafile);
+
+	nautilus_metadata_process_ready_copies ();
+	nautilus_metadata_process_ready_removals ();
 }
 
 static void

Attachment: signature.asc
Description: This is a digitally signed message part



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]