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