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