[io-layer] Extract error (#4279)
[mono.git] / mono / metadata / assembly.c
1 /*
2  * assembly.c: Routines for loading assemblies.
3  * 
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12 #include <config.h>
13 #include <stdio.h>
14 #include <glib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include "assembly.h"
19 #include "assembly-internals.h"
20 #include "image.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
45
46 #ifndef HOST_WIN32
47 #include <sys/types.h>
48 #include <unistd.h>
49 #include <sys/stat.h>
50 #endif
51
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
54 #endif
55
56 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
57 typedef struct  {
58         const char* assembly_name;
59         guint8 version_set_index;
60         const char* new_assembly_name;
61         gboolean only_lower_versions;
62 } AssemblyVersionMap;
63
64 /* the default search path is empty, the first slot is replaced with the computed value */
65 static const char*
66 default_path [] = {
67         NULL,
68         NULL,
69         NULL
70 };
71
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
74
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
77
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
79 /* The list of system assemblies what will be remapped to the running
80  * runtime version. WARNING: this list must be sorted.
81  * The integer number is an index in the MonoRuntimeInfo structure, whose
82  * values can be found in domain.c - supported_runtimes. Look there
83  * to understand what remapping will be made.
84  *
85  * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
86  *
87  */
88 static const AssemblyVersionMap framework_assemblies [] = {
89         {"Accessibility", 0},
90         {"Commons.Xml.Relaxng", 0},
91         {"I18N", 0},
92         {"I18N.CJK", 0},
93         {"I18N.MidEast", 0},
94         {"I18N.Other", 0},
95         {"I18N.Rare", 0},
96         {"I18N.West", 0},
97         {"Microsoft.Build.Engine", 2, NULL, TRUE},
98         {"Microsoft.Build.Framework", 2, NULL, TRUE},
99         {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
100         {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
101         {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
102         {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
103         {"Microsoft.VisualBasic", 1},
104         {"Microsoft.VisualC", 1},
105         {"Mono.Cairo", 0},
106         {"Mono.CompilerServices.SymbolWriter", 0},
107         {"Mono.Data", 0},
108         {"Mono.Data.SybaseClient", 0},
109         {"Mono.Data.Tds", 0},
110         {"Mono.Data.TdsClient", 0},
111         {"Mono.GetOptions", 0},
112         {"Mono.Http", 0},
113         {"Mono.Posix", 0},
114         {"Mono.Security", 0},
115         {"Mono.Security.Win32", 0},
116         {"Mono.Xml.Ext", 0},
117         {"Novell.Directory.Ldap", 0},
118         {"PEAPI", 0},
119         {"System", 0},
120         {"System.ComponentModel.Composition", 2},
121         {"System.ComponentModel.DataAnnotations", 2},
122         {"System.Configuration", 0},
123         {"System.Configuration.Install", 0},
124         {"System.Core", 2},
125         {"System.Data", 0},
126         {"System.Data.Linq", 2},
127         {"System.Data.OracleClient", 0},
128         {"System.Data.Services", 2},
129         {"System.Data.Services.Client", 2},
130         {"System.Data.SqlXml", 0},
131         {"System.Design", 0},
132         {"System.DirectoryServices", 0},
133         {"System.Drawing", 0},
134         {"System.Drawing.Design", 0},
135         {"System.EnterpriseServices", 0},
136         {"System.IdentityModel", 3},
137         {"System.IdentityModel.Selectors", 3},
138         {"System.Management", 0},
139         {"System.Messaging", 0},
140         {"System.Net", 2},
141         {"System.Runtime.Remoting", 0},
142         {"System.Runtime.Serialization", 3},
143         {"System.Runtime.Serialization.Formatters.Soap", 0},
144         {"System.Security", 0},
145         {"System.ServiceModel", 3},
146         {"System.ServiceModel.Web", 2},
147         {"System.ServiceProcess", 0},
148         {"System.Transactions", 0},
149         {"System.Web", 0},
150         {"System.Web.Abstractions", 2},
151         {"System.Web.DynamicData", 2},
152         {"System.Web.Extensions", 2},
153         {"System.Web.Mobile", 0},
154         {"System.Web.Routing", 2},
155         {"System.Web.Services", 0},
156         {"System.Windows.Forms", 0},
157         {"System.Xml", 0},
158         {"System.Xml.Linq", 2},
159         {"WindowsBase", 3},
160         {"mscorlib", 0}
161 };
162 #endif
163
164 /*
165  * keeps track of loaded assemblies
166  */
167 static GList *loaded_assemblies = NULL;
168 static MonoAssembly *corlib;
169
170 #if defined(__native_client__)
171
172 /* On Native Client, allow mscorlib to be loaded from memory  */
173 /* instead of loaded off disk.  If these are not set, default */
174 /* mscorlib loading will take place                           */
175
176 /* NOTE: If mscorlib data is passed to mono in this way then */
177 /* it needs to remain allocated during the use of mono.      */
178
179 static void *corlibData = NULL;
180 static size_t corlibSize = 0;
181
182 void
183 mono_set_corlib_data (void *data, size_t size)
184 {
185   corlibData = data;
186   corlibSize = size;
187 }
188
189 #endif
190
191 static char* unquote (const char *str);
192
193 /* This protects loaded_assemblies and image->references */
194 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
195 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
196 static mono_mutex_t assemblies_mutex;
197
198 /* If defined, points to the bundled assembly information */
199 const MonoBundledAssembly **bundles;
200
201 static mono_mutex_t assembly_binding_mutex;
202
203 /* Loaded assembly binding info */
204 static GSList *loaded_assembly_bindings = NULL;
205
206 /* Class lazy loading functions */
207 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
208 static MonoAssembly*
209 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
210 static MonoAssembly*
211 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
212 static MonoBoolean
213 mono_assembly_is_in_gac (const gchar *filanem);
214
215 static MonoAssembly*
216 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
217
218 static gchar*
219 encode_public_tok (const guchar *token, gint32 len)
220 {
221         const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
222         gchar *res;
223         int i;
224
225         res = (gchar *)g_malloc (len * 2 + 1);
226         for (i = 0; i < len; i++) {
227                 res [i * 2] = allowed [token [i] >> 4];
228                 res [i * 2 + 1] = allowed [token [i] & 0xF];
229         }
230         res [len * 2] = 0;
231         return res;
232 }
233
234 /**
235  * mono_public_tokens_are_equal:
236  * @pubt1: first public key token
237  * @pubt2: second public key token
238  *
239  * Compare two public key tokens and return #TRUE is they are equal and #FALSE
240  * otherwise.
241  */
242 gboolean
243 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
244 {
245         return memcmp (pubt1, pubt2, 16) == 0;
246 }
247
248 /**
249  * mono_set_assemblies_path:
250  * @path: list of paths that contain directories where Mono will look for assemblies
251  *
252  * Use this method to override the standard assembly lookup system and
253  * override any assemblies coming from the GAC.  This is the method
254  * that supports the MONO_PATH variable.
255  *
256  * Notice that MONO_PATH and this method are really a very bad idea as
257  * it prevents the GAC from working and it prevents the standard
258  * resolution mechanisms from working.  Nonetheless, for some debugging
259  * situations and bootstrapping setups, this is useful to have. 
260  */
261 void
262 mono_set_assemblies_path (const char* path)
263 {
264         char **splitted, **dest;
265
266         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
267         if (assemblies_path)
268                 g_strfreev (assemblies_path);
269         assemblies_path = dest = splitted;
270         while (*splitted) {
271                 char *tmp = *splitted;
272                 if (*tmp)
273                         *dest++ = mono_path_canonicalize (tmp);
274                 g_free (tmp);
275                 splitted++;
276         }
277         *dest = *splitted;
278
279         if (g_getenv ("MONO_DEBUG") == NULL)
280                 return;
281
282         splitted = assemblies_path;
283         while (*splitted) {
284                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
285                         g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
286
287                 splitted++;
288         }
289 }
290
291 /* Native Client can't get this info from an environment variable so */
292 /* it's passed in to the runtime, or set manually by embedding code. */
293 #ifdef __native_client__
294 char* nacl_mono_path = NULL;
295 #endif
296
297 static void
298 check_path_env (void)
299 {
300         const char* path;
301         path = g_getenv ("MONO_PATH");
302 #ifdef __native_client__
303         if (!path)
304                 path = nacl_mono_path;
305 #endif
306         if (!path || assemblies_path != NULL)
307                 return;
308
309         mono_set_assemblies_path(path);
310 }
311
312 static void
313 check_extra_gac_path_env (void) {
314         const char *path;
315         char **splitted, **dest;
316         
317         path = g_getenv ("MONO_GAC_PREFIX");
318         if (!path)
319                 return;
320
321         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
322         if (extra_gac_paths)
323                 g_strfreev (extra_gac_paths);
324         extra_gac_paths = dest = splitted;
325         while (*splitted){
326                 if (**splitted)
327                         *dest++ = *splitted;
328                 splitted++;
329         }
330         *dest = *splitted;
331         
332         if (g_getenv ("MONO_DEBUG") == NULL)
333                 return;
334
335         while (*splitted) {
336                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
337                         g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
338
339                 splitted++;
340         }
341 }
342
343 static gboolean
344 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
345 {
346         if (!info || !info->name)
347                 return FALSE;
348
349         if (strcmp (info->name, aname->name))
350                 return FALSE;
351
352         if (info->major != aname->major || info->minor != aname->minor)
353                 return FALSE;
354
355         if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0])) 
356                 return FALSE;
357         
358         if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
359                 return FALSE;
360         
361         if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
362                 return FALSE;
363
364         return TRUE;
365 }
366
367 static void
368 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
369 {
370         if (!info)
371                 return;
372
373         g_free (info->name);
374         g_free (info->culture);
375 }
376
377 static void
378 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
379 {
380         MonoTableInfo *t;
381         guint32 cols [MONO_MANIFEST_SIZE];
382         const gchar *filename;
383         gchar *subpath, *fullpath;
384
385         t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
386         /* MS Impl. accepts policy assemblies with more than
387          * one manifest resource, and only takes the first one */
388         if (t->rows < 1) {
389                 binding_info->is_valid = FALSE;
390                 return;
391         }
392         
393         mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
394         if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
395                 binding_info->is_valid = FALSE;
396                 return;
397         }
398         
399         filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
400         g_assert (filename != NULL);
401         
402         subpath = g_path_get_dirname (image->name);
403         fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
404         mono_config_parse_publisher_policy (fullpath, binding_info);
405         g_free (subpath);
406         g_free (fullpath);
407         
408         /* Define the optional elements/attributes before checking */
409         if (!binding_info->culture)
410                 binding_info->culture = g_strdup ("");
411         
412         /* Check that the most important elements/attributes exist */
413         if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
414                         !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
415                 mono_assembly_binding_info_free (binding_info);
416                 binding_info->is_valid = FALSE;
417                 return;
418         }
419
420         binding_info->is_valid = TRUE;
421 }
422
423 static int
424 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
425 {
426         if (v->major > aname->major)
427                 return 1;
428         else if (v->major < aname->major)
429                 return -1;
430
431         if (v->minor > aname->minor)
432                 return 1;
433         else if (v->minor < aname->minor)
434                 return -1;
435
436         if (v->build > aname->build)
437                 return 1;
438         else if (v->build < aname->build)
439                 return -1;
440
441         if (v->revision > aname->revision)
442                 return 1;
443         else if (v->revision < aname->revision)
444                 return -1;
445
446         return 0;
447 }
448
449 static gboolean
450 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
451 {
452         if (!info->is_valid)
453                 return FALSE;
454         
455         /* If has_old_version_top doesn't exist, we don't have an interval */
456         if (!info->has_old_version_top) {
457                 if (compare_versions (&info->old_version_bottom, name) == 0)
458                         return TRUE;
459
460                 return FALSE;
461         }
462
463         /* Check that the version defined by name is valid for the interval */
464         if (compare_versions (&info->old_version_top, name) < 0)
465                 return FALSE;
466
467         /* We should be greater or equal than the small version */
468         if (compare_versions (&info->old_version_bottom, name) > 0)
469                 return FALSE;
470
471         return TRUE;
472 }
473
474 /**
475  * mono_assembly_names_equal:
476  * @l: first assembly
477  * @r: second assembly.
478  *
479  * Compares two MonoAssemblyNames and returns whether they are equal.
480  *
481  * This compares the names, the cultures, the release version and their
482  * public tokens.
483  *
484  * Returns: TRUE if both assembly names are equal.
485  */
486 gboolean
487 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
488 {
489         if (!l->name || !r->name)
490                 return FALSE;
491
492         if (strcmp (l->name, r->name))
493                 return FALSE;
494
495         if (l->culture && r->culture && strcmp (l->culture, r->culture))
496                 return FALSE;
497
498         if (l->major != r->major || l->minor != r->minor ||
499                         l->build != r->build || l->revision != r->revision)
500                 if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
501                         return FALSE;
502
503         if (!l->public_key_token [0] || !r->public_key_token [0])
504                 return TRUE;
505
506         if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
507                 return FALSE;
508
509         return TRUE;
510 }
511
512 static MonoAssembly *
513 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
514 {
515         int i;
516         char *fullpath;
517         MonoAssembly *result;
518
519         for (i = 0; search_path [i]; ++i) {
520                 fullpath = g_build_filename (search_path [i], basename, NULL);
521                 result = mono_assembly_open_full (fullpath, status, refonly);
522                 g_free (fullpath);
523                 if (result)
524                         return result;
525         }
526         return NULL;
527 }
528
529 /**
530  * mono_assembly_setrootdir:
531  * @root_dir: The pathname of the root directory where we will locate assemblies
532  *
533  * This routine sets the internal default root directory for looking up
534  * assemblies.
535  *
536  * This is used by Windows installations to compute dynamically the
537  * place where the Mono assemblies are located.
538  *
539  */
540 void
541 mono_assembly_setrootdir (const char *root_dir)
542 {
543         /*
544          * Override the MONO_ASSEMBLIES directory configured at compile time.
545          */
546         /* Leak if called more than once */
547         default_path [0] = g_strdup (root_dir);
548 }
549
550 /**
551  * mono_assembly_getrootdir:
552  * 
553  * Obtains the root directory used for looking up assemblies.
554  *
555  * Returns: a string with the directory, this string should not be freed.
556  */
557 G_CONST_RETURN gchar *
558 mono_assembly_getrootdir (void)
559 {
560         return default_path [0];
561 }
562
563 /**
564  * mono_native_getrootdir:
565  * 
566  * Obtains the root directory used for looking up native libs (.so, .dylib).
567  *
568  * Returns: a string with the directory, this string should be freed by
569  * the caller.
570  */
571 gchar *
572 mono_native_getrootdir (void)
573 {
574         gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
575         return fullpath;
576 }
577
578 /**
579  * mono_set_dirs:
580  * @assembly_dir: the base directory for assemblies
581  * @config_dir: the base directory for configuration files
582  *
583  * This routine is used internally and by developers embedding
584  * the runtime into their own applications.
585  *
586  * There are a number of cases to consider: Mono as a system-installed
587  * package that is available on the location preconfigured or Mono in
588  * a relocated location.
589  *
590  * If you are using a system-installed Mono, you can pass NULL
591  * to both parameters.  If you are not, you should compute both
592  * directory values and call this routine.
593  *
594  * The values for a given PREFIX are:
595  *
596  *    assembly_dir: PREFIX/lib
597  *    config_dir:   PREFIX/etc
598  *
599  * Notice that embedders that use Mono in a relocated way must
600  * compute the location at runtime, as they will be in control
601  * of where Mono is installed.
602  */
603 void
604 mono_set_dirs (const char *assembly_dir, const char *config_dir)
605 {
606         if (assembly_dir == NULL)
607                 assembly_dir = mono_config_get_assemblies_dir ();
608         if (config_dir == NULL)
609                 config_dir = mono_config_get_cfg_dir ();
610         mono_assembly_setrootdir (assembly_dir);
611         mono_set_config_dir (config_dir);
612 }
613
614 #ifndef HOST_WIN32
615
616 static char *
617 compute_base (char *path)
618 {
619         char *p = strrchr (path, '/');
620         if (p == NULL)
621                 return NULL;
622
623         /* Not a well known Mono executable, we are embedded, cant guess the base  */
624         if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
625                 return NULL;
626             
627         *p = 0;
628         p = strrchr (path, '/');
629         if (p == NULL)
630                 return NULL;
631         
632         if (strcmp (p, "/bin") != 0)
633                 return NULL;
634         *p = 0;
635         return path;
636 }
637
638 static void
639 fallback (void)
640 {
641         mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
642 }
643
644 static G_GNUC_UNUSED void
645 set_dirs (char *exe)
646 {
647         char *base;
648         char *config, *lib, *mono;
649         struct stat buf;
650         const char *bindir;
651         
652         /*
653          * Only /usr prefix is treated specially
654          */
655         bindir = mono_config_get_bin_dir ();
656         g_assert (bindir);
657         if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
658                 fallback ();
659                 return;
660         }
661
662         config = g_build_filename (base, "etc", NULL);
663         lib = g_build_filename (base, "lib", NULL);
664         mono = g_build_filename (lib, "mono/4.5", NULL);  // FIXME: stop hardcoding 4.5 here
665         if (stat (mono, &buf) == -1)
666                 fallback ();
667         else {
668                 mono_set_dirs (lib, config);
669         }
670         
671         g_free (config);
672         g_free (lib);
673         g_free (mono);
674 }
675
676 #endif /* HOST_WIN32 */
677
678 /**
679  * mono_set_rootdir:
680  *
681  * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
682  * this auto-detects the prefix where Mono was installed. 
683  */
684 void
685 mono_set_rootdir (void)
686 {
687 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
688         gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
689
690 #ifdef HOST_WIN32
691         name = mono_get_module_file_name ((HMODULE) &__ImageBase);
692 #else
693         {
694                 /* 
695                  * _NSGetExecutablePath may return -1 to indicate buf is not large
696                  *  enough, but we ignore that case to avoid having to do extra dynamic
697                  *  allocation for the path and hope that 4096 is enough - this is 
698                  *  ok in the Linux/Solaris case below at least...
699                  */
700                 
701                 gchar buf[4096];
702                 guint buf_size = sizeof (buf);
703  
704                 name = NULL;
705                 if (_NSGetExecutablePath (buf, &buf_size) == 0)
706                         name = g_strdup (buf);
707  
708                 if (name == NULL) {
709                         fallback ();
710                         return;
711                 }
712         }
713 #endif
714
715         resolvedname = mono_path_resolve_symlinks (name);
716
717         bindir = g_path_get_dirname (resolvedname);
718         installdir = g_path_get_dirname (bindir);
719         root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
720
721         config = g_build_filename (root, "..", "etc", NULL);
722 #ifdef HOST_WIN32
723         mono_set_dirs (root, config);
724 #else
725         if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
726                 mono_set_dirs (root, config);
727         else
728                 fallback ();
729 #endif
730
731         g_free (config);
732         g_free (root);
733         g_free (installdir);
734         g_free (bindir);
735         g_free (name);
736         g_free (resolvedname);
737 #elif defined(DISABLE_MONO_AUTODETECTION)
738         fallback ();
739 #else
740         char buf [4096];
741         int  s;
742         char *str;
743
744         /* Linux style */
745         s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
746
747         if (s != -1){
748                 buf [s] = 0;
749                 set_dirs (buf);
750                 return;
751         }
752
753         /* Solaris 10 style */
754         str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
755         s = readlink (str, buf, sizeof (buf)-1);
756         g_free (str);
757         if (s != -1){
758                 buf [s] = 0;
759                 set_dirs (buf);
760                 return;
761         } 
762         fallback ();
763 #endif
764 }
765
766 /**
767  * mono_assemblies_init:
768  *
769  *  Initialize global variables used by this module.
770  */
771 void
772 mono_assemblies_init (void)
773 {
774         /*
775          * Initialize our internal paths if we have not been initialized yet.
776          * This happens when embedders use Mono.
777          */
778         if (mono_assembly_getrootdir () == NULL)
779                 mono_set_rootdir ();
780
781         check_path_env ();
782         check_extra_gac_path_env ();
783
784         mono_os_mutex_init_recursive (&assemblies_mutex);
785         mono_os_mutex_init (&assembly_binding_mutex);
786 }
787
788 static void
789 mono_assembly_binding_lock (void)
790 {
791         mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
792 }
793
794 static void
795 mono_assembly_binding_unlock (void)
796 {
797         mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
798 }
799
800 gboolean
801 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
802 {
803         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
804         guint32 cols [MONO_ASSEMBLY_SIZE];
805         gint32 machine, flags;
806
807         if (!t->rows)
808                 return FALSE;
809
810         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
811
812         aname->hash_len = 0;
813         aname->hash_value = NULL;
814         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
815         if (copyBlobs)
816                 aname->name = g_strdup (aname->name);
817         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
818         if (copyBlobs)
819                 aname->culture = g_strdup (aname->culture);
820         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
821         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
822         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
823         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
824         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
825         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
826         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
827                 guchar* token = (guchar *)g_malloc (8);
828                 gchar* encoded;
829                 const gchar* pkey;
830                 int len;
831
832                 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
833                 len = mono_metadata_decode_blob_size (pkey, &pkey);
834                 aname->public_key = (guchar*)pkey;
835
836                 mono_digest_get_public_token (token, aname->public_key, len);
837                 encoded = encode_public_tok (token, 8);
838                 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
839
840                 g_free (encoded);
841                 g_free (token);
842         }
843         else {
844                 aname->public_key = NULL;
845                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
846         }
847
848         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
849                 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
850                 if (copyBlobs) {
851                         const gchar *pkey_end;
852                         int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
853                         pkey_end += len; /* move to end */
854                         size_t size = pkey_end - (const gchar*)aname->public_key;
855                         guchar *tmp = g_new (guchar, size);
856                         memcpy (tmp, aname->public_key, size);
857                         aname->public_key = tmp;
858                 }
859
860         }
861         else
862                 aname->public_key = 0;
863
864         machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
865         flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
866         switch (machine) {
867         case COFF_MACHINE_I386:
868                 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
869                 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
870                         aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
871                 else if ((flags & 0x70) == 0x70)
872                         aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
873                 else
874                         aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
875                 break;
876         case COFF_MACHINE_IA64:
877                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
878                 break;
879         case COFF_MACHINE_AMD64:
880                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
881                 break;
882         case COFF_MACHINE_ARM:
883                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
884                 break;
885         default:
886                 break;
887         }
888
889         return TRUE;
890 }
891
892 gboolean
893 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
894 {
895         return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
896 }
897
898 /**
899  * mono_stringify_assembly_name:
900  * @aname: the assembly name.
901  *
902  * Convert @aname into its string format. The returned string is dynamically
903  * allocated and should be freed by the caller.
904  *
905  * Returns: a newly allocated string with a string representation of
906  * the assembly name.
907  */
908 char*
909 mono_stringify_assembly_name (MonoAssemblyName *aname)
910 {
911         const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
912
913         return g_strdup_printf (
914                 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
915                 quote, aname->name, quote,
916                 aname->major, aname->minor, aname->build, aname->revision,
917                 aname->culture && *aname->culture? aname->culture: "neutral",
918                 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
919                 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
920 }
921
922 static gchar*
923 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
924 {
925         const gchar *public_tok;
926         int len;
927
928         public_tok = mono_metadata_blob_heap (image, key_index);
929         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
930
931         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
932                 guchar token [8];
933                 mono_digest_get_public_token (token, (guchar*)public_tok, len);
934                 return encode_public_tok (token, 8);
935         }
936
937         return encode_public_tok ((guchar*)public_tok, len);
938 }
939
940 /**
941  * mono_assembly_addref:
942  * @assemnly: the assembly to reference
943  *
944  * This routine increments the reference count on a MonoAssembly.
945  * The reference count is reduced every time the method mono_assembly_close() is
946  * invoked.
947  */
948 void
949 mono_assembly_addref (MonoAssembly *assembly)
950 {
951         InterlockedIncrement (&assembly->ref_count);
952 }
953
954 /*
955  * CAUTION: This table must be kept in sync with
956  *          ivkm/reflect/Fusion.cs
957  */
958
959 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
960 #define WINFX_KEY "31bf3856ad364e35"
961 #define ECMA_KEY "b77a5c561934e089"
962 #define MSFINAL_KEY "b03f5f7f11d50a3a"
963 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
964
965 typedef struct {
966         const char *name;
967         const char *from;
968         const char *to;
969 } KeyRemapEntry;
970
971 static KeyRemapEntry key_remap_table[] = {
972         { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
973         { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
974         { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
975         { "System", SILVERLIGHT_KEY, ECMA_KEY },
976         { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
977         { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
978         { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
979         { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
980         { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
981         { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
982         { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
983         { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
984         { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
985         // FIXME: MS uses MSFINAL_KEY for .NET 4.5
986         { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
987         { "System.Numerics", WINFX_KEY, ECMA_KEY },
988         { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
989         { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
990         { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
991         { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
992         { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
993         { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
994         { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
995         { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
996         { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
997         { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
998         { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
999         { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1000         { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1001 };
1002
1003 static void
1004 remap_keys (MonoAssemblyName *aname)
1005 {
1006         int i;
1007         for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1008                 const KeyRemapEntry *entry = &key_remap_table [i];
1009
1010                 if (strcmp (aname->name, entry->name) ||
1011                     !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1012                         continue;
1013
1014                 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1015                      
1016                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1017                             "Remapped public key token of retargetable assembly %s from %s to %s",
1018                             aname->name, entry->from, entry->to);
1019                 return;
1020         }
1021 }
1022
1023 static MonoAssemblyName *
1024 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1025 {
1026         const MonoRuntimeInfo *current_runtime;
1027         int pos, first, last;
1028
1029         if (aname->name == NULL) return aname;
1030
1031         current_runtime = mono_get_runtime_info ();
1032
1033         if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1034                 const AssemblyVersionSet* vset;
1035
1036                 /* Remap to current runtime */
1037                 vset = &current_runtime->version_sets [0];
1038
1039                 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1040                 dest_aname->major = vset->major;
1041                 dest_aname->minor = vset->minor;
1042                 dest_aname->build = vset->build;
1043                 dest_aname->revision = vset->revision;
1044                 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1045
1046                 /* Remap assembly name */
1047                 if (!strcmp (aname->name, "System.Net"))
1048                         dest_aname->name = g_strdup ("System");
1049                 
1050                 remap_keys (dest_aname);
1051
1052                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1053                                         "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1054                                         aname->name,
1055                                         aname->major, aname->minor, aname->build, aname->revision,
1056                                         dest_aname->name,
1057                                         vset->major, vset->minor, vset->build, vset->revision
1058                                         );
1059
1060                 return dest_aname;
1061         }
1062         
1063 #ifndef DISABLE_ASSEMBLY_REMAPPING
1064         first = 0;
1065         last = G_N_ELEMENTS (framework_assemblies) - 1;
1066         
1067         while (first <= last) {
1068                 int res;
1069                 pos = first + (last - first) / 2;
1070                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1071                 if (res == 0) {
1072                         const AssemblyVersionSet* vset;
1073                         int index = framework_assemblies[pos].version_set_index;
1074                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1075                         vset = &current_runtime->version_sets [index];
1076
1077                         if (aname->major == vset->major && aname->minor == vset->minor &&
1078                                 aname->build == vset->build && aname->revision == vset->revision)
1079                                 return aname;
1080                 
1081                         if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1082                                 return aname;
1083
1084                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1085                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1086                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1087                                                         aname->name,
1088                                                         aname->major, aname->minor, aname->build, aname->revision,
1089                                                         vset->major, vset->minor, vset->build, vset->revision
1090                                                         );
1091                         
1092                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1093                         dest_aname->major = vset->major;
1094                         dest_aname->minor = vset->minor;
1095                         dest_aname->build = vset->build;
1096                         dest_aname->revision = vset->revision;
1097                         if (framework_assemblies[pos].new_assembly_name != NULL) {
1098                                 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1099                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1100                                                         "The assembly name %s was remapped to %s",
1101                                                         aname->name,
1102                                                         dest_aname->name);
1103                         }
1104                         return dest_aname;
1105                 } else if (res < 0) {
1106                         last = pos - 1;
1107                 } else {
1108                         first = pos + 1;
1109                 }
1110         }
1111 #endif
1112
1113         return aname;
1114 }
1115
1116 /**
1117  * mono_assembly_get_assemblyref:
1118  * @image: pointer to the MonoImage to extract the information from.
1119  * @index: index to the assembly reference in the image.
1120  * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1121  *
1122  * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1123  */
1124 void
1125 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1126 {
1127         MonoTableInfo *t;
1128         guint32 cols [MONO_ASSEMBLYREF_SIZE];
1129         const char *hash;
1130
1131         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1132
1133         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1134                 
1135         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1136         aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1137         aname->hash_value = hash;
1138         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1139         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1140         aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1141         aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1142         aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1143         aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1144         aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1145
1146         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1147                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1148                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1149                 g_free (token);
1150         } else {
1151                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1152         }
1153 }
1154
1155 void
1156 mono_assembly_load_reference (MonoImage *image, int index)
1157 {
1158         MonoAssembly *reference;
1159         MonoAssemblyName aname;
1160         MonoImageOpenStatus status;
1161
1162         /*
1163          * image->references is shared between threads, so we need to access
1164          * it inside a critical section.
1165          */
1166         mono_assemblies_lock ();
1167         if (!image->references) {
1168                 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1169         
1170                 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1171                 image->nreferences = t->rows;
1172         }
1173         reference = image->references [index];
1174         mono_assemblies_unlock ();
1175         if (reference)
1176                 return;
1177
1178         mono_assembly_get_assemblyref (image, index, &aname);
1179
1180         if (image->assembly && image->assembly->ref_only) {
1181                 /* We use the loaded corlib */
1182                 if (!strcmp (aname.name, "mscorlib"))
1183                         reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1184                 else {
1185                         reference = mono_assembly_loaded_full (&aname, TRUE);
1186                         if (!reference)
1187                                 /* Try a postload search hook */
1188                                 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1189                 }
1190
1191                 /*
1192                  * Here we must advice that the error was due to
1193                  * a non loaded reference using the ReflectionOnly api
1194                 */
1195                 if (!reference)
1196                         reference = (MonoAssembly *)REFERENCE_MISSING;
1197         } else {
1198                 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1199                  * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1200                  * accordingly, it would fail on the MS runtime before).
1201                  * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1202                  * example bug-349190.2.cs and who knows how much more code in the wild.
1203                  */
1204                 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1205                 if (!reference && image->assembly)
1206                         reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1207         }
1208
1209         if (reference == NULL){
1210                 char *extra_msg;
1211
1212                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1213                         extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" );
1214                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1215                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1216                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1217                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1218                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1219                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1220                 } else {
1221                         extra_msg = g_strdup ("");
1222                 }
1223                 
1224                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1225                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
1226                                    "     Version:    %d.%d.%d.%d\n"
1227                                    "     Public Key: %s\n%s",
1228                                    image->name, aname.name, index,
1229                                    aname.major, aname.minor, aname.build, aname.revision,
1230                                    strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1231                 g_free (extra_msg);
1232
1233         }
1234
1235         mono_assemblies_lock ();
1236         if (reference == NULL) {
1237                 /* Flag as not found */
1238                 reference = (MonoAssembly *)REFERENCE_MISSING;
1239         }       
1240
1241         if (!image->references [index]) {
1242                 if (reference != REFERENCE_MISSING){
1243                         mono_assembly_addref (reference);
1244                         if (image->assembly)
1245                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1246                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1247                 } else {
1248                         if (image->assembly)
1249                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1250                                     image->assembly->aname.name, image->assembly);
1251                 }
1252                 
1253                 image->references [index] = reference;
1254         }
1255         mono_assemblies_unlock ();
1256
1257         if (image->references [index] != reference) {
1258                 /* Somebody loaded it before us */
1259                 mono_assembly_close (reference);
1260         }
1261 }
1262
1263 /**
1264  * mono_assembly_load_references:
1265  * @image: 
1266  * @status:
1267  * @deprecated: There is no reason to use this method anymore, it does nothing
1268  *
1269  * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1270  */
1271 void
1272 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1273 {
1274         /* This is a no-op now but it is part of the embedding API so we can't remove it */
1275         *status = MONO_IMAGE_OK;
1276 }
1277
1278 typedef struct AssemblyLoadHook AssemblyLoadHook;
1279 struct AssemblyLoadHook {
1280         AssemblyLoadHook *next;
1281         MonoAssemblyLoadFunc func;
1282         gpointer user_data;
1283 };
1284
1285 AssemblyLoadHook *assembly_load_hook = NULL;
1286
1287 void
1288 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1289 {
1290         AssemblyLoadHook *hook;
1291
1292         for (hook = assembly_load_hook; hook; hook = hook->next) {
1293                 hook->func (ass, hook->user_data);
1294         }
1295 }
1296
1297 void
1298 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1299 {
1300         AssemblyLoadHook *hook;
1301         
1302         g_return_if_fail (func != NULL);
1303
1304         hook = g_new0 (AssemblyLoadHook, 1);
1305         hook->func = func;
1306         hook->user_data = user_data;
1307         hook->next = assembly_load_hook;
1308         assembly_load_hook = hook;
1309 }
1310
1311 static void
1312 free_assembly_load_hooks (void)
1313 {
1314         AssemblyLoadHook *hook, *next;
1315
1316         for (hook = assembly_load_hook; hook; hook = next) {
1317                 next = hook->next;
1318                 g_free (hook);
1319         }
1320 }
1321
1322 typedef struct AssemblySearchHook AssemblySearchHook;
1323 struct AssemblySearchHook {
1324         AssemblySearchHook *next;
1325         MonoAssemblySearchFunc func;
1326         gboolean refonly;
1327         gboolean postload;
1328         gpointer user_data;
1329 };
1330
1331 AssemblySearchHook *assembly_search_hook = NULL;
1332
1333 static MonoAssembly*
1334 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1335 {
1336         AssemblySearchHook *hook;
1337
1338         for (hook = assembly_search_hook; hook; hook = hook->next) {
1339                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1340                         MonoAssembly *ass;
1341                         /**
1342                           * A little explanation is in order here.
1343                           *
1344                           * The default postload search hook needs to know the requesting assembly to report it to managed code.
1345                           * The embedding API exposes a search hook that doesn't take such argument.
1346                           *
1347                           * The original fix would call the default search hook before all the registered ones and pass
1348                           * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1349                           * rely on. Which is the ordering between user hooks and the default runtime hook.
1350                           *
1351                           * Registering the hook after mono_jit_init would let your hook run before the default one and
1352                           * when using it to handle non standard app layouts this could save your app from a massive amount
1353                           * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1354                           * are all using this trick and if we broke this assumption they would be very disapointed at us.
1355                           *
1356                           * So what's the fix? We register the default hook using regular means and special case it when iterating
1357                           * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1358                           * assembly.
1359                           */
1360                         if (hook->func == (void*)mono_domain_assembly_postload_search)
1361                                 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1362                         else
1363                                 ass = hook->func (aname, hook->user_data);
1364                         if (ass)
1365                                 return ass;
1366                 }
1367         }
1368
1369         return NULL;
1370 }
1371
1372 MonoAssembly*
1373 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1374 {
1375         return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1376 }
1377
1378 static void
1379 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1380 {
1381         AssemblySearchHook *hook;
1382         
1383         g_return_if_fail (func != NULL);
1384
1385         hook = g_new0 (AssemblySearchHook, 1);
1386         hook->func = func;
1387         hook->user_data = user_data;
1388         hook->refonly = refonly;
1389         hook->postload = postload;
1390         hook->next = assembly_search_hook;
1391         assembly_search_hook = hook;
1392 }
1393
1394 void          
1395 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1396 {
1397         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1398 }       
1399
1400 static void
1401 free_assembly_search_hooks (void)
1402 {
1403         AssemblySearchHook *hook, *next;
1404
1405         for (hook = assembly_search_hook; hook; hook = next) {
1406                 next = hook->next;
1407                 g_free (hook);
1408         }
1409 }
1410
1411 void
1412 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1413 {
1414         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1415 }
1416
1417 void          
1418 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1419 {
1420         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1421 }       
1422
1423 void
1424 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1425 {
1426         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1427 }
1428
1429 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1430 struct AssemblyPreLoadHook {
1431         AssemblyPreLoadHook *next;
1432         MonoAssemblyPreLoadFunc func;
1433         gpointer user_data;
1434 };
1435
1436 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1437 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1438
1439 static MonoAssembly *
1440 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1441 {
1442         AssemblyPreLoadHook *hook;
1443         MonoAssembly *assembly;
1444
1445         for (hook = assembly_preload_hook; hook; hook = hook->next) {
1446                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1447                 if (assembly != NULL)
1448                         return assembly;
1449         }
1450
1451         return NULL;
1452 }
1453
1454 static MonoAssembly *
1455 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1456 {
1457         AssemblyPreLoadHook *hook;
1458         MonoAssembly *assembly;
1459
1460         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1461                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1462                 if (assembly != NULL)
1463                         return assembly;
1464         }
1465
1466         return NULL;
1467 }
1468
1469 void
1470 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1471 {
1472         AssemblyPreLoadHook *hook;
1473         
1474         g_return_if_fail (func != NULL);
1475
1476         hook = g_new0 (AssemblyPreLoadHook, 1);
1477         hook->func = func;
1478         hook->user_data = user_data;
1479         hook->next = assembly_preload_hook;
1480         assembly_preload_hook = hook;
1481 }
1482
1483 void
1484 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1485 {
1486         AssemblyPreLoadHook *hook;
1487         
1488         g_return_if_fail (func != NULL);
1489
1490         hook = g_new0 (AssemblyPreLoadHook, 1);
1491         hook->func = func;
1492         hook->user_data = user_data;
1493         hook->next = assembly_refonly_preload_hook;
1494         assembly_refonly_preload_hook = hook;
1495 }
1496
1497 static void
1498 free_assembly_preload_hooks (void)
1499 {
1500         AssemblyPreLoadHook *hook, *next;
1501
1502         for (hook = assembly_preload_hook; hook; hook = next) {
1503                 next = hook->next;
1504                 g_free (hook);
1505         }
1506
1507         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1508                 next = hook->next;
1509                 g_free (hook);
1510         }
1511 }
1512
1513 static gchar *
1514 absolute_dir (const gchar *filename)
1515 {
1516         gchar *cwd;
1517         gchar *mixed;
1518         gchar **parts;
1519         gchar *part;
1520         GList *list, *tmp;
1521         GString *result;
1522         gchar *res;
1523         gint i;
1524
1525         if (g_path_is_absolute (filename)) {
1526                 part = g_path_get_dirname (filename);
1527                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1528                 g_free (part);
1529                 return res;
1530         }
1531
1532         cwd = g_get_current_dir ();
1533         mixed = g_build_filename (cwd, filename, NULL);
1534         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1535         g_free (mixed);
1536         g_free (cwd);
1537
1538         list = NULL;
1539         for (i = 0; (part = parts [i]) != NULL; i++) {
1540                 if (!strcmp (part, "."))
1541                         continue;
1542
1543                 if (!strcmp (part, "..")) {
1544                         if (list && list->next) /* Don't remove root */
1545                                 list = g_list_delete_link (list, list);
1546                 } else {
1547                         list = g_list_prepend (list, part);
1548                 }
1549         }
1550
1551         result = g_string_new ("");
1552         list = g_list_reverse (list);
1553
1554         /* Ignores last data pointer, which should be the filename */
1555         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1556                 if (tmp->data)
1557                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1558                                                                 G_DIR_SEPARATOR);
1559         }
1560
1561         res = result->str;
1562         g_string_free (result, FALSE);
1563         g_list_free (list);
1564         g_strfreev (parts);
1565         if (*res == '\0') {
1566                 g_free (res);
1567                 return g_strdup (".");
1568         }
1569
1570         return res;
1571 }
1572
1573 /** 
1574  * mono_assembly_open_from_bundle:
1575  * @filename: Filename requested
1576  * @status: return status code
1577  *
1578  * This routine tries to open the assembly specified by `filename' from the
1579  * defined bundles, if found, returns the MonoImage for it, if not found
1580  * returns NULL
1581  */
1582 MonoImage *
1583 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1584 {
1585         int i;
1586         char *name;
1587         gchar *lowercase_filename;
1588         MonoImage *image = NULL;
1589         gboolean is_satellite = FALSE;
1590         /*
1591          * we do a very simple search for bundled assemblies: it's not a general 
1592          * purpose assembly loading mechanism.
1593          */
1594
1595         if (!bundles)
1596                 return NULL;
1597
1598         lowercase_filename = g_utf8_strdown (filename, -1);
1599         is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1600         g_free (lowercase_filename);
1601         name = g_path_get_basename (filename);
1602         mono_assemblies_lock ();
1603         for (i = 0; !image && bundles [i]; ++i) {
1604                 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1605                         image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1606                         break;
1607                 }
1608         }
1609         mono_assemblies_unlock ();
1610         if (image) {
1611                 mono_image_addref (image);
1612                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1613                 g_free (name);
1614                 return image;
1615         }
1616         g_free (name);
1617         return NULL;
1618 }
1619
1620 /**
1621  * mono_assemblies_open_full:
1622  * @filename: the file to load
1623  * @status: return status code 
1624  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1625
1626  * This loads an assembly from the specified @filename.   The @filename allows
1627  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1628  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1629  * is treated as a local path.
1630  *
1631  * First, an attempt is made to load the assembly from the bundled executable (for those
1632  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1633  * assembly has been registered as an embedded assembly).   If this is not the case, then
1634  * the assembly is loaded from disk using `api:mono_image_open_full`.
1635  *
1636  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1637  * the assembly is made.
1638  *
1639  * If @refonly is set to true, then the assembly is loaded purely for inspection with
1640  * the `System.Reflection` API.
1641  *
1642  * Returns: NULL on error, with the @status set to an error code, or a pointer
1643  * to the assembly.
1644  */
1645 MonoAssembly *
1646 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1647 {
1648         MonoImage *image;
1649         MonoAssembly *ass;
1650         MonoImageOpenStatus def_status;
1651         gchar *fname;
1652         gchar *new_fname;
1653         gboolean loaded_from_bundle;
1654         
1655         g_return_val_if_fail (filename != NULL, NULL);
1656
1657         if (!status)
1658                 status = &def_status;
1659         *status = MONO_IMAGE_OK;
1660
1661         if (strncmp (filename, "file://", 7) == 0) {
1662                 GError *error = NULL;
1663                 gchar *uri = (gchar *) filename;
1664                 gchar *tmpuri;
1665
1666                 /*
1667                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1668                  * They also throw an IndexOutOfRangeException if "file://"
1669                  */
1670                 if (uri [7] != '/')
1671                         uri = g_strdup_printf ("file:///%s", uri + 7);
1672         
1673                 tmpuri = uri;
1674                 uri = mono_escape_uri_string (tmpuri);
1675                 fname = g_filename_from_uri (uri, NULL, &error);
1676                 g_free (uri);
1677
1678                 if (tmpuri != filename)
1679                         g_free (tmpuri);
1680
1681                 if (error != NULL) {
1682                         g_warning ("%s\n", error->message);
1683                         g_error_free (error);
1684                         fname = g_strdup (filename);
1685                 }
1686         } else {
1687                 fname = g_strdup (filename);
1688         }
1689
1690         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1691                         "Assembly Loader probing location: '%s'.", fname);
1692
1693         new_fname = NULL;
1694         if (!mono_assembly_is_in_gac (fname)) {
1695                 MonoError error;
1696                 new_fname = mono_make_shadow_copy (fname, &error);
1697                 if (!is_ok (&error)) {
1698                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1699                                     "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1700                         mono_error_cleanup (&error);
1701                         *status = MONO_IMAGE_IMAGE_INVALID;
1702                         g_free (fname);
1703                         return NULL;
1704                 }
1705         }
1706         if (new_fname && new_fname != fname) {
1707                 g_free (fname);
1708                 fname = new_fname;
1709                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1710                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1711         }
1712         
1713         image = NULL;
1714
1715         // If VM built with mkbundle
1716         loaded_from_bundle = FALSE;
1717         if (bundles != NULL) {
1718                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1719                 loaded_from_bundle = image != NULL;
1720         }
1721
1722         if (!image)
1723                 image = mono_image_open_full (fname, status, refonly);
1724
1725         if (!image){
1726                 if (*status == MONO_IMAGE_OK)
1727                         *status = MONO_IMAGE_ERROR_ERRNO;
1728                 g_free (fname);
1729                 return NULL;
1730         }
1731
1732         if (image->assembly) {
1733                 /* Already loaded by another appdomain */
1734                 mono_assembly_invoke_load_hook (image->assembly);
1735                 mono_image_close (image);
1736                 g_free (fname);
1737                 return image->assembly;
1738         }
1739
1740         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1741
1742         if (ass) {
1743                 if (!loaded_from_bundle)
1744                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1745                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1746                 if (!refonly)
1747                         mono_config_for_assembly (ass->image);
1748         }
1749
1750         /* Clear the reference added by mono_image_open */
1751         mono_image_close (image);
1752         
1753         g_free (fname);
1754
1755         return ass;
1756 }
1757
1758 static void
1759 free_item (gpointer val, gpointer user_data)
1760 {
1761         g_free (val);
1762 }
1763
1764 /**
1765  * mono_assembly_load_friends:
1766  * @ass: an assembly
1767  *
1768  * Load the list of friend assemblies that are allowed to access
1769  * the assembly's internal types and members. They are stored as assembly
1770  * names in custom attributes.
1771  *
1772  * This is an internal method, we need this because when we load mscorlib
1773  * we do not have the internals visible cattr loaded yet,
1774  * so we need to load these after we initialize the runtime. 
1775  *
1776  * LOCKING: Acquires the assemblies lock plus the loader lock.
1777  */
1778 void
1779 mono_assembly_load_friends (MonoAssembly* ass)
1780 {
1781         MonoError error;
1782         int i;
1783         MonoCustomAttrInfo* attrs;
1784         GSList *list;
1785
1786         if (ass->friend_assembly_names_inited)
1787                 return;
1788
1789         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1790         mono_error_assert_ok (&error);
1791         if (!attrs) {
1792                 mono_assemblies_lock ();
1793                 ass->friend_assembly_names_inited = TRUE;
1794                 mono_assemblies_unlock ();
1795                 return;
1796         }
1797
1798         mono_assemblies_lock ();
1799         if (ass->friend_assembly_names_inited) {
1800                 mono_assemblies_unlock ();
1801                 return;
1802         }
1803         mono_assemblies_unlock ();
1804
1805         list = NULL;
1806         /* 
1807          * We build the list outside the assemblies lock, the worse that can happen
1808          * is that we'll need to free the allocated list.
1809          */
1810         for (i = 0; i < attrs->num_attrs; ++i) {
1811                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1812                 MonoAssemblyName *aname;
1813                 const gchar *data;
1814                 /* Do some sanity checking */
1815                 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1816                         continue;
1817                 if (attr->data_size < 4)
1818                         continue;
1819                 data = (const char*)attr->data;
1820                 /* 0xFF means null string, see custom attr format */
1821                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1822                         continue;
1823                 mono_metadata_decode_value (data + 2, &data);
1824                 aname = g_new0 (MonoAssemblyName, 1);
1825                 /*g_print ("friend ass: %s\n", data);*/
1826                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1827                         list = g_slist_prepend (list, aname);
1828                 } else {
1829                         g_free (aname);
1830                 }
1831         }
1832         mono_custom_attrs_free (attrs);
1833
1834         mono_assemblies_lock ();
1835         if (ass->friend_assembly_names_inited) {
1836                 mono_assemblies_unlock ();
1837                 g_slist_foreach (list, free_item, NULL);
1838                 g_slist_free (list);
1839                 return;
1840         }
1841         ass->friend_assembly_names = list;
1842
1843         /* Because of the double checked locking pattern above */
1844         mono_memory_barrier ();
1845         ass->friend_assembly_names_inited = TRUE;
1846         mono_assemblies_unlock ();
1847 }
1848
1849 struct HasReferenceAssemblyAttributeIterData {
1850         gboolean has_attr;
1851 };
1852
1853 static gboolean
1854 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1855 {
1856         gboolean stop_scanning = FALSE;
1857         struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1858
1859         if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1860                 /* Note we don't check the assembly name, same as coreCLR. */
1861                 iter_data->has_attr = TRUE;
1862                 stop_scanning = TRUE;
1863         }
1864
1865         return stop_scanning;
1866 }
1867
1868 /**
1869  * mono_assembly_has_reference_assembly_attribute:
1870  * @assembly: a MonoAssembly
1871  * @error: set on error.
1872  *
1873  * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1874  * On error returns FALSE and sets @error.
1875  */
1876 gboolean
1877 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1878 {
1879         mono_error_init (error);
1880
1881         /*
1882          * This might be called during assembly loading, so do everything using the low-level
1883          * metadata APIs.
1884          */
1885
1886         struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1887
1888         mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1889
1890         return iter_data.has_attr;
1891 }
1892
1893 /**
1894  * mono_assembly_open:
1895  * @filename: Opens the assembly pointed out by this name
1896  * @status: return status code
1897  *
1898  * This loads an assembly from the specified @filename.   The @filename allows
1899  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1900  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1901  * is treated as a local path.
1902  *
1903  * First, an attempt is made to load the assembly from the bundled executable (for those
1904  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1905  * assembly has been registered as an embedded assembly).   If this is not the case, then
1906  * the assembly is loaded from disk using `api:mono_image_open_full`.
1907  *
1908  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1909  * the assembly is made.
1910  *
1911  * Return: a pointer to the MonoAssembly if @filename contains a valid
1912  * assembly or NULL on error.  Details about the error are stored in the
1913  * @status variable.
1914  */
1915 MonoAssembly *
1916 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1917 {
1918         return mono_assembly_open_full (filename, status, FALSE);
1919 }
1920
1921 /**
1922  * mono_assembly_load_from_full:
1923  * @image: Image to load the assembly from
1924  * @fname: assembly name to associate with the assembly
1925  * @status: returns the status condition
1926  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1927  *
1928  * If the provided @image has an assembly reference, it will process the given
1929  * image as an assembly with the given name.
1930  *
1931  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1932  *
1933  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1934  * set to #MONO_IMAGE_OK;  or NULL on error.
1935  *
1936  * If there is an error loading the assembly the @status will indicate the
1937  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1938  * image did not contain an assembly reference table.
1939  */
1940 MonoAssembly *
1941 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1942                               MonoImageOpenStatus *status, gboolean refonly)
1943 {
1944         MonoAssembly *ass, *ass2;
1945         char *base_dir;
1946
1947         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1948                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1949                 *status = MONO_IMAGE_IMAGE_INVALID;
1950                 return NULL;
1951         }
1952
1953 #if defined (HOST_WIN32)
1954         {
1955                 gchar *tmp_fn;
1956                 int i;
1957
1958                 tmp_fn = g_strdup (fname);
1959                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1960                         if (tmp_fn [i] == '/')
1961                                 tmp_fn [i] = '\\';
1962                 }
1963
1964                 base_dir = absolute_dir (tmp_fn);
1965                 g_free (tmp_fn);
1966         }
1967 #else
1968         base_dir = absolute_dir (fname);
1969 #endif
1970
1971         /*
1972          * Create assembly struct, and enter it into the assembly cache
1973          */
1974         ass = g_new0 (MonoAssembly, 1);
1975         ass->basedir = base_dir;
1976         ass->ref_only = refonly;
1977         ass->image = image;
1978
1979         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1980
1981         mono_assembly_fill_assembly_name (image, &ass->aname);
1982
1983         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1984                 // MS.NET doesn't support loading other mscorlibs
1985                 g_free (ass);
1986                 g_free (base_dir);
1987                 mono_image_addref (mono_defaults.corlib);
1988                 *status = MONO_IMAGE_OK;
1989                 return mono_defaults.corlib->assembly;
1990         }
1991
1992         /* Add a non-temporary reference because of ass->image */
1993         mono_image_addref (image);
1994
1995         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
1996
1997         /* 
1998          * The load hooks might take locks so we can't call them while holding the
1999          * assemblies lock.
2000          */
2001         if (ass->aname.name) {
2002                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2003                 if (ass2) {
2004                         g_free (ass);
2005                         g_free (base_dir);
2006                         mono_image_close (image);
2007                         *status = MONO_IMAGE_OK;
2008                         return ass2;
2009                 }
2010         }
2011
2012         /* We need to check for ReferenceAssmeblyAttribute before we
2013          * mark the assembly as loaded and before we fire the load
2014          * hook. Otherwise mono_domain_fire_assembly_load () in
2015          * appdomain.c will cache a mapping from the assembly name to
2016          * this image and we won't be able to look for a different
2017          * candidate. */
2018
2019         if (!refonly) {
2020                 MonoError refasm_error;
2021                 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2022                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2023                         g_free (ass);
2024                         g_free (base_dir);
2025                         mono_image_close (image);
2026                         *status = MONO_IMAGE_IMAGE_INVALID;
2027                         return NULL;
2028                 }
2029                 mono_error_cleanup (&refasm_error);
2030         }
2031
2032         mono_assemblies_lock ();
2033
2034         if (image->assembly) {
2035                 /*
2036                  * This means another thread has already loaded the assembly, but not yet
2037                  * called the load hooks so the search hook can't find the assembly.
2038                  */
2039                 mono_assemblies_unlock ();
2040                 ass2 = image->assembly;
2041                 g_free (ass);
2042                 g_free (base_dir);
2043                 mono_image_close (image);
2044                 *status = MONO_IMAGE_OK;
2045                 return ass2;
2046         }
2047
2048         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2049
2050         image->assembly = ass;
2051
2052         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2053         mono_assemblies_unlock ();
2054
2055 #ifdef HOST_WIN32
2056         if (image->is_module_handle)
2057                 mono_image_fixup_vtable (image);
2058 #endif
2059
2060         mono_assembly_invoke_load_hook (ass);
2061
2062         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2063         
2064         return ass;
2065 }
2066
2067 /**
2068  * mono_assembly_load_from:
2069  * @image: Image to load the assembly from
2070  * @fname: assembly name to associate with the assembly
2071  * @status: return status code
2072  *
2073  * If the provided @image has an assembly reference, it will process the given
2074  * image as an assembly with the given name.
2075  *
2076  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2077  *
2078  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2079  * @refonly parameter set to FALSE.
2080  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2081  * set to #MONO_IMAGE_OK;  or NULL on error.
2082  *
2083  * If there is an error loading the assembly the @status will indicate the
2084  * reason with @status being set to `MONO_IMAGE_INVALID` if the
2085  * image did not contain an assembly reference table.
2086  
2087  */
2088 MonoAssembly *
2089 mono_assembly_load_from (MonoImage *image, const char *fname,
2090                          MonoImageOpenStatus *status)
2091 {
2092         return mono_assembly_load_from_full (image, fname, status, FALSE);
2093 }
2094
2095 /**
2096  * mono_assembly_name_free:
2097  * @aname: assembly name to free
2098  * 
2099  * Frees the provided assembly name object.
2100  * (it does not frees the object itself, only the name members).
2101  */
2102 void
2103 mono_assembly_name_free (MonoAssemblyName *aname)
2104 {
2105         if (aname == NULL)
2106                 return;
2107
2108         g_free ((void *) aname->name);
2109         g_free ((void *) aname->culture);
2110         g_free ((void *) aname->hash_value);
2111         g_free ((guint8*) aname->public_key);
2112 }
2113
2114 static gboolean
2115 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2116 {
2117         const gchar *pkey;
2118         gchar header [16], val, *arr;
2119         gint i, j, offset, bitlen, keylen, pkeylen;
2120         
2121         keylen = strlen (key) >> 1;
2122         if (keylen < 1)
2123                 return FALSE;
2124
2125         /* allow the ECMA standard key */
2126         if (strcmp (key, "00000000000000000400000000000000") == 0) {
2127                 if (pubkey) {
2128                         *pubkey = g_strdup (key);
2129                         *is_ecma = TRUE;
2130                 }
2131                 return TRUE;
2132         }
2133         *is_ecma = FALSE;
2134         val = g_ascii_xdigit_value (key [0]) << 4;
2135         val |= g_ascii_xdigit_value (key [1]);
2136         switch (val) {
2137                 case 0x00:
2138                         if (keylen < 13)
2139                                 return FALSE;
2140                         val = g_ascii_xdigit_value (key [24]);
2141                         val |= g_ascii_xdigit_value (key [25]);
2142                         if (val != 0x06)
2143                                 return FALSE;
2144                         pkey = key + 24;
2145                         break;
2146                 case 0x06:
2147                         pkey = key;
2148                         break;
2149                 default:
2150                         return FALSE;
2151         }
2152                 
2153         /* We need the first 16 bytes
2154         * to check whether this key is valid or not */
2155         pkeylen = strlen (pkey) >> 1;
2156         if (pkeylen < 16)
2157                 return FALSE;
2158                 
2159         for (i = 0, j = 0; i < 16; i++) {
2160                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2161                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2162         }
2163
2164         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2165                         header [1] != 0x02 || /* Version (0x02) */
2166                         header [2] != 0x00 || /* Reserved (word) */
2167                         header [3] != 0x00 ||
2168                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2169                 return FALSE;
2170
2171         /* Based on this length, we _should_ be able to know if the length is right */
2172         bitlen = read32 (header + 12) >> 3;
2173         if ((bitlen + 16 + 4) != pkeylen)
2174                 return FALSE;
2175
2176         /* parsing is OK and the public key itself is not requested back */
2177         if (!pubkey)
2178                 return TRUE;
2179                 
2180         /* Encode the size of the blob */
2181         offset = 0;
2182         if (keylen <= 127) {
2183                 arr = (gchar *)g_malloc (keylen + 1);
2184                 arr [offset++] = keylen;
2185         } else {
2186                 arr = (gchar *)g_malloc (keylen + 2);
2187                 arr [offset++] = 0x80; /* 10bs */
2188                 arr [offset++] = keylen;
2189         }
2190                 
2191         for (i = offset, j = 0; i < keylen + offset; i++) {
2192                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2193                 arr [i] |= g_ascii_xdigit_value (key [j++]);
2194         }
2195
2196         *pubkey = arr;
2197
2198         return TRUE;
2199 }
2200
2201 static gboolean
2202 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, guint32 arch, MonoAssemblyName *aname, gboolean save_public_key)
2203 {
2204         gint major, minor, build, revision;
2205         gint len;
2206         gint version_parts;
2207         gchar *pkey, *pkeyptr, *encoded, tok [8];
2208
2209         memset (aname, 0, sizeof (MonoAssemblyName));
2210
2211         if (version) {
2212                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2213                 if (version_parts < 2 || version_parts > 4)
2214                         return FALSE;
2215
2216                 /* FIXME: we should set build & revision to -1 (instead of 0)
2217                 if these are not set in the version string. That way, later on,
2218                 we can still determine if these were specified. */
2219                 aname->major = major;
2220                 aname->minor = minor;
2221                 if (version_parts >= 3)
2222                         aname->build = build;
2223                 else
2224                         aname->build = 0;
2225                 if (version_parts == 4)
2226                         aname->revision = revision;
2227                 else
2228                         aname->revision = 0;
2229         }
2230         
2231         aname->flags = flags;
2232         aname->arch = arch;
2233         aname->name = g_strdup (name);
2234         
2235         if (culture) {
2236                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2237                         aname->culture = g_strdup ("");
2238                 else
2239                         aname->culture = g_strdup (culture);
2240         }
2241         
2242         if (token && strncmp (token, "null", 4) != 0) {
2243                 char *lower;
2244
2245                 /* the constant includes the ending NULL, hence the -1 */
2246                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2247                         mono_assembly_name_free (aname);
2248                         return FALSE;
2249                 }
2250                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2251                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2252                 g_free (lower);
2253         }
2254
2255         if (key) {
2256                 gboolean is_ecma;
2257                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2258                         mono_assembly_name_free (aname);
2259                         return FALSE;
2260                 }
2261
2262                 if (is_ecma) {
2263                         if (save_public_key)
2264                                 aname->public_key = (guint8*)pkey;
2265                         else
2266                                 g_free (pkey);
2267                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2268                         return TRUE;
2269                 }
2270                 
2271                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2272                 // We also need to generate the key token
2273                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2274                 encoded = encode_public_tok ((guchar*) tok, 8);
2275                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2276                 g_free (encoded);
2277
2278                 if (save_public_key)
2279                         aname->public_key = (guint8*) pkey;
2280                 else
2281                         g_free (pkey);
2282         }
2283
2284         return TRUE;
2285 }
2286
2287 static gboolean
2288 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2289 {
2290         gchar **parts;
2291         gboolean res;
2292         
2293         parts = g_strsplit (dirname, "_", 3);
2294         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2295                 g_strfreev (parts);
2296                 return FALSE;
2297         }
2298         
2299         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2300         g_strfreev (parts);
2301         return res;
2302 }
2303
2304 static gboolean
2305 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2306 {
2307         char *eqsign = strchr (pair, '=');
2308         if (!eqsign) {
2309                 *key = NULL;
2310                 *keylen = 0;
2311                 *value = NULL;
2312                 return FALSE;
2313         }
2314
2315         *key = (gchar*)pair;
2316         *keylen = eqsign - *key;
2317         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2318                 (*keylen)--;
2319         *value = g_strstrip (eqsign + 1);
2320         return TRUE;
2321 }
2322
2323 gboolean
2324 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2325 {
2326         gchar *dllname;
2327         gchar *dllname_uq;
2328         gchar *version = NULL;
2329         gchar *version_uq;
2330         gchar *culture = NULL;
2331         gchar *culture_uq;
2332         gchar *token = NULL;
2333         gchar *token_uq;
2334         gchar *key = NULL;
2335         gchar *key_uq;
2336         gchar *retargetable = NULL;
2337         gchar *retargetable_uq;
2338         gchar *procarch;
2339         gchar *procarch_uq;
2340         gboolean res;
2341         gchar *value, *part_name;
2342         guint32 part_name_len;
2343         gchar **parts;
2344         gchar **tmp;
2345         gboolean version_defined;
2346         gboolean token_defined;
2347         guint32 flags = 0;
2348         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2349
2350         if (!is_version_defined)
2351                 is_version_defined = &version_defined;
2352         *is_version_defined = FALSE;
2353         if (!is_token_defined)
2354                 is_token_defined = &token_defined;
2355         *is_token_defined = FALSE;
2356         
2357         parts = tmp = g_strsplit (name, ",", 6);
2358         if (!tmp || !*tmp) {
2359                 g_strfreev (tmp);
2360                 return FALSE;
2361         }
2362
2363         dllname = g_strstrip (*tmp);
2364         
2365         tmp++;
2366
2367         while (*tmp) {
2368                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2369                         goto cleanup_and_fail;
2370
2371                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2372                         *is_version_defined = TRUE;
2373                         version = value;
2374                         if (strlen (version) == 0) {
2375                                 goto cleanup_and_fail;
2376                         }
2377                         tmp++;
2378                         continue;
2379                 }
2380
2381                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2382                         culture = value;
2383                         if (strlen (culture) == 0) {
2384                                 goto cleanup_and_fail;
2385                         }
2386                         tmp++;
2387                         continue;
2388                 }
2389
2390                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2391                         *is_token_defined = TRUE;
2392                         token = value;
2393                         if (strlen (token) == 0) {
2394                                 goto cleanup_and_fail;
2395                         }
2396                         tmp++;
2397                         continue;
2398                 }
2399
2400                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2401                         key = value;
2402                         if (strlen (key) == 0) {
2403                                 goto cleanup_and_fail;
2404                         }
2405                         tmp++;
2406                         continue;
2407                 }
2408
2409                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2410                         retargetable = value;
2411                         retargetable_uq = unquote (retargetable);
2412                         if (retargetable_uq != NULL)
2413                                 retargetable = retargetable_uq;
2414
2415                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2416                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2417                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2418                                 g_free (retargetable_uq);
2419                                 goto cleanup_and_fail;
2420                         }
2421
2422                         g_free (retargetable_uq);
2423                         tmp++;
2424                         continue;
2425                 }
2426
2427                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2428                         procarch = value;
2429                         procarch_uq = unquote (procarch);
2430                         if (procarch_uq != NULL)
2431                                 procarch = procarch_uq;
2432
2433                         if (!g_ascii_strcasecmp (procarch, "MSIL"))
2434                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2435                         else if (!g_ascii_strcasecmp (procarch, "X86"))
2436                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2437                         else if (!g_ascii_strcasecmp (procarch, "IA64"))
2438                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2439                         else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2440                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2441                         else {
2442                                 g_free (procarch_uq);
2443                                 goto cleanup_and_fail;
2444                         }
2445
2446                         g_free (procarch_uq);
2447                         tmp++;
2448                         continue;
2449                 }
2450
2451                 g_strfreev (parts);
2452                 return FALSE;
2453         }
2454
2455         /* if retargetable flag is set, then we must have a fully qualified name */
2456         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2457                 goto cleanup_and_fail;
2458         }
2459
2460         dllname_uq = unquote (dllname);
2461         version_uq = unquote (version);
2462         culture_uq = unquote (culture);
2463         token_uq = unquote (token);
2464         key_uq = unquote (key);
2465
2466         res = build_assembly_name (
2467                 dllname_uq == NULL ? dllname : dllname_uq,
2468                 version_uq == NULL ? version : version_uq,
2469                 culture_uq == NULL ? culture : culture_uq,
2470                 token_uq == NULL ? token : token_uq,
2471                 key_uq == NULL ? key : key_uq,
2472                 flags, arch, aname, save_public_key);
2473
2474         g_free (dllname_uq);
2475         g_free (version_uq);
2476         g_free (culture_uq);
2477         g_free (token_uq);
2478         g_free (key_uq);
2479
2480         g_strfreev (parts);
2481         return res;
2482
2483 cleanup_and_fail:
2484         g_strfreev (parts);
2485         return FALSE;
2486 }
2487
2488 static char*
2489 unquote (const char *str)
2490 {
2491         gint slen;
2492         const char *end;
2493
2494         if (str == NULL)
2495                 return NULL;
2496
2497         slen = strlen (str);
2498         if (slen < 2)
2499                 return NULL;
2500
2501         if (*str != '\'' && *str != '\"')
2502                 return NULL;
2503
2504         end = str + slen - 1;
2505         if (*str != *end)
2506                 return NULL;
2507
2508         return g_strndup (str + 1, slen - 2);
2509 }
2510
2511 /**
2512  * mono_assembly_name_parse:
2513  * @name: name to parse
2514  * @aname: the destination assembly name
2515  * 
2516  * Parses an assembly qualified type name and assigns the name,
2517  * version, culture and token to the provided assembly name object.
2518  *
2519  * Returns: TRUE if the name could be parsed.
2520  */
2521 gboolean
2522 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2523 {
2524         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2525 }
2526
2527 /**
2528  * mono_assembly_name_new:
2529  * @name: name to parse
2530  *
2531  * Allocate a new MonoAssemblyName and fill its values from the
2532  * passed @name.
2533  *
2534  * Returns: a newly allocated structure or NULL if there was any failure.
2535  */
2536 MonoAssemblyName*
2537 mono_assembly_name_new (const char *name)
2538 {
2539         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2540         if (mono_assembly_name_parse (name, aname))
2541                 return aname;
2542         g_free (aname);
2543         return NULL;
2544 }
2545
2546 const char*
2547 mono_assembly_name_get_name (MonoAssemblyName *aname)
2548 {
2549         return aname->name;
2550 }
2551
2552 const char*
2553 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2554 {
2555         return aname->culture;
2556 }
2557
2558 mono_byte*
2559 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2560 {
2561         if (aname->public_key_token [0])
2562                 return aname->public_key_token;
2563         return NULL;
2564 }
2565
2566 uint16_t
2567 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2568 {
2569         if (minor)
2570                 *minor = aname->minor;
2571         if (build)
2572                 *build = aname->build;
2573         if (revision)
2574                 *revision = aname->revision;
2575         return aname->major;
2576 }
2577
2578 static MonoAssembly*
2579 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2580 {
2581         gchar *fullpath = NULL;
2582         GDir *dirhandle;
2583         const char* direntry;
2584         MonoAssemblyName gac_aname;
2585         gint major=-1, minor=0, build=0, revision=0;
2586         gboolean exact_version;
2587         
2588         dirhandle = g_dir_open (basepath, 0, NULL);
2589         if (!dirhandle)
2590                 return NULL;
2591                 
2592         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2593
2594         while ((direntry = g_dir_read_name (dirhandle))) {
2595                 gboolean match = TRUE;
2596                 
2597                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2598                         continue;
2599                 
2600                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2601                         match = FALSE;
2602                         
2603                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2604                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2605                         match = FALSE;
2606                 
2607                 if (match) {
2608                         if (exact_version) {
2609                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2610                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2611                         }
2612                         else if (gac_aname.major < major)
2613                                 match = FALSE;
2614                         else if (gac_aname.major == major) {
2615                                 if (gac_aname.minor < minor)
2616                                         match = FALSE;
2617                                 else if (gac_aname.minor == minor) {
2618                                         if (gac_aname.build < build)
2619                                                 match = FALSE;
2620                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2621                                                 match = FALSE; 
2622                                 }
2623                         }
2624                 }
2625                 
2626                 if (match) {
2627                         major = gac_aname.major;
2628                         minor = gac_aname.minor;
2629                         build = gac_aname.build;
2630                         revision = gac_aname.revision;
2631                         g_free (fullpath);
2632                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2633                 }
2634
2635                 mono_assembly_name_free (&gac_aname);
2636         }
2637         
2638         g_dir_close (dirhandle);
2639         
2640         if (fullpath == NULL)
2641                 return NULL;
2642         else {
2643                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2644                 g_free (fullpath);
2645                 return res;
2646         }
2647 }
2648
2649 /**
2650  * mono_assembly_load_with_partial_name:
2651  * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2652  * @status: return status code
2653  *
2654  * Loads a Mono Assembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2655  * so it might contain a qualified type name, version, culture and token.
2656  *
2657  * This will load the assembly from the file whose name is derived from the assembly name
2658  * by appending the .dll extension.
2659  *
2660  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2661  * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2662  * if that fails from the GAC.
2663  *
2664  * Returns: NULL on failure, or a pointer to a MonoAssembly on success.   
2665  */
2666 MonoAssembly*
2667 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2668 {
2669         MonoError error;
2670         MonoAssembly *res;
2671         MonoAssemblyName *aname, base_name;
2672         MonoAssemblyName mapped_aname;
2673         gchar *fullname, *gacpath;
2674         gchar **paths;
2675
2676         memset (&base_name, 0, sizeof (MonoAssemblyName));
2677         aname = &base_name;
2678
2679         if (!mono_assembly_name_parse (name, aname))
2680                 return NULL;
2681
2682         /* 
2683          * If no specific version has been requested, make sure we load the
2684          * correct version for system assemblies.
2685          */ 
2686         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2687                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2688         
2689         res = mono_assembly_loaded (aname);
2690         if (res) {
2691                 mono_assembly_name_free (aname);
2692                 return res;
2693         }
2694
2695         res = invoke_assembly_preload_hook (aname, assemblies_path);
2696         if (res) {
2697                 res->in_gac = FALSE;
2698                 mono_assembly_name_free (aname);
2699                 return res;
2700         }
2701
2702         fullname = g_strdup_printf ("%s.dll", aname->name);
2703
2704         if (extra_gac_paths) {
2705                 paths = extra_gac_paths;
2706                 while (!res && *paths) {
2707                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2708                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2709                         g_free (gacpath);
2710                         paths++;
2711                 }
2712         }
2713
2714         if (res) {
2715                 res->in_gac = TRUE;
2716                 g_free (fullname);
2717                 mono_assembly_name_free (aname);
2718                 return res;
2719         }
2720
2721         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2722         res = probe_for_partial_name (gacpath, fullname, aname, status);
2723         g_free (gacpath);
2724
2725         g_free (fullname);
2726         mono_assembly_name_free (aname);
2727
2728         if (res)
2729                 res->in_gac = TRUE;
2730         else {
2731                 MonoDomain *domain = mono_domain_get ();
2732
2733                 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2734                 if (!is_ok (&error)) {
2735                         mono_error_cleanup (&error);
2736                         if (*status == MONO_IMAGE_OK)
2737                                 *status = MONO_IMAGE_IMAGE_INVALID;
2738                 }
2739         }
2740
2741         return res;
2742 }
2743
2744 static MonoBoolean
2745 mono_assembly_is_in_gac (const gchar *filename)
2746 {
2747         const gchar *rootdir;
2748         gchar *gp;
2749         gchar **paths;
2750
2751         if (filename == NULL)
2752                 return FALSE;
2753
2754         for (paths = extra_gac_paths; paths && *paths; paths++) {
2755                 if (strstr (*paths, filename) != *paths)
2756                         continue;
2757
2758                 gp = (gchar *) (filename + strlen (*paths));
2759                 if (*gp != G_DIR_SEPARATOR)
2760                         continue;
2761                 gp++;
2762                 if (strncmp (gp, "lib", 3))
2763                         continue;
2764                 gp += 3;
2765                 if (*gp != G_DIR_SEPARATOR)
2766                         continue;
2767                 gp++;
2768                 if (strncmp (gp, "mono", 4))
2769                         continue;
2770                 gp += 4;
2771                 if (*gp != G_DIR_SEPARATOR)
2772                         continue;
2773                 gp++;
2774                 if (strncmp (gp, "gac", 3))
2775                         continue;
2776                 gp += 3;
2777                 if (*gp != G_DIR_SEPARATOR)
2778                         continue;
2779
2780                 return TRUE;
2781         }
2782
2783         rootdir = mono_assembly_getrootdir ();
2784         if (strstr (filename, rootdir) != filename)
2785                 return FALSE;
2786
2787         gp = (gchar *) (filename + strlen (rootdir));
2788         if (*gp != G_DIR_SEPARATOR)
2789                 return FALSE;
2790         gp++;
2791         if (strncmp (gp, "mono", 4))
2792                 return FALSE;
2793         gp += 4;
2794         if (*gp != G_DIR_SEPARATOR)
2795                 return FALSE;
2796         gp++;
2797         if (strncmp (gp, "gac", 3))
2798                 return FALSE;
2799         gp += 3;
2800         if (*gp != G_DIR_SEPARATOR)
2801                 return FALSE;
2802         return TRUE;
2803 }
2804
2805 static MonoImage*
2806 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2807 {
2808         MonoImage *image;
2809         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2810         gchar **paths;
2811         gint32 len;
2812
2813         if (strstr (aname->name, ".dll")) {
2814                 len = strlen (aname->name) - 4;
2815                 name = (gchar *)g_malloc (len + 1);
2816                 strncpy (name, aname->name, len);
2817                 name[len] = 0;
2818         } else
2819                 name = g_strdup (aname->name);
2820         
2821         if (aname->culture)
2822                 culture = g_utf8_strdown (aname->culture, -1);
2823         else
2824                 culture = g_strdup ("");
2825         
2826         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2827         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2828         g_free (name);
2829         g_free (culture);
2830         
2831         filename = g_strconcat (pname, ".dll", NULL);
2832         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2833         g_free (pname);
2834         g_free (version);
2835         g_free (filename);
2836
2837         image = NULL;
2838         if (extra_gac_paths) {
2839                 paths = extra_gac_paths;
2840                 while (!image && *paths) {
2841                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2842                                         "lib", "mono", "gac", subpath, NULL);
2843                         image = mono_image_open (fullpath, NULL);
2844                         g_free (fullpath);
2845                         paths++;
2846                 }
2847         }
2848
2849         if (image) {
2850                 g_free (subpath);
2851                 return image;
2852         }
2853
2854         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2855                         "mono", "gac", subpath, NULL);
2856         image = mono_image_open (fullpath, NULL);
2857         g_free (subpath);
2858         g_free (fullpath);
2859         
2860         return image;
2861 }
2862
2863 static MonoAssemblyName*
2864 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2865 {
2866         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2867         dest_name->major = info->new_version.major;
2868         dest_name->minor = info->new_version.minor;
2869         dest_name->build = info->new_version.build;
2870         dest_name->revision = info->new_version.revision;
2871         
2872         return dest_name;
2873 }
2874
2875 /* LOCKING: assembly_binding lock must be held */
2876 static MonoAssemblyBindingInfo*
2877 search_binding_loaded (MonoAssemblyName *aname)
2878 {
2879         GSList *tmp;
2880
2881         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2882                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2883                 if (assembly_binding_maps_name (info, aname))
2884                         return info;
2885         }
2886
2887         return NULL;
2888 }
2889
2890 static inline gboolean
2891 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2892 {
2893         if (left->major != right->major || left->minor != right->minor ||
2894             left->build != right->build || left->revision != right->revision)
2895                 return FALSE;
2896
2897         return TRUE;
2898 }
2899
2900 static inline gboolean
2901 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2902 {
2903         if (left->has_old_version_bottom != right->has_old_version_bottom)
2904                 return FALSE;
2905
2906         if (left->has_old_version_top != right->has_old_version_top)
2907                 return FALSE;
2908
2909         if (left->has_new_version != right->has_new_version)
2910                 return FALSE;
2911
2912         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2913                 return FALSE;
2914
2915         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2916                 return FALSE;
2917
2918         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2919                 return FALSE;
2920
2921         return TRUE;
2922 }
2923
2924 /* LOCKING: assumes all the necessary locks are held */
2925 static void
2926 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2927 {
2928         MonoAssemblyBindingInfo *info_copy;
2929         GSList *tmp;
2930         MonoAssemblyBindingInfo *info_tmp;
2931         MonoDomain *domain = (MonoDomain*)user_data;
2932
2933         if (!domain)
2934                 return;
2935
2936         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2937                 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2938                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2939                         return;
2940         }
2941
2942         info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2943         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2944         if (info->name)
2945                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2946         if (info->culture)
2947                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2948
2949         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2950 }
2951
2952 static int
2953 get_version_number (int major, int minor)
2954 {
2955         return major * 256 + minor;
2956 }
2957
2958 static inline gboolean
2959 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2960 {
2961         int aname_version_number = get_version_number (aname->major, aname->minor);
2962         if (!info->has_old_version_bottom)
2963                 return FALSE;
2964
2965         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2966                 return FALSE;
2967
2968         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2969                 return FALSE;
2970
2971         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2972         info->major = aname->major;
2973         info->minor = aname->minor;
2974
2975         return TRUE;
2976 }
2977
2978 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2979 static MonoAssemblyBindingInfo*
2980 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2981 {
2982         MonoAssemblyBindingInfo *info;
2983         GSList *list;
2984
2985         if (!domain->assembly_bindings)
2986                 return NULL;
2987
2988         info = NULL;
2989         for (list = domain->assembly_bindings; list; list = list->next) {
2990                 info = (MonoAssemblyBindingInfo *)list->data;
2991                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2992                         break;
2993                 info = NULL;
2994         }
2995
2996         if (info) {
2997                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2998                     info->has_new_version && assembly_binding_maps_name (info, aname))
2999                         info->is_valid = TRUE;
3000                 else
3001                         info->is_valid = FALSE;
3002         }
3003
3004         return info;
3005 }
3006
3007 static MonoAssemblyName*
3008 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3009 {
3010         MonoError error;
3011         MonoAssemblyBindingInfo *info, *info2;
3012         MonoImage *ppimage;
3013         MonoDomain *domain;
3014
3015         if (aname->public_key_token [0] == 0)
3016                 return aname;
3017
3018         domain = mono_domain_get ();
3019
3020         mono_assembly_binding_lock ();
3021         info = search_binding_loaded (aname);
3022         mono_assembly_binding_unlock ();
3023
3024         if (!info) {
3025                 mono_domain_lock (domain);
3026                 info = get_per_domain_assembly_binding_info (domain, aname);
3027                 mono_domain_unlock (domain);
3028         }
3029
3030         if (info) {
3031                 if (!check_policy_versions (info, aname))
3032                         return aname;
3033                 
3034                 mono_assembly_bind_version (info, aname, dest_name);
3035                 return dest_name;
3036         }
3037
3038         if (domain && domain->setup && domain->setup->configuration_file) {
3039                 mono_domain_lock (domain);
3040                 if (!domain->assembly_bindings_parsed) {
3041                         gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3042                         /* expect this to succeed because mono_domain_set_options_from_config () did
3043                          * the same thing when the domain was created. */
3044                         mono_error_assert_ok (&error);
3045
3046                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3047
3048                         if (!domain_config_file_path)
3049                                 domain_config_file_path = domain_config_file_name;
3050                         
3051                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3052                         domain->assembly_bindings_parsed = TRUE;
3053                         if (domain_config_file_name != domain_config_file_path)
3054                                 g_free (domain_config_file_name);
3055                         g_free (domain_config_file_path);
3056                 }
3057
3058                 info2 = get_per_domain_assembly_binding_info (domain, aname);
3059
3060                 if (info2) {
3061                         info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3062                         info->name = g_strdup (info2->name);
3063                         info->culture = g_strdup (info2->culture);
3064                         info->domain_id = domain->domain_id;
3065                 }
3066
3067                 mono_domain_unlock (domain);
3068         }
3069
3070         if (!info) {
3071                 info = g_new0 (MonoAssemblyBindingInfo, 1);
3072                 info->major = aname->major;
3073                 info->minor = aname->minor;
3074         }
3075
3076         if (!info->is_valid) {
3077                 ppimage = mono_assembly_load_publisher_policy (aname);
3078                 if (ppimage) {
3079                         get_publisher_policy_info (ppimage, aname, info);
3080                         mono_image_close (ppimage);
3081                 }
3082         }
3083
3084         /* Define default error value if needed */
3085         if (!info->is_valid) {
3086                 info->name = g_strdup (aname->name);
3087                 info->culture = g_strdup (aname->culture);
3088                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3089         }
3090         
3091         mono_assembly_binding_lock ();
3092         info2 = search_binding_loaded (aname);
3093         if (info2) {
3094                 /* This binding was added by another thread 
3095                  * before us */
3096                 mono_assembly_binding_info_free (info);
3097                 g_free (info);
3098                 
3099                 info = info2;
3100         } else
3101                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3102                 
3103         mono_assembly_binding_unlock ();
3104         
3105         if (!info->is_valid || !check_policy_versions (info, aname))
3106                 return aname;
3107
3108         mono_assembly_bind_version (info, aname, dest_name);
3109         return dest_name;
3110 }
3111
3112 /**
3113  * mono_assembly_load_from_gac
3114  *
3115  * @aname: The assembly name object
3116  */
3117 static MonoAssembly*
3118 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3119 {
3120         MonoAssembly *result = NULL;
3121         gchar *name, *version, *culture, *fullpath, *subpath;
3122         gint32 len;
3123         gchar **paths;
3124         char *pubtok;
3125
3126         if (aname->public_key_token [0] == 0) {
3127                 return NULL;
3128         }
3129
3130         if (strstr (aname->name, ".dll")) {
3131                 len = strlen (filename) - 4;
3132                 name = (gchar *)g_malloc (len + 1);
3133                 strncpy (name, aname->name, len);
3134                 name[len] = 0;
3135         } else {
3136                 name = g_strdup (aname->name);
3137         }
3138
3139         if (aname->culture) {
3140                 culture = g_utf8_strdown (aname->culture, -1);
3141         } else {
3142                 culture = g_strdup ("");
3143         }
3144
3145         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3146         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3147                         aname->minor, aname->build, aname->revision,
3148                         culture, pubtok);
3149         g_free (pubtok);
3150         
3151         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3152         g_free (name);
3153         g_free (version);
3154         g_free (culture);
3155
3156         if (extra_gac_paths) {
3157                 paths = extra_gac_paths;
3158                 while (!result && *paths) {
3159                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3160                         result = mono_assembly_open_full (fullpath, status, refonly);
3161                         g_free (fullpath);
3162                         paths++;
3163                 }
3164         }
3165
3166         if (result) {
3167                 result->in_gac = TRUE;
3168                 g_free (subpath);
3169                 return result;
3170         }
3171
3172         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3173                         "mono", "gac", subpath, NULL);
3174         result = mono_assembly_open_full (fullpath, status, refonly);
3175         g_free (fullpath);
3176
3177         if (result)
3178                 result->in_gac = TRUE;
3179         
3180         g_free (subpath);
3181
3182         return result;
3183 }
3184
3185 MonoAssembly*
3186 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3187 {
3188         char *corlib_file;
3189         MonoAssemblyName *aname;
3190
3191         if (corlib) {
3192                 /* g_print ("corlib already loaded\n"); */
3193                 return corlib;
3194         }
3195
3196         // In native client, Corlib is embedded in the executable as static variable corlibData
3197 #if defined(__native_client__)
3198         if (corlibData != NULL && corlibSize != 0) {
3199                 int status = 0;
3200                 /* First "FALSE" instructs mono not to make a copy. */
3201                 /* Second "FALSE" says this is not just a ref.      */
3202                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3203                 if (image == NULL || status != 0)
3204                         g_print("mono_image_open_from_data_full failed: %d\n", status);
3205                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3206                 if (corlib == NULL || status != 0)
3207                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
3208                 if (corlib)
3209                         return corlib;
3210         }
3211 #endif
3212
3213         // A nonstandard preload hook may provide a special mscorlib assembly
3214         aname = mono_assembly_name_new ("mscorlib.dll");
3215         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3216         mono_assembly_name_free (aname);
3217         g_free (aname);
3218         if (corlib != NULL)
3219                 goto return_corlib_and_facades;
3220
3221         // This unusual directory layout can occur if mono is being built and run out of its own source repo
3222         if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3223                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3224                 if (corlib)
3225                         goto return_corlib_and_facades;
3226         }
3227
3228         /* Normal case: Load corlib from mono/<version> */
3229         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3230         if (assemblies_path) { // Custom assemblies path
3231                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3232                 if (corlib) {
3233                         g_free (corlib_file);
3234                         goto return_corlib_and_facades;
3235                 }
3236         }
3237         corlib = load_in_path (corlib_file, default_path, status, FALSE);
3238         g_free (corlib_file);
3239
3240 return_corlib_and_facades:
3241         if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3242                 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3243                 
3244         return corlib;
3245 }
3246
3247 static MonoAssembly*
3248 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3249 {
3250         MonoError refasm_error;
3251         mono_error_init (&refasm_error);
3252         if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3253                 candidate = NULL;
3254         }
3255         mono_error_cleanup (&refasm_error);
3256         return candidate;
3257 }
3258
3259
3260 MonoAssembly*
3261 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
3262                                                                   const char       *basedir, 
3263                                                                   MonoImageOpenStatus *status,
3264                                                                   gboolean refonly)
3265 {
3266         MonoAssembly *result;
3267         char *fullpath, *filename;
3268         MonoAssemblyName maped_aname;
3269         MonoAssemblyName maped_name_pp;
3270         int ext_index;
3271         const char *ext;
3272         int len;
3273
3274         aname = mono_assembly_remap_version (aname, &maped_aname);
3275         
3276         /* Reflection only assemblies don't get assembly binding */
3277         if (!refonly)
3278                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3279         
3280         result = mono_assembly_loaded_full (aname, refonly);
3281         if (result)
3282                 return result;
3283
3284         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3285         if (result) {
3286                 result->in_gac = FALSE;
3287                 return result;
3288         }
3289
3290         /* Currently we retrieve the loaded corlib for reflection 
3291          * only requests, like a common reflection only assembly 
3292          */
3293         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3294                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3295         }
3296
3297         len = strlen (aname->name);
3298         for (ext_index = 0; ext_index < 2; ext_index ++) {
3299                 ext = ext_index == 0 ? ".dll" : ".exe";
3300                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3301                         filename = g_strdup (aname->name);
3302                         /* Don't try appending .dll/.exe if it already has one of those extensions */
3303                         ext_index++;
3304                 } else {
3305                         filename = g_strconcat (aname->name, ext, NULL);
3306                 }
3307
3308                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3309                 if (result) {
3310                         g_free (filename);
3311                         return result;
3312                 }
3313
3314                 if (basedir) {
3315                         fullpath = g_build_filename (basedir, filename, NULL);
3316                         result = mono_assembly_open_full (fullpath, status, refonly);
3317                         g_free (fullpath);
3318                         if (result) {
3319                                 result->in_gac = FALSE;
3320                                 g_free (filename);
3321                                 return result;
3322                         }
3323                 }
3324
3325                 result = load_in_path (filename, default_path, status, refonly);
3326                 if (result)
3327                         result->in_gac = FALSE;
3328                 g_free (filename);
3329                 if (result)
3330                         return result;
3331         }
3332
3333         return result;
3334 }
3335
3336 MonoAssembly*
3337 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3338 {
3339         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3340
3341         if (!result) {
3342                 /* Try a postload search hook */
3343                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3344                 result = prevent_reference_assembly_from_running (result, refonly);
3345         }
3346         return result;
3347 }
3348
3349 /**
3350  * mono_assembly_load_full:
3351  * @aname: A MonoAssemblyName with the assembly name to load.
3352  * @basedir: A directory to look up the assembly at.
3353  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3354  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3355  *
3356  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3357  * attempts to load the assembly from that directory before probing the standard locations.
3358  *
3359  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
3360  * assembly binding takes place.
3361  *
3362  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3363  * value pointed by status is updated with an error code.
3364  */
3365 MonoAssembly*
3366 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3367 {
3368         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3369 }
3370
3371 /**
3372  * mono_assembly_load:
3373  * @aname: A MonoAssemblyName with the assembly name to load.
3374  * @basedir: A directory to look up the assembly at.
3375  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3376  *
3377  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3378  * attempts to load the assembly from that directory before probing the standard locations.
3379  *
3380  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3381  * value pointed by status is updated with an error code.
3382  */
3383 MonoAssembly*
3384 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3385 {
3386         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3387 }
3388
3389 /**
3390  * mono_assembly_loaded_full:
3391  * @aname: an assembly to look for.
3392  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3393  *
3394  * This is used to determine if the specified assembly has been loaded
3395  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3396  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3397  */
3398 MonoAssembly*
3399 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3400 {
3401         MonoAssembly *res;
3402         MonoAssemblyName maped_aname;
3403
3404         aname = mono_assembly_remap_version (aname, &maped_aname);
3405
3406         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3407
3408         return res;
3409 }
3410
3411 /**
3412  * mono_assembly_loaded:
3413  * @aname: an assembly to look for.
3414  *
3415  * This is used to determine if the specified assembly has been loaded
3416  
3417  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3418  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3419  */
3420 MonoAssembly*
3421 mono_assembly_loaded (MonoAssemblyName *aname)
3422 {
3423         return mono_assembly_loaded_full (aname, FALSE);
3424 }
3425
3426 void
3427 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3428 {
3429         if (assembly == NULL || assembly == REFERENCE_MISSING)
3430                 return;
3431
3432         if (assembly_is_dynamic (assembly)) {
3433                 int i;
3434                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3435                 for (i = 0; i < dynimg->image.module_count; ++i)
3436                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3437                 mono_dynamic_image_release_gc_roots (dynimg);
3438         }
3439 }
3440
3441 /*
3442  * Returns whether mono_assembly_close_finish() must be called as
3443  * well.  See comment for mono_image_close_except_pools() for why we
3444  * unload in two steps.
3445  */
3446 gboolean
3447 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3448 {
3449         GSList *tmp;
3450         g_return_val_if_fail (assembly != NULL, FALSE);
3451
3452         if (assembly == REFERENCE_MISSING)
3453                 return FALSE;
3454
3455         /* Might be 0 already */
3456         if (InterlockedDecrement (&assembly->ref_count) > 0)
3457                 return FALSE;
3458
3459         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3460
3461         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3462
3463         mono_debug_close_image (assembly->image);
3464
3465         mono_assemblies_lock ();
3466         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3467         mono_assemblies_unlock ();
3468
3469         assembly->image->assembly = NULL;
3470
3471         if (!mono_image_close_except_pools (assembly->image))
3472                 assembly->image = NULL;
3473
3474         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3475                 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3476                 mono_assembly_name_free (fname);
3477                 g_free (fname);
3478         }
3479         g_slist_free (assembly->friend_assembly_names);
3480         g_free (assembly->basedir);
3481
3482         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3483
3484         return TRUE;
3485 }
3486
3487 void
3488 mono_assembly_close_finish (MonoAssembly *assembly)
3489 {
3490         g_assert (assembly && assembly != REFERENCE_MISSING);
3491
3492         if (assembly->image)
3493                 mono_image_close_finish (assembly->image);
3494
3495         if (assembly_is_dynamic (assembly)) {
3496                 g_free ((char*)assembly->aname.culture);
3497         } else {
3498                 g_free (assembly);
3499         }
3500 }
3501
3502 /**
3503  * mono_assembly_close:
3504  * @assembly: the assembly to release.
3505  *
3506  * This method releases a reference to the @assembly.  The assembly is
3507  * only released when all the outstanding references to it are released.
3508  */
3509 void
3510 mono_assembly_close (MonoAssembly *assembly)
3511 {
3512         if (mono_assembly_close_except_image_pools (assembly))
3513                 mono_assembly_close_finish (assembly);
3514 }
3515
3516 MonoImage*
3517 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3518 {
3519         MonoError error;
3520         MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3521         mono_error_assert_ok (&error);
3522         return result;
3523 }
3524
3525 MONO_API MonoImage*
3526 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3527 {
3528         return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3529 }
3530
3531
3532 /**
3533  * mono_assembly_foreach:
3534  * @func: function to invoke for each assembly loaded
3535  * @user_data: data passed to the callback
3536  *
3537  * Invokes the provided @func callback for each assembly loaded into
3538  * the runtime.   The first parameter passed to the callback  is the
3539  * `MonoAssembly*`, and the second parameter is the @user_data.
3540  *
3541  * This is done for all assemblies loaded in the runtime, not just
3542  * those loaded in the current application domain.
3543  */
3544 void
3545 mono_assembly_foreach (GFunc func, gpointer user_data)
3546 {
3547         GList *copy;
3548
3549         /*
3550          * We make a copy of the list to avoid calling the callback inside the 
3551          * lock, which could lead to deadlocks.
3552          */
3553         mono_assemblies_lock ();
3554         copy = g_list_copy (loaded_assemblies);
3555         mono_assemblies_unlock ();
3556
3557         g_list_foreach (loaded_assemblies, func, user_data);
3558
3559         g_list_free (copy);
3560 }
3561
3562 /**
3563  * mono_assemblies_cleanup:
3564  *
3565  * Free all resources used by this module.
3566  */
3567 void
3568 mono_assemblies_cleanup (void)
3569 {
3570         GSList *l;
3571
3572         mono_os_mutex_destroy (&assemblies_mutex);
3573         mono_os_mutex_destroy (&assembly_binding_mutex);
3574
3575         for (l = loaded_assembly_bindings; l; l = l->next) {
3576                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3577
3578                 mono_assembly_binding_info_free (info);
3579                 g_free (info);
3580         }
3581         g_slist_free (loaded_assembly_bindings);
3582
3583         free_assembly_load_hooks ();
3584         free_assembly_search_hooks ();
3585         free_assembly_preload_hooks ();
3586 }
3587
3588 /*LOCKING takes the assembly_binding lock*/
3589 void
3590 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3591 {
3592         GSList **iter;
3593
3594         mono_assembly_binding_lock ();
3595         iter = &loaded_assembly_bindings;
3596         while (*iter) {
3597                 GSList *l = *iter;
3598                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3599
3600                 if (info->domain_id == domain_id) {
3601                         *iter = l->next;
3602                         mono_assembly_binding_info_free (info);
3603                         g_free (info);
3604                         g_slist_free_1 (l);
3605                 } else {
3606                         iter = &l->next;
3607                 }
3608         }
3609         mono_assembly_binding_unlock ();
3610 }
3611
3612 /*
3613  * Holds the assembly of the application, for
3614  * System.Diagnostics.Process::MainModule
3615  */
3616 static MonoAssembly *main_assembly=NULL;
3617
3618 void
3619 mono_assembly_set_main (MonoAssembly *assembly)
3620 {
3621         main_assembly = assembly;
3622 }
3623
3624 /**
3625  * mono_assembly_get_main:
3626  *
3627  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3628  */
3629 MonoAssembly *
3630 mono_assembly_get_main (void)
3631 {
3632         return (main_assembly);
3633 }
3634
3635 /**
3636  * mono_assembly_get_image:
3637  * @assembly: The assembly to retrieve the image from
3638  *
3639  * Returns: the MonoImage associated with this assembly.
3640  */
3641 MonoImage*
3642 mono_assembly_get_image (MonoAssembly *assembly)
3643 {
3644         return assembly->image;
3645 }
3646
3647 /**
3648  * mono_assembly_get_name:
3649  * @assembly: The assembly to retrieve the name from
3650  *
3651  * The returned name's lifetime is the same as @assembly's.
3652  *
3653  * Returns: the MonoAssemblyName associated with this assembly.
3654  */
3655 MonoAssemblyName *
3656 mono_assembly_get_name (MonoAssembly *assembly)
3657 {
3658         return &assembly->aname;
3659 }
3660
3661 void
3662 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3663 {
3664         bundles = assemblies;
3665 }
3666
3667 #define MONO_DECLSEC_FORMAT_10          0x3C
3668 #define MONO_DECLSEC_FORMAT_20          0x2E
3669 #define MONO_DECLSEC_FIELD              0x53
3670 #define MONO_DECLSEC_PROPERTY           0x54
3671
3672 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3673 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3674 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3675 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3676 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3677
3678 static gboolean
3679 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3680 {
3681         int len;
3682         switch (*p++) {
3683         case MONO_DECLSEC_PROPERTY:
3684                 break;
3685         case MONO_DECLSEC_FIELD:
3686         default:
3687                 *abort_decoding = TRUE;
3688                 return FALSE;
3689                 break;
3690         }
3691
3692         if (*p++ != MONO_TYPE_BOOLEAN) {
3693                 *abort_decoding = TRUE;
3694                 return FALSE;
3695         }
3696                 
3697         /* property name length */
3698         len = mono_metadata_decode_value (p, &p);
3699
3700         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3701                 p += len;
3702                 return *p;
3703         }
3704         p += len + 1;
3705
3706         *resp = p;
3707         return FALSE;
3708 }
3709
3710 static gboolean
3711 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3712 {
3713         int i, j, num, len, params_len;
3714
3715         if (*p == MONO_DECLSEC_FORMAT_10) {
3716                 gsize read, written;
3717                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3718                 if (res) {
3719                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3720                         g_free (res);
3721                         return found;
3722                 }
3723                 return FALSE;
3724         }
3725         if (*p++ != MONO_DECLSEC_FORMAT_20)
3726                 return FALSE;
3727
3728         /* number of encoded permission attributes */
3729         num = mono_metadata_decode_value (p, &p);
3730         for (i = 0; i < num; ++i) {
3731                 gboolean is_valid = FALSE;
3732                 gboolean abort_decoding = FALSE;
3733
3734                 /* attribute name length */
3735                 len =  mono_metadata_decode_value (p, &p);
3736
3737                 /* We don't really need to fully decode the type. Comparing the name is enough */
3738                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3739
3740                 p += len;
3741
3742                 /*size of the params table*/
3743                 params_len =  mono_metadata_decode_value (p, &p);
3744                 if (is_valid) {
3745                         const char *params_end = p + params_len;
3746                         
3747                         /* number of parameters */
3748                         len = mono_metadata_decode_value (p, &p);
3749         
3750                         for (j = 0; j < len; ++j) {
3751                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3752                                         return TRUE;
3753                                 if (abort_decoding)
3754                                         break;
3755                         }
3756                         p = params_end;
3757                 } else {
3758                         p += params_len;
3759                 }
3760         }
3761         
3762         return FALSE;
3763 }
3764
3765
3766 gboolean
3767 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3768 {
3769         MonoTableInfo *t;       
3770         guint32 cols [MONO_DECL_SECURITY_SIZE];
3771         const char *blob;
3772         int i, len;
3773
3774         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3775                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3776
3777         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3778
3779         for (i = 0; i < t->rows; ++i) {
3780                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3781                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3782                         continue;
3783                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3784                         continue;
3785
3786                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3787                 len = mono_metadata_decode_blob_size (blob, &blob);
3788                 if (!len)
3789                         continue;
3790
3791                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3792                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3793                         return TRUE;
3794                 }
3795         }
3796
3797         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3798         return FALSE;
3799 }