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