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