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