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