Hey, 

I'm re-sending this patch, since the corrected version was only sent by
mistake to Miguel, Paolo and Ben.

Ben, I applied your change, do you think it's ok?

Carlos.

El mar, 02-08-2005 a las 14:41 -0500, Carlos Alberto Cortez escribió:
> Hello,
> 
> The changes suggested by Ben are attached.
> 
> Carlos.
> 

Index: assembly.c
===================================================================
--- assembly.c	(revisión: 47896)
+++ assembly.c	(copia de trabajo)
@@ -20,6 +20,7 @@
 #include <mono/metadata/loader.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/class-internals.h>
 #include <mono/metadata/domain-internals.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/mono-uri.h>
@@ -193,6 +194,249 @@
 	}
 }
 
+static gboolean
+assembly_binding_maps_name (AssemblyBindingInfo *info, MonoAssemblyName *aname)
+{
+	if (info->public_key_token [0] == 0 || aname->public_key_token [0] == 0)
+		return FALSE;
+	
+	if (strcmp (info->name, aname->name))
+		return FALSE;
+
+	if (info->major != aname->major || info->minor != aname->minor)
+		return FALSE;
+
+	if ((info->culture != NULL) != (aname->culture != NULL))
+		return FALSE;
+	
+	if (info->culture && strcmp (info->culture, aname->culture))
+		return FALSE;
+	
+	if (strcmp (info->public_key_token, aname->public_key_token))
+		return FALSE;
+
+	return TRUE;
+}
+
+void
+assembly_binding_info_free (AssemblyBindingInfo *info)
+{
+	g_free (info->name);
+	g_free (info->culture);
+}
+
+static void
+start_element (GMarkupParseContext *context, 
+		const gchar *element_name,
+		const gchar **attribute_names,
+		const gchar **attribute_values,
+		gpointer user_data,
+		GError **error)
+{
+	AssemblyBindingInfo *info;
+	int n;
+
+	info = user_data;
+	if (!strcmp (element_name, "assemblyIdentity")) {
+		for (n = 0; attribute_names [n]; n++) {
+			const gchar *attribute_name = attribute_names [n];
+			
+			if (!strcmp (attribute_name, "name"))
+				info->name = g_strdup (attribute_values [n]);
+			else if (!strcmp (attribute_name, "publicKeyToken")) {
+				if (strlen (attribute_values [n]) == MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)
+					g_strlcpy (info->public_key_token, attribute_values [n], MONO_PUBLIC_KEY_TOKEN_LENGTH);
+			}
+			else if (!strcmp (attribute_name, "culture")) {
+				if (!strcmp (attribute_values [n], "neutral"))
+					info->culture = g_strdup ("");
+				else
+					info->culture = g_strdup (attribute_values [n]);
+			}
+		}
+	}
+	else if (!strcmp (element_name, "bindingRedirect")) {
+		for (n = 0; attribute_names [n]; n++) {
+			const gchar *attribute_name = attribute_names [n];
+
+			if (!strcmp (attribute_name, "oldVersion")) {
+				gchar **numbers, **version, **versions;
+
+				/* Invalid value */
+				if (!strcmp (attribute_values [n], ""))
+					return;
+				
+				versions = g_strsplit (attribute_values [n], "-", 2);
+				version = g_strsplit (*versions, ".", 4);
+
+				numbers = version;
+				info->old_version_bottom.major = *numbers ? atoi (*numbers++) : -1;
+				info->old_version_bottom.minor = *numbers ? atoi (*numbers++) : -1;
+				info->old_version_bottom.build = *numbers ? atoi (*numbers++) : -1;
+				info->old_version_bottom.revision = *numbers ? atoi (*numbers) : -1;
+				g_strfreev (version);
+
+				if (!*(versions + 1)) {
+					g_strfreev (versions);
+					continue;
+				}
+				
+				numbers = version = g_strsplit (*(versions + 1), ".", 4);
+				info->old_version_top.major = *numbers ? atoi (*numbers++) : -1;
+				info->old_version_top.minor = *numbers ? atoi (*numbers++) : -1;
+				info->old_version_top.build = *numbers ? atoi (*numbers++) : -1;
+				info->old_version_top.revision = *numbers ? atoi (*numbers) : 1;
+				g_strfreev (version);
+
+				g_strfreev (versions);
+			}
+			else if (!strcmp (attribute_name, "newVersion")) {
+				gchar **numbers, **version;
+
+				/* Invalid value */
+				if (!strcmp (attribute_values [n], ""))
+					return;
+
+				numbers = version = g_strsplit (attribute_values [n], ".", 4);
+				info->new_version.major = *numbers ? atoi (*numbers++) : -1;
+				info->new_version.minor = *numbers ? atoi (*numbers++) : -1;
+				info->new_version.build = *numbers ? atoi (*numbers++) : -1;
+				info->new_version.revision = *numbers ? atoi (*numbers) : -1;
+				g_strfreev (version);
+			}
+		}
+	}
+}
+
+static const GMarkupParser
+policy_parser = {
+	start_element,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static gboolean
+get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, AssemblyBindingInfo *binding_info)
+{
+	GMarkupParseContext *context;
+	MonoTableInfo *t;
+	guint32 cols [MONO_MANIFEST_SIZE];
+	const gchar *filename;
+	gchar *config_file, *subpath, *fullpath;
+	gboolean could_read;
+	gsize len;
+
+	t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
+	/* MS Impl. accepts policy assemblies with more than
+	 * one manifest resource, and only takes the first one */
+	if (t->rows < 1)
+		return FALSE;
+	
+	mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
+	if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE)
+		return FALSE;
+	
+	filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
+	g_assert (filename != NULL);
+	
+	subpath = g_path_get_dirname (image->name);
+	fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
+	could_read = g_file_get_contents (fullpath, &config_file, &len, NULL);
+	g_free (subpath);
+	g_free (fullpath);
+
+	if (!could_read)
+		return FALSE;
+	
+	binding_info->major = aname->major;
+	binding_info->minor = aname->minor;
+	binding_info->new_version.major = binding_info->new_version.minor = binding_info->new_version.build = binding_info->new_version.revision = -1;
+	binding_info->old_version_bottom = binding_info->new_version;
+	binding_info->old_version_top = binding_info->new_version;
+	
+	context = g_markup_parse_context_new (
+			&policy_parser, /* GMarkupParser */
+			0, /* flags */
+			binding_info, /* user_data */
+			NULL);
+
+	if (g_markup_parse_context_parse (context, config_file, len, NULL))
+		g_markup_parse_context_end_parse (context, NULL);
+	
+	g_markup_parse_context_free (context);
+	g_free (config_file);
+
+	/* Define the optional elements/attributes */
+	if (!binding_info->culture)
+		binding_info->culture = g_strdup ("");
+	
+	/* Check that the most important elements/attributes exist */
+	if (!binding_info->name || !binding_info->public_key_token [0] || binding_info->new_version.major < 0 || binding_info->new_version.minor < 0 || 
+			binding_info->new_version.revision < 0 || binding_info->new_version.build < 0 || binding_info->old_version_bottom.major < 0 || 
+			binding_info->old_version_bottom.minor < 0 || binding_info->old_version_bottom.revision < 0 || 
+			binding_info->old_version_bottom.build < 0 || !assembly_binding_maps_name (binding_info, aname)) {
+		
+		assembly_binding_info_free (binding_info);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int
+compare_versions (struct version *v, MonoAssemblyName *aname)
+{
+	if (v->major > aname->major)
+		return 1;
+	else if (v->major < aname->major)
+		return -1;
+
+	if (v->minor > aname->minor)
+		return 1;
+	else if (v->minor < aname->minor)
+		return -1;
+
+	if (v->build > aname->build)
+		return 1;
+	else if (v->build < aname->build)
+		return -1;
+
+	if (v->revision > aname->revision)
+		return 1;
+	else if (v->revision < aname->revision)
+		return -1;
+
+	return 0;
+}
+
+static gboolean
+check_policy_versions (AssemblyBindingInfo *info, MonoAssemblyName *name)
+{
+	/* If we have defined the top old version numbers as -1,
+	 * then we don't have a range, so we need to have the exact version
+	 * pointed by info->old_version_bottom */
+	if (info->old_version_top.major == -1 && info->old_version_top.minor == -1 &&
+			info->old_version_top.build == -1 && info->old_version_top.revision == -1) {
+	
+		if (compare_versions (&info->old_version_bottom, name) == 0)
+			return TRUE;
+
+		return FALSE;
+	}
+
+	/* Check that the version defined by name is valid for the range */
+	if (compare_versions (&info->old_version_top, name) < 0)
+		return FALSE;
+
+	/* We should be greater or equal than the small version */
+	if (compare_versions (&info->old_version_bottom, name) > 0)
+		return FALSE;
+
+	return TRUE;
+}
+
 gboolean
 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
 {
@@ -1287,6 +1531,160 @@
 	return res;
 }
 
+static MonoImage*
+mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
+{
+	MonoImage *image;
+	gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
+	gchar **paths;
+	gint32 len;
+
+	if (aname->public_key_token [0] == 0)
+		return NULL;
+
+	if (strstr (aname->name, ".dll")) {
+		len = strlen (aname->name) - 4;
+		name = g_malloc (len);
+		strncpy (name, aname->name, len);
+	} else
+		name = g_strdup (aname->name);
+	
+	if (aname->culture) {
+		culture = g_strdup (aname->culture);
+		g_strdown (culture);
+	}
+	else
+		culture = g_strdup ("");
+	
+	pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
+	version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
+	g_free (name);
+	g_free (culture);
+	
+	filename = g_strconcat (pname, ".dll", NULL);
+	subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
+	g_free (pname);
+	g_free (version);
+	g_free (filename);
+
+	image = NULL;
+	if (extra_gac_paths) {
+		paths = extra_gac_paths;
+		while (!image && *paths) {
+			fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
+					"lib", "mono", "gac", subpath, NULL);
+			image = mono_image_open (fullpath, NULL);
+			g_free (fullpath);
+			paths++;
+		}
+	}
+
+	if (image) {
+		g_free (subpath);
+		return image;
+	}
+
+	fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
+			"mono", "gac", subpath, NULL);
+	image = mono_image_open (fullpath, NULL);
+	g_free (subpath);
+	g_free (fullpath);
+	
+	return image;
+}
+
+static MonoAssemblyName*
+mono_assembly_bind_version (AssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
+{
+	memcpy (dest_name, aname, sizeof (MonoAssemblyName));
+	dest_name->major = info->new_version.major;
+	dest_name->minor = info->new_version.minor;
+	dest_name->build = info->new_version.build;
+	dest_name->revision = info->new_version.revision;
+	
+	return dest_name;
+}
+
+/* LOCKING: Assumes that we are already locked */
+static AssemblyBindingInfo*
+search_binding_loaded (MonoAssemblyName *aname)
+{
+	GSList *tmp;
+	MonoDomain *domain = mono_domain_get ();
+
+	for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
+		AssemblyBindingInfo *info = tmp->data;
+		if (assembly_binding_maps_name (info, aname))
+			return info;
+	}
+
+	return NULL;
+}
+
+static MonoAssemblyName*
+mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
+{
+	AssemblyBindingInfo *info, *info2;
+	MonoDomain *domain = mono_domain_get ();
+	MonoImage *ppimage;
+	gboolean is_policy_valid;
+
+	if (aname->public_key_token [0] == 0)
+		return aname;
+
+	mono_loader_lock ();
+	info = search_binding_loaded (aname);
+	mono_loader_unlock ();
+	if (info) {
+		if (!check_policy_versions (info, aname))
+			return aname;
+		
+		mono_assembly_bind_version (info, aname, dest_name);
+		return dest_name;
+	}
+
+	info = g_new0 (AssemblyBindingInfo, 1);
+	ppimage = mono_assembly_load_publisher_policy (aname);
+	if (!ppimage)
+		is_policy_valid = FALSE;
+	else {
+		is_policy_valid = get_publisher_policy_info (ppimage, aname, info);
+		mono_image_close (ppimage);
+	}
+
+	/* Define default error value */
+	if (!is_policy_valid) {
+		info->name = g_strdup (aname->name);
+		info->culture = g_strdup (aname->culture);
+		info->major = aname->major;
+		info->minor = aname->minor;
+		info->new_version.major = info->new_version.minor = info->new_version.build = info->new_version.revision = -1;
+		info->old_version_bottom = info->new_version;
+		info->old_version_top = info->new_version;
+		g_strlcpy (info->public_key_token, aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+	}
+	
+	mono_loader_lock ();
+	info2 = search_binding_loaded (aname);
+	if (info2) {
+		/* This binding was added by another thread 
+		 * before us */
+		assembly_binding_info_free (info);
+		g_free (info);
+		
+		info = info2;
+	} else
+		domain->assembly_bindings = g_slist_prepend (domain->assembly_bindings, info);
+		
+	mono_loader_unlock ();
+	
+	if (!is_policy_valid || !check_policy_versions (info, aname))
+		return aname;
+
+	mono_assembly_bind_version (info, aname, dest_name);
+	return dest_name;
+}
+
 /**
  * mono_assembly_load_from_gac
  *
@@ -1396,10 +1794,14 @@
 {
 	MonoAssembly *result;
 	char *fullpath, *filename;
-	MonoAssemblyName maped_aname;
+	MonoAssemblyName maped_aname, maped_name_pp;
 
 	aname = mono_assembly_remap_version (aname, &maped_aname);
 	
+	/* Reflection only assemblies don't get assembly binding */
+	if (!refonly)
+		aname = mono_assembly_apply_binding (aname, &maped_name_pp);
+	
 	result = mono_assembly_loaded_full (aname, refonly);
 	if (result)
 		return result;
Index: metadata-internals.h
===================================================================
--- metadata-internals.h	(revisión: 47896)
+++ metadata-internals.h	(copia de trabajo)
@@ -236,6 +236,25 @@
 	MonoDynamicTable tables [MONO_TABLE_NUM];
 };
 
