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