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