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