Add [Category ("NotWorking")] to failing test.
[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;
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         switch (machine) {
808         case COFF_MACHINE_I386:
809                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
810                 break;
811         case COFF_MACHINE_IA64:
812                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
813                 break;
814         case COFF_MACHINE_AMD64:
815                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
816                 break;
817         case COFF_MACHINE_ARM:
818                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
819                 break;
820         default:
821                 break;
822         }
823
824         return TRUE;
825 }
826
827 /**
828  * mono_stringify_assembly_name:
829  * @aname: the assembly name.
830  *
831  * Convert @aname into its string format. The returned string is dynamically
832  * allocated and should be freed by the caller.
833  *
834  * Returns: a newly allocated string with a string representation of
835  * the assembly name.
836  */
837 char*
838 mono_stringify_assembly_name (MonoAssemblyName *aname)
839 {
840         const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
841
842         return g_strdup_printf (
843                 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
844                 quote, aname->name, quote,
845                 aname->major, aname->minor, aname->build, aname->revision,
846                 aname->culture && *aname->culture? aname->culture: "neutral",
847                 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
848                 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
849 }
850
851 static gchar*
852 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
853 {
854         const gchar *public_tok;
855         int len;
856
857         public_tok = mono_metadata_blob_heap (image, key_index);
858         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
859
860         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
861                 guchar token [8];
862                 mono_digest_get_public_token (token, (guchar*)public_tok, len);
863                 return encode_public_tok (token, 8);
864         }
865
866         return encode_public_tok ((guchar*)public_tok, len);
867 }
868
869 /**
870  * mono_assembly_addref:
871  * @assemnly: the assembly to reference
872  *
873  * This routine increments the reference count on a MonoAssembly.
874  * The reference count is reduced every time the method mono_assembly_close() is
875  * invoked.
876  */
877 void
878 mono_assembly_addref (MonoAssembly *assembly)
879 {
880         InterlockedIncrement (&assembly->ref_count);
881 }
882
883 /*
884  * CAUTION: This table must be kept in sync with
885  *          ivkm/reflect/Fusion.cs
886  */
887
888 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
889 #define WINFX_KEY "31bf3856ad364e35"
890 #define ECMA_KEY "b77a5c561934e089"
891 #define MSFINAL_KEY "b03f5f7f11d50a3a"
892
893 typedef struct {
894         const char *name;
895         const char *from;
896         const char *to;
897 } KeyRemapEntry;
898
899 static KeyRemapEntry key_remap_table[] = {
900         { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
901         { "System", SILVERLIGHT_KEY, ECMA_KEY },
902         { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
903         { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
904         { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
905         // FIXME: MS uses MSFINAL_KEY for .NET 4.5
906         { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
907         { "System.Numerics", WINFX_KEY, ECMA_KEY },
908         { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
909         { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
910         { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
911         { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
912         { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
913         { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
914         { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
915 };
916
917 static void
918 remap_keys (MonoAssemblyName *aname)
919 {
920         int i;
921         for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
922                 const KeyRemapEntry *entry = &key_remap_table [i];
923
924                 if (strcmp (aname->name, entry->name) ||
925                     !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
926                         continue;
927
928                 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
929                      
930                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
931                             "Remapped public key token of retargetable assembly %s from %s to %s",
932                             aname->name, entry->from, entry->to);
933                 return;
934         }
935 }
936
937 static MonoAssemblyName *
938 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
939 {
940         const MonoRuntimeInfo *current_runtime;
941         int pos, first, last;
942
943         if (aname->name == NULL) return aname;
944
945         current_runtime = mono_get_runtime_info ();
946
947         if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
948                 const AssemblyVersionSet* vset;
949
950                 /* Remap to current runtime */
951                 vset = &current_runtime->version_sets [0];
952
953                 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
954                 dest_aname->major = vset->major;
955                 dest_aname->minor = vset->minor;
956                 dest_aname->build = vset->build;
957                 dest_aname->revision = vset->revision;
958                 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
959
960                 /* Remap assembly name */
961                 if (!strcmp (aname->name, "System.Net"))
962                         dest_aname->name = g_strdup ("System");
963                 
964                 remap_keys (dest_aname);
965
966                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
967                                         "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
968                                         aname->name,
969                                         aname->major, aname->minor, aname->build, aname->revision,
970                                         dest_aname->name,
971                                         vset->major, vset->minor, vset->build, vset->revision
972                                         );
973
974                 return dest_aname;
975         }
976         
977 #ifndef DISABLE_ASSEMBLY_REMAPPING
978         first = 0;
979         last = G_N_ELEMENTS (framework_assemblies) - 1;
980         
981         while (first <= last) {
982                 int res;
983                 pos = first + (last - first) / 2;
984                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
985                 if (res == 0) {
986                         const AssemblyVersionSet* vset;
987                         int index = framework_assemblies[pos].version_set_index;
988                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
989                         vset = &current_runtime->version_sets [index];
990
991                         if (aname->major == vset->major && aname->minor == vset->minor &&
992                                 aname->build == vset->build && aname->revision == vset->revision)
993                                 return aname;
994                 
995                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
996                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
997                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
998                                                         aname->name,
999                                                         aname->major, aname->minor, aname->build, aname->revision,
1000                                                         vset->major, vset->minor, vset->build, vset->revision
1001                                                         );
1002                         
1003                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1004                         dest_aname->major = vset->major;
1005                         dest_aname->minor = vset->minor;
1006                         dest_aname->build = vset->build;
1007                         dest_aname->revision = vset->revision;
1008                         return dest_aname;
1009                 } else if (res < 0) {
1010                         last = pos - 1;
1011                 } else {
1012                         first = pos + 1;
1013                 }
1014         }
1015 #endif
1016
1017         return aname;
1018 }
1019
1020 /*
1021  * mono_assembly_get_assemblyref:
1022  *
1023  *   Fill out ANAME with the assembly name of the INDEXth assembly reference in IMAGE.
1024  */
1025 void
1026 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1027 {
1028         MonoTableInfo *t;
1029         guint32 cols [MONO_ASSEMBLYREF_SIZE];
1030         const char *hash;
1031
1032         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1033
1034         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1035                 
1036         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1037         aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1038         aname->hash_value = hash;
1039         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1040         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1041         aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1042         aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1043         aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1044         aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1045         aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1046
1047         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1048                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1049                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1050                 g_free (token);
1051         } else {
1052                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1053         }
1054 }
1055
1056 void
1057 mono_assembly_load_reference (MonoImage *image, int index)
1058 {
1059         MonoAssembly *reference;
1060         MonoAssemblyName aname;
1061         MonoImageOpenStatus status;
1062
1063         /*
1064          * image->references is shared between threads, so we need to access
1065          * it inside a critical section.
1066          */
1067         mono_assemblies_lock ();
1068         if (!image->references) {
1069                 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1070         
1071                 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1072                 image->nreferences = t->rows;
1073         }
1074         reference = image->references [index];
1075         mono_assemblies_unlock ();
1076         if (reference)
1077                 return;
1078
1079         mono_assembly_get_assemblyref (image, index, &aname);
1080
1081         if (image->assembly && image->assembly->ref_only) {
1082                 /* We use the loaded corlib */
1083                 if (!strcmp (aname.name, "mscorlib"))
1084                         reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
1085                 else {
1086                         reference = mono_assembly_loaded_full (&aname, TRUE);
1087                         if (!reference)
1088                                 /* Try a postload search hook */
1089                                 reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
1090                 }
1091
1092                 /*
1093                  * Here we must advice that the error was due to
1094                  * a non loaded reference using the ReflectionOnly api
1095                 */
1096                 if (!reference)
1097                         reference = REFERENCE_MISSING;
1098         } else
1099                 reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status);
1100
1101         if (reference == NULL){
1102                 char *extra_msg;
1103
1104                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1105                         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 : "" );
1106                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1107                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1108                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1109                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1110                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1111                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1112                 } else {
1113                         extra_msg = g_strdup ("");
1114                 }
1115                 
1116                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1117                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
1118                                    "     Version:    %d.%d.%d.%d\n"
1119                                    "     Public Key: %s\n%s",
1120                                    image->name, aname.name, index,
1121                                    aname.major, aname.minor, aname.build, aname.revision,
1122                                    strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1123                 g_free (extra_msg);
1124         }
1125
1126         mono_assemblies_lock ();
1127         if (reference == NULL) {
1128                 /* Flag as not found */
1129                 reference = REFERENCE_MISSING;
1130         }       
1131
1132         if (!image->references [index]) {
1133                 if (reference != REFERENCE_MISSING){
1134                         mono_assembly_addref (reference);
1135                         if (image->assembly)
1136                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1137                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1138                 } else {
1139                         if (image->assembly)
1140                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1141                                     image->assembly->aname.name, image->assembly);
1142                 }
1143                 
1144                 image->references [index] = reference;
1145         }
1146         mono_assemblies_unlock ();
1147
1148         if (image->references [index] != reference) {
1149                 /* Somebody loaded it before us */
1150                 mono_assembly_close (reference);
1151         }
1152 }
1153
1154 void
1155 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1156 {
1157         /* This is a no-op now but it is part of the embedding API so we can't remove it */
1158         *status = MONO_IMAGE_OK;
1159 }
1160
1161 typedef struct AssemblyLoadHook AssemblyLoadHook;
1162 struct AssemblyLoadHook {
1163         AssemblyLoadHook *next;
1164         MonoAssemblyLoadFunc func;
1165         gpointer user_data;
1166 };
1167
1168 AssemblyLoadHook *assembly_load_hook = NULL;
1169
1170 void
1171 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1172 {
1173         AssemblyLoadHook *hook;
1174
1175         for (hook = assembly_load_hook; hook; hook = hook->next) {
1176                 hook->func (ass, hook->user_data);
1177         }
1178 }
1179
1180 void
1181 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1182 {
1183         AssemblyLoadHook *hook;
1184         
1185         g_return_if_fail (func != NULL);
1186
1187         hook = g_new0 (AssemblyLoadHook, 1);
1188         hook->func = func;
1189         hook->user_data = user_data;
1190         hook->next = assembly_load_hook;
1191         assembly_load_hook = hook;
1192 }
1193
1194 static void
1195 free_assembly_load_hooks (void)
1196 {
1197         AssemblyLoadHook *hook, *next;
1198
1199         for (hook = assembly_load_hook; hook; hook = next) {
1200                 next = hook->next;
1201                 g_free (hook);
1202         }
1203 }
1204
1205 typedef struct AssemblySearchHook AssemblySearchHook;
1206 struct AssemblySearchHook {
1207         AssemblySearchHook *next;
1208         MonoAssemblySearchFunc func;
1209         gboolean refonly;
1210         gboolean postload;
1211         gpointer user_data;
1212 };
1213
1214 AssemblySearchHook *assembly_search_hook = NULL;
1215
1216 static MonoAssembly*
1217 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload)
1218 {
1219         AssemblySearchHook *hook;
1220
1221         for (hook = assembly_search_hook; hook; hook = hook->next) {
1222                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1223                         MonoAssembly *ass = hook->func (aname, hook->user_data);
1224                         if (ass)
1225                                 return ass;
1226                 }
1227         }
1228
1229         return NULL;
1230 }
1231
1232 MonoAssembly*
1233 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1234 {
1235         return mono_assembly_invoke_search_hook_internal (aname, FALSE, FALSE);
1236 }
1237
1238 static void
1239 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1240 {
1241         AssemblySearchHook *hook;
1242         
1243         g_return_if_fail (func != NULL);
1244
1245         hook = g_new0 (AssemblySearchHook, 1);
1246         hook->func = func;
1247         hook->user_data = user_data;
1248         hook->refonly = refonly;
1249         hook->postload = postload;
1250         hook->next = assembly_search_hook;
1251         assembly_search_hook = hook;
1252 }
1253
1254 void          
1255 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1256 {
1257         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1258 }       
1259
1260 static void
1261 free_assembly_search_hooks (void)
1262 {
1263         AssemblySearchHook *hook, *next;
1264
1265         for (hook = assembly_search_hook; hook; hook = next) {
1266                 next = hook->next;
1267                 g_free (hook);
1268         }
1269 }
1270
1271 void
1272 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1273 {
1274         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1275 }
1276
1277 void          
1278 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1279 {
1280         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1281 }       
1282
1283 void
1284 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1285 {
1286         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1287 }
1288
1289 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1290 struct AssemblyPreLoadHook {
1291         AssemblyPreLoadHook *next;
1292         MonoAssemblyPreLoadFunc func;
1293         gpointer user_data;
1294 };
1295
1296 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1297 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1298
1299 static MonoAssembly *
1300 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1301 {
1302         AssemblyPreLoadHook *hook;
1303         MonoAssembly *assembly;
1304
1305         for (hook = assembly_preload_hook; hook; hook = hook->next) {
1306                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1307                 if (assembly != NULL)
1308                         return assembly;
1309         }
1310
1311         return NULL;
1312 }
1313
1314 static MonoAssembly *
1315 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1316 {
1317         AssemblyPreLoadHook *hook;
1318         MonoAssembly *assembly;
1319
1320         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1321                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1322                 if (assembly != NULL)
1323                         return assembly;
1324         }
1325
1326         return NULL;
1327 }
1328
1329 void
1330 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1331 {
1332         AssemblyPreLoadHook *hook;
1333         
1334         g_return_if_fail (func != NULL);
1335
1336         hook = g_new0 (AssemblyPreLoadHook, 1);
1337         hook->func = func;
1338         hook->user_data = user_data;
1339         hook->next = assembly_preload_hook;
1340         assembly_preload_hook = hook;
1341 }
1342
1343 void
1344 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1345 {
1346         AssemblyPreLoadHook *hook;
1347         
1348         g_return_if_fail (func != NULL);
1349
1350         hook = g_new0 (AssemblyPreLoadHook, 1);
1351         hook->func = func;
1352         hook->user_data = user_data;
1353         hook->next = assembly_refonly_preload_hook;
1354         assembly_refonly_preload_hook = hook;
1355 }
1356
1357 static void
1358 free_assembly_preload_hooks (void)
1359 {
1360         AssemblyPreLoadHook *hook, *next;
1361
1362         for (hook = assembly_preload_hook; hook; hook = next) {
1363                 next = hook->next;
1364                 g_free (hook);
1365         }
1366
1367         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1368                 next = hook->next;
1369                 g_free (hook);
1370         }
1371 }
1372
1373 static gchar *
1374 absolute_dir (const gchar *filename)
1375 {
1376         gchar *cwd;
1377         gchar *mixed;
1378         gchar **parts;
1379         gchar *part;
1380         GList *list, *tmp;
1381         GString *result;
1382         gchar *res;
1383         gint i;
1384
1385         if (g_path_is_absolute (filename)) {
1386                 part = g_path_get_dirname (filename);
1387                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1388                 g_free (part);
1389                 return res;
1390         }
1391
1392         cwd = g_get_current_dir ();
1393         mixed = g_build_filename (cwd, filename, NULL);
1394         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1395         g_free (mixed);
1396         g_free (cwd);
1397
1398         list = NULL;
1399         for (i = 0; (part = parts [i]) != NULL; i++) {
1400                 if (!strcmp (part, "."))
1401                         continue;
1402
1403                 if (!strcmp (part, "..")) {
1404                         if (list && list->next) /* Don't remove root */
1405                                 list = g_list_delete_link (list, list);
1406                 } else {
1407                         list = g_list_prepend (list, part);
1408                 }
1409         }
1410
1411         result = g_string_new ("");
1412         list = g_list_reverse (list);
1413
1414         /* Ignores last data pointer, which should be the filename */
1415         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1416                 if (tmp->data)
1417                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1418                                                                 G_DIR_SEPARATOR);
1419         }
1420
1421         res = result->str;
1422         g_string_free (result, FALSE);
1423         g_list_free (list);
1424         g_strfreev (parts);
1425         if (*res == '\0') {
1426                 g_free (res);
1427                 return g_strdup (".");
1428         }
1429
1430         return res;
1431 }
1432
1433 /** 
1434  * mono_assembly_open_from_bundle:
1435  * @filename: Filename requested
1436  * @status: return value
1437  *
1438  * This routine tries to open the assembly specified by `filename' from the
1439  * defined bundles, if found, returns the MonoImage for it, if not found
1440  * returns NULL
1441  */
1442 MonoImage *
1443 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1444 {
1445         int i;
1446         char *name;
1447         MonoImage *image = NULL;
1448
1449         /*
1450          * we do a very simple search for bundled assemblies: it's not a general 
1451          * purpose assembly loading mechanism.
1452          */
1453
1454         if (!bundles)
1455                 return NULL;
1456
1457         name = g_path_get_basename (filename);
1458
1459         mono_assemblies_lock ();
1460         for (i = 0; !image && bundles [i]; ++i) {
1461                 if (strcmp (bundles [i]->name, name) == 0) {
1462                         image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1463                         break;
1464                 }
1465         }
1466         mono_assemblies_unlock ();
1467         g_free (name);
1468         if (image) {
1469                 mono_image_addref (image);
1470                 return image;
1471         }
1472         return NULL;
1473 }
1474
1475 MonoAssembly *
1476 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1477 {
1478         MonoImage *image;
1479         MonoAssembly *ass;
1480         MonoImageOpenStatus def_status;
1481         gchar *fname;
1482         gchar *new_fname;
1483         
1484         g_return_val_if_fail (filename != NULL, NULL);
1485
1486         if (!status)
1487                 status = &def_status;
1488         *status = MONO_IMAGE_OK;
1489
1490         if (strncmp (filename, "file://", 7) == 0) {
1491                 GError *error = NULL;
1492                 gchar *uri = (gchar *) filename;
1493                 gchar *tmpuri;
1494
1495                 /*
1496                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1497                  * They also throw an IndexOutOfRangeException if "file://"
1498                  */
1499                 if (uri [7] != '/')
1500                         uri = g_strdup_printf ("file:///%s", uri + 7);
1501         
1502                 tmpuri = uri;
1503                 uri = mono_escape_uri_string (tmpuri);
1504                 fname = g_filename_from_uri (uri, NULL, &error);
1505                 g_free (uri);
1506
1507                 if (tmpuri != filename)
1508                         g_free (tmpuri);
1509
1510                 if (error != NULL) {
1511                         g_warning ("%s\n", error->message);
1512                         g_error_free (error);
1513                         fname = g_strdup (filename);
1514                 }
1515         } else {
1516                 fname = g_strdup (filename);
1517         }
1518
1519         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1520                         "Assembly Loader probing location: '%s'.", fname);
1521
1522         new_fname = NULL;
1523         if (!mono_assembly_is_in_gac (fname))
1524                 new_fname = mono_make_shadow_copy (fname);
1525         if (new_fname && new_fname != fname) {
1526                 g_free (fname);
1527                 fname = new_fname;
1528                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1529                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1530         }
1531         
1532         image = NULL;
1533
1534         if (bundles != NULL)
1535                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1536
1537         if (!image)
1538                 image = mono_image_open_full (fname, status, refonly);
1539
1540         if (!image){
1541                 if (*status == MONO_IMAGE_OK)
1542                         *status = MONO_IMAGE_ERROR_ERRNO;
1543                 g_free (fname);
1544                 return NULL;
1545         }
1546
1547         if (image->assembly) {
1548                 /* Already loaded by another appdomain */
1549                 mono_assembly_invoke_load_hook (image->assembly);
1550                 mono_image_close (image);
1551                 g_free (fname);
1552                 return image->assembly;
1553         }
1554
1555         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1556
1557         if (ass) {
1558                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1559                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1560                 if (!refonly)
1561                         mono_config_for_assembly (ass->image);
1562         }
1563
1564         /* Clear the reference added by mono_image_open */
1565         mono_image_close (image);
1566         
1567         g_free (fname);
1568
1569         return ass;
1570 }
1571
1572 static void
1573 free_item (gpointer val, gpointer user_data)
1574 {
1575         g_free (val);
1576 }
1577
1578 /*
1579  * mono_assembly_load_friends:
1580  * @ass: an assembly
1581  *
1582  * Load the list of friend assemblies that are allowed to access
1583  * the assembly's internal types and members. They are stored as assembly
1584  * names in custom attributes.
1585  *
1586  * This is an internal method, we need this because when we load mscorlib
1587  * we do not have the mono_defaults.internals_visible_class loaded yet,
1588  * so we need to load these after we initialize the runtime. 
1589  *
1590  * LOCKING: Acquires the assemblies lock plus the loader lock.
1591  */
1592 void
1593 mono_assembly_load_friends (MonoAssembly* ass)
1594 {
1595         int i;
1596         MonoCustomAttrInfo* attrs;
1597         GSList *list;
1598
1599         if (ass->friend_assembly_names_inited)
1600                 return;
1601
1602         attrs = mono_custom_attrs_from_assembly (ass);
1603         if (!attrs) {
1604                 mono_assemblies_lock ();
1605                 ass->friend_assembly_names_inited = TRUE;
1606                 mono_assemblies_unlock ();
1607                 return;
1608         }
1609
1610         mono_assemblies_lock ();
1611         if (ass->friend_assembly_names_inited) {
1612                 mono_assemblies_unlock ();
1613                 return;
1614         }
1615         mono_assemblies_unlock ();
1616
1617         list = NULL;
1618         /* 
1619          * We build the list outside the assemblies lock, the worse that can happen
1620          * is that we'll need to free the allocated list.
1621          */
1622         for (i = 0; i < attrs->num_attrs; ++i) {
1623                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1624                 MonoAssemblyName *aname;
1625                 const gchar *data;
1626                 guint slen;
1627                 /* Do some sanity checking */
1628                 if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
1629                         continue;
1630                 if (attr->data_size < 4)
1631                         continue;
1632                 data = (const char*)attr->data;
1633                 /* 0xFF means null string, see custom attr format */
1634                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1635                         continue;
1636                 slen = mono_metadata_decode_value (data + 2, &data);
1637                 aname = g_new0 (MonoAssemblyName, 1);
1638                 /*g_print ("friend ass: %s\n", data);*/
1639                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1640                         list = g_slist_prepend (list, aname);
1641                 } else {
1642                         g_free (aname);
1643                 }
1644         }
1645         mono_custom_attrs_free (attrs);
1646
1647         mono_assemblies_lock ();
1648         if (ass->friend_assembly_names_inited) {
1649                 mono_assemblies_unlock ();
1650                 g_slist_foreach (list, free_item, NULL);
1651                 g_slist_free (list);
1652                 return;
1653         }
1654         ass->friend_assembly_names = list;
1655
1656         /* Because of the double checked locking pattern above */
1657         mono_memory_barrier ();
1658         ass->friend_assembly_names_inited = TRUE;
1659         mono_assemblies_unlock ();
1660 }
1661
1662 /**
1663  * mono_assembly_open:
1664  * @filename: Opens the assembly pointed out by this name
1665  * @status: where a status code can be returned
1666  *
1667  * mono_assembly_open opens the PE-image pointed by @filename, and
1668  * loads any external assemblies referenced by it.
1669  *
1670  * Return: a pointer to the MonoAssembly if @filename contains a valid
1671  * assembly or NULL on error.  Details about the error are stored in the
1672  * @status variable.
1673  */
1674 MonoAssembly *
1675 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1676 {
1677         return mono_assembly_open_full (filename, status, FALSE);
1678 }
1679
1680 MonoAssembly *
1681 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1682                               MonoImageOpenStatus *status, gboolean refonly)
1683 {
1684         MonoAssembly *ass, *ass2;
1685         char *base_dir;
1686
1687         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1688                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1689                 *status = MONO_IMAGE_IMAGE_INVALID;
1690                 return NULL;
1691         }
1692
1693 #if defined (HOST_WIN32)
1694         {
1695                 gchar *tmp_fn;
1696                 int i;
1697
1698                 tmp_fn = g_strdup (fname);
1699                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1700                         if (tmp_fn [i] == '/')
1701                                 tmp_fn [i] = '\\';
1702                 }
1703
1704                 base_dir = absolute_dir (tmp_fn);
1705                 g_free (tmp_fn);
1706         }
1707 #else
1708         base_dir = absolute_dir (fname);
1709 #endif
1710
1711         /*
1712          * Create assembly struct, and enter it into the assembly cache
1713          */
1714         ass = g_new0 (MonoAssembly, 1);
1715         ass->basedir = base_dir;
1716         ass->ref_only = refonly;
1717         ass->image = image;
1718
1719         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1720
1721         mono_assembly_fill_assembly_name (image, &ass->aname);
1722
1723         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1724                 // MS.NET doesn't support loading other mscorlibs
1725                 g_free (ass);
1726                 g_free (base_dir);
1727                 mono_image_addref (mono_defaults.corlib);
1728                 *status = MONO_IMAGE_OK;
1729                 return mono_defaults.corlib->assembly;
1730         }
1731
1732         /* Add a non-temporary reference because of ass->image */
1733         mono_image_addref (image);
1734
1735         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);
1736
1737         /* 
1738          * The load hooks might take locks so we can't call them while holding the
1739          * assemblies lock.
1740          */
1741         if (ass->aname.name) {
1742                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE);
1743                 if (ass2) {
1744                         g_free (ass);
1745                         g_free (base_dir);
1746                         mono_image_close (image);
1747                         *status = MONO_IMAGE_OK;
1748                         return ass2;
1749                 }
1750         }
1751
1752         mono_assemblies_lock ();
1753
1754         if (image->assembly) {
1755                 /* 
1756                  * This means another thread has already loaded the assembly, but not yet
1757                  * called the load hooks so the search hook can't find the assembly.
1758                  */
1759                 mono_assemblies_unlock ();
1760                 ass2 = image->assembly;
1761                 g_free (ass);
1762                 g_free (base_dir);
1763                 mono_image_close (image);
1764                 *status = MONO_IMAGE_OK;
1765                 return ass2;
1766         }
1767
1768         image->assembly = ass;
1769
1770         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1771         mono_assemblies_unlock ();
1772
1773 #ifdef HOST_WIN32
1774         if (image->is_module_handle)
1775                 mono_image_fixup_vtable (image);
1776 #endif
1777
1778         mono_assembly_invoke_load_hook (ass);
1779
1780         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1781         
1782         return ass;
1783 }
1784
1785 MonoAssembly *
1786 mono_assembly_load_from (MonoImage *image, const char *fname,
1787                          MonoImageOpenStatus *status)
1788 {
1789         return mono_assembly_load_from_full (image, fname, status, FALSE);
1790 }
1791
1792 /**
1793  * mono_assembly_name_free:
1794  * @aname: assembly name to free
1795  * 
1796  * Frees the provided assembly name object.
1797  * (it does not frees the object itself, only the name members).
1798  */
1799 void
1800 mono_assembly_name_free (MonoAssemblyName *aname)
1801 {
1802         if (aname == NULL)
1803                 return;
1804
1805         g_free ((void *) aname->name);
1806         g_free ((void *) aname->culture);
1807         g_free ((void *) aname->hash_value);
1808 }
1809
1810 static gboolean
1811 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
1812 {
1813         const gchar *pkey;
1814         gchar header [16], val, *arr;
1815         gint i, j, offset, bitlen, keylen, pkeylen;
1816         
1817         keylen = strlen (key) >> 1;
1818         if (keylen < 1)
1819                 return FALSE;
1820
1821         /* allow the ECMA standard key */
1822         if (strcmp (key, "00000000000000000400000000000000") == 0) {
1823                 if (pubkey) {
1824                         *pubkey = g_strdup (key);
1825                         *is_ecma = TRUE;
1826                 }
1827                 return TRUE;
1828         }
1829         *is_ecma = FALSE;
1830         val = g_ascii_xdigit_value (key [0]) << 4;
1831         val |= g_ascii_xdigit_value (key [1]);
1832         switch (val) {
1833                 case 0x00:
1834                         if (keylen < 13)
1835                                 return FALSE;
1836                         val = g_ascii_xdigit_value (key [24]);
1837                         val |= g_ascii_xdigit_value (key [25]);
1838                         if (val != 0x06)
1839                                 return FALSE;
1840                         pkey = key + 24;
1841                         break;
1842                 case 0x06:
1843                         pkey = key;
1844                         break;
1845                 default:
1846                         return FALSE;
1847         }
1848                 
1849         /* We need the first 16 bytes
1850         * to check whether this key is valid or not */
1851         pkeylen = strlen (pkey) >> 1;
1852         if (pkeylen < 16)
1853                 return FALSE;
1854                 
1855         for (i = 0, j = 0; i < 16; i++) {
1856                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
1857                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
1858         }
1859
1860         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
1861                         header [1] != 0x02 || /* Version (0x02) */
1862                         header [2] != 0x00 || /* Reserved (word) */
1863                         header [3] != 0x00 ||
1864                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
1865                 return FALSE;
1866
1867         /* Based on this length, we _should_ be able to know if the length is right */
1868         bitlen = read32 (header + 12) >> 3;
1869         if ((bitlen + 16 + 4) != pkeylen)
1870                 return FALSE;
1871
1872         /* parsing is OK and the public key itself is not requested back */
1873         if (!pubkey)
1874                 return TRUE;
1875                 
1876         /* Encode the size of the blob */
1877         offset = 0;
1878         if (keylen <= 127) {
1879                 arr = g_malloc (keylen + 1);
1880                 arr [offset++] = keylen;
1881         } else {
1882                 arr = g_malloc (keylen + 2);
1883                 arr [offset++] = 0x80; /* 10bs */
1884                 arr [offset++] = keylen;
1885         }
1886                 
1887         for (i = offset, j = 0; i < keylen + offset; i++) {
1888                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
1889                 arr [i] |= g_ascii_xdigit_value (key [j++]);
1890         }
1891
1892         *pubkey = arr;
1893
1894         return TRUE;
1895 }
1896
1897 static gboolean
1898 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)
1899 {
1900         gint major, minor, build, revision;
1901         gint len;
1902         gint version_parts;
1903         gchar *pkey, *pkeyptr, *encoded, tok [8];
1904
1905         memset (aname, 0, sizeof (MonoAssemblyName));
1906
1907         if (version) {
1908                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
1909                 if (version_parts < 2 || version_parts > 4)
1910                         return FALSE;
1911
1912                 /* FIXME: we should set build & revision to -1 (instead of 0)
1913                 if these are not set in the version string. That way, later on,
1914                 we can still determine if these were specified. */
1915                 aname->major = major;
1916                 aname->minor = minor;
1917                 if (version_parts >= 3)
1918                         aname->build = build;
1919                 else
1920                         aname->build = 0;
1921                 if (version_parts == 4)
1922                         aname->revision = revision;
1923                 else
1924                         aname->revision = 0;
1925         }
1926         
1927         aname->flags = flags;
1928         aname->arch = arch;
1929         aname->name = g_strdup (name);
1930         
1931         if (culture) {
1932                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
1933                         aname->culture = g_strdup ("");
1934                 else
1935                         aname->culture = g_strdup (culture);
1936         }
1937         
1938         if (token && strncmp (token, "null", 4) != 0) {
1939                 char *lower;
1940
1941                 /* the constant includes the ending NULL, hence the -1 */
1942                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
1943                         mono_assembly_name_free (aname);
1944                         return FALSE;
1945                 }
1946                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1947                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1948                 g_free (lower);
1949         }
1950
1951         if (key) {
1952                 gboolean is_ecma;
1953                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
1954                         mono_assembly_name_free (aname);
1955                         return FALSE;
1956                 }
1957
1958                 if (is_ecma) {
1959                         if (save_public_key)
1960                                 aname->public_key = (guint8*)pkey;
1961                         else
1962                                 g_free (pkey);
1963                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
1964                         return TRUE;
1965                 }
1966                 
1967                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
1968                 // We also need to generate the key token
1969                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
1970                 encoded = encode_public_tok ((guchar*) tok, 8);
1971                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1972                 g_free (encoded);
1973
1974                 if (save_public_key)
1975                         aname->public_key = (guint8*) pkey;
1976                 else
1977                         g_free (pkey);
1978         }
1979
1980         return TRUE;
1981 }
1982
1983 static gboolean
1984 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
1985 {
1986         gchar **parts;
1987         gboolean res;
1988         
1989         parts = g_strsplit (dirname, "_", 3);
1990         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
1991                 g_strfreev (parts);
1992                 return FALSE;
1993         }
1994         
1995         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
1996         g_strfreev (parts);
1997         return res;
1998 }
1999
2000 static gboolean
2001 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2002 {
2003         char *eqsign = strchr (pair, '=');
2004         if (!eqsign) {
2005                 *key = NULL;
2006                 *keylen = 0;
2007                 *value = NULL;
2008                 return FALSE;
2009         }
2010
2011         *key = (gchar*)pair;
2012         *keylen = eqsign - *key;
2013         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2014                 (*keylen)--;
2015         *value = g_strstrip (eqsign + 1);
2016         return TRUE;
2017 }
2018
2019 gboolean
2020 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2021 {
2022         gchar *dllname;
2023         gchar *version = NULL;
2024         gchar *culture = NULL;
2025         gchar *token = NULL;
2026         gchar *key = NULL;
2027         gchar *retargetable = NULL;
2028         gboolean res;
2029         gchar *value, *part_name;
2030         guint32 part_name_len;
2031         gchar **parts;
2032         gchar **tmp;
2033         gboolean version_defined;
2034         gboolean token_defined;
2035         guint32 flags = 0;
2036         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2037
2038         if (!is_version_defined)
2039                 is_version_defined = &version_defined;
2040         *is_version_defined = FALSE;
2041         if (!is_token_defined)
2042                 is_token_defined = &token_defined;
2043         *is_token_defined = FALSE;
2044         
2045         parts = tmp = g_strsplit (name, ",", 6);
2046         if (!tmp || !*tmp) {
2047                 g_strfreev (tmp);
2048                 return FALSE;
2049         }
2050
2051         dllname = g_strstrip (*tmp);
2052         
2053         tmp++;
2054
2055         while (*tmp) {
2056                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2057                         goto cleanup_and_fail;
2058
2059                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2060                         *is_version_defined = TRUE;
2061                         version = value;
2062                         if (strlen (version) == 0) {
2063                                 goto cleanup_and_fail;
2064                         }
2065                         tmp++;
2066                         continue;
2067                 }
2068
2069                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2070                         culture = value;
2071                         if (strlen (culture) == 0) {
2072                                 goto cleanup_and_fail;
2073                         }
2074                         tmp++;
2075                         continue;
2076                 }
2077
2078                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2079                         *is_token_defined = TRUE;
2080                         token = value;
2081                         if (strlen (token) == 0) {
2082                                 goto cleanup_and_fail;
2083                         }
2084                         tmp++;
2085                         continue;
2086                 }
2087
2088                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2089                         key = value;
2090                         if (strlen (key) == 0) {
2091                                 goto cleanup_and_fail;
2092                         }
2093                         tmp++;
2094                         continue;
2095                 }
2096
2097                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2098                         retargetable = value;
2099                         if (strlen (retargetable) == 0) {
2100                                 goto cleanup_and_fail;
2101                         }
2102                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2103                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2104                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2105                                 goto cleanup_and_fail;
2106                         }
2107                         tmp++;
2108                         continue;
2109                 }
2110
2111                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2112                         if (!g_ascii_strcasecmp (value, "None"))
2113                                 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2114                         else if (!g_ascii_strcasecmp (value, "MSIL"))
2115                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2116                         else if (!g_ascii_strcasecmp (value, "X86"))
2117                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2118                         else if (!g_ascii_strcasecmp (value, "IA64"))
2119                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2120                         else if (!g_ascii_strcasecmp (value, "AMD64"))
2121                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2122                         else
2123                                 goto cleanup_and_fail;
2124                         tmp++;
2125                         continue;
2126                 }
2127
2128                 g_strfreev (parts);
2129                 return FALSE;
2130         }
2131
2132         /* if retargetable flag is set, then we must have a fully qualified name */
2133         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2134                 goto cleanup_and_fail;
2135         }
2136
2137         res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
2138                 aname, save_public_key);
2139         g_strfreev (parts);
2140         return res;
2141
2142 cleanup_and_fail:
2143         g_strfreev (parts);
2144         return FALSE;
2145 }
2146
2147 /**
2148  * mono_assembly_name_parse:
2149  * @name: name to parse
2150  * @aname: the destination assembly name
2151  * 
2152  * Parses an assembly qualified type name and assigns the name,
2153  * version, culture and token to the provided assembly name object.
2154  *
2155  * Returns: true if the name could be parsed.
2156  */
2157 gboolean
2158 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2159 {
2160         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2161 }
2162
2163 /**
2164  * mono_assembly_name_new:
2165  * @name: name to parse
2166  *
2167  * Allocate a new MonoAssemblyName and fill its values from the
2168  * passed @name.
2169  *
2170  * Returns: a newly allocated structure or NULL if there was any failure.
2171  */
2172 MonoAssemblyName*
2173 mono_assembly_name_new (const char *name)
2174 {
2175         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2176         if (mono_assembly_name_parse (name, aname))
2177                 return aname;
2178         g_free (aname);
2179         return NULL;
2180 }
2181
2182 const char*
2183 mono_assembly_name_get_name (MonoAssemblyName *aname)
2184 {
2185         return aname->name;
2186 }
2187
2188 const char*
2189 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2190 {
2191         return aname->culture;
2192 }
2193
2194 mono_byte*
2195 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2196 {
2197         if (aname->public_key_token [0])
2198                 return aname->public_key_token;
2199         return NULL;
2200 }
2201
2202 uint16_t
2203 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2204 {
2205         if (minor)
2206                 *minor = aname->minor;
2207         if (build)
2208                 *build = aname->build;
2209         if (revision)
2210                 *revision = aname->revision;
2211         return aname->major;
2212 }
2213
2214 static MonoAssembly*
2215 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2216 {
2217         gchar *fullpath = NULL;
2218         GDir *dirhandle;
2219         const char* direntry;
2220         MonoAssemblyName gac_aname;
2221         gint major=-1, minor=0, build=0, revision=0;
2222         gboolean exact_version;
2223         
2224         dirhandle = g_dir_open (basepath, 0, NULL);
2225         if (!dirhandle)
2226                 return NULL;
2227                 
2228         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2229
2230         while ((direntry = g_dir_read_name (dirhandle))) {
2231                 gboolean match = TRUE;
2232                 
2233                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2234                         continue;
2235                 
2236                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2237                         match = FALSE;
2238                         
2239                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2240                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2241                         match = FALSE;
2242                 
2243                 if (match) {
2244                         if (exact_version) {
2245                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2246                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2247                         }
2248                         else if (gac_aname.major < major)
2249                                 match = FALSE;
2250                         else if (gac_aname.major == major) {
2251                                 if (gac_aname.minor < minor)
2252                                         match = FALSE;
2253                                 else if (gac_aname.minor == minor) {
2254                                         if (gac_aname.build < build)
2255                                                 match = FALSE;
2256                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2257                                                 match = FALSE; 
2258                                 }
2259                         }
2260                 }
2261                 
2262                 if (match) {
2263                         major = gac_aname.major;
2264                         minor = gac_aname.minor;
2265                         build = gac_aname.build;
2266                         revision = gac_aname.revision;
2267                         g_free (fullpath);
2268                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2269                 }
2270
2271                 mono_assembly_name_free (&gac_aname);
2272         }
2273         
2274         g_dir_close (dirhandle);
2275         
2276         if (fullpath == NULL)
2277                 return NULL;
2278         else {
2279                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2280                 g_free (fullpath);
2281                 return res;
2282         }
2283 }
2284
2285 MonoAssembly*
2286 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2287 {
2288         MonoAssembly *res;
2289         MonoAssemblyName *aname, base_name;
2290         MonoAssemblyName mapped_aname;
2291         gchar *fullname, *gacpath;
2292         gchar **paths;
2293
2294         memset (&base_name, 0, sizeof (MonoAssemblyName));
2295         aname = &base_name;
2296
2297         if (!mono_assembly_name_parse (name, aname))
2298                 return NULL;
2299
2300         /* 
2301          * If no specific version has been requested, make sure we load the
2302          * correct version for system assemblies.
2303          */ 
2304         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2305                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2306         
2307         res = mono_assembly_loaded (aname);
2308         if (res) {
2309                 mono_assembly_name_free (aname);
2310                 return res;
2311         }
2312
2313         res = invoke_assembly_preload_hook (aname, assemblies_path);
2314         if (res) {
2315                 res->in_gac = FALSE;
2316                 mono_assembly_name_free (aname);
2317                 return res;
2318         }
2319
2320         fullname = g_strdup_printf ("%s.dll", aname->name);
2321
2322         if (extra_gac_paths) {
2323                 paths = extra_gac_paths;
2324                 while (!res && *paths) {
2325                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2326                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2327                         g_free (gacpath);
2328                         paths++;
2329                 }
2330         }
2331
2332         if (res) {
2333                 res->in_gac = TRUE;
2334                 g_free (fullname);
2335                 mono_assembly_name_free (aname);
2336                 return res;
2337         }
2338
2339         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2340         res = probe_for_partial_name (gacpath, fullname, aname, status);
2341         g_free (gacpath);
2342
2343         if (res)
2344                 res->in_gac = TRUE;
2345         else {
2346                 MonoDomain *domain = mono_domain_get ();
2347                 MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
2348                 if (refasm)
2349                         res = refasm->assembly;
2350         }
2351         
2352         g_free (fullname);
2353         mono_assembly_name_free (aname);
2354
2355         return res;
2356 }
2357
2358 static MonoBoolean
2359 mono_assembly_is_in_gac (const gchar *filename)
2360 {
2361         const gchar *rootdir;
2362         gchar *gp;
2363         gchar **paths;
2364
2365         if (filename == NULL)
2366                 return FALSE;
2367
2368         for (paths = extra_gac_paths; paths && *paths; paths++) {
2369                 if (strstr (*paths, filename) != *paths)
2370                         continue;
2371
2372                 gp = (gchar *) (filename + strlen (*paths));
2373                 if (*gp != G_DIR_SEPARATOR)
2374                         continue;
2375                 gp++;
2376                 if (strncmp (gp, "lib", 3))
2377                         continue;
2378                 gp += 3;
2379                 if (*gp != G_DIR_SEPARATOR)
2380                         continue;
2381                 gp++;
2382                 if (strncmp (gp, "mono", 4))
2383                         continue;
2384                 gp += 4;
2385                 if (*gp != G_DIR_SEPARATOR)
2386                         continue;
2387                 gp++;
2388                 if (strncmp (gp, "gac", 3))
2389                         continue;
2390                 gp += 3;
2391                 if (*gp != G_DIR_SEPARATOR)
2392                         continue;
2393
2394                 return TRUE;
2395         }
2396
2397         rootdir = mono_assembly_getrootdir ();
2398         if (strstr (filename, rootdir) != filename)
2399                 return FALSE;
2400
2401         gp = (gchar *) (filename + strlen (rootdir));
2402         if (*gp != G_DIR_SEPARATOR)
2403                 return FALSE;
2404         gp++;
2405         if (strncmp (gp, "mono", 4))
2406                 return FALSE;
2407         gp += 4;
2408         if (*gp != G_DIR_SEPARATOR)
2409                 return FALSE;
2410         gp++;
2411         if (strncmp (gp, "gac", 3))
2412                 return FALSE;
2413         gp += 3;
2414         if (*gp != G_DIR_SEPARATOR)
2415                 return FALSE;
2416         return TRUE;
2417 }
2418
2419 static MonoImage*
2420 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2421 {
2422         MonoImage *image;
2423         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2424         gchar **paths;
2425         gint32 len;
2426
2427         if (strstr (aname->name, ".dll")) {
2428                 len = strlen (aname->name) - 4;
2429                 name = g_malloc (len);
2430                 strncpy (name, aname->name, len);
2431         } else
2432                 name = g_strdup (aname->name);
2433         
2434         if (aname->culture)
2435                 culture = g_utf8_strdown (aname->culture, -1);
2436         else
2437                 culture = g_strdup ("");
2438         
2439         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2440         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2441         g_free (name);
2442         g_free (culture);
2443         
2444         filename = g_strconcat (pname, ".dll", NULL);
2445         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2446         g_free (pname);
2447         g_free (version);
2448         g_free (filename);
2449
2450         image = NULL;
2451         if (extra_gac_paths) {
2452                 paths = extra_gac_paths;
2453                 while (!image && *paths) {
2454                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2455                                         "lib", "mono", "gac", subpath, NULL);
2456                         image = mono_image_open (fullpath, NULL);
2457                         g_free (fullpath);
2458                         paths++;
2459                 }
2460         }
2461
2462         if (image) {
2463                 g_free (subpath);
2464                 return image;
2465         }
2466
2467         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2468                         "mono", "gac", subpath, NULL);
2469         image = mono_image_open (fullpath, NULL);
2470         g_free (subpath);
2471         g_free (fullpath);
2472         
2473         return image;
2474 }
2475
2476 static MonoAssemblyName*
2477 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2478 {
2479         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2480         dest_name->major = info->new_version.major;
2481         dest_name->minor = info->new_version.minor;
2482         dest_name->build = info->new_version.build;
2483         dest_name->revision = info->new_version.revision;
2484         
2485         return dest_name;
2486 }
2487
2488 /* LOCKING: assembly_binding lock must be held */
2489 static MonoAssemblyBindingInfo*
2490 search_binding_loaded (MonoAssemblyName *aname)
2491 {
2492         GSList *tmp;
2493
2494         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2495                 MonoAssemblyBindingInfo *info = tmp->data;
2496                 if (assembly_binding_maps_name (info, aname))
2497                         return info;
2498         }
2499
2500         return NULL;
2501 }
2502
2503 static inline gboolean
2504 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2505 {
2506         if (left->major != right->major || left->minor != right->minor ||
2507             left->build != right->build || left->revision != right->revision)
2508                 return FALSE;
2509
2510         return TRUE;
2511 }
2512
2513 static inline gboolean
2514 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2515 {
2516         if (left->has_old_version_bottom != right->has_old_version_bottom)
2517                 return FALSE;
2518
2519         if (left->has_old_version_top != right->has_old_version_top)
2520                 return FALSE;
2521
2522         if (left->has_new_version != right->has_new_version)
2523                 return FALSE;
2524
2525         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2526                 return FALSE;
2527
2528         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2529                 return FALSE;
2530
2531         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2532                 return FALSE;
2533
2534         return TRUE;
2535 }
2536
2537 /* LOCKING: assumes all the necessary locks are held */
2538 static void
2539 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2540 {
2541         MonoAssemblyBindingInfo *info_copy;
2542         GSList *tmp;
2543         MonoAssemblyBindingInfo *info_tmp;
2544         MonoDomain *domain = (MonoDomain*)user_data;
2545
2546         if (!domain)
2547                 return;
2548
2549         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2550                 info_tmp = tmp->data;
2551                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2552                         return;
2553         }
2554
2555         info_copy = mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2556         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2557         if (info->name)
2558                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2559         if (info->culture)
2560                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2561
2562         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2563 }
2564
2565 static inline gboolean
2566 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2567 {
2568         if (!info->has_old_version_bottom)
2569                 return FALSE;
2570
2571         if (info->old_version_bottom.major > aname->major || info->old_version_bottom.minor > aname->minor)
2572                 return FALSE;
2573
2574         if (info->has_old_version_top && (info->old_version_top.major < aname->major || info->old_version_top.minor < aname->minor))
2575                 return FALSE;
2576
2577         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2578         info->major = aname->major;
2579         info->minor = aname->minor;
2580
2581         return TRUE;
2582 }
2583
2584 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2585 static MonoAssemblyBindingInfo*
2586 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2587 {
2588         MonoAssemblyBindingInfo *info;
2589         GSList *list;
2590
2591         if (!domain->assembly_bindings)
2592                 return NULL;
2593
2594         info = NULL;
2595         for (list = domain->assembly_bindings; list; list = list->next) {
2596                 info = list->data;
2597                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2598                         break;
2599                 info = NULL;
2600         }
2601
2602         if (info) {
2603                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2604                     info->has_new_version && assembly_binding_maps_name (info, aname))
2605                         info->is_valid = TRUE;
2606                 else
2607                         info->is_valid = FALSE;
2608         }
2609
2610         return info;
2611 }
2612
2613 static MonoAssemblyName*
2614 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2615 {
2616         MonoAssemblyBindingInfo *info, *info2;
2617         MonoImage *ppimage;
2618         MonoDomain *domain;
2619
2620         if (aname->public_key_token [0] == 0)
2621                 return aname;
2622
2623         domain = mono_domain_get ();
2624
2625         mono_assembly_binding_lock ();
2626         info = search_binding_loaded (aname);
2627         mono_assembly_binding_unlock ();
2628
2629         if (!info) {
2630                 mono_domain_lock (domain);
2631                 info = get_per_domain_assembly_binding_info (domain, aname);
2632                 mono_domain_unlock (domain);
2633         }
2634
2635         if (info) {
2636                 if (!check_policy_versions (info, aname))
2637                         return aname;
2638                 
2639                 mono_assembly_bind_version (info, aname, dest_name);
2640                 return dest_name;
2641         }
2642
2643         if (domain && domain->setup && domain->setup->configuration_file) {
2644                 mono_domain_lock (domain);
2645                 if (!domain->assembly_bindings_parsed) {
2646                         gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
2647                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2648
2649                         if (!domain_config_file_path)
2650                                 domain_config_file_path = domain_config_file_name;
2651                         
2652                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2653                         domain->assembly_bindings_parsed = TRUE;
2654                         if (domain_config_file_name != domain_config_file_path)
2655                                 g_free (domain_config_file_name);
2656                         g_free (domain_config_file_path);
2657                 }
2658
2659                 info2 = get_per_domain_assembly_binding_info (domain, aname);
2660
2661                 if (info2) {
2662                         info = g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2663                         info->name = g_strdup (info2->name);
2664                         info->culture = g_strdup (info2->culture);
2665                         info->domain_id = domain->domain_id;
2666                 }
2667
2668                 mono_domain_unlock (domain);
2669         }
2670
2671         if (!info) {
2672                 info = g_new0 (MonoAssemblyBindingInfo, 1);
2673                 info->major = aname->major;
2674                 info->minor = aname->minor;
2675         }
2676
2677         if (!info->is_valid) {
2678                 ppimage = mono_assembly_load_publisher_policy (aname);
2679                 if (ppimage) {
2680                         get_publisher_policy_info (ppimage, aname, info);
2681                         mono_image_close (ppimage);
2682                 }
2683         }
2684
2685         /* Define default error value if needed */
2686         if (!info->is_valid) {
2687                 info->name = g_strdup (aname->name);
2688                 info->culture = g_strdup (aname->culture);
2689                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2690         }
2691         
2692         mono_assembly_binding_lock ();
2693         info2 = search_binding_loaded (aname);
2694         if (info2) {
2695                 /* This binding was added by another thread 
2696                  * before us */
2697                 mono_assembly_binding_info_free (info);
2698                 g_free (info);
2699                 
2700                 info = info2;
2701         } else
2702                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2703                 
2704         mono_assembly_binding_unlock ();
2705         
2706         if (!info->is_valid || !check_policy_versions (info, aname))
2707                 return aname;
2708
2709         mono_assembly_bind_version (info, aname, dest_name);
2710         return dest_name;
2711 }
2712
2713 /**
2714  * mono_assembly_load_from_gac
2715  *
2716  * @aname: The assembly name object
2717  */
2718 static MonoAssembly*
2719 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2720 {
2721         MonoAssembly *result = NULL;
2722         gchar *name, *version, *culture, *fullpath, *subpath;
2723         gint32 len;
2724         gchar **paths;
2725         char *pubtok;
2726
2727         if (aname->public_key_token [0] == 0) {
2728                 return NULL;
2729         }
2730
2731         if (strstr (aname->name, ".dll")) {
2732                 len = strlen (filename) - 4;
2733                 name = g_malloc (len);
2734                 strncpy (name, aname->name, len);
2735         } else {
2736                 name = g_strdup (aname->name);
2737         }
2738
2739         if (aname->culture) {
2740                 culture = g_utf8_strdown (aname->culture, -1);
2741         } else {
2742                 culture = g_strdup ("");
2743         }
2744
2745         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2746         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
2747                         aname->minor, aname->build, aname->revision,
2748                         culture, pubtok);
2749         g_free (pubtok);
2750         
2751         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
2752         g_free (name);
2753         g_free (version);
2754         g_free (culture);
2755
2756         if (extra_gac_paths) {
2757                 paths = extra_gac_paths;
2758                 while (!result && *paths) {
2759                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
2760                         result = mono_assembly_open_full (fullpath, status, refonly);
2761                         g_free (fullpath);
2762                         paths++;
2763                 }
2764         }
2765
2766         if (result) {
2767                 result->in_gac = TRUE;
2768                 g_free (subpath);
2769                 return result;
2770         }
2771
2772         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2773                         "mono", "gac", subpath, NULL);
2774         result = mono_assembly_open_full (fullpath, status, refonly);
2775         g_free (fullpath);
2776
2777         if (result)
2778                 result->in_gac = TRUE;
2779         
2780         g_free (subpath);
2781
2782         return result;
2783 }
2784
2785 MonoAssembly*
2786 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
2787 {
2788         char *corlib_file;
2789         MonoAssemblyName *aname;
2790
2791         if (corlib) {
2792                 /* g_print ("corlib already loaded\n"); */
2793                 return corlib;
2794         }
2795
2796 #if defined(__native_client__)
2797         if (corlibData != NULL && corlibSize != 0) {
2798                 int status = 0;
2799                 /* First "FALSE" instructs mono not to make a copy. */
2800                 /* Second "FALSE" says this is not just a ref.      */
2801                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
2802                 if (image == NULL || status != 0)
2803                         g_print("mono_image_open_from_data_full failed: %d\n", status);
2804                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
2805                 if (corlib == NULL || status != 0)
2806                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
2807                 if (corlib)
2808                         return corlib;
2809         }
2810 #endif
2811
2812         aname = mono_assembly_name_new ("mscorlib.dll");
2813         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
2814         mono_assembly_name_free (aname);
2815         g_free (aname);
2816         if (corlib != NULL)
2817                 return corlib;
2818
2819         if (assemblies_path) {
2820                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
2821                 if (corlib)
2822                         return corlib;
2823         }
2824
2825         /* Load corlib from mono/<version> */
2826         
2827         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
2828         if (assemblies_path) {
2829                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
2830                 if (corlib) {
2831                         g_free (corlib_file);
2832                         return corlib;
2833                 }
2834         }
2835         corlib = load_in_path (corlib_file, default_path, status, FALSE);
2836         g_free (corlib_file);
2837         
2838         if (corlib && !strcmp (runtime->framework_version, "4.5"))
2839                 default_path [1] = g_strdup_printf ("%s/mono/4.5/Facades", default_path [0]);
2840                 
2841         return corlib;
2842 }
2843
2844 MonoAssembly*
2845 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
2846                                                                   const char       *basedir, 
2847                                                                   MonoImageOpenStatus *status,
2848                                                                   gboolean refonly)
2849 {
2850         MonoAssembly *result;
2851         char *fullpath, *filename;
2852         MonoAssemblyName maped_aname;
2853         MonoAssemblyName maped_name_pp;
2854         int ext_index;
2855         const char *ext;
2856         int len;
2857
2858         aname = mono_assembly_remap_version (aname, &maped_aname);
2859         
2860         /* Reflection only assemblies don't get assembly binding */
2861         if (!refonly)
2862                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
2863         
2864         result = mono_assembly_loaded_full (aname, refonly);
2865         if (result)
2866                 return result;
2867
2868         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
2869         if (result) {
2870                 result->in_gac = FALSE;
2871                 return result;
2872         }
2873
2874         /* Currently we retrieve the loaded corlib for reflection 
2875          * only requests, like a common reflection only assembly 
2876          */
2877         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
2878                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
2879         }
2880
2881         len = strlen (aname->name);
2882         for (ext_index = 0; ext_index < 2; ext_index ++) {
2883                 ext = ext_index == 0 ? ".dll" : ".exe";
2884                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
2885                         filename = g_strdup (aname->name);
2886                         /* Don't try appending .dll/.exe if it already has one of those extensions */
2887                         ext_index++;
2888                 } else {
2889                         filename = g_strconcat (aname->name, ext, NULL);
2890                 }
2891
2892                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
2893                 if (result) {
2894                         g_free (filename);
2895                         return result;
2896                 }
2897
2898                 if (basedir) {
2899                         fullpath = g_build_filename (basedir, filename, NULL);
2900                         result = mono_assembly_open_full (fullpath, status, refonly);
2901                         g_free (fullpath);
2902                         if (result) {
2903                                 result->in_gac = FALSE;
2904                                 g_free (filename);
2905                                 return result;
2906                         }
2907                 }
2908
2909                 result = load_in_path (filename, default_path, status, refonly);
2910                 if (result)
2911                         result->in_gac = FALSE;
2912                 g_free (filename);
2913                 if (result)
2914                         return result;
2915         }
2916
2917         return result;
2918 }
2919
2920 /**
2921  * mono_assembly_load_full:
2922  * @aname: A MonoAssemblyName with the assembly name to load.
2923  * @basedir: A directory to look up the assembly at.
2924  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2925  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
2926  *
2927  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2928  * attempts to load the assembly from that directory before probing the standard locations.
2929  *
2930  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
2931  * assembly binding takes place.
2932  *
2933  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2934  * value pointed by status is updated with an error code.
2935  */
2936 MonoAssembly*
2937 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
2938 {
2939         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
2940         
2941         if (!result)
2942                 /* Try a postload search hook */
2943                 result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
2944         return result;
2945 }
2946
2947 /**
2948  * mono_assembly_load:
2949  * @aname: A MonoAssemblyName with the assembly name to load.
2950  * @basedir: A directory to look up the assembly at.
2951  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2952  *
2953  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2954  * attempts to load the assembly from that directory before probing the standard locations.
2955  *
2956  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2957  * value pointed by status is updated with an error code.
2958  */
2959 MonoAssembly*
2960 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
2961 {
2962         return mono_assembly_load_full (aname, basedir, status, FALSE);
2963 }
2964         
2965 MonoAssembly*
2966 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
2967 {
2968         MonoAssembly *res;
2969         MonoAssemblyName maped_aname;
2970
2971         aname = mono_assembly_remap_version (aname, &maped_aname);
2972
2973         res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
2974
2975         return res;
2976 }
2977
2978 /**
2979  * mono_assembly_loaded:
2980  * @aname: an assembly to look for.
2981  *
2982  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
2983  * a MonoAssembly that matches the MonoAssemblyName specified.
2984  */
2985 MonoAssembly*
2986 mono_assembly_loaded (MonoAssemblyName *aname)
2987 {
2988         return mono_assembly_loaded_full (aname, FALSE);
2989 }
2990
2991 void
2992 mono_assembly_release_gc_roots (MonoAssembly *assembly)
2993 {
2994         if (assembly == NULL || assembly == REFERENCE_MISSING)
2995                 return;
2996
2997         if (assembly->dynamic) {
2998                 int i;
2999                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3000                 for (i = 0; i < dynimg->image.module_count; ++i)
3001                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3002                 mono_dynamic_image_release_gc_roots (dynimg);
3003         }
3004 }
3005
3006 /*
3007  * Returns whether mono_assembly_close_finish() must be called as
3008  * well.  See comment for mono_image_close_except_pools() for why we
3009  * unload in two steps.
3010  */
3011 gboolean
3012 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3013 {
3014         GSList *tmp;
3015         g_return_val_if_fail (assembly != NULL, FALSE);
3016
3017         if (assembly == REFERENCE_MISSING)
3018                 return FALSE;
3019
3020         /* Might be 0 already */
3021         if (InterlockedDecrement (&assembly->ref_count) > 0)
3022                 return FALSE;
3023
3024         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3025
3026         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3027
3028         mono_debug_close_image (assembly->image);
3029
3030         mono_assemblies_lock ();
3031         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3032         mono_assemblies_unlock ();
3033
3034         assembly->image->assembly = NULL;
3035
3036         if (!mono_image_close_except_pools (assembly->image))
3037                 assembly->image = NULL;
3038
3039         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3040                 MonoAssemblyName *fname = tmp->data;
3041                 mono_assembly_name_free (fname);
3042                 g_free (fname);
3043         }
3044         g_slist_free (assembly->friend_assembly_names);
3045         g_free (assembly->basedir);
3046
3047         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3048
3049         return TRUE;
3050 }
3051
3052 void
3053 mono_assembly_close_finish (MonoAssembly *assembly)
3054 {
3055         g_assert (assembly && assembly != REFERENCE_MISSING);
3056
3057         if (assembly->image)
3058                 mono_image_close_finish (assembly->image);
3059
3060         if (assembly->dynamic) {
3061                 g_free ((char*)assembly->aname.culture);
3062         } else {
3063                 g_free (assembly);
3064         }
3065 }
3066
3067 /**
3068  * mono_assembly_close:
3069  * @assembly: the assembly to release.
3070  *
3071  * This method releases a reference to the @assembly.  The assembly is
3072  * only released when all the outstanding references to it are released.
3073  */
3074 void
3075 mono_assembly_close (MonoAssembly *assembly)
3076 {
3077         if (mono_assembly_close_except_image_pools (assembly))
3078                 mono_assembly_close_finish (assembly);
3079 }
3080
3081 MonoImage*
3082 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3083 {
3084         return mono_image_load_file_for_image (assembly->image, idx);
3085 }
3086
3087 void
3088 mono_assembly_foreach (GFunc func, gpointer user_data)
3089 {
3090         GList *copy;
3091
3092         /*
3093          * We make a copy of the list to avoid calling the callback inside the 
3094          * lock, which could lead to deadlocks.
3095          */
3096         mono_assemblies_lock ();
3097         copy = g_list_copy (loaded_assemblies);
3098         mono_assemblies_unlock ();
3099
3100         g_list_foreach (loaded_assemblies, func, user_data);
3101
3102         g_list_free (copy);
3103 }
3104
3105 /**
3106  * mono_assemblies_cleanup:
3107  *
3108  * Free all resources used by this module.
3109  */
3110 void
3111 mono_assemblies_cleanup (void)
3112 {
3113         GSList *l;
3114
3115         DeleteCriticalSection (&assemblies_mutex);
3116         mono_mutex_destroy (&assembly_binding_mutex);
3117
3118         for (l = loaded_assembly_bindings; l; l = l->next) {
3119                 MonoAssemblyBindingInfo *info = l->data;
3120
3121                 mono_assembly_binding_info_free (info);
3122                 g_free (info);
3123         }
3124         g_slist_free (loaded_assembly_bindings);
3125
3126         free_assembly_load_hooks ();
3127         free_assembly_search_hooks ();
3128         free_assembly_preload_hooks ();
3129 }
3130
3131 /*LOCKING takes the assembly_binding lock*/
3132 void
3133 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3134 {
3135         GSList **iter;
3136
3137         mono_assembly_binding_lock ();
3138         iter = &loaded_assembly_bindings;
3139         while (*iter) {
3140                 GSList *l = *iter;
3141                 MonoAssemblyBindingInfo *info = l->data;
3142
3143                 if (info->domain_id == domain_id) {
3144                         *iter = l->next;
3145                         mono_assembly_binding_info_free (info);
3146                         g_free (info);
3147                         g_slist_free_1 (l);
3148                 } else {
3149                         iter = &l->next;
3150                 }
3151         }
3152         mono_assembly_binding_unlock ();
3153 }
3154
3155 /*
3156  * Holds the assembly of the application, for
3157  * System.Diagnostics.Process::MainModule
3158  */
3159 static MonoAssembly *main_assembly=NULL;
3160
3161 void
3162 mono_assembly_set_main (MonoAssembly *assembly)
3163 {
3164         main_assembly = assembly;
3165 }
3166
3167 /**
3168  * mono_assembly_get_main:
3169  *
3170  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3171  */
3172 MonoAssembly *
3173 mono_assembly_get_main (void)
3174 {
3175         return (main_assembly);
3176 }
3177
3178 /**
3179  * mono_assembly_get_image:
3180  * @assembly: The assembly to retrieve the image from
3181  *
3182  * Returns: the MonoImage associated with this assembly.
3183  */
3184 MonoImage*
3185 mono_assembly_get_image (MonoAssembly *assembly)
3186 {
3187         return assembly->image;
3188 }
3189
3190 void
3191 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3192 {
3193         bundles = assemblies;
3194 }
3195
3196 #define MONO_DECLSEC_FORMAT_10          0x3C
3197 #define MONO_DECLSEC_FORMAT_20          0x2E
3198 #define MONO_DECLSEC_FIELD              0x53
3199 #define MONO_DECLSEC_PROPERTY           0x54
3200
3201 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3202 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3203 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3204 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3205 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3206
3207 static gboolean
3208 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3209 {
3210         int len;
3211         switch (*p++) {
3212         case MONO_DECLSEC_PROPERTY:
3213                 break;
3214         case MONO_DECLSEC_FIELD:
3215         default:
3216                 *abort_decoding = TRUE;
3217                 return FALSE;
3218                 break;
3219         }
3220
3221         if (*p++ != MONO_TYPE_BOOLEAN) {
3222                 *abort_decoding = TRUE;
3223                 return FALSE;
3224         }
3225                 
3226         /* property name length */
3227         len = mono_metadata_decode_value (p, &p);
3228
3229         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3230                 p += len;
3231                 return *p;
3232         }
3233         p += len + 1;
3234
3235         *resp = p;
3236         return FALSE;
3237 }
3238
3239 static gboolean
3240 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3241 {
3242         int i, j, num, len, params_len;
3243
3244         if (*p == MONO_DECLSEC_FORMAT_10) {
3245                 gsize read, written;
3246                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3247                 if (res) {
3248                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3249                         g_free (res);
3250                         return found;
3251                 }
3252                 return FALSE;
3253         }
3254         if (*p++ != MONO_DECLSEC_FORMAT_20)
3255                 return FALSE;
3256
3257         /* number of encoded permission attributes */
3258         num = mono_metadata_decode_value (p, &p);
3259         for (i = 0; i < num; ++i) {
3260                 gboolean is_valid = FALSE;
3261                 gboolean abort_decoding = FALSE;
3262
3263                 /* attribute name length */
3264                 len =  mono_metadata_decode_value (p, &p);
3265
3266                 /* We don't really need to fully decode the type. Comparing the name is enough */
3267                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3268
3269                 p += len;
3270
3271                 /*size of the params table*/
3272                 params_len =  mono_metadata_decode_value (p, &p);
3273                 if (is_valid) {
3274                         const char *params_end = p + params_len;
3275                         
3276                         /* number of parameters */
3277                         len = mono_metadata_decode_value (p, &p);
3278         
3279                         for (j = 0; j < len; ++j) {
3280                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3281                                         return TRUE;
3282                                 if (abort_decoding)
3283                                         break;
3284                         }
3285                         p = params_end;
3286                 } else {
3287                         p += params_len;
3288                 }
3289         }
3290         
3291         return FALSE;
3292 }
3293
3294
3295 gboolean
3296 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3297 {
3298         MonoTableInfo *t;       
3299         guint32 cols [MONO_DECL_SECURITY_SIZE];
3300         const char *blob;
3301         int i, len;
3302
3303         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3304                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3305
3306         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3307
3308         for (i = 0; i < t->rows; ++i) {
3309                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3310                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3311                         continue;
3312                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3313                         continue;
3314
3315                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3316                 len = mono_metadata_decode_blob_size (blob, &blob);
3317                 if (!len)
3318                         continue;
3319
3320                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3321                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3322                         return TRUE;
3323                 }
3324         }
3325
3326         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3327         return FALSE;
3328 }