#include <mono/metadata/mono-config.h>
#include <mono/utils/mono-digest.h>
#include <mono/utils/mono-logger.h>
-#include <mono/os/util.h>
+#include <mono/metadata/reflection.h>
+
+#ifndef PLATFORM_WIN32
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
/* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
typedef struct {
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:
*
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) {
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) {
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
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.
*/
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);
}
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);
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)) {
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);