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