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