Index: libnautilus-private/nautilus-metafile.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-metafile.c,v
retrieving revision 1.41
diff -u -p -r1.41 nautilus-metafile.c
--- libnautilus-private/nautilus-metafile.c	12 Aug 2005 18:11:29 -0000	1.41
+++ libnautilus-private/nautilus-metafile.c	30 Aug 2005 19:59:16 -0000
@@ -1406,6 +1406,162 @@ nautilus_metafile_apply_pending_changes 
 	metafile->details->changes = NULL;
 }
 
+/* metafile copies are delayed until both, the source and the destination file, are read */
+static GList *pending_copies;
+
+static GList *
+get_pending_metadata_copy (NautilusMetafile *source_metafile,
+		 	   const char       *source_filename,
+			   NautilusMetafile *destination_metafile,
+			   const char       *destination_filename)
+{
+	GList *l;
+
+	for (l = pending_copies; l != NULL; l = g_list_nth (l, 4)) {
+		/* no need to strcmp, the filename strings are identical to those in pending_copies */
+		if (l->data == source_metafile
+		    && l->next->data == source_filename
+		    && l->next->data == destination_metafile
+		    && l->next->next->data == destination_filename) {
+			return l;
+		}
+	}
+
+	return NULL;
+}
+
+static gboolean
+has_pending_metadata_copy (NautilusMetafile *source_metafile,
+			   const char       *source_filename,
+			   NautilusMetafile *destination_metafile,
+			   const char       *destination_filename)
+{
+	return (get_pending_metadata_copy (source_metafile, source_filename,
+					   destination_metafile, destination_filename) != NULL);
+}
+
+static gboolean
+get_any_pending_metadata_copy_next (GList **l,
+				    NautilusMetafile   *source_or_destination_metafile,
+				    NautilusMetafile  **source_metafile,
+				    const char        **source_filename,
+				    NautilusMetafile  **destination_metafile,
+				    const char        **destination_filename)
+{
+	if (*l == NULL) {
+		*l = pending_copies;
+	} else {
+		*l = g_list_nth (*l, 4);
+	}
+
+	for (; *l != NULL; *l = g_list_nth (*l, 4)) {
+		if ((*l)->data == source_or_destination_metafile
+		    || (*l)->next->next->data == source_or_destination_metafile) {
+			*source_metafile = (*l)->data;
+			*source_filename = (*l)->next->data;
+			*destination_metafile = (*l)->next->next->data;
+			*destination_filename = (*l)->next->next->next->data;
+			return TRUE;
+		}
+	}
+
+	*source_metafile = NULL;
+	*source_filename = NULL;
+	*destination_metafile = NULL;
+	*destination_filename = NULL;
+
+	return FALSE;
+}
+
+static void
+schedule_metadata_copy (NautilusMetafile *source_metafile,
+			const char       *source_filename,
+			NautilusMetafile *destination_metafile,
+			const char       *destination_filename)
+{
+	if (has_pending_metadata_copy (source_metafile, source_filename,
+				       destination_metafile, destination_filename)) {
+		return;
+	}
+
+	pending_copies = g_list_prepend (pending_copies, g_strdup (destination_filename));
+	pending_copies = g_list_prepend (pending_copies, bonobo_object_ref (BONOBO_OBJECT (destination_metafile)));
+	pending_copies = g_list_prepend (pending_copies, g_strdup (source_filename));
+	pending_copies = g_list_prepend (pending_copies, bonobo_object_ref (BONOBO_OBJECT (source_metafile)));
+}
+
+static gboolean
+unschedule_metadata_copy (NautilusMetafile *source,
+			  const char       *source_filename,
+			  NautilusMetafile *destination,
+			  const char       *destination_filename)
+{
+	GList *l;
+
+	l = get_pending_metadata_copy (source, source_filename, destination, destination_filename);
+	if (l != NULL) {
+		/* destination_filename */
+		g_free (l->next->next->next->data);
+		l = g_list_delete_link (l, l->next->next->next);
+		/* destination metafile */
+		bonobo_object_unref (BONOBO_OBJECT (l->next->next->data));
+		l = g_list_delete_link (l, l->next->next);
+		/* source filename */
+		g_free (l->next->data);
+		l = g_list_delete_link (l, l->next);
+		/* source metafile */
+		bonobo_object_unref (BONOBO_OBJECT (l->data));
+		pending_copies = g_list_delete_link (pending_copies, l);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+unschedule_pending_metadata_copies (NautilusMetafile *metafile)
+{
+	GList *l;
+	NautilusMetafile *source_metafile, *destination_metafile;
+	const char *source_filename, *destination_filename;
+
+	l = NULL;
+	while (get_any_pending_metadata_copy_next
+		(&l, metafile,
+		 &source_metafile, &source_filename,
+		 &destination_metafile, &destination_filename)) {
+		unschedule_metadata_copy (source_metafile, source_filename,
+					  destination_metafile, destination_filename);
+	}
+}
+
+static void
+process_pending_metadata_copies (NautilusMetafile *metafile)
+{
+	GList *l;
+	NautilusMetafile *source_metafile, *destination_metafile;
+	const char *source_filename, *destination_filename;
+
+	l = NULL;
+	while (get_any_pending_metadata_copy_next
+		(&l, metafile,
+		 &source_metafile, &source_filename,
+		 &destination_metafile, &destination_filename)) {
+		if (!source_metafile->details->is_read
+		    || !destination_metafile->details->is_read) {
+			continue;
+		}
+
+		unschedule_metadata_copy (source_metafile, source_filename,
+					  destination_metafile, destination_filename);
+		copy_file_metadata (source_metafile,
+				    source_filename,
+				    destination_metafile,
+				    destination_filename);
+	}
+}
+
+
 static void
 copy_file_metadata (NautilusMetafile *source_metafile,
 		    const char *source_file_name,
@@ -1420,10 +1576,18 @@ copy_file_metadata (NautilusMetafile *so
 	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.
-	 */
+	if (!source_metafile->details->is_read
+	    || !destination_metafile->details->is_read) {
+		schedule_metadata_copy (source_metafile, source_file_name,
+					destination_metafile, destination_file_name);
+		if (!source_metafile->details->is_read) {
+			async_read_start (source_metafile);
+		} else {
+			async_read_start (destination_metafile);
+		}
+
+		return;
+	}
 
 	remove_file_metadata
 		(destination_metafile, destination_file_name);
@@ -1431,20 +1595,13 @@ copy_file_metadata (NautilusMetafile *so
 
 	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);
 	}
 
 	hash = source_metafile->details->changes;
@@ -1594,7 +1751,6 @@ metafile_read_failed (NautilusMetafile *
 
 	metafile_read_done (metafile);
 }
-
 static void
 metafile_read_done_callback (GnomeVFSResult result,
 			     GnomeVFSFileSize file_size,
@@ -1611,6 +1767,7 @@ metafile_read_done_callback (GnomeVFSRes
 	if (result != GNOME_VFS_OK) {
 		g_assert (file_contents == NULL);
 		metafile_read_failed (metafile);
+		unschedule_pending_metadata_copies (metafile);
 		return;
 	}
 
@@ -1618,6 +1775,7 @@ metafile_read_done_callback (GnomeVFSRes
 	if ((GnomeVFSFileSize) size != file_size) {
 		g_free (file_contents);
 		metafile_read_failed (metafile);
+		unschedule_pending_metadata_copies (metafile);
 		return;
 	}
 	
@@ -1628,6 +1786,8 @@ metafile_read_done_callback (GnomeVFSRes
 	g_free (buffer);
 
 	metafile_read_done (metafile);
+
+	process_pending_metadata_copies (metafile);
 }
 
 static void
