Safety check for "diamond dependencies" on netmodules
[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         } else if (!image->assembly->ref_only) {
1198                 MonoError error;
1199                 if (mono_assembly_get_reference_assembly_attribute (reference, &error)) {
1200                         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following reference assembly assembly referenced from %s was not loaded.  Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context:\n"
1201                                     "     Assembly:   %s    (assemblyref_index=%d)\n"
1202                                     "     Version:    %d.%d.%d.%d\n"
1203                                     "     Public Key: %s\n",
1204                                     image->name, aname.name, index,
1205                                     aname.major, aname.minor, aname.build, aname.revision,
1206                                     strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token);
1207                         reference = NULL; /* don't load reference assemblies for execution */
1208                 }
1209                 if (!is_ok (&error)) {
1210                         reference = NULL;
1211                         mono_error_cleanup (&error);
1212                 }
1213         }
1214
1215         mono_assemblies_lock ();
1216         if (reference == NULL) {
1217                 /* Flag as not found */
1218                 reference = (MonoAssembly *)REFERENCE_MISSING;
1219         }       
1220
1221         if (!image->references [index]) {
1222                 if (reference != REFERENCE_MISSING){
1223                         mono_assembly_addref (reference);
1224                         if (image->assembly)
1225                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1226                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1227                 } else {
1228                         if (image->assembly)
1229                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1230                                     image->assembly->aname.name, image->assembly);
1231                 }
1232                 
1233                 image->references [index] = reference;
1234         }
1235         mono_assemblies_unlock ();
1236
1237         if (image->references [index] != reference) {
1238                 /* Somebody loaded it before us */
1239                 mono_assembly_close (reference);
1240         }
1241 }
1242
1243 /**
1244  * mono_assembly_load_references:
1245  * @image: 
1246  * @status:
1247  * @deprecated: There is no reason to use this method anymore, it does nothing
1248  *
1249  * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1250  */
1251 void
1252 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1253 {
1254         /* This is a no-op now but it is part of the embedding API so we can't remove it */
1255         *status = MONO_IMAGE_OK;
1256 }
1257
1258 typedef struct AssemblyLoadHook AssemblyLoadHook;
1259 struct AssemblyLoadHook {
1260         AssemblyLoadHook *next;
1261         MonoAssemblyLoadFunc func;
1262         gpointer user_data;
1263 };
1264
1265 AssemblyLoadHook *assembly_load_hook = NULL;
1266
1267 void
1268 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1269 {
1270         AssemblyLoadHook *hook;
1271
1272         for (hook = assembly_load_hook; hook; hook = hook->next) {
1273                 hook->func (ass, hook->user_data);
1274         }
1275 }
1276
1277 void
1278 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1279 {
1280         AssemblyLoadHook *hook;
1281         
1282         g_return_if_fail (func != NULL);
1283
1284         hook = g_new0 (AssemblyLoadHook, 1);
1285         hook->func = func;
1286         hook->user_data = user_data;
1287         hook->next = assembly_load_hook;
1288         assembly_load_hook = hook;
1289 }
1290
1291 static void
1292 free_assembly_load_hooks (void)
1293 {
1294         AssemblyLoadHook *hook, *next;
1295
1296         for (hook = assembly_load_hook; hook; hook = next) {
1297                 next = hook->next;
1298                 g_free (hook);
1299         }
1300 }
1301
1302 typedef struct AssemblySearchHook AssemblySearchHook;
1303 struct AssemblySearchHook {
1304         AssemblySearchHook *next;
1305         MonoAssemblySearchFunc func;
1306         gboolean refonly;
1307         gboolean postload;
1308         gpointer user_data;
1309 };
1310
1311 AssemblySearchHook *assembly_search_hook = NULL;
1312
1313 static MonoAssembly*
1314 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1315 {
1316         AssemblySearchHook *hook;
1317
1318         for (hook = assembly_search_hook; hook; hook = hook->next) {
1319                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1320                         MonoAssembly *ass;
1321                         /**
1322                           * A little explanation is in order here.
1323                           *
1324                           * The default postload search hook needs to know the requesting assembly to report it to managed code.
1325                           * The embedding API exposes a search hook that doesn't take such argument.
1326                           *
1327                           * The original fix would call the default search hook before all the registered ones and pass
1328                           * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1329                           * rely on. Which is the ordering between user hooks and the default runtime hook.
1330                           *
1331                           * Registering the hook after mono_jit_init would let your hook run before the default one and
1332                           * when using it to handle non standard app layouts this could save your app from a massive amount
1333                           * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1334                           * are all using this trick and if we broke this assumption they would be very disapointed at us.
1335                           *
1336                           * So what's the fix? We register the default hook using regular means and special case it when iterating
1337                           * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1338                           * assembly.
1339                           */
1340                         if (hook->func == (void*)mono_domain_assembly_postload_search)
1341                                 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1342                         else
1343                                 ass = hook->func (aname, hook->user_data);
1344                         if (ass)
1345                                 return ass;
1346                 }
1347         }
1348
1349         return NULL;
1350 }
1351
1352 MonoAssembly*
1353 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1354 {
1355         return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1356 }
1357
1358 static void
1359 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1360 {
1361         AssemblySearchHook *hook;
1362         
1363         g_return_if_fail (func != NULL);
1364
1365         hook = g_new0 (AssemblySearchHook, 1);
1366         hook->func = func;
1367         hook->user_data = user_data;
1368         hook->refonly = refonly;
1369         hook->postload = postload;
1370         hook->next = assembly_search_hook;
1371         assembly_search_hook = hook;
1372 }
1373
1374 void          
1375 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1376 {
1377         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1378 }       
1379
1380 static void
1381 free_assembly_search_hooks (void)
1382 {
1383         AssemblySearchHook *hook, *next;
1384
1385         for (hook = assembly_search_hook; hook; hook = next) {
1386                 next = hook->next;
1387                 g_free (hook);
1388         }
1389 }
1390
1391 void
1392 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1393 {
1394         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1395 }
1396
1397 void          
1398 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1399 {
1400         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1401 }       
1402
1403 void
1404 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1405 {
1406         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1407 }
1408
1409 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1410 struct AssemblyPreLoadHook {
1411         AssemblyPreLoadHook *next;
1412         MonoAssemblyPreLoadFunc func;
1413         gpointer user_data;
1414 };
1415
1416 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1417 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1418
1419 static MonoAssembly *
1420 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1421 {
1422         AssemblyPreLoadHook *hook;
1423         MonoAssembly *assembly;
1424
1425         for (hook = assembly_preload_hook; hook; hook = hook->next) {
1426                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1427                 if (assembly != NULL)
1428                         return assembly;
1429         }
1430
1431         return NULL;
1432 }
1433
1434 static MonoAssembly *
1435 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1436 {
1437         AssemblyPreLoadHook *hook;
1438         MonoAssembly *assembly;
1439
1440         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1441                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1442                 if (assembly != NULL)
1443                         return assembly;
1444         }
1445
1446         return NULL;
1447 }
1448
1449 void
1450 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1451 {
1452         AssemblyPreLoadHook *hook;
1453         
1454         g_return_if_fail (func != NULL);
1455
1456         hook = g_new0 (AssemblyPreLoadHook, 1);
1457         hook->func = func;
1458         hook->user_data = user_data;
1459         hook->next = assembly_preload_hook;
1460         assembly_preload_hook = hook;
1461 }
1462
1463 void
1464 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1465 {
1466         AssemblyPreLoadHook *hook;
1467         
1468         g_return_if_fail (func != NULL);
1469
1470         hook = g_new0 (AssemblyPreLoadHook, 1);
1471         hook->func = func;
1472         hook->user_data = user_data;
1473         hook->next = assembly_refonly_preload_hook;
1474         assembly_refonly_preload_hook = hook;
1475 }
1476
1477 static void
1478 free_assembly_preload_hooks (void)
1479 {
1480         AssemblyPreLoadHook *hook, *next;
1481
1482         for (hook = assembly_preload_hook; hook; hook = next) {
1483                 next = hook->next;
1484                 g_free (hook);
1485         }
1486
1487         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1488                 next = hook->next;
1489                 g_free (hook);
1490         }
1491 }
1492
1493 static gchar *
1494 absolute_dir (const gchar *filename)
1495 {
1496         gchar *cwd;
1497         gchar *mixed;
1498         gchar **parts;
1499         gchar *part;
1500         GList *list, *tmp;
1501         GString *result;
1502         gchar *res;
1503         gint i;
1504
1505         if (g_path_is_absolute (filename)) {
1506                 part = g_path_get_dirname (filename);
1507                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1508                 g_free (part);
1509                 return res;
1510         }
1511
1512         cwd = g_get_current_dir ();
1513         mixed = g_build_filename (cwd, filename, NULL);
1514         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1515         g_free (mixed);
1516         g_free (cwd);
1517
1518         list = NULL;
1519         for (i = 0; (part = parts [i]) != NULL; i++) {
1520                 if (!strcmp (part, "."))
1521                         continue;
1522
1523                 if (!strcmp (part, "..")) {
1524                         if (list && list->next) /* Don't remove root */
1525                                 list = g_list_delete_link (list, list);
1526                 } else {
1527                         list = g_list_prepend (list, part);
1528                 }
1529         }
1530
1531         result = g_string_new ("");
1532         list = g_list_reverse (list);
1533
1534         /* Ignores last data pointer, which should be the filename */
1535         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1536                 if (tmp->data)
1537                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1538                                                                 G_DIR_SEPARATOR);
1539         }
1540
1541         res = result->str;
1542         g_string_free (result, FALSE);
1543         g_list_free (list);
1544         g_strfreev (parts);
1545         if (*res == '\0') {
1546                 g_free (res);
1547                 return g_strdup (".");
1548         }
1549
1550         return res;
1551 }
1552
1553 /** 
1554  * mono_assembly_open_from_bundle:
1555  * @filename: Filename requested
1556  * @status: return status code
1557  *
1558  * This routine tries to open the assembly specified by `filename' from the
1559  * defined bundles, if found, returns the MonoImage for it, if not found
1560  * returns NULL
1561  */
1562 MonoImage *
1563 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1564 {
1565         int i;
1566         char *name;
1567         MonoImage *image = NULL;
1568
1569         /*
1570          * we do a very simple search for bundled assemblies: it's not a general 
1571          * purpose assembly loading mechanism.
1572          */
1573
1574         if (!bundles)
1575                 return NULL;
1576
1577         name = g_path_get_basename (filename);
1578
1579         mono_assemblies_lock ();
1580         for (i = 0; !image && bundles [i]; ++i) {
1581                 if (strcmp (bundles [i]->name, name) == 0) {
1582                         image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1583                         break;
1584                 }
1585         }
1586         mono_assemblies_unlock ();
1587         if (image) {
1588                 mono_image_addref (image);
1589                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1590                 g_free (name);
1591                 return image;
1592         }
1593         g_free (name);
1594         return NULL;
1595 }
1596
1597 /**
1598  * mono_assemblies_open_full:
1599  * @filename: the file to load
1600  * @status: return status code 
1601  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1602
1603  * This loads an assembly from the specified @filename.   The @filename allows
1604  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1605  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1606  * is treated as a local path.
1607  *
1608  * First, an attempt is made to load the assembly from the bundled executable (for those
1609  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1610  * assembly has been registered as an embedded assembly).   If this is not the case, then
1611  * the assembly is loaded from disk using `api:mono_image_open_full`.
1612  *
1613  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1614  * the assembly is made.
1615  *
1616  * If @refonly is set to true, then the assembly is loaded purely for inspection with
1617  * the `System.Reflection` API.
1618  *
1619  * Returns: NULL on error, with the @status set to an error code, or a pointer
1620  * to the assembly.
1621  */
1622 MonoAssembly *
1623 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1624 {
1625         MonoImage *image;
1626         MonoAssembly *ass;
1627         MonoImageOpenStatus def_status;
1628         gchar *fname;
1629         gchar *new_fname;
1630         gboolean loaded_from_bundle;
1631         
1632         g_return_val_if_fail (filename != NULL, NULL);
1633
1634         if (!status)
1635                 status = &def_status;
1636         *status = MONO_IMAGE_OK;
1637
1638         if (strncmp (filename, "file://", 7) == 0) {
1639                 GError *error = NULL;
1640                 gchar *uri = (gchar *) filename;
1641                 gchar *tmpuri;
1642
1643                 /*
1644                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1645                  * They also throw an IndexOutOfRangeException if "file://"
1646                  */
1647                 if (uri [7] != '/')
1648                         uri = g_strdup_printf ("file:///%s", uri + 7);
1649         
1650                 tmpuri = uri;
1651                 uri = mono_escape_uri_string (tmpuri);
1652                 fname = g_filename_from_uri (uri, NULL, &error);
1653                 g_free (uri);
1654
1655                 if (tmpuri != filename)
1656                         g_free (tmpuri);
1657
1658                 if (error != NULL) {
1659                         g_warning ("%s\n", error->message);
1660                         g_error_free (error);
1661                         fname = g_strdup (filename);
1662                 }
1663         } else {
1664                 fname = g_strdup (filename);
1665         }
1666
1667         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1668                         "Assembly Loader probing location: '%s'.", fname);
1669
1670         new_fname = NULL;
1671         if (!mono_assembly_is_in_gac (fname)) {
1672                 MonoError error;
1673                 new_fname = mono_make_shadow_copy (fname, &error);
1674                 if (!is_ok (&error)) {
1675                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1676                                     "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1677                         mono_error_cleanup (&error);
1678                         *status = MONO_IMAGE_IMAGE_INVALID;
1679                         g_free (fname);
1680                         return NULL;
1681                 }
1682         }
1683         if (new_fname && new_fname != fname) {
1684                 g_free (fname);
1685                 fname = new_fname;
1686                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1687                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1688         }
1689         
1690         image = NULL;
1691
1692         // If VM built with mkbundle
1693         loaded_from_bundle = FALSE;
1694         if (bundles != NULL) {
1695                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1696                 loaded_from_bundle = image != NULL;
1697         }
1698
1699         if (!image)
1700                 image = mono_image_open_full (fname, status, refonly);
1701
1702         if (!image){
1703                 if (*status == MONO_IMAGE_OK)
1704                         *status = MONO_IMAGE_ERROR_ERRNO;
1705                 g_free (fname);
1706                 return NULL;
1707         }
1708
1709         if (image->assembly) {
1710                 /* Already loaded by another appdomain */
1711                 mono_assembly_invoke_load_hook (image->assembly);
1712                 mono_image_close (image);
1713                 g_free (fname);
1714                 return image->assembly;
1715         }
1716
1717         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1718
1719         if (ass) {
1720                 if (!loaded_from_bundle)
1721                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1722                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1723                 if (!refonly)
1724                         mono_config_for_assembly (ass->image);
1725         }
1726
1727         /* Clear the reference added by mono_image_open */
1728         mono_image_close (image);
1729         
1730         g_free (fname);
1731
1732         return ass;
1733 }
1734
1735 static void
1736 free_item (gpointer val, gpointer user_data)
1737 {
1738         g_free (val);
1739 }
1740
1741 /**
1742  * mono_assembly_load_friends:
1743  * @ass: an assembly
1744  *
1745  * Load the list of friend assemblies that are allowed to access
1746  * the assembly's internal types and members. They are stored as assembly
1747  * names in custom attributes.
1748  *
1749  * This is an internal method, we need this because when we load mscorlib
1750  * we do not have the internals visible cattr loaded yet,
1751  * so we need to load these after we initialize the runtime. 
1752  *
1753  * LOCKING: Acquires the assemblies lock plus the loader lock.
1754  */
1755 void
1756 mono_assembly_load_friends (MonoAssembly* ass)
1757 {
1758         MonoError error;
1759         int i;
1760         MonoCustomAttrInfo* attrs;
1761         GSList *list;
1762
1763         if (ass->friend_assembly_names_inited)
1764                 return;
1765
1766         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1767         mono_error_assert_ok (&error);
1768         if (!attrs) {
1769                 mono_assemblies_lock ();
1770                 ass->friend_assembly_names_inited = TRUE;
1771                 mono_assemblies_unlock ();
1772                 return;
1773         }
1774
1775         mono_assemblies_lock ();
1776         if (ass->friend_assembly_names_inited) {
1777                 mono_assemblies_unlock ();
1778                 return;
1779         }
1780         mono_assemblies_unlock ();
1781
1782         list = NULL;
1783         /* 
1784          * We build the list outside the assemblies lock, the worse that can happen
1785          * is that we'll need to free the allocated list.
1786          */
1787         for (i = 0; i < attrs->num_attrs; ++i) {
1788                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1789                 MonoAssemblyName *aname;
1790                 const gchar *data;
1791                 /* Do some sanity checking */
1792                 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1793                         continue;
1794                 if (attr->data_size < 4)
1795                         continue;
1796                 data = (const char*)attr->data;
1797                 /* 0xFF means null string, see custom attr format */
1798                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1799                         continue;
1800                 mono_metadata_decode_value (data + 2, &data);
1801                 aname = g_new0 (MonoAssemblyName, 1);
1802                 /*g_print ("friend ass: %s\n", data);*/
1803                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1804                         list = g_slist_prepend (list, aname);
1805                 } else {
1806                         g_free (aname);
1807                 }
1808         }
1809         mono_custom_attrs_free (attrs);
1810
1811         mono_assemblies_lock ();
1812         if (ass->friend_assembly_names_inited) {
1813                 mono_assemblies_unlock ();
1814                 g_slist_foreach (list, free_item, NULL);
1815                 g_slist_free (list);
1816                 return;
1817         }
1818         ass->friend_assembly_names = list;
1819
1820         /* Because of the double checked locking pattern above */
1821         mono_memory_barrier ();
1822         ass->friend_assembly_names_inited = TRUE;
1823         mono_assemblies_unlock ();
1824 }
1825
1826
1827 /**
1828  * mono_assembly_get_reference_assembly_attribute:
1829  * @assembly: a MonoAssembly
1830  * @error: set on error.
1831  *
1832  * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1833  * On error returns FALSE and sets @error.
1834  */
1835 gboolean
1836 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1837 {
1838         mono_error_init (error);
1839
1840         MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1841         return_val_if_nok (error, FALSE);
1842         if (!attrs)
1843                 return FALSE;
1844         MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1845         gboolean result = FALSE;
1846         for (int i = 0; i < attrs->num_attrs; ++i) {
1847                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1848                 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1849                         result = TRUE;
1850                         break;
1851                 }
1852         }
1853         mono_custom_attrs_free (attrs);
1854         return result;
1855 }
1856
1857 /**
1858  * mono_assembly_open:
1859  * @filename: Opens the assembly pointed out by this name
1860  * @status: return status code
1861  *
1862  * This loads an assembly from the specified @filename.   The @filename allows
1863  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1864  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1865  * is treated as a local path.
1866  *
1867  * First, an attempt is made to load the assembly from the bundled executable (for those
1868  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1869  * assembly has been registered as an embedded assembly).   If this is not the case, then
1870  * the assembly is loaded from disk using `api:mono_image_open_full`.
1871  *
1872  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1873  * the assembly is made.
1874  *
1875  * Return: a pointer to the MonoAssembly if @filename contains a valid
1876  * assembly or NULL on error.  Details about the error are stored in the
1877  * @status variable.
1878  */
1879 MonoAssembly *
1880 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1881 {
1882         return mono_assembly_open_full (filename, status, FALSE);
1883 }
1884
1885 /**
1886  * mono_assembly_load_from_full:
1887  * @image: Image to load the assembly from
1888  * @fname: assembly name to associate with the assembly
1889  * @status: returns the status condition
1890  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1891  *
1892  * If the provided @image has an assembly reference, it will process the given
1893  * image as an assembly with the given name.
1894  *
1895  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1896  *
1897  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1898  * set to #MONO_IMAGE_OK;  or NULL on error.
1899  *
1900  * If there is an error loading the assembly the @status will indicate the
1901  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1902  * image did not contain an assembly reference table.
1903  */
1904 MonoAssembly *
1905 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1906                               MonoImageOpenStatus *status, gboolean refonly)
1907 {
1908         MonoAssembly *ass, *ass2;
1909         char *base_dir;
1910
1911         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1912                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1913                 *status = MONO_IMAGE_IMAGE_INVALID;
1914                 return NULL;
1915         }
1916
1917 #if defined (HOST_WIN32)
1918         {
1919                 gchar *tmp_fn;
1920                 int i;
1921
1922                 tmp_fn = g_strdup (fname);
1923                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1924                         if (tmp_fn [i] == '/')
1925                                 tmp_fn [i] = '\\';
1926                 }
1927
1928                 base_dir = absolute_dir (tmp_fn);
1929                 g_free (tmp_fn);
1930         }
1931 #else
1932         base_dir = absolute_dir (fname);
1933 #endif
1934
1935         /*
1936          * Create assembly struct, and enter it into the assembly cache
1937          */
1938         ass = g_new0 (MonoAssembly, 1);
1939         ass->basedir = base_dir;
1940         ass->ref_only = refonly;
1941         ass->image = image;
1942
1943         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1944
1945         mono_assembly_fill_assembly_name (image, &ass->aname);
1946
1947         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1948                 // MS.NET doesn't support loading other mscorlibs
1949                 g_free (ass);
1950                 g_free (base_dir);
1951                 mono_image_addref (mono_defaults.corlib);
1952                 *status = MONO_IMAGE_OK;
1953                 return mono_defaults.corlib->assembly;
1954         }
1955
1956         /* Add a non-temporary reference because of ass->image */
1957         mono_image_addref (image);
1958
1959         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);
1960
1961         /* 
1962          * The load hooks might take locks so we can't call them while holding the
1963          * assemblies lock.
1964          */
1965         if (ass->aname.name) {
1966                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1967                 if (ass2) {
1968                         g_free (ass);
1969                         g_free (base_dir);
1970                         mono_image_close (image);
1971                         *status = MONO_IMAGE_OK;
1972                         return ass2;
1973                 }
1974         }
1975
1976         mono_assemblies_lock ();
1977
1978         if (image->assembly) {
1979                 /* 
1980                  * This means another thread has already loaded the assembly, but not yet
1981                  * called the load hooks so the search hook can't find the assembly.
1982                  */
1983                 mono_assemblies_unlock ();
1984                 ass2 = image->assembly;
1985                 g_free (ass);
1986                 g_free (base_dir);
1987                 mono_image_close (image);
1988                 *status = MONO_IMAGE_OK;
1989                 return ass2;
1990         }
1991
1992         image->assembly = ass;
1993
1994         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1995         mono_assemblies_unlock ();
1996
1997 #ifdef HOST_WIN32
1998         if (image->is_module_handle)
1999                 mono_image_fixup_vtable (image);
2000 #endif
2001
2002         mono_assembly_invoke_load_hook (ass);
2003
2004         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2005         
2006         return ass;
2007 }
2008
2009 /**
2010  * mono_assembly_load_from:
2011  * @image: Image to load the assembly from
2012  * @fname: assembly name to associate with the assembly
2013  * @status: return status code
2014  *
2015  * If the provided @image has an assembly reference, it will process the given
2016  * image as an assembly with the given name.
2017  *
2018  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2019  *
2020  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2021  * @refonly parameter set to FALSE.
2022  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2023  * set to #MONO_IMAGE_OK;  or NULL on error.
2024  *
2025  * If there is an error loading the assembly the @status will indicate the
2026  * reason with @status being set to `MONO_IMAGE_INVALID` if the
2027  * image did not contain an assembly reference table.
2028  
2029  */
2030 MonoAssembly *
2031 mono_assembly_load_from (MonoImage *image, const char *fname,
2032                          MonoImageOpenStatus *status)
2033 {
2034         return mono_assembly_load_from_full (image, fname, status, FALSE);
2035 }
2036
2037 /**
2038  * mono_assembly_name_free:
2039  * @aname: assembly name to free
2040  * 
2041  * Frees the provided assembly name object.
2042  * (it does not frees the object itself, only the name members).
2043  */
2044 void
2045 mono_assembly_name_free (MonoAssemblyName *aname)
2046 {
2047         if (aname == NULL)
2048                 return;
2049
2050         g_free ((void *) aname->name);
2051         g_free ((void *) aname->culture);
2052         g_free ((void *) aname->hash_value);
2053         g_free ((guint8*) aname->public_key);
2054 }
2055
2056 static gboolean
2057 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2058 {
2059         const gchar *pkey;
2060         gchar header [16], val, *arr;
2061         gint i, j, offset, bitlen, keylen, pkeylen;
2062         
2063         keylen = strlen (key) >> 1;
2064         if (keylen < 1)
2065                 return FALSE;
2066
2067         /* allow the ECMA standard key */
2068         if (strcmp (key, "00000000000000000400000000000000") == 0) {
2069                 if (pubkey) {
2070                         *pubkey = g_strdup (key);
2071                         *is_ecma = TRUE;
2072                 }
2073                 return TRUE;
2074         }
2075         *is_ecma = FALSE;
2076         val = g_ascii_xdigit_value (key [0]) << 4;
2077         val |= g_ascii_xdigit_value (key [1]);
2078         switch (val) {
2079                 case 0x00:
2080                         if (keylen < 13)
2081                                 return FALSE;
2082                         val = g_ascii_xdigit_value (key [24]);
2083                         val |= g_ascii_xdigit_value (key [25]);
2084                         if (val != 0x06)
2085                                 return FALSE;
2086                         pkey = key + 24;
2087                         break;
2088                 case 0x06:
2089                         pkey = key;
2090                         break;
2091                 default:
2092                         return FALSE;
2093         }
2094                 
2095         /* We need the first 16 bytes
2096         * to check whether this key is valid or not */
2097         pkeylen = strlen (pkey) >> 1;
2098         if (pkeylen < 16)
2099                 return FALSE;
2100                 
2101         for (i = 0, j = 0; i < 16; i++) {
2102                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2103                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2104         }
2105
2106         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2107                         header [1] != 0x02 || /* Version (0x02) */
2108                         header [2] != 0x00 || /* Reserved (word) */
2109                         header [3] != 0x00 ||
2110                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2111                 return FALSE;
2112
2113         /* Based on this length, we _should_ be able to know if the length is right */
2114         bitlen = read32 (header + 12) >> 3;
2115         if ((bitlen + 16 + 4) != pkeylen)
2116                 return FALSE;
2117
2118         /* parsing is OK and the public key itself is not requested back */
2119         if (!pubkey)
2120                 return TRUE;
2121                 
2122         /* Encode the size of the blob */
2123         offset = 0;
2124         if (keylen <= 127) {
2125                 arr = (gchar *)g_malloc (keylen + 1);
2126                 arr [offset++] = keylen;
2127         } else {
2128                 arr = (gchar *)g_malloc (keylen + 2);
2129                 arr [offset++] = 0x80; /* 10bs */
2130                 arr [offset++] = keylen;
2131         }
2132                 
2133         for (i = offset, j = 0; i < keylen + offset; i++) {
2134                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2135                 arr [i] |= g_ascii_xdigit_value (key [j++]);
2136         }
2137
2138         *pubkey = arr;
2139
2140         return TRUE;
2141 }
2142
2143 static gboolean
2144 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)
2145 {
2146         gint major, minor, build, revision;
2147         gint len;
2148         gint version_parts;
2149         gchar *pkey, *pkeyptr, *encoded, tok [8];
2150
2151         memset (aname, 0, sizeof (MonoAssemblyName));
2152
2153         if (version) {
2154                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2155                 if (version_parts < 2 || version_parts > 4)
2156                         return FALSE;
2157
2158                 /* FIXME: we should set build & revision to -1 (instead of 0)
2159                 if these are not set in the version string. That way, later on,
2160                 we can still determine if these were specified. */
2161                 aname->major = major;
2162                 aname->minor = minor;
2163                 if (version_parts >= 3)
2164                         aname->build = build;
2165                 else
2166                         aname->build = 0;
2167                 if (version_parts == 4)
2168                         aname->revision = revision;
2169                 else
2170                         aname->revision = 0;
2171         }
2172         
2173         aname->flags = flags;
2174         aname->arch = arch;
2175         aname->name = g_strdup (name);
2176         
2177         if (culture) {
2178                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2179                         aname->culture = g_strdup ("");
2180                 else
2181                         aname->culture = g_strdup (culture);
2182         }
2183         
2184         if (token && strncmp (token, "null", 4) != 0) {
2185                 char *lower;
2186
2187                 /* the constant includes the ending NULL, hence the -1 */
2188                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2189                         mono_assembly_name_free (aname);
2190                         return FALSE;
2191                 }
2192                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2193                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2194                 g_free (lower);
2195         }
2196
2197         if (key) {
2198                 gboolean is_ecma;
2199                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2200                         mono_assembly_name_free (aname);
2201                         return FALSE;
2202                 }
2203
2204                 if (is_ecma) {
2205                         if (save_public_key)
2206                                 aname->public_key = (guint8*)pkey;
2207                         else
2208                                 g_free (pkey);
2209                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2210                         return TRUE;
2211                 }
2212                 
2213                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2214                 // We also need to generate the key token
2215                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2216                 encoded = encode_public_tok ((guchar*) tok, 8);
2217                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2218                 g_free (encoded);
2219
2220                 if (save_public_key)
2221                         aname->public_key = (guint8*) pkey;
2222                 else
2223                         g_free (pkey);
2224         }
2225
2226         return TRUE;
2227 }
2228
2229 static gboolean
2230 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2231 {
2232         gchar **parts;
2233         gboolean res;
2234         
2235         parts = g_strsplit (dirname, "_", 3);
2236         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2237                 g_strfreev (parts);
2238                 return FALSE;
2239         }
2240         
2241         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2242         g_strfreev (parts);
2243         return res;
2244 }
2245
2246 static gboolean
2247 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2248 {
2249         char *eqsign = strchr (pair, '=');
2250         if (!eqsign) {
2251                 *key = NULL;
2252                 *keylen = 0;
2253                 *value = NULL;
2254                 return FALSE;
2255         }
2256
2257         *key = (gchar*)pair;
2258         *keylen = eqsign - *key;
2259         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2260                 (*keylen)--;
2261         *value = g_strstrip (eqsign + 1);
2262         return TRUE;
2263 }
2264
2265 gboolean
2266 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2267 {
2268         gchar *dllname;
2269         gchar *dllname_uq;
2270         gchar *version = NULL;
2271         gchar *version_uq;
2272         gchar *culture = NULL;
2273         gchar *culture_uq;
2274         gchar *token = NULL;
2275         gchar *token_uq;
2276         gchar *key = NULL;
2277         gchar *key_uq;
2278         gchar *retargetable = NULL;
2279         gchar *retargetable_uq;
2280         gchar *procarch;
2281         gchar *procarch_uq;
2282         gboolean res;
2283         gchar *value, *part_name;
2284         guint32 part_name_len;
2285         gchar **parts;
2286         gchar **tmp;
2287         gboolean version_defined;
2288         gboolean token_defined;
2289         guint32 flags = 0;
2290         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2291
2292         if (!is_version_defined)
2293                 is_version_defined = &version_defined;
2294         *is_version_defined = FALSE;
2295         if (!is_token_defined)
2296                 is_token_defined = &token_defined;
2297         *is_token_defined = FALSE;
2298         
2299         parts = tmp = g_strsplit (name, ",", 6);
2300         if (!tmp || !*tmp) {
2301                 g_strfreev (tmp);
2302                 return FALSE;
2303         }
2304
2305         dllname = g_strstrip (*tmp);
2306         
2307         tmp++;
2308
2309         while (*tmp) {
2310                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2311                         goto cleanup_and_fail;
2312
2313                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2314                         *is_version_defined = TRUE;
2315                         version = value;
2316                         if (strlen (version) == 0) {
2317                                 goto cleanup_and_fail;
2318                         }
2319                         tmp++;
2320                         continue;
2321                 }
2322
2323                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2324                         culture = value;
2325                         if (strlen (culture) == 0) {
2326                                 goto cleanup_and_fail;
2327                         }
2328                         tmp++;
2329                         continue;
2330                 }
2331
2332                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2333                         *is_token_defined = TRUE;
2334                         token = value;
2335                         if (strlen (token) == 0) {
2336                                 goto cleanup_and_fail;
2337                         }
2338                         tmp++;
2339                         continue;
2340                 }
2341
2342                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2343                         key = value;
2344                         if (strlen (key) == 0) {
2345                                 goto cleanup_and_fail;
2346                         }
2347                         tmp++;
2348                         continue;
2349                 }
2350
2351                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2352                         retargetable = value;
2353                         retargetable_uq = unquote (retargetable);
2354                         if (retargetable_uq != NULL)
2355                                 retargetable = retargetable_uq;
2356
2357                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2358                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2359                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2360                                 g_free (retargetable_uq);
2361                                 goto cleanup_and_fail;
2362                         }
2363
2364                         g_free (retargetable_uq);
2365                         tmp++;
2366                         continue;
2367                 }
2368
2369                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2370                         procarch = value;
2371                         procarch_uq = unquote (procarch);
2372                         if (procarch_uq != NULL)
2373                                 procarch = procarch_uq;
2374
2375                         if (!g_ascii_strcasecmp (procarch, "MSIL"))
2376                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2377                         else if (!g_ascii_strcasecmp (procarch, "X86"))
2378                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2379                         else if (!g_ascii_strcasecmp (procarch, "IA64"))
2380                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2381                         else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2382                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2383                         else {
2384                                 g_free (procarch_uq);
2385                                 goto cleanup_and_fail;
2386                         }
2387
2388                         g_free (procarch_uq);
2389                         tmp++;
2390                         continue;
2391                 }
2392
2393                 g_strfreev (parts);
2394                 return FALSE;
2395         }
2396
2397         /* if retargetable flag is set, then we must have a fully qualified name */
2398         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2399                 goto cleanup_and_fail;
2400         }
2401
2402         dllname_uq = unquote (dllname);
2403         version_uq = unquote (version);
2404         culture_uq = unquote (culture);
2405         token_uq = unquote (token);
2406         key_uq = unquote (key);
2407
2408         res = build_assembly_name (
2409                 dllname_uq == NULL ? dllname : dllname_uq,
2410                 version_uq == NULL ? version : version_uq,
2411                 culture_uq == NULL ? culture : culture_uq,
2412                 token_uq == NULL ? token : token_uq,
2413                 key_uq == NULL ? key : key_uq,
2414                 flags, arch, aname, save_public_key);
2415
2416         g_free (dllname_uq);
2417         g_free (version_uq);
2418         g_free (culture_uq);
2419         g_free (token_uq);
2420         g_free (key_uq);
2421
2422         g_strfreev (parts);
2423         return res;
2424
2425 cleanup_and_fail:
2426         g_strfreev (parts);
2427         return FALSE;
2428 }
2429
2430 static char*
2431 unquote (const char *str)
2432 {
2433         gint slen;
2434         const char *end;
2435
2436         if (str == NULL)
2437                 return NULL;
2438
2439         slen = strlen (str);
2440         if (slen < 2)
2441                 return NULL;
2442
2443         if (*str != '\'' && *str != '\"')
2444                 return NULL;
2445
2446         end = str + slen - 1;
2447         if (*str != *end)
2448                 return NULL;
2449
2450         return g_strndup (str + 1, slen - 2);
2451 }
2452
2453 /**
2454  * mono_assembly_name_parse:
2455  * @name: name to parse
2456  * @aname: the destination assembly name
2457  * 
2458  * Parses an assembly qualified type name and assigns the name,
2459  * version, culture and token to the provided assembly name object.
2460  *
2461  * Returns: TRUE if the name could be parsed.
2462  */
2463 gboolean
2464 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2465 {
2466         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2467 }
2468
2469 /**
2470  * mono_assembly_name_new:
2471  * @name: name to parse
2472  *
2473  * Allocate a new MonoAssemblyName and fill its values from the
2474  * passed @name.
2475  *
2476  * Returns: a newly allocated structure or NULL if there was any failure.
2477  */
2478 MonoAssemblyName*
2479 mono_assembly_name_new (const char *name)
2480 {
2481         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2482         if (mono_assembly_name_parse (name, aname))
2483                 return aname;
2484         g_free (aname);
2485         return NULL;
2486 }
2487
2488 const char*
2489 mono_assembly_name_get_name (MonoAssemblyName *aname)
2490 {
2491         return aname->name;
2492 }
2493
2494 const char*
2495 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2496 {
2497         return aname->culture;
2498 }
2499
2500 mono_byte*
2501 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2502 {
2503         if (aname->public_key_token [0])
2504                 return aname->public_key_token;
2505         return NULL;
2506 }
2507
2508 uint16_t
2509 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2510 {
2511         if (minor)
2512                 *minor = aname->minor;
2513         if (build)
2514                 *build = aname->build;
2515         if (revision)
2516                 *revision = aname->revision;
2517         return aname->major;
2518 }
2519
2520 static MonoAssembly*
2521 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2522 {
2523         gchar *fullpath = NULL;
2524         GDir *dirhandle;
2525         const char* direntry;
2526         MonoAssemblyName gac_aname;
2527         gint major=-1, minor=0, build=0, revision=0;
2528         gboolean exact_version;
2529         
2530         dirhandle = g_dir_open (basepath, 0, NULL);
2531         if (!dirhandle)
2532                 return NULL;
2533                 
2534         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2535
2536         while ((direntry = g_dir_read_name (dirhandle))) {
2537                 gboolean match = TRUE;
2538                 
2539                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2540                         continue;
2541                 
2542                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2543                         match = FALSE;
2544                         
2545                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2546                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2547                         match = FALSE;
2548                 
2549                 if (match) {
2550                         if (exact_version) {
2551                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2552                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2553                         }
2554                         else if (gac_aname.major < major)
2555                                 match = FALSE;
2556                         else if (gac_aname.major == major) {
2557                                 if (gac_aname.minor < minor)
2558                                         match = FALSE;
2559                                 else if (gac_aname.minor == minor) {
2560                                         if (gac_aname.build < build)
2561                                                 match = FALSE;
2562                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2563                                                 match = FALSE; 
2564                                 }
2565                         }
2566                 }
2567                 
2568                 if (match) {
2569                         major = gac_aname.major;
2570                         minor = gac_aname.minor;
2571                         build = gac_aname.build;
2572                         revision = gac_aname.revision;
2573                         g_free (fullpath);
2574                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2575                 }
2576
2577                 mono_assembly_name_free (&gac_aname);
2578         }
2579         
2580         g_dir_close (dirhandle);
2581         
2582         if (fullpath == NULL)
2583                 return NULL;
2584         else {
2585                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2586                 g_free (fullpath);
2587                 return res;
2588         }
2589 }
2590
2591 /**
2592  * mono_assembly_load_with_partial_name:
2593  * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2594  * @status: return status code
2595  *
2596  * Loads a Mono Assembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2597  * so it might contain a qualified type name, version, culture and token.
2598  *
2599  * This will load the assembly from the file whose name is derived from the assembly name
2600  * by appending the .dll extension.
2601  *
2602  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2603  * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2604  * if that fails from the GAC.
2605  *
2606  * Returns: NULL on failure, or a pointer to a MonoAssembly on success.   
2607  */
2608 MonoAssembly*
2609 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2610 {
2611         MonoError error;
2612         MonoAssembly *res;
2613         MonoAssemblyName *aname, base_name;
2614         MonoAssemblyName mapped_aname;
2615         gchar *fullname, *gacpath;
2616         gchar **paths;
2617
2618         memset (&base_name, 0, sizeof (MonoAssemblyName));
2619         aname = &base_name;
2620
2621         if (!mono_assembly_name_parse (name, aname))
2622                 return NULL;
2623
2624         /* 
2625          * If no specific version has been requested, make sure we load the
2626          * correct version for system assemblies.
2627          */ 
2628         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2629                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2630         
2631         res = mono_assembly_loaded (aname);
2632         if (res) {
2633                 mono_assembly_name_free (aname);
2634                 return res;
2635         }
2636
2637         res = invoke_assembly_preload_hook (aname, assemblies_path);
2638         if (res) {
2639                 res->in_gac = FALSE;
2640                 mono_assembly_name_free (aname);
2641                 return res;
2642         }
2643
2644         fullname = g_strdup_printf ("%s.dll", aname->name);
2645
2646         if (extra_gac_paths) {
2647                 paths = extra_gac_paths;
2648                 while (!res && *paths) {
2649                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2650                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2651                         g_free (gacpath);
2652                         paths++;
2653                 }
2654         }
2655
2656         if (res) {
2657                 res->in_gac = TRUE;
2658                 g_free (fullname);
2659                 mono_assembly_name_free (aname);
2660                 return res;
2661         }
2662
2663         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2664         res = probe_for_partial_name (gacpath, fullname, aname, status);
2665         g_free (gacpath);
2666
2667         if (res)
2668                 res->in_gac = TRUE;
2669         else {
2670                 MonoDomain *domain = mono_domain_get ();
2671                 MonoReflectionAssembly *refasm;
2672
2673                 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2674                 if (!is_ok (&error)) {
2675                         g_free (fullname);
2676                         mono_assembly_name_free (aname);
2677                         mono_error_cleanup (&error);
2678                         if (*status == MONO_IMAGE_OK)
2679                                 *status = MONO_IMAGE_IMAGE_INVALID;
2680                 }
2681
2682                 if (refasm)
2683                         res = refasm->assembly;
2684         }
2685         
2686         g_free (fullname);
2687         mono_assembly_name_free (aname);
2688
2689         return res;
2690 }
2691
2692 static MonoBoolean
2693 mono_assembly_is_in_gac (const gchar *filename)
2694 {
2695         const gchar *rootdir;
2696         gchar *gp;
2697         gchar **paths;
2698
2699         if (filename == NULL)
2700                 return FALSE;
2701
2702         for (paths = extra_gac_paths; paths && *paths; paths++) {
2703                 if (strstr (*paths, filename) != *paths)
2704                         continue;
2705
2706                 gp = (gchar *) (filename + strlen (*paths));
2707                 if (*gp != G_DIR_SEPARATOR)
2708                         continue;
2709                 gp++;
2710                 if (strncmp (gp, "lib", 3))
2711                         continue;
2712                 gp += 3;
2713                 if (*gp != G_DIR_SEPARATOR)
2714                         continue;
2715                 gp++;
2716                 if (strncmp (gp, "mono", 4))
2717                         continue;
2718                 gp += 4;
2719                 if (*gp != G_DIR_SEPARATOR)
2720                         continue;
2721                 gp++;
2722                 if (strncmp (gp, "gac", 3))
2723                         continue;
2724                 gp += 3;
2725                 if (*gp != G_DIR_SEPARATOR)
2726                         continue;
2727
2728                 return TRUE;
2729         }
2730
2731         rootdir = mono_assembly_getrootdir ();
2732         if (strstr (filename, rootdir) != filename)
2733                 return FALSE;
2734
2735         gp = (gchar *) (filename + strlen (rootdir));
2736         if (*gp != G_DIR_SEPARATOR)
2737                 return FALSE;
2738         gp++;
2739         if (strncmp (gp, "mono", 4))
2740                 return FALSE;
2741         gp += 4;
2742         if (*gp != G_DIR_SEPARATOR)
2743                 return FALSE;
2744         gp++;
2745         if (strncmp (gp, "gac", 3))
2746                 return FALSE;
2747         gp += 3;
2748         if (*gp != G_DIR_SEPARATOR)
2749                 return FALSE;
2750         return TRUE;
2751 }
2752
2753 static MonoImage*
2754 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2755 {
2756         MonoImage *image;
2757         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2758         gchar **paths;
2759         gint32 len;
2760
2761         if (strstr (aname->name, ".dll")) {
2762                 len = strlen (aname->name) - 4;
2763                 name = (gchar *)g_malloc (len + 1);
2764                 strncpy (name, aname->name, len);
2765                 name[len] = 0;
2766         } else
2767                 name = g_strdup (aname->name);
2768         
2769         if (aname->culture)
2770                 culture = g_utf8_strdown (aname->culture, -1);
2771         else
2772                 culture = g_strdup ("");
2773         
2774         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2775         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2776         g_free (name);
2777         g_free (culture);
2778         
2779         filename = g_strconcat (pname, ".dll", NULL);
2780         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2781         g_free (pname);
2782         g_free (version);
2783         g_free (filename);
2784
2785         image = NULL;
2786         if (extra_gac_paths) {
2787                 paths = extra_gac_paths;
2788                 while (!image && *paths) {
2789                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2790                                         "lib", "mono", "gac", subpath, NULL);
2791                         image = mono_image_open (fullpath, NULL);
2792                         g_free (fullpath);
2793                         paths++;
2794                 }
2795         }
2796
2797         if (image) {
2798                 g_free (subpath);
2799                 return image;
2800         }
2801
2802         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2803                         "mono", "gac", subpath, NULL);
2804         image = mono_image_open (fullpath, NULL);
2805         g_free (subpath);
2806         g_free (fullpath);
2807         
2808         return image;
2809 }
2810
2811 static MonoAssemblyName*
2812 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2813 {
2814         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2815         dest_name->major = info->new_version.major;
2816         dest_name->minor = info->new_version.minor;
2817         dest_name->build = info->new_version.build;
2818         dest_name->revision = info->new_version.revision;
2819         
2820         return dest_name;
2821 }
2822
2823 /* LOCKING: assembly_binding lock must be held */
2824 static MonoAssemblyBindingInfo*
2825 search_binding_loaded (MonoAssemblyName *aname)
2826 {
2827         GSList *tmp;
2828
2829         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2830                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2831                 if (assembly_binding_maps_name (info, aname))
2832                         return info;
2833         }
2834
2835         return NULL;
2836 }
2837
2838 static inline gboolean
2839 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2840 {
2841         if (left->major != right->major || left->minor != right->minor ||
2842             left->build != right->build || left->revision != right->revision)
2843                 return FALSE;
2844
2845         return TRUE;
2846 }
2847
2848 static inline gboolean
2849 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2850 {
2851         if (left->has_old_version_bottom != right->has_old_version_bottom)
2852                 return FALSE;
2853
2854         if (left->has_old_version_top != right->has_old_version_top)
2855                 return FALSE;
2856
2857         if (left->has_new_version != right->has_new_version)
2858                 return FALSE;
2859
2860         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2861                 return FALSE;
2862
2863         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2864                 return FALSE;
2865
2866         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2867                 return FALSE;
2868
2869         return TRUE;
2870 }
2871
2872 /* LOCKING: assumes all the necessary locks are held */
2873 static void
2874 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2875 {
2876         MonoAssemblyBindingInfo *info_copy;
2877         GSList *tmp;
2878         MonoAssemblyBindingInfo *info_tmp;
2879         MonoDomain *domain = (MonoDomain*)user_data;
2880
2881         if (!domain)
2882                 return;
2883
2884         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2885                 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2886                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2887                         return;
2888         }
2889
2890         info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2891         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2892         if (info->name)
2893                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2894         if (info->culture)
2895                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2896
2897         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2898 }
2899
2900 static int
2901 get_version_number (int major, int minor)
2902 {
2903         return major * 256 + minor;
2904 }
2905
2906 static inline gboolean
2907 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2908 {
2909         int aname_version_number = get_version_number (aname->major, aname->minor);
2910         if (!info->has_old_version_bottom)
2911                 return FALSE;
2912
2913         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2914                 return FALSE;
2915
2916         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2917                 return FALSE;
2918
2919         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2920         info->major = aname->major;
2921         info->minor = aname->minor;
2922
2923         return TRUE;
2924 }
2925
2926 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2927 static MonoAssemblyBindingInfo*
2928 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2929 {
2930         MonoAssemblyBindingInfo *info;
2931         GSList *list;
2932
2933         if (!domain->assembly_bindings)
2934                 return NULL;
2935
2936         info = NULL;
2937         for (list = domain->assembly_bindings; list; list = list->next) {
2938                 info = (MonoAssemblyBindingInfo *)list->data;
2939                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2940                         break;
2941                 info = NULL;
2942         }
2943
2944         if (info) {
2945                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2946                     info->has_new_version && assembly_binding_maps_name (info, aname))
2947                         info->is_valid = TRUE;
2948                 else
2949                         info->is_valid = FALSE;
2950         }
2951
2952         return info;
2953 }
2954
2955 static MonoAssemblyName*
2956 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2957 {
2958         MonoError error;
2959         MonoAssemblyBindingInfo *info, *info2;
2960         MonoImage *ppimage;
2961         MonoDomain *domain;
2962
2963         if (aname->public_key_token [0] == 0)
2964                 return aname;
2965
2966         domain = mono_domain_get ();
2967
2968         mono_assembly_binding_lock ();
2969         info = search_binding_loaded (aname);
2970         mono_assembly_binding_unlock ();
2971
2972         if (!info) {
2973                 mono_domain_lock (domain);
2974                 info = get_per_domain_assembly_binding_info (domain, aname);
2975                 mono_domain_unlock (domain);
2976         }
2977
2978         if (info) {
2979                 if (!check_policy_versions (info, aname))
2980                         return aname;
2981                 
2982                 mono_assembly_bind_version (info, aname, dest_name);
2983                 return dest_name;
2984         }
2985
2986         if (domain && domain->setup && domain->setup->configuration_file) {
2987                 mono_domain_lock (domain);
2988                 if (!domain->assembly_bindings_parsed) {
2989                         gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2990                         /* expect this to succeed because mono_domain_set_options_from_config () did
2991                          * the same thing when the domain was created. */
2992                         mono_error_assert_ok (&error);
2993
2994                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2995
2996                         if (!domain_config_file_path)
2997                                 domain_config_file_path = domain_config_file_name;
2998                         
2999                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3000                         domain->assembly_bindings_parsed = TRUE;
3001                         if (domain_config_file_name != domain_config_file_path)
3002                                 g_free (domain_config_file_name);
3003                         g_free (domain_config_file_path);
3004                 }
3005
3006                 info2 = get_per_domain_assembly_binding_info (domain, aname);
3007
3008                 if (info2) {
3009                         info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3010                         info->name = g_strdup (info2->name);
3011                         info->culture = g_strdup (info2->culture);
3012                         info->domain_id = domain->domain_id;
3013                 }
3014
3015                 mono_domain_unlock (domain);
3016         }
3017
3018         if (!info) {
3019                 info = g_new0 (MonoAssemblyBindingInfo, 1);
3020                 info->major = aname->major;
3021                 info->minor = aname->minor;
3022         }
3023
3024         if (!info->is_valid) {
3025                 ppimage = mono_assembly_load_publisher_policy (aname);
3026                 if (ppimage) {
3027                         get_publisher_policy_info (ppimage, aname, info);
3028                         mono_image_close (ppimage);
3029                 }
3030         }
3031
3032         /* Define default error value if needed */
3033         if (!info->is_valid) {
3034                 info->name = g_strdup (aname->name);
3035                 info->culture = g_strdup (aname->culture);
3036                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3037         }
3038         
3039         mono_assembly_binding_lock ();
3040         info2 = search_binding_loaded (aname);
3041         if (info2) {
3042                 /* This binding was added by another thread 
3043                  * before us */
3044                 mono_assembly_binding_info_free (info);
3045                 g_free (info);
3046                 
3047                 info = info2;
3048         } else
3049                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3050                 
3051         mono_assembly_binding_unlock ();
3052         
3053         if (!info->is_valid || !check_policy_versions (info, aname))
3054                 return aname;
3055
3056         mono_assembly_bind_version (info, aname, dest_name);
3057         return dest_name;
3058 }
3059
3060 /**
3061  * mono_assembly_load_from_gac
3062  *
3063  * @aname: The assembly name object
3064  */
3065 static MonoAssembly*
3066 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3067 {
3068         MonoAssembly *result = NULL;
3069         gchar *name, *version, *culture, *fullpath, *subpath;
3070         gint32 len;
3071         gchar **paths;
3072         char *pubtok;
3073
3074         if (aname->public_key_token [0] == 0) {
3075                 return NULL;
3076         }
3077
3078         if (strstr (aname->name, ".dll")) {
3079                 len = strlen (filename) - 4;
3080                 name = (gchar *)g_malloc (len + 1);
3081                 strncpy (name, aname->name, len);
3082                 name[len] = 0;
3083         } else {
3084                 name = g_strdup (aname->name);
3085         }
3086
3087         if (aname->culture) {
3088                 culture = g_utf8_strdown (aname->culture, -1);
3089         } else {
3090                 culture = g_strdup ("");
3091         }
3092
3093         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3094         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3095                         aname->minor, aname->build, aname->revision,
3096                         culture, pubtok);
3097         g_free (pubtok);
3098         
3099         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3100         g_free (name);
3101         g_free (version);
3102         g_free (culture);
3103
3104         if (extra_gac_paths) {
3105                 paths = extra_gac_paths;
3106                 while (!result && *paths) {
3107                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3108                         result = mono_assembly_open_full (fullpath, status, refonly);
3109                         g_free (fullpath);
3110                         paths++;
3111                 }
3112         }
3113
3114         if (result) {
3115                 result->in_gac = TRUE;
3116                 g_free (subpath);
3117                 return result;
3118         }
3119
3120         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3121                         "mono", "gac", subpath, NULL);
3122         result = mono_assembly_open_full (fullpath, status, refonly);
3123         g_free (fullpath);
3124
3125         if (result)
3126                 result->in_gac = TRUE;
3127         
3128         g_free (subpath);
3129
3130         return result;
3131 }
3132
3133 MonoAssembly*
3134 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3135 {
3136         char *corlib_file;
3137         MonoAssemblyName *aname;
3138
3139         if (corlib) {
3140                 /* g_print ("corlib already loaded\n"); */
3141                 return corlib;
3142         }
3143
3144         // In native client, Corlib is embedded in the executable as static variable corlibData
3145 #if defined(__native_client__)
3146         if (corlibData != NULL && corlibSize != 0) {
3147                 int status = 0;
3148                 /* First "FALSE" instructs mono not to make a copy. */
3149                 /* Second "FALSE" says this is not just a ref.      */
3150                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3151                 if (image == NULL || status != 0)
3152                         g_print("mono_image_open_from_data_full failed: %d\n", status);
3153                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3154                 if (corlib == NULL || status != 0)
3155                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
3156                 if (corlib)
3157                         return corlib;
3158         }
3159 #endif
3160
3161         // A nonstandard preload hook may provide a special mscorlib assembly
3162         aname = mono_assembly_name_new ("mscorlib.dll");
3163         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3164         mono_assembly_name_free (aname);
3165         g_free (aname);
3166         if (corlib != NULL)
3167                 goto return_corlib_and_facades;
3168
3169         // This unusual directory layout can occur if mono is being built and run out of its own source repo
3170         if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3171                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3172                 if (corlib)
3173                         goto return_corlib_and_facades;
3174         }
3175
3176         /* Normal case: Load corlib from mono/<version> */
3177         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3178         if (assemblies_path) { // Custom assemblies path
3179                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3180                 if (corlib) {
3181                         g_free (corlib_file);
3182                         goto return_corlib_and_facades;
3183                 }
3184         }
3185         corlib = load_in_path (corlib_file, default_path, status, FALSE);
3186         g_free (corlib_file);
3187
3188 return_corlib_and_facades:
3189         if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3190                 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3191                 
3192         return corlib;
3193 }
3194
3195 MonoAssembly*
3196 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
3197                                                                   const char       *basedir, 
3198                                                                   MonoImageOpenStatus *status,
3199                                                                   gboolean refonly)
3200 {
3201         MonoAssembly *result;
3202         char *fullpath, *filename;
3203         MonoAssemblyName maped_aname;
3204         MonoAssemblyName maped_name_pp;
3205         int ext_index;
3206         const char *ext;
3207         int len;
3208
3209         aname = mono_assembly_remap_version (aname, &maped_aname);
3210         
3211         /* Reflection only assemblies don't get assembly binding */
3212         if (!refonly)
3213                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3214         
3215         result = mono_assembly_loaded_full (aname, refonly);
3216         if (result)
3217                 return result;
3218
3219         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3220         if (result) {
3221                 result->in_gac = FALSE;
3222                 return result;
3223         }
3224
3225         /* Currently we retrieve the loaded corlib for reflection 
3226          * only requests, like a common reflection only assembly 
3227          */
3228         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3229                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3230         }
3231
3232         len = strlen (aname->name);
3233         for (ext_index = 0; ext_index < 2; ext_index ++) {
3234                 ext = ext_index == 0 ? ".dll" : ".exe";
3235                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3236                         filename = g_strdup (aname->name);
3237                         /* Don't try appending .dll/.exe if it already has one of those extensions */
3238                         ext_index++;
3239                 } else {
3240                         filename = g_strconcat (aname->name, ext, NULL);
3241                 }
3242
3243                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3244                 if (result) {
3245                         g_free (filename);
3246                         return result;
3247                 }
3248
3249                 if (basedir) {
3250                         fullpath = g_build_filename (basedir, filename, NULL);
3251                         result = mono_assembly_open_full (fullpath, status, refonly);
3252                         g_free (fullpath);
3253                         if (result) {
3254                                 result->in_gac = FALSE;
3255                                 g_free (filename);
3256                                 return result;
3257                         }
3258                 }
3259
3260                 result = load_in_path (filename, default_path, status, refonly);
3261                 if (result)
3262                         result->in_gac = FALSE;
3263                 g_free (filename);
3264                 if (result)
3265                         return result;
3266         }
3267
3268         return result;
3269 }
3270
3271 MonoAssembly*
3272 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3273 {
3274         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3275
3276         if (!result)
3277                 /* Try a postload search hook */
3278                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3279         return result;
3280 }
3281
3282 /**
3283  * mono_assembly_load_full:
3284  * @aname: A MonoAssemblyName with the assembly name to load.
3285  * @basedir: A directory to look up the assembly at.
3286  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3287  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3288  *
3289  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3290  * attempts to load the assembly from that directory before probing the standard locations.
3291  *
3292  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
3293  * assembly binding takes place.
3294  *
3295  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3296  * value pointed by status is updated with an error code.
3297  */
3298 MonoAssembly*
3299 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3300 {
3301         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3302 }
3303
3304 /**
3305  * mono_assembly_load:
3306  * @aname: A MonoAssemblyName with the assembly name to load.
3307  * @basedir: A directory to look up the assembly at.
3308  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3309  *
3310  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3311  * attempts to load the assembly from that directory before probing the standard locations.
3312  *
3313  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3314  * value pointed by status is updated with an error code.
3315  */
3316 MonoAssembly*
3317 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3318 {
3319         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3320 }
3321
3322 /**
3323  * mono_assembly_loaded_full:
3324  * @aname: an assembly to look for.
3325  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3326  *
3327  * This is used to determine if the specified assembly has been loaded
3328  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3329  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3330  */
3331 MonoAssembly*
3332 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3333 {
3334         MonoAssembly *res;
3335         MonoAssemblyName maped_aname;
3336
3337         aname = mono_assembly_remap_version (aname, &maped_aname);
3338
3339         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3340
3341         return res;
3342 }
3343
3344 /**
3345  * mono_assembly_loaded:
3346  * @aname: an assembly to look for.
3347  *
3348  * This is used to determine if the specified assembly has been loaded
3349  
3350  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3351  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3352  */
3353 MonoAssembly*
3354 mono_assembly_loaded (MonoAssemblyName *aname)
3355 {
3356         return mono_assembly_loaded_full (aname, FALSE);
3357 }
3358
3359 void
3360 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3361 {
3362         if (assembly == NULL || assembly == REFERENCE_MISSING)
3363                 return;
3364
3365         if (assembly_is_dynamic (assembly)) {
3366                 int i;
3367                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3368                 for (i = 0; i < dynimg->image.module_count; ++i)
3369                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3370                 mono_dynamic_image_release_gc_roots (dynimg);
3371         }
3372 }
3373
3374 /*
3375  * Returns whether mono_assembly_close_finish() must be called as
3376  * well.  See comment for mono_image_close_except_pools() for why we
3377  * unload in two steps.
3378  */
3379 gboolean
3380 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3381 {
3382         GSList *tmp;
3383         g_return_val_if_fail (assembly != NULL, FALSE);
3384
3385         if (assembly == REFERENCE_MISSING)
3386                 return FALSE;
3387
3388         /* Might be 0 already */
3389         if (InterlockedDecrement (&assembly->ref_count) > 0)
3390                 return FALSE;
3391
3392         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3393
3394         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3395
3396         mono_debug_close_image (assembly->image);
3397
3398         mono_assemblies_lock ();
3399         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3400         mono_assemblies_unlock ();
3401
3402         assembly->image->assembly = NULL;
3403
3404         if (!mono_image_close_except_pools (assembly->image))
3405                 assembly->image = NULL;
3406
3407         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3408                 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3409                 mono_assembly_name_free (fname);
3410                 g_free (fname);
3411         }
3412         g_slist_free (assembly->friend_assembly_names);
3413         g_free (assembly->basedir);
3414
3415         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3416
3417         return TRUE;
3418 }
3419
3420 void
3421 mono_assembly_close_finish (MonoAssembly *assembly)
3422 {
3423         g_assert (assembly && assembly != REFERENCE_MISSING);
3424
3425         if (assembly->image)
3426                 mono_image_close_finish (assembly->image);
3427
3428         if (assembly_is_dynamic (assembly)) {
3429                 g_free ((char*)assembly->aname.culture);
3430         } else {
3431                 g_free (assembly);
3432         }
3433 }
3434
3435 /**
3436  * mono_assembly_close:
3437  * @assembly: the assembly to release.
3438  *
3439  * This method releases a reference to the @assembly.  The assembly is
3440  * only released when all the outstanding references to it are released.
3441  */
3442 void
3443 mono_assembly_close (MonoAssembly *assembly)
3444 {
3445         if (mono_assembly_close_except_image_pools (assembly))
3446                 mono_assembly_close_finish (assembly);
3447 }
3448
3449 MonoImage*
3450 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3451 {
3452         return mono_image_load_file_for_image (assembly->image, idx);
3453 }
3454
3455 MONO_API MonoImage*
3456 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3457 {
3458         return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3459 }
3460
3461
3462 /**
3463  * mono_assembly_foreach:
3464  * @func: function to invoke for each assembly loaded
3465  * @user_data: data passed to the callback
3466  *
3467  * Invokes the provided @func callback for each assembly loaded into
3468  * the runtime.   The first parameter passed to the callback  is the
3469  * `MonoAssembly*`, and the second parameter is the @user_data.
3470  *
3471  * This is done for all assemblies loaded in the runtime, not just
3472  * those loaded in the current application domain.
3473  */
3474 void
3475 mono_assembly_foreach (GFunc func, gpointer user_data)
3476 {
3477         GList *copy;
3478
3479         /*
3480          * We make a copy of the list to avoid calling the callback inside the 
3481          * lock, which could lead to deadlocks.
3482          */
3483         mono_assemblies_lock ();
3484         copy = g_list_copy (loaded_assemblies);
3485         mono_assemblies_unlock ();
3486
3487         g_list_foreach (loaded_assemblies, func, user_data);
3488
3489         g_list_free (copy);
3490 }
3491
3492 /**
3493  * mono_assemblies_cleanup:
3494  *
3495  * Free all resources used by this module.
3496  */
3497 void
3498 mono_assemblies_cleanup (void)
3499 {
3500         GSList *l;
3501
3502         mono_os_mutex_destroy (&assemblies_mutex);
3503         mono_os_mutex_destroy (&assembly_binding_mutex);
3504
3505         for (l = loaded_assembly_bindings; l; l = l->next) {
3506                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3507
3508                 mono_assembly_binding_info_free (info);
3509                 g_free (info);
3510         }
3511         g_slist_free (loaded_assembly_bindings);
3512
3513         free_assembly_load_hooks ();
3514         free_assembly_search_hooks ();
3515         free_assembly_preload_hooks ();
3516 }
3517
3518 /*LOCKING takes the assembly_binding lock*/
3519 void
3520 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3521 {
3522         GSList **iter;
3523
3524         mono_assembly_binding_lock ();
3525         iter = &loaded_assembly_bindings;
3526         while (*iter) {
3527                 GSList *l = *iter;
3528                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3529
3530                 if (info->domain_id == domain_id) {
3531                         *iter = l->next;
3532                         mono_assembly_binding_info_free (info);
3533                         g_free (info);
3534                         g_slist_free_1 (l);
3535                 } else {
3536                         iter = &l->next;
3537                 }
3538         }
3539         mono_assembly_binding_unlock ();
3540 }
3541
3542 /*
3543  * Holds the assembly of the application, for
3544  * System.Diagnostics.Process::MainModule
3545  */
3546 static MonoAssembly *main_assembly=NULL;
3547
3548 void
3549 mono_assembly_set_main (MonoAssembly *assembly)
3550 {
3551         main_assembly = assembly;
3552 }
3553
3554 /**
3555  * mono_assembly_get_main:
3556  *
3557  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3558  */
3559 MonoAssembly *
3560 mono_assembly_get_main (void)
3561 {
3562         return (main_assembly);
3563 }
3564
3565 /**
3566  * mono_assembly_get_image:
3567  * @assembly: The assembly to retrieve the image from
3568  *
3569  * Returns: the MonoImage associated with this assembly.
3570  */
3571 MonoImage*
3572 mono_assembly_get_image (MonoAssembly *assembly)
3573 {
3574         return assembly->image;
3575 }
3576
3577 /**
3578  * mono_assembly_get_name:
3579  * @assembly: The assembly to retrieve the name from
3580  *
3581  * The returned name's lifetime is the same as @assembly's.
3582  *
3583  * Returns: the MonoAssemblyName associated with this assembly.
3584  */
3585 MonoAssemblyName *
3586 mono_assembly_get_name (MonoAssembly *assembly)
3587 {
3588         return &assembly->aname;
3589 }
3590
3591 void
3592 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3593 {
3594         bundles = assemblies;
3595 }
3596
3597 #define MONO_DECLSEC_FORMAT_10          0x3C
3598 #define MONO_DECLSEC_FORMAT_20          0x2E
3599 #define MONO_DECLSEC_FIELD              0x53
3600 #define MONO_DECLSEC_PROPERTY           0x54
3601
3602 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3603 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3604 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3605 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3606 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3607
3608 static gboolean
3609 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3610 {
3611         int len;
3612         switch (*p++) {
3613         case MONO_DECLSEC_PROPERTY:
3614                 break;
3615         case MONO_DECLSEC_FIELD:
3616         default:
3617                 *abort_decoding = TRUE;
3618                 return FALSE;
3619                 break;
3620         }
3621
3622         if (*p++ != MONO_TYPE_BOOLEAN) {
3623                 *abort_decoding = TRUE;
3624                 return FALSE;
3625         }
3626                 
3627         /* property name length */
3628         len = mono_metadata_decode_value (p, &p);
3629
3630         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3631                 p += len;
3632                 return *p;
3633         }
3634         p += len + 1;
3635
3636         *resp = p;
3637         return FALSE;
3638 }
3639
3640 static gboolean
3641 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3642 {
3643         int i, j, num, len, params_len;
3644
3645         if (*p == MONO_DECLSEC_FORMAT_10) {
3646                 gsize read, written;
3647                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3648                 if (res) {
3649                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3650                         g_free (res);
3651                         return found;
3652                 }
3653                 return FALSE;
3654         }
3655         if (*p++ != MONO_DECLSEC_FORMAT_20)
3656                 return FALSE;
3657
3658         /* number of encoded permission attributes */
3659         num = mono_metadata_decode_value (p, &p);
3660         for (i = 0; i < num; ++i) {
3661                 gboolean is_valid = FALSE;
3662                 gboolean abort_decoding = FALSE;
3663
3664                 /* attribute name length */
3665                 len =  mono_metadata_decode_value (p, &p);
3666
3667                 /* We don't really need to fully decode the type. Comparing the name is enough */
3668                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3669
3670                 p += len;
3671
3672                 /*size of the params table*/
3673                 params_len =  mono_metadata_decode_value (p, &p);
3674                 if (is_valid) {
3675                         const char *params_end = p + params_len;
3676                         
3677                         /* number of parameters */
3678                         len = mono_metadata_decode_value (p, &p);
3679         
3680                         for (j = 0; j < len; ++j) {
3681                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3682                                         return TRUE;
3683                                 if (abort_decoding)
3684                                         break;
3685                         }
3686                         p = params_end;
3687                 } else {
3688                         p += params_len;
3689                 }
3690         }
3691         
3692         return FALSE;
3693 }
3694
3695
3696 gboolean
3697 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3698 {
3699         MonoTableInfo *t;       
3700         guint32 cols [MONO_DECL_SECURITY_SIZE];
3701         const char *blob;
3702         int i, len;
3703
3704         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3705                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3706
3707         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3708
3709         for (i = 0; i < t->rows; ++i) {
3710                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3711                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3712                         continue;
3713                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3714                         continue;
3715
3716                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3717                 len = mono_metadata_decode_blob_size (blob, &blob);
3718                 if (!len)
3719                         continue;
3720
3721                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3722                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3723                         return TRUE;
3724                 }
3725         }
3726
3727         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3728         return FALSE;
3729 }