Hey,
the attached patch works ok, and applies the last suggestions you did.
Carlos.
El lun, 15-08-2005 a las 19:55 +0200, Paolo Molaro escribió:
> On 08/13/05 Carlos Alberto Cortez wrote:
> > > struct version doesn't conform to the mono naming conventions.
> > > Use a typedef and something like MonoAssemblyVersion.
> >
> > This was based on the fact I wanted to keep it -at least initially- as
> > private. We can rename it the way you want, however.
>
> I just noticed we have already AssemblyVersionSet in domain-internals.h, so
> please use that.
>
> > > Why do you associate assembly bindings to domains? Since they are stored
> > > in the GAC they seem to be valid for all the domains.
> >
> > That's the way they are associated in .Net in both 1.0 and 1.1. In .Net
> > 2.0 they are domain neutral. So, it's a matter of deciding where we
> > should put them.
>
> >From my limited understanding of it, it makes no sense to have them
> per-domain, unless there is also a separate mechanims to tell the
> runtime about policy files that is per-domain. If the files are in the
> GAC, you end up with the same copy of the policy info in each domain.
>
> > > Since this stuff sseems to be used only in one file, there is no point
> > > in exposing them in the headers.
> >
> > I needed it for freeing in mono_domain_unload, but since we are going to
>
> This was missing from the patch.
> Thanks.
>
> lupus
>
Index: assembly.c
===================================================================
--- assembly.c (revisión: 48473)
+++ 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>
@@ -128,6 +129,9 @@
/* Reflection only private hook functions */
static MonoAssembly* mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname);
+/* Loaded assembly binding info */
+static GSList *loaded_assembly_bindings = NULL;
+
static gchar*
encode_public_tok (const guchar *token, gint32 len)
{
@@ -193,6 +197,132 @@
}
}
+static gboolean
+assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
+{
+ 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 ((const char *)info->public_key_token, (const char *)aname->public_key_token))
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
+{
+ g_free (info->name);
+ g_free (info->culture);
+}
+
+static void
+get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
+{
+ MonoTableInfo *t;
+ guint32 cols [MONO_MANIFEST_SIZE];
+ const gchar *filename;
+ gchar *subpath, *fullpath;
+
+ 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) {
+ binding_info->is_valid = FALSE;
+ return;
+ }
+
+ mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
+ if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
+ binding_info->is_valid = FALSE;
+ return;
+ }
+
+ filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
+ g_assert (filename != NULL);
+
+ /* By default is invalid */
+ subpath = g_path_get_dirname (image->name);
+ fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
+ mono_config_parse_publisher_policy (fullpath, binding_info);
+ g_free (subpath);
+ g_free (fullpath);
+
+ /* Define the optional elements/attributes before checking */
+ 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->has_old_version_bottom ||
+ !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
+ mono_assembly_binding_info_free (binding_info);
+ binding_info->is_valid = FALSE;
+ return;
+ }
+
+ binding_info->is_valid = TRUE;
+}
+
+static int
+compare_versions (AssemblyVersionSet *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 (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
+{
+ if (!info->is_valid)
+ return FALSE;
+
+ /* If has_old_version_top doesn't exist, we don't have an interval */
+ if (!info->has_old_version_top) {
+ if (compare_versions (&info->old_version_bottom, name) == 0)
+ return TRUE;
+
+ return FALSE;
+ }
+
+ /* Check that the version defined by name is valid for the interval */
+ 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 +1417,150 @@
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 (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 (MonoAssemblyBindingInfo *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 MonoAssemblyBindingInfo*
+search_binding_loaded (MonoAssemblyName *aname)
+{
+ GSList *tmp;
+
+ for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
+ MonoAssemblyBindingInfo *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)
+{
+ MonoAssemblyBindingInfo *info, *info2;
+ MonoImage *ppimage;
+
+ 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 (MonoAssemblyBindingInfo, 1);
+ info->major = aname->major;
+ info->minor = aname->minor;
+
+ ppimage = mono_assembly_load_publisher_policy (aname);
+ if (ppimage) {
+ get_publisher_policy_info (ppimage, aname, info);
+ mono_image_close (ppimage);
+ }
+
+ /* Define default error value if needed */
+ if (!info->is_valid) {
+ info->name = g_strdup (aname->name);
+ info->culture = g_strdup (aname->culture);
+ g_strlcpy ((char *)info->public_key_token, (const char *)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 */
+ mono_assembly_binding_info_free (info);
+ g_free (info);
+
+ info = info2;
+ } else
+ loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
+
+ mono_loader_unlock ();
+
+ if (!info->is_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 +1670,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: 48473)
+++ metadata-internals.h (copia de trabajo)
@@ -5,6 +5,7 @@
#include "mono/metadata/image.h"
#include "mono/metadata/blob.h"
#include "mono/metadata/mempool.h"
+#include "mono/metadata/domain-internals.h"
#include "mono/utils/mono-hash.h"
struct _MonoAssembly {
@@ -236,6 +237,22 @@
MonoDynamicTable tables [MONO_TABLE_NUM];
};
+/* Contains information about assembly binding */
+typedef struct _MonoAssemblyBindingInfo {
+ char *name;
+ char *culture;
+ guchar public_key_token [MONO_PUBLIC_KEY_TOKEN_LENGTH];
+ int major;
+ int minor;
+ AssemblyVersionSet old_version_bottom;
+ AssemblyVersionSet old_version_top;
+ AssemblyVersionSet new_version;
+ guint has_old_version_bottom : 1;
+ guint has_old_version_top : 1;
+ guint has_new_version;
+ guint is_valid : 1;
+} MonoAssemblyBindingInfo;
+
/* for use with allocated memory blocks (assumes alignment is to 8 bytes) */
guint mono_aligned_addr_hash (gconstpointer ptr);
@@ -311,5 +328,8 @@
void mono_dynamic_stream_reset (MonoDynamicStream* stream);
void mono_assembly_addref (MonoAssembly *assembly);
+void mono_assembly_binding_info_free (MonoAssemblyBindingInfo *binding_info);
+void mono_config_parse_publisher_policy (const char *filename, MonoAssemblyBindingInfo *binding_info);
+
#endif /* __MONO_METADATA_INTERNALS_H__ */
Index: mono-config.c
===================================================================
--- mono-config.c (revisión: 48473)
+++ mono-config.c (copia de trabajo)
@@ -418,3 +418,127 @@
return mono_cfg_dir;
}
+static void
+publisher_policy_start (gpointer user_data,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ MonoAssemblyBindingInfo *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 ((char *) 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;
+ gint major, minor, build, revision;
+
+ /* Invalid value */
+ if (!strcmp (attribute_values [n], ""))
+ return;
+
+ versions = g_strsplit (attribute_values [n], "-", 2);
+ version = g_strsplit (*versions, ".", 4);
+
+ /* We assign the values to gint vars to do the checks */
+ numbers = version;
+ major = *numbers ? atoi (*numbers++) : -1;
+ minor = *numbers ? atoi (*numbers++) : -1;
+ build = *numbers ? atoi (*numbers++) : -1;
+ revision = *numbers ? atoi (*numbers) : -1;
+ g_strfreev (version);
+ if (major < 0 || minor < 0 || build < 0 || revision < 0) {
+ g_strfreev (versions);
+ return;
+ }
+
+ info->old_version_bottom.major = major;
+ info->old_version_bottom.minor = minor;
+ info->old_version_bottom.build = build;
+ info->old_version_bottom.revision = revision;
+ info->has_old_version_bottom = TRUE;
+
+ if (!*(versions + 1)) {
+ g_strfreev (versions);
+ continue;
+ }
+
+ numbers = version = g_strsplit (*(versions + 1), ".", 4);
+ major = *numbers ? atoi (*numbers++) : -1;
+ minor = *numbers ? atoi (*numbers++) : -1;
+ build = *numbers ? atoi (*numbers++) : -1;
+ revision = *numbers ? atoi (*numbers) : 1;
+ g_strfreev (version);
+ if (major < 0 || minor < 0 || build < 0 || revision < 0) {
+ g_strfreev (versions);
+ return;
+ }
+
+ info->old_version_top.major = major;
+ info->old_version_top.minor = minor;
+ info->old_version_top.build = build;
+ info->old_version_top.revision = revision;
+ info->has_old_version_top = TRUE;
+
+ 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;
+ info->has_new_version = TRUE;
+ g_strfreev (version);
+ }
+ }
+ }
+}
+
+static MonoParseHandler
+publisher_policy_parser = {
+ "", /* We don't need to use declare an xml element */
+ NULL,
+ publisher_policy_start,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+mono_config_parse_publisher_policy (const gchar *filename, MonoAssemblyBindingInfo *info)
+{
+ ParseState state = {
+ &publisher_policy_parser, /* MonoParseHandler */
+ info, /* user_data */
+ NULL, /* MonoImage (we don't need it right now)*/
+ TRUE /* We are already inited */
+ };
+
+ mono_config_parse_file_with_context (&state, filename);
+}
+
_______________________________________________
Mono-devel-list mailing list
[email protected]
http://lists.ximian.com/mailman/listinfo/mono-devel-list