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