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