X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fassembly.c;h=b72ce7fb3fc38e3fc62f93269442ca7d5b258595;hb=e043ad6df539b39dbe4a370aa6affe8e2c39bb48;hp=cdd680983dd429c79b988cd76978df069b86de4c;hpb=c13f5adae1982f94afc68a472c77e6a434c87af9;p=mono.git diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index cdd680983dd..b72ce7fb3fc 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -28,7 +28,13 @@ #include #include #include -#include +#include + +#ifndef PLATFORM_WIN32 +#include +#include +#include +#endif /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */ typedef struct { @@ -430,6 +436,178 @@ mono_assembly_getrootdir (void) return default_path [0]; } +/** + * mono_set_dirs: + * @assembly_dir: the base directory for assemblies + * @config_dir: the base directory for configuration files + * + * This routine is used internally and by developers embedding + * the runtime into their own applications. There are a number + * of cases to consider: Mono as a system-installed package that + * is available on the location preconfigured or Mono in a relocated + * location. + * + * If you are using a system-installed Mono, you can pass NULL + * to both parameters. If you are not, you should compute both + * directory values and call this routine. + * + * The values for a given PREFIX are: + * + * assembly_dir: PREFIX/lib + * config_dir: PREFIX/etc + * + * Notice that embedders that use Mono in a relocated way must + * compute the location at runtime, as they will be in control + * of where Mono is installed. + */ +void +mono_set_dirs (const char *assembly_dir, const char *config_dir) +{ +#if defined (MONO_ASSEMBLIES) + if (assembly_dir == NULL) + assembly_dir = MONO_ASSEMBLIES; +#endif +#if defined (MONO_CFG_DIR) + if (config_dir == NULL) + config_dir = MONO_CFG_DIR; +#endif + mono_assembly_setrootdir (assembly_dir); + mono_set_config_dir (config_dir); +} + +#ifndef PLATFORM_WIN32 + +static char * +compute_base (char *path) +{ + char *p = rindex (path, '/'); + if (p == NULL) + return NULL; + + /* Not a well known Mono executable, we are embedded, cant guess the base */ + if (strcmp (p, "/mono") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet")) + return NULL; + + *p = 0; + p = rindex (path, '/'); + if (p == NULL) + return NULL; + + if (strcmp (p, "/bin") != 0) + return NULL; + *p = 0; + return path; +} + +static void +fallback (void) +{ + mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR); +} + +static void +set_dirs (char *exe) +{ + char *base; + char *config, *lib, *mono; + struct stat buf; + + /* + * Only /usr prefix is treated specially + */ + if (strncmp (exe, MONO_BINDIR, strlen (MONO_BINDIR)) == 0 || (base = compute_base (exe)) == NULL){ + fallback (); + return; + } + + config = g_build_filename (base, "etc", NULL); + lib = g_build_filename (base, "lib", NULL); + mono = g_build_filename (lib, "mono/1.0", NULL); + if (stat (mono, &buf) == -1) + fallback (); + else { + mono_set_dirs (lib, config); + } + + g_free (config); + g_free (lib); + g_free (mono); +} + +#endif /* PLATFORM_WIN32 */ + +#ifdef UNDER_CE +#undef GetModuleFileName +#define GetModuleFileName ceGetModuleFileNameA + +DWORD ceGetModuleFileNameA(HMODULE hModule, char* lpFilename, DWORD nSize) +{ + DWORD res = 0; + wchar_t* wbuff = (wchar_t*)LocalAlloc(LPTR, nSize*2); + res = GetModuleFileNameW(hModule, wbuff, nSize); + if (res) { + int len = wcslen(wbuff); + WideCharToMultiByte(CP_ACP, 0, wbuff, len, lpFilename, len, NULL, NULL); + } + LocalFree(wbuff); + return res; +} +#endif + +/** + * mono_set_rootdir: + * + * Registers the root directory for the Mono runtime, for Linux and Solaris 10, + * this auto-detects the prefix where Mono was installed. + */ +void +mono_set_rootdir (void) +{ +#ifdef PLATFORM_WIN32 + gunichar2 moddir [MAXPATHLEN]; + gchar *bindir, *installdir, *root, *utf8name, *config; + + GetModuleFileNameW (NULL, moddir, MAXPATHLEN); + utf8name = g_utf16_to_utf8 (moddir, -1, NULL, NULL, NULL); + bindir = g_path_get_dirname (utf8name); + installdir = g_path_get_dirname (bindir); + root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL); + + config = g_build_filename (root, "..", "etc", NULL); + mono_set_dirs (root, config); + + g_free (config); + g_free (root); + g_free (installdir); + g_free (bindir); + g_free (utf8name); +#else + char buf [4096]; + int s; + char *str; + + /* Linux style */ + s = readlink ("/proc/self/exe", buf, sizeof (buf)-1); + + if (s != -1){ + buf [s] = 0; + set_dirs (buf); + return; + } + + /* Solaris 10 style */ + str = g_strdup_printf ("/proc/%d/path/a.out", getpid ()); + s = readlink (str, buf, sizeof (buf)-1); + g_free (str); + if (s != -1){ + buf [s] = 0; + set_dirs (buf); + return; + } + fallback (); +#endif +} + /** * mono_assemblies_init: * @@ -700,12 +878,13 @@ mono_assembly_load_reference (MonoImage *image, int index) if (reference == NULL) { /* Flag as not found */ reference = (gpointer)-1; - } else { - mono_assembly_addref (reference); } - if (!image->references [index]) + if (!image->references [index]) { + mono_assembly_addref (reference); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n", image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count); image->references [index] = reference; + } mono_assemblies_unlock (); if (image->references [index] != reference) { @@ -1071,6 +1250,12 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo return NULL; } + if (image->assembly) { + /* Already loaded by another appdomain */ + mono_assembly_invoke_load_hook (image->assembly); + return image->assembly; + } + ass = mono_assembly_load_from_full (image, fname, status, refonly); if (ass) { @@ -1085,6 +1270,47 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo return ass; } +/* + * load_friend_assemblies: + * @ass: an assembly + * + * Load the list of friend assemblies that are allowed to access + * the assembly's internal types and members. They are stored as assembly + * names in custom attributes. + */ +static void +load_friend_assemblies (MonoAssembly* ass) +{ + int i; + MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass); + if (!attrs) + return; + for (i = 0; i < attrs->num_attrs; ++i) { + MonoCustomAttrEntry *attr = &attrs->attrs [i]; + MonoAssemblyName *aname; + const guchar *data; + guint slen; + /* Do some sanity checking */ + if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class) + continue; + if (attr->data_size < 4) + continue; + data = attr->data; + /* 0xFF means null string, see custom attr format */ + if (data [0] != 1 || data [1] != 0 || data [2] == 0xFF) + continue; + slen = mono_metadata_decode_value (data + 2, &data); + aname = g_new0 (MonoAssemblyName, 1); + /*g_print ("friend ass: %s\n", data);*/ + if (mono_assembly_name_parse_full (data, aname, TRUE, NULL)) { + ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname); + } else { + g_free (aname); + } + } + mono_custom_attrs_free (attrs); +} + /** * mono_assembly_open: * @filename: Opens the assembly pointed out by this name @@ -1144,10 +1370,13 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, ass->basedir = base_dir; ass->ref_only = refonly; ass->image = image; - ass->ref_count = 1; + + mono_image_addref (image); mono_assembly_fill_assembly_name (image, &ass->aname); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d\n", ass->aname.name, ass, image->name, image, image->ref_count); + /* * Atomically search the loaded list and add ourselves to it if necessary. */ @@ -1170,6 +1399,7 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, g_hash_table_insert (ass_loading, GetCurrentThread (), loading); mono_assemblies_unlock (); + g_assert (image->assembly == NULL); image->assembly = ass; mono_assembly_load_references (image, status); @@ -1200,6 +1430,8 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, } loaded_assemblies = g_list_prepend (loaded_assemblies, ass); + if (mono_defaults.internals_visible_class) + load_friend_assemblies (ass); mono_assemblies_unlock (); mono_assembly_invoke_load_hook (ass); @@ -1328,14 +1560,17 @@ build_assembly_name (const char *name, const char *version, const char *culture, aname->name = g_strdup (name); if (culture) { - if (g_strcasecmp (culture, "neutral") == 0) + if (g_ascii_strcasecmp (culture, "neutral") == 0) aname->culture = g_strdup (""); else aname->culture = g_strdup (culture); } - if (token && strncmp (token, "null", 4) != 0) - g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH); + if (token && strncmp (token, "null", 4) != 0) { + char *lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH); + g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH); + g_free (lower); + } if (key && strncmp (key, "null", 4) != 0) { if (!parse_public_key (key, &pkey)) { @@ -1945,20 +2180,38 @@ mono_assembly_loaded (MonoAssemblyName *aname) void mono_assembly_close (MonoAssembly *assembly) { + GSList *tmp; g_return_if_fail (assembly != NULL); - if (InterlockedDecrement (&assembly->ref_count)) + /* Might be 0 already */ + if (InterlockedDecrement (&assembly->ref_count) > 0) return; - + + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly); + mono_assemblies_lock (); loaded_assemblies = g_list_remove (loaded_assemblies, assembly); mono_assemblies_unlock (); - /* assemblies belong to domains, so the domain code takes care of unloading the - * referenced assemblies - */ + + if (assembly->image->references) { + int i; + + for (i = 0; assembly->image->references [i]; i++) { + if (assembly->image->references [i]) + mono_assembly_close (assembly->image->references [i]); + } + } + + assembly->image->assembly = NULL; mono_image_close (assembly->image); + for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) { + MonoAssemblyName *fname = tmp->data; + mono_assembly_name_free (fname); + g_free (fname); + } + g_slist_free (assembly->friend_assembly_names); g_free (assembly->basedir); if (!assembly->dynamic) g_free (assembly);