+struct version {
+	int major;
+	int minor;
+	int build;
+	int revision;
+};
+
+/* Contains information about assembly binding */
+typedef struct _AssemblyBindingInfo {
+	char *name;
+	char *culture;
+	guchar public_key_token [MONO_PUBLIC_KEY_TOKEN_LENGTH];
+	int major;
+	int minor;
+	struct version old_version_bottom;
+	struct version old_version_top;
+	struct version new_version;
+} AssemblyBindingInfo;
+
 /* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
 guint mono_aligned_addr_hash (gconstpointer ptr);
 
@@ -311,5 +330,7 @@
 void mono_dynamic_stream_reset (MonoDynamicStream* stream);
 void mono_assembly_addref      (MonoAssembly *assembly);
 
+void assembly_binding_info_free 	    (AssemblyBindingInfo   *info);
+
 #endif /* __MONO_METADATA_INTERNALS_H__ */
 
Index: domain-internals.h
===================================================================
--- domain-internals.h	(revisión: 47896)
+++ domain-internals.h	(copia de trabajo)
@@ -89,6 +89,7 @@
 	MonoGHashTable     *env;
 	GSList             *domain_assemblies;
 	MonoAssembly       *entry_assembly;
+	GSList 		   *assembly_bindings;
 	MonoAppDomainSetup *setup;
 	char               *friendly_name;
 	guint32            state;
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to