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