Merge pull request #5014 from vkargov/vk-kasha
[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 PLATFORM_MACOSX
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(PLATFORM_MACOSX) && !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         error_init (error);
2112
2113         /*
2114          * This might be called during assembly loading, so do everything using the low-level
2115          * metadata APIs.
2116          */
2117
2118         struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2119
2120         mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2121
2122         return iter_data.has_attr;
2123 }
2124
2125 /**
2126  * mono_assembly_open:
2127  * \param filename Opens the assembly pointed out by this name
2128  * \param status return status code
2129  *
2130  * This loads an assembly from the specified \p filename. The \p filename allows
2131  * a local URL (starting with a \c file:// prefix).  If a file prefix is used, the
2132  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
2133  * is treated as a local path.
2134  *
2135  * First, an attempt is made to load the assembly from the bundled executable (for those
2136  * deployments that have been done with the \c mkbundle tool or for scenarios where the
2137  * assembly has been registered as an embedded assembly).   If this is not the case, then
2138  * the assembly is loaded from disk using `api:mono_image_open_full`.
2139  *
2140  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2141  * the assembly is made.
2142  *
2143  * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2144  * assembly or NULL on error.  Details about the error are stored in the
2145  * \p status variable.
2146  */
2147 MonoAssembly *
2148 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2149 {
2150         return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2151 }
2152
2153 /**
2154  * mono_assembly_load_from_full:
2155  * \param image Image to load the assembly from
2156  * \param fname assembly name to associate with the assembly
2157  * \param status returns the status condition
2158  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2159  *
2160  * If the provided \p image has an assembly reference, it will process the given
2161  * image as an assembly with the given name.
2162  *
2163  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2164  *
2165  * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2166  * set to \c MONO_IMAGE_OK;  or NULL on error.
2167  *
2168  * If there is an error loading the assembly the \p status will indicate the
2169  * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2170  * image did not contain an assembly reference table.
2171  */
2172 MonoAssembly *
2173 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
2174                               MonoImageOpenStatus *status, gboolean refonly)
2175 {
2176         return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2177 }
2178
2179 MonoAssembly *
2180 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2181                                    gboolean refonly,
2182                                    MonoAssemblyCandidatePredicate predicate,
2183                                    gpointer user_data,
2184                                    MonoImageOpenStatus *status)
2185 {
2186         MonoAssembly *ass, *ass2;
2187         char *base_dir;
2188
2189         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2190                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2191                 *status = MONO_IMAGE_IMAGE_INVALID;
2192                 return NULL;
2193         }
2194
2195 #if defined (HOST_WIN32)
2196         {
2197                 gchar *tmp_fn;
2198                 int i;
2199
2200                 tmp_fn = g_strdup (fname);
2201                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2202                         if (tmp_fn [i] == '/')
2203                                 tmp_fn [i] = '\\';
2204                 }
2205
2206                 base_dir = absolute_dir (tmp_fn);
2207                 g_free (tmp_fn);
2208         }
2209 #else
2210         base_dir = absolute_dir (fname);
2211 #endif
2212
2213         /*
2214          * Create assembly struct, and enter it into the assembly cache
2215          */
2216         ass = g_new0 (MonoAssembly, 1);
2217         ass->basedir = base_dir;
2218         ass->ref_only = refonly;
2219         ass->image = image;
2220
2221         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2222
2223         mono_assembly_fill_assembly_name (image, &ass->aname);
2224
2225         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2226                 // MS.NET doesn't support loading other mscorlibs
2227                 g_free (ass);
2228                 g_free (base_dir);
2229                 mono_image_addref (mono_defaults.corlib);
2230                 *status = MONO_IMAGE_OK;
2231                 return mono_defaults.corlib->assembly;
2232         }
2233
2234         /* Add a non-temporary reference because of ass->image */
2235         mono_image_addref (image);
2236
2237         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);
2238
2239         /* 
2240          * The load hooks might take locks so we can't call them while holding the
2241          * assemblies lock.
2242          */
2243         if (ass->aname.name) {
2244                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2245                 if (ass2) {
2246                         g_free (ass);
2247                         g_free (base_dir);
2248                         mono_image_close (image);
2249                         *status = MONO_IMAGE_OK;
2250                         return ass2;
2251                 }
2252         }
2253
2254         /* We need to check for ReferenceAssmeblyAttribute before we
2255          * mark the assembly as loaded and before we fire the load
2256          * hook. Otherwise mono_domain_fire_assembly_load () in
2257          * appdomain.c will cache a mapping from the assembly name to
2258          * this image and we won't be able to look for a different
2259          * candidate. */
2260
2261         if (!refonly) {
2262                 MonoError refasm_error;
2263                 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2264                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2265                         g_free (ass);
2266                         g_free (base_dir);
2267                         mono_image_close (image);
2268                         *status = MONO_IMAGE_IMAGE_INVALID;
2269                         return NULL;
2270                 }
2271                 mono_error_cleanup (&refasm_error);
2272         }
2273
2274         if (predicate && !predicate (ass, user_data)) {
2275                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2276                 g_free (ass);
2277                 g_free (base_dir);
2278                 mono_image_close (image);
2279                 *status = MONO_IMAGE_IMAGE_INVALID;
2280                 return NULL;
2281         }
2282
2283         mono_assemblies_lock ();
2284
2285         if (image->assembly) {
2286                 /*
2287                  * This means another thread has already loaded the assembly, but not yet
2288                  * called the load hooks so the search hook can't find the assembly.
2289                  */
2290                 mono_assemblies_unlock ();
2291                 ass2 = image->assembly;
2292                 g_free (ass);
2293                 g_free (base_dir);
2294                 mono_image_close (image);
2295                 *status = MONO_IMAGE_OK;
2296                 return ass2;
2297         }
2298
2299         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2300
2301         image->assembly = ass;
2302
2303         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2304         mono_assemblies_unlock ();
2305
2306 #ifdef HOST_WIN32
2307         if (image->is_module_handle)
2308                 mono_image_fixup_vtable (image);
2309 #endif
2310
2311         mono_assembly_invoke_load_hook (ass);
2312
2313         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2314         
2315         return ass;
2316 }
2317
2318 /**
2319  * mono_assembly_load_from:
2320  * \param image Image to load the assembly from
2321  * \param fname assembly name to associate with the assembly
2322  * \param status return status code
2323  *
2324  * If the provided \p image has an assembly reference, it will process the given
2325  * image as an assembly with the given name.
2326  *
2327  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2328  *
2329  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2330  * \p refonly parameter set to FALSE.
2331  * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2332  * set to \c MONO_IMAGE_OK; or NULL on error.
2333  *
2334  * If there is an error loading the assembly the \p status will indicate the
2335  * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2336  * image did not contain an assembly reference table.
2337  
2338  */
2339 MonoAssembly *
2340 mono_assembly_load_from (MonoImage *image, const char *fname,
2341                          MonoImageOpenStatus *status)
2342 {
2343         return mono_assembly_load_from_full (image, fname, status, FALSE);
2344 }
2345
2346 /**
2347  * mono_assembly_name_free:
2348  * \param aname assembly name to free
2349  * 
2350  * Frees the provided assembly name object.
2351  * (it does not frees the object itself, only the name members).
2352  */
2353 void
2354 mono_assembly_name_free (MonoAssemblyName *aname)
2355 {
2356         if (aname == NULL)
2357                 return;
2358
2359         g_free ((void *) aname->name);
2360         g_free ((void *) aname->culture);
2361         g_free ((void *) aname->hash_value);
2362         g_free ((guint8*) aname->public_key);
2363 }
2364
2365 static gboolean
2366 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2367 {
2368         const gchar *pkey;
2369         gchar header [16], val, *arr;
2370         gint i, j, offset, bitlen, keylen, pkeylen;
2371         
2372         keylen = strlen (key) >> 1;
2373         if (keylen < 1)
2374                 return FALSE;
2375
2376         /* allow the ECMA standard key */
2377         if (strcmp (key, "00000000000000000400000000000000") == 0) {
2378                 if (pubkey) {
2379                         *pubkey = g_strdup (key);
2380                         *is_ecma = TRUE;
2381                 }
2382                 return TRUE;
2383         }
2384         *is_ecma = FALSE;
2385         val = g_ascii_xdigit_value (key [0]) << 4;
2386         val |= g_ascii_xdigit_value (key [1]);
2387         switch (val) {
2388                 case 0x00:
2389                         if (keylen < 13)
2390                                 return FALSE;
2391                         val = g_ascii_xdigit_value (key [24]);
2392                         val |= g_ascii_xdigit_value (key [25]);
2393                         if (val != 0x06)
2394                                 return FALSE;
2395                         pkey = key + 24;
2396                         break;
2397                 case 0x06:
2398                         pkey = key;
2399                         break;
2400                 default:
2401                         return FALSE;
2402         }
2403                 
2404         /* We need the first 16 bytes
2405         * to check whether this key is valid or not */
2406         pkeylen = strlen (pkey) >> 1;
2407         if (pkeylen < 16)
2408                 return FALSE;
2409                 
2410         for (i = 0, j = 0; i < 16; i++) {
2411                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2412                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2413         }
2414
2415         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2416                         header [1] != 0x02 || /* Version (0x02) */
2417                         header [2] != 0x00 || /* Reserved (word) */
2418                         header [3] != 0x00 ||
2419                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2420                 return FALSE;
2421
2422         /* Based on this length, we _should_ be able to know if the length is right */
2423         bitlen = read32 (header + 12) >> 3;
2424         if ((bitlen + 16 + 4) != pkeylen)
2425                 return FALSE;
2426
2427         /* parsing is OK and the public key itself is not requested back */
2428         if (!pubkey)
2429                 return TRUE;
2430                 
2431         /* Encode the size of the blob */
2432         offset = 0;
2433         if (keylen <= 127) {
2434                 arr = (gchar *)g_malloc (keylen + 1);
2435                 arr [offset++] = keylen;
2436         } else {
2437                 arr = (gchar *)g_malloc (keylen + 2);
2438                 arr [offset++] = 0x80; /* 10bs */
2439                 arr [offset++] = keylen;
2440         }
2441                 
2442         for (i = offset, j = 0; i < keylen + offset; i++) {
2443                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2444                 arr [i] |= g_ascii_xdigit_value (key [j++]);
2445         }
2446
2447         *pubkey = arr;
2448
2449         return TRUE;
2450 }
2451
2452 static gboolean
2453 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)
2454 {
2455         gint major, minor, build, revision;
2456         gint len;
2457         gint version_parts;
2458         gchar *pkey, *pkeyptr, *encoded, tok [8];
2459
2460         memset (aname, 0, sizeof (MonoAssemblyName));
2461
2462         if (version) {
2463                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2464                 if (version_parts < 2 || version_parts > 4)
2465                         return FALSE;
2466
2467                 /* FIXME: we should set build & revision to -1 (instead of 0)
2468                 if these are not set in the version string. That way, later on,
2469                 we can still determine if these were specified. */
2470                 aname->major = major;
2471                 aname->minor = minor;
2472                 if (version_parts >= 3)
2473                         aname->build = build;
2474                 else
2475                         aname->build = 0;
2476                 if (version_parts == 4)
2477                         aname->revision = revision;
2478                 else
2479                         aname->revision = 0;
2480         }
2481         
2482         aname->flags = flags;
2483         aname->arch = arch;
2484         aname->name = g_strdup (name);
2485         
2486         if (culture) {
2487                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2488                         aname->culture = g_strdup ("");
2489                 else
2490                         aname->culture = g_strdup (culture);
2491         }
2492         
2493         if (token && strncmp (token, "null", 4) != 0) {
2494                 char *lower;
2495
2496                 /* the constant includes the ending NULL, hence the -1 */
2497                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2498                         mono_assembly_name_free (aname);
2499                         return FALSE;
2500                 }
2501                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2502                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2503                 g_free (lower);
2504         }
2505
2506         if (key) {
2507                 gboolean is_ecma;
2508                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2509                         mono_assembly_name_free (aname);
2510                         return FALSE;
2511                 }
2512
2513                 if (is_ecma) {
2514                         if (save_public_key)
2515                                 aname->public_key = (guint8*)pkey;
2516                         else
2517                                 g_free (pkey);
2518                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2519                         return TRUE;
2520                 }
2521                 
2522                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2523                 // We also need to generate the key token
2524                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2525                 encoded = encode_public_tok ((guchar*) tok, 8);
2526                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2527                 g_free (encoded);
2528
2529                 if (save_public_key)
2530                         aname->public_key = (guint8*) pkey;
2531                 else
2532                         g_free (pkey);
2533         }
2534
2535         return TRUE;
2536 }
2537
2538 static gboolean
2539 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2540 {
2541         gchar **parts;
2542         gboolean res;
2543         
2544         parts = g_strsplit (dirname, "_", 3);
2545         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2546                 g_strfreev (parts);
2547                 return FALSE;
2548         }
2549         
2550         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2551         g_strfreev (parts);
2552         return res;
2553 }
2554
2555 static gboolean
2556 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2557 {
2558         char *eqsign = strchr (pair, '=');
2559         if (!eqsign) {
2560                 *key = NULL;
2561                 *keylen = 0;
2562                 *value = NULL;
2563                 return FALSE;
2564         }
2565
2566         *key = (gchar*)pair;
2567         *keylen = eqsign - *key;
2568         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2569                 (*keylen)--;
2570         *value = g_strstrip (eqsign + 1);
2571         return TRUE;
2572 }
2573
2574 gboolean
2575 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2576 {
2577         gchar *dllname;
2578         gchar *dllname_uq;
2579         gchar *version = NULL;
2580         gchar *version_uq;
2581         gchar *culture = NULL;
2582         gchar *culture_uq;
2583         gchar *token = NULL;
2584         gchar *token_uq;
2585         gchar *key = NULL;
2586         gchar *key_uq;
2587         gchar *retargetable = NULL;
2588         gchar *retargetable_uq;
2589         gchar *procarch;
2590         gchar *procarch_uq;
2591         gboolean res;
2592         gchar *value, *part_name;
2593         guint32 part_name_len;
2594         gchar **parts;
2595         gchar **tmp;
2596         gboolean version_defined;
2597         gboolean token_defined;
2598         guint32 flags = 0;
2599         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2600
2601         if (!is_version_defined)
2602                 is_version_defined = &version_defined;
2603         *is_version_defined = FALSE;
2604         if (!is_token_defined)
2605                 is_token_defined = &token_defined;
2606         *is_token_defined = FALSE;
2607         
2608         parts = tmp = g_strsplit (name, ",", 6);
2609         if (!tmp || !*tmp) {
2610                 g_strfreev (tmp);
2611                 return FALSE;
2612         }
2613
2614         dllname = g_strstrip (*tmp);
2615         
2616         tmp++;
2617
2618         while (*tmp) {
2619                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2620                         goto cleanup_and_fail;
2621
2622                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2623                         *is_version_defined = TRUE;
2624                         version = value;
2625                         if (strlen (version) == 0) {
2626                                 goto cleanup_and_fail;
2627                         }
2628                         tmp++;
2629                         continue;
2630                 }
2631
2632                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2633                         culture = value;
2634                         if (strlen (culture) == 0) {
2635                                 goto cleanup_and_fail;
2636                         }
2637                         tmp++;
2638                         continue;
2639                 }
2640
2641                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2642                         *is_token_defined = TRUE;
2643                         token = value;
2644                         if (strlen (token) == 0) {
2645                                 goto cleanup_and_fail;
2646                         }
2647                         tmp++;
2648                         continue;
2649                 }
2650
2651                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2652                         key = value;
2653                         if (strlen (key) == 0) {
2654                                 goto cleanup_and_fail;
2655                         }
2656                         tmp++;
2657                         continue;
2658                 }
2659
2660                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2661                         retargetable = value;
2662                         retargetable_uq = unquote (retargetable);
2663                         if (retargetable_uq != NULL)
2664                                 retargetable = retargetable_uq;
2665
2666                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2667                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2668                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2669                                 g_free (retargetable_uq);
2670                                 goto cleanup_and_fail;
2671                         }
2672
2673                         g_free (retargetable_uq);
2674                         tmp++;
2675                         continue;
2676                 }
2677
2678                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2679                         procarch = value;
2680                         procarch_uq = unquote (procarch);
2681                         if (procarch_uq != NULL)
2682                                 procarch = procarch_uq;
2683
2684                         if (!g_ascii_strcasecmp (procarch, "MSIL"))
2685                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2686                         else if (!g_ascii_strcasecmp (procarch, "X86"))
2687                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2688                         else if (!g_ascii_strcasecmp (procarch, "IA64"))
2689                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2690                         else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2691                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2692                         else {
2693                                 g_free (procarch_uq);
2694                                 goto cleanup_and_fail;
2695                         }
2696
2697                         g_free (procarch_uq);
2698                         tmp++;
2699                         continue;
2700                 }
2701
2702                 g_strfreev (parts);
2703                 return FALSE;
2704         }
2705
2706         /* if retargetable flag is set, then we must have a fully qualified name */
2707         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2708                 goto cleanup_and_fail;
2709         }
2710
2711         dllname_uq = unquote (dllname);
2712         version_uq = unquote (version);
2713         culture_uq = unquote (culture);
2714         token_uq = unquote (token);
2715         key_uq = unquote (key);
2716
2717         res = build_assembly_name (
2718                 dllname_uq == NULL ? dllname : dllname_uq,
2719                 version_uq == NULL ? version : version_uq,
2720                 culture_uq == NULL ? culture : culture_uq,
2721                 token_uq == NULL ? token : token_uq,
2722                 key_uq == NULL ? key : key_uq,
2723                 flags, arch, aname, save_public_key);
2724
2725         g_free (dllname_uq);
2726         g_free (version_uq);
2727         g_free (culture_uq);
2728         g_free (token_uq);
2729         g_free (key_uq);
2730
2731         g_strfreev (parts);
2732         return res;
2733
2734 cleanup_and_fail:
2735         g_strfreev (parts);
2736         return FALSE;
2737 }
2738
2739 static char*
2740 unquote (const char *str)
2741 {
2742         gint slen;
2743         const char *end;
2744
2745         if (str == NULL)
2746                 return NULL;
2747
2748         slen = strlen (str);
2749         if (slen < 2)
2750                 return NULL;
2751
2752         if (*str != '\'' && *str != '\"')
2753                 return NULL;
2754
2755         end = str + slen - 1;
2756         if (*str != *end)
2757                 return NULL;
2758
2759         return g_strndup (str + 1, slen - 2);
2760 }
2761
2762 /**
2763  * mono_assembly_name_parse:
2764  * \param name name to parse
2765  * \param aname the destination assembly name
2766  * 
2767  * Parses an assembly qualified type name and assigns the name,
2768  * version, culture and token to the provided assembly name object.
2769  *
2770  * \returns TRUE if the name could be parsed.
2771  */
2772 gboolean
2773 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2774 {
2775         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2776 }
2777
2778 /**
2779  * mono_assembly_name_new:
2780  * \param name name to parse
2781  *
2782  * Allocate a new \c MonoAssemblyName and fill its values from the
2783  * passed \p name.
2784  *
2785  * \returns a newly allocated structure or NULL if there was any failure.
2786  */
2787 MonoAssemblyName*
2788 mono_assembly_name_new (const char *name)
2789 {
2790         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2791         if (mono_assembly_name_parse (name, aname))
2792                 return aname;
2793         g_free (aname);
2794         return NULL;
2795 }
2796
2797 /**
2798  * mono_assembly_name_get_name:
2799  */
2800 const char*
2801 mono_assembly_name_get_name (MonoAssemblyName *aname)
2802 {
2803         return aname->name;
2804 }
2805
2806 /**
2807  * mono_assembly_name_get_culture:
2808  */
2809 const char*
2810 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2811 {
2812         return aname->culture;
2813 }
2814
2815 /**
2816  * mono_assembly_name_get_pubkeytoken:
2817  */
2818 mono_byte*
2819 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2820 {
2821         if (aname->public_key_token [0])
2822                 return aname->public_key_token;
2823         return NULL;
2824 }
2825
2826 /**
2827  * mono_assembly_name_get_version:
2828  */
2829 uint16_t
2830 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2831 {
2832         if (minor)
2833                 *minor = aname->minor;
2834         if (build)
2835                 *build = aname->build;
2836         if (revision)
2837                 *revision = aname->revision;
2838         return aname->major;
2839 }
2840
2841 static MonoAssembly*
2842 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2843 {
2844         gchar *fullpath = NULL;
2845         GDir *dirhandle;
2846         const char* direntry;
2847         MonoAssemblyName gac_aname;
2848         gint major=-1, minor=0, build=0, revision=0;
2849         gboolean exact_version;
2850         
2851         dirhandle = g_dir_open (basepath, 0, NULL);
2852         if (!dirhandle)
2853                 return NULL;
2854                 
2855         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2856
2857         while ((direntry = g_dir_read_name (dirhandle))) {
2858                 gboolean match = TRUE;
2859                 
2860                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2861                         continue;
2862                 
2863                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2864                         match = FALSE;
2865                         
2866                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2867                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2868                         match = FALSE;
2869                 
2870                 if (match) {
2871                         if (exact_version) {
2872                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2873                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2874                         }
2875                         else if (gac_aname.major < major)
2876                                 match = FALSE;
2877                         else if (gac_aname.major == major) {
2878                                 if (gac_aname.minor < minor)
2879                                         match = FALSE;
2880                                 else if (gac_aname.minor == minor) {
2881                                         if (gac_aname.build < build)
2882                                                 match = FALSE;
2883                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2884                                                 match = FALSE; 
2885                                 }
2886                         }
2887                 }
2888                 
2889                 if (match) {
2890                         major = gac_aname.major;
2891                         minor = gac_aname.minor;
2892                         build = gac_aname.build;
2893                         revision = gac_aname.revision;
2894                         g_free (fullpath);
2895                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2896                 }
2897
2898                 mono_assembly_name_free (&gac_aname);
2899         }
2900         
2901         g_dir_close (dirhandle);
2902         
2903         if (fullpath == NULL)
2904                 return NULL;
2905         else {
2906                 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2907                 g_free (fullpath);
2908                 return res;
2909         }
2910 }
2911
2912 /**
2913  * mono_assembly_load_with_partial_name:
2914  * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2915  * \param status return status code
2916  *
2917  * Loads a \c MonoAssembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2918  * so it might contain a qualified type name, version, culture and token.
2919  *
2920  * This will load the assembly from the file whose name is derived from the assembly name
2921  * by appending the \c .dll extension.
2922  *
2923  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2924  * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2925  * if that fails from the GAC.
2926  *
2927  * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2928  */
2929 MonoAssembly*
2930 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2931 {
2932         MonoError error;
2933         MonoAssembly *res;
2934         MonoAssemblyName *aname, base_name;
2935         MonoAssemblyName mapped_aname;
2936         gchar *fullname, *gacpath;
2937         gchar **paths;
2938
2939         memset (&base_name, 0, sizeof (MonoAssemblyName));
2940         aname = &base_name;
2941
2942         if (!mono_assembly_name_parse (name, aname))
2943                 return NULL;
2944
2945         /* 
2946          * If no specific version has been requested, make sure we load the
2947          * correct version for system assemblies.
2948          */ 
2949         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2950                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2951         
2952         res = mono_assembly_loaded (aname);
2953         if (res) {
2954                 mono_assembly_name_free (aname);
2955                 return res;
2956         }
2957
2958         res = invoke_assembly_preload_hook (aname, assemblies_path);
2959         if (res) {
2960                 res->in_gac = FALSE;
2961                 mono_assembly_name_free (aname);
2962                 return res;
2963         }
2964
2965         fullname = g_strdup_printf ("%s.dll", aname->name);
2966
2967         if (extra_gac_paths) {
2968                 paths = extra_gac_paths;
2969                 while (!res && *paths) {
2970                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2971                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2972                         g_free (gacpath);
2973                         paths++;
2974                 }
2975         }
2976
2977         if (res) {
2978                 res->in_gac = TRUE;
2979                 g_free (fullname);
2980                 mono_assembly_name_free (aname);
2981                 return res;
2982         }
2983
2984         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2985         res = probe_for_partial_name (gacpath, fullname, aname, status);
2986         g_free (gacpath);
2987
2988         g_free (fullname);
2989         mono_assembly_name_free (aname);
2990
2991         if (res)
2992                 res->in_gac = TRUE;
2993         else {
2994                 MonoDomain *domain = mono_domain_get ();
2995
2996                 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2997                 if (!is_ok (&error)) {
2998                         mono_error_cleanup (&error);
2999                         if (*status == MONO_IMAGE_OK)
3000                                 *status = MONO_IMAGE_IMAGE_INVALID;
3001                 }
3002         }
3003
3004         return res;
3005 }
3006
3007 static MonoBoolean
3008 mono_assembly_is_in_gac (const gchar *filename)
3009 {
3010         const gchar *rootdir;
3011         gchar *gp;
3012         gchar **paths;
3013
3014         if (filename == NULL)
3015                 return FALSE;
3016
3017         for (paths = extra_gac_paths; paths && *paths; paths++) {
3018                 if (strstr (*paths, filename) != *paths)
3019                         continue;
3020
3021                 gp = (gchar *) (filename + strlen (*paths));
3022                 if (*gp != G_DIR_SEPARATOR)
3023                         continue;
3024                 gp++;
3025                 if (strncmp (gp, "lib", 3))
3026                         continue;
3027                 gp += 3;
3028                 if (*gp != G_DIR_SEPARATOR)
3029                         continue;
3030                 gp++;
3031                 if (strncmp (gp, "mono", 4))
3032                         continue;
3033                 gp += 4;
3034                 if (*gp != G_DIR_SEPARATOR)
3035                         continue;
3036                 gp++;
3037                 if (strncmp (gp, "gac", 3))
3038                         continue;
3039                 gp += 3;
3040                 if (*gp != G_DIR_SEPARATOR)
3041                         continue;
3042
3043                 return TRUE;
3044         }
3045
3046         rootdir = mono_assembly_getrootdir ();
3047         if (strstr (filename, rootdir) != filename)
3048                 return FALSE;
3049
3050         gp = (gchar *) (filename + strlen (rootdir));
3051         if (*gp != G_DIR_SEPARATOR)
3052                 return FALSE;
3053         gp++;
3054         if (strncmp (gp, "mono", 4))
3055                 return FALSE;
3056         gp += 4;
3057         if (*gp != G_DIR_SEPARATOR)
3058                 return FALSE;
3059         gp++;
3060         if (strncmp (gp, "gac", 3))
3061                 return FALSE;
3062         gp += 3;
3063         if (*gp != G_DIR_SEPARATOR)
3064                 return FALSE;
3065         return TRUE;
3066 }
3067
3068 static MonoImage*
3069 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3070 {
3071         MonoImage *image;
3072         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3073         gchar **paths;
3074         gint32 len;
3075
3076         if (strstr (aname->name, ".dll")) {
3077                 len = strlen (aname->name) - 4;
3078                 name = (gchar *)g_malloc (len + 1);
3079                 memcpy (name, aname->name, len);
3080                 name[len] = 0;
3081         } else
3082                 name = g_strdup (aname->name);
3083         
3084         if (aname->culture)
3085                 culture = g_utf8_strdown (aname->culture, -1);
3086         else
3087                 culture = g_strdup ("");
3088         
3089         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3090         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3091         g_free (name);
3092         g_free (culture);
3093         
3094         filename = g_strconcat (pname, ".dll", NULL);
3095         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3096         g_free (pname);
3097         g_free (version);
3098         g_free (filename);
3099
3100         image = NULL;
3101         if (extra_gac_paths) {
3102                 paths = extra_gac_paths;
3103                 while (!image && *paths) {
3104                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3105                                         "lib", "mono", "gac", subpath, NULL);
3106                         image = mono_image_open (fullpath, NULL);
3107                         g_free (fullpath);
3108                         paths++;
3109                 }
3110         }
3111
3112         if (image) {
3113                 g_free (subpath);
3114                 return image;
3115         }
3116
3117         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
3118                         "mono", "gac", subpath, NULL);
3119         image = mono_image_open (fullpath, NULL);
3120         g_free (subpath);
3121         g_free (fullpath);
3122         
3123         return image;
3124 }
3125
3126 static MonoAssemblyName*
3127 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3128 {
3129         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3130         dest_name->major = info->new_version.major;
3131         dest_name->minor = info->new_version.minor;
3132         dest_name->build = info->new_version.build;
3133         dest_name->revision = info->new_version.revision;
3134         
3135         return dest_name;
3136 }
3137
3138 /* LOCKING: assembly_binding lock must be held */
3139 static MonoAssemblyBindingInfo*
3140 search_binding_loaded (MonoAssemblyName *aname)
3141 {
3142         GSList *tmp;
3143
3144         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3145                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3146                 if (assembly_binding_maps_name (info, aname))
3147                         return info;
3148         }
3149
3150         return NULL;
3151 }
3152
3153 static inline gboolean
3154 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3155 {
3156         if (left->major != right->major || left->minor != right->minor ||
3157             left->build != right->build || left->revision != right->revision)
3158                 return FALSE;
3159
3160         return TRUE;
3161 }
3162
3163 static inline gboolean
3164 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3165 {
3166         if (left->has_old_version_bottom != right->has_old_version_bottom)
3167                 return FALSE;
3168
3169         if (left->has_old_version_top != right->has_old_version_top)
3170                 return FALSE;
3171
3172         if (left->has_new_version != right->has_new_version)
3173                 return FALSE;
3174
3175         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3176                 return FALSE;
3177
3178         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3179                 return FALSE;
3180
3181         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3182                 return FALSE;
3183
3184         return TRUE;
3185 }
3186
3187 /* LOCKING: assumes all the necessary locks are held */
3188 static void
3189 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3190 {
3191         MonoAssemblyBindingInfo *info_copy;
3192         GSList *tmp;
3193         MonoAssemblyBindingInfo *info_tmp;
3194         MonoDomain *domain = (MonoDomain*)user_data;
3195
3196         if (!domain)
3197                 return;
3198
3199         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)) {
3200                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3201                         info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3202                 return;
3203         }
3204
3205         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3206                 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3207                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3208                         return;
3209         }
3210
3211         info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3212         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3213         if (info->name)
3214                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3215         if (info->culture)
3216                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3217
3218         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3219 }
3220
3221 static int
3222 get_version_number (int major, int minor)
3223 {
3224         return major * 256 + minor;
3225 }
3226
3227 static inline gboolean
3228 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3229 {
3230         int aname_version_number = get_version_number (aname->major, aname->minor);
3231         if (!info->has_old_version_bottom)
3232                 return FALSE;
3233
3234         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3235                 return FALSE;
3236
3237         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3238                 return FALSE;
3239
3240         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3241         info->major = aname->major;
3242         info->minor = aname->minor;
3243
3244         return TRUE;
3245 }
3246
3247 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3248 static MonoAssemblyBindingInfo*
3249 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3250 {
3251         MonoAssemblyBindingInfo *info;
3252         GSList *list;
3253
3254         if (!domain->assembly_bindings)
3255                 return NULL;
3256
3257         info = NULL;
3258         for (list = domain->assembly_bindings; list; list = list->next) {
3259                 info = (MonoAssemblyBindingInfo *)list->data;
3260                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3261                         break;
3262                 info = NULL;
3263         }
3264
3265         if (info) {
3266                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3267                     info->has_new_version && assembly_binding_maps_name (info, aname))
3268                         info->is_valid = TRUE;
3269                 else
3270                         info->is_valid = FALSE;
3271         }
3272
3273         return info;
3274 }
3275
3276 void
3277 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3278 {
3279         if (domain->assembly_bindings_parsed)
3280                 return;
3281         mono_domain_lock (domain);
3282         if (!domain->assembly_bindings_parsed) {
3283
3284                 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3285
3286                 if (!domain_config_file_path)
3287                         domain_config_file_path = domain_config_file_name;
3288
3289                 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3290                 domain->assembly_bindings_parsed = TRUE;
3291                 if (domain_config_file_name != domain_config_file_path)
3292                         g_free (domain_config_file_path);
3293         }
3294
3295         mono_domain_unlock (domain);
3296 }
3297
3298 static MonoAssemblyName*
3299 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3300 {
3301         MonoError error;
3302         MonoAssemblyBindingInfo *info, *info2;
3303         MonoImage *ppimage;
3304         MonoDomain *domain;
3305
3306         if (aname->public_key_token [0] == 0)
3307                 return aname;
3308
3309         domain = mono_domain_get ();
3310
3311         mono_assembly_binding_lock ();
3312         info = search_binding_loaded (aname);
3313         mono_assembly_binding_unlock ();
3314
3315         if (!info) {
3316                 mono_domain_lock (domain);
3317                 info = get_per_domain_assembly_binding_info (domain, aname);
3318                 mono_domain_unlock (domain);
3319         }
3320
3321         if (info) {
3322                 if (!check_policy_versions (info, aname))
3323                         return aname;
3324                 
3325                 mono_assembly_bind_version (info, aname, dest_name);
3326                 return dest_name;
3327         }
3328
3329         if (domain && domain->setup && domain->setup->configuration_file) {
3330                 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3331                 /* expect this to succeed because mono_domain_set_options_from_config () did
3332                  * the same thing when the domain was created. */
3333                 mono_error_assert_ok (&error);
3334                 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3335                 g_free (domain_config_file_name);
3336
3337                 mono_domain_lock (domain);
3338                 info2 = get_per_domain_assembly_binding_info (domain, aname);
3339
3340                 if (info2) {
3341                         info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3342                         info->name = g_strdup (info2->name);
3343                         info->culture = g_strdup (info2->culture);
3344                         info->domain_id = domain->domain_id;
3345                 }
3346
3347                 mono_domain_unlock (domain);
3348
3349         }
3350
3351         if (!info) {
3352                 info = g_new0 (MonoAssemblyBindingInfo, 1);
3353                 info->major = aname->major;
3354                 info->minor = aname->minor;
3355         }
3356
3357         if (!info->is_valid) {
3358                 ppimage = mono_assembly_load_publisher_policy (aname);
3359                 if (ppimage) {
3360                         get_publisher_policy_info (ppimage, aname, info);
3361                         mono_image_close (ppimage);
3362                 }
3363         }
3364
3365         /* Define default error value if needed */
3366         if (!info->is_valid) {
3367                 info->name = g_strdup (aname->name);
3368                 info->culture = g_strdup (aname->culture);
3369                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3370         }
3371         
3372         mono_assembly_binding_lock ();
3373         info2 = search_binding_loaded (aname);
3374         if (info2) {
3375                 /* This binding was added by another thread 
3376                  * before us */
3377                 mono_assembly_binding_info_free (info);
3378                 g_free (info);
3379                 
3380                 info = info2;
3381         } else
3382                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3383                 
3384         mono_assembly_binding_unlock ();
3385         
3386         if (!info->is_valid || !check_policy_versions (info, aname))
3387                 return aname;
3388
3389         mono_assembly_bind_version (info, aname, dest_name);
3390         return dest_name;
3391 }
3392
3393 /**
3394  * mono_assembly_load_from_gac
3395  *
3396  * \param aname The assembly name object
3397  */
3398 static MonoAssembly*
3399 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3400 {
3401         MonoAssembly *result = NULL;
3402         gchar *name, *version, *culture, *fullpath, *subpath;
3403         gint32 len;
3404         gchar **paths;
3405         char *pubtok;
3406
3407         if (aname->public_key_token [0] == 0) {
3408                 return NULL;
3409         }
3410
3411         if (strstr (aname->name, ".dll")) {
3412                 len = strlen (filename) - 4;
3413                 name = (gchar *)g_malloc (len + 1);
3414                 memcpy (name, aname->name, len);
3415                 name[len] = 0;
3416         } else {
3417                 name = g_strdup (aname->name);
3418         }
3419
3420         if (aname->culture) {
3421                 culture = g_utf8_strdown (aname->culture, -1);
3422         } else {
3423                 culture = g_strdup ("");
3424         }
3425
3426         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3427         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3428                         aname->minor, aname->build, aname->revision,
3429                         culture, pubtok);
3430         g_free (pubtok);
3431         
3432         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3433         g_free (name);
3434         g_free (version);
3435         g_free (culture);
3436
3437         if (extra_gac_paths) {
3438                 paths = extra_gac_paths;
3439                 while (!result && *paths) {
3440                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3441                         result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3442                         g_free (fullpath);
3443                         paths++;
3444                 }
3445         }
3446
3447         if (result) {
3448                 result->in_gac = TRUE;
3449                 g_free (subpath);
3450                 return result;
3451         }
3452
3453         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3454                         "mono", "gac", subpath, NULL);
3455         result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3456         g_free (fullpath);
3457
3458         if (result)
3459                 result->in_gac = TRUE;
3460         
3461         g_free (subpath);
3462
3463         return result;
3464 }
3465
3466 MonoAssembly*
3467 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3468 {
3469         char *corlib_file;
3470         MonoAssemblyName *aname;
3471
3472         if (corlib) {
3473                 /* g_print ("corlib already loaded\n"); */
3474                 return corlib;
3475         }
3476
3477         // A nonstandard preload hook may provide a special mscorlib assembly
3478         aname = mono_assembly_name_new ("mscorlib.dll");
3479         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3480         mono_assembly_name_free (aname);
3481         g_free (aname);
3482         if (corlib != NULL)
3483                 goto return_corlib_and_facades;
3484
3485         // This unusual directory layout can occur if mono is being built and run out of its own source repo
3486         if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3487                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3488                 if (corlib)
3489                         goto return_corlib_and_facades;
3490         }
3491
3492         /* Normal case: Load corlib from mono/<version> */
3493         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3494         if (assemblies_path) { // Custom assemblies path
3495                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3496                 if (corlib) {
3497                         g_free (corlib_file);
3498                         goto return_corlib_and_facades;
3499                 }
3500         }
3501         corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3502         g_free (corlib_file);
3503
3504 return_corlib_and_facades:
3505         if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3506                 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3507                 
3508         return corlib;
3509 }
3510
3511 static MonoAssembly*
3512 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3513 {
3514         MonoError refasm_error;
3515         error_init (&refasm_error);
3516         if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3517                 candidate = NULL;
3518         }
3519         mono_error_cleanup (&refasm_error);
3520         return candidate;
3521 }
3522
3523 gboolean
3524 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3525 {
3526         MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3527         MonoAssemblyName *candidate_name = &candidate->aname;
3528
3529         g_assert (wanted_name != NULL);
3530         g_assert (candidate_name != NULL);
3531
3532         if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3533                 char * s = mono_stringify_assembly_name (wanted_name);
3534                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3535                 g_free (s);
3536                 s = mono_stringify_assembly_name (candidate_name);
3537                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3538                 g_free (s);
3539         }
3540
3541
3542         /* Wanted name has no token, not strongly named: always matches. */
3543         if (0 == wanted_name->public_key_token [0]) {
3544                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3545                 return TRUE;
3546         }
3547
3548         /* Candidate name has no token, not strongly named: never matches */
3549         if (0 == candidate_name->public_key_token [0]) {
3550                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3551                 return FALSE;
3552         }
3553
3554         return exact_sn_match (wanted_name, candidate_name) ||
3555                 framework_assembly_sn_match (wanted_name, candidate_name);
3556 }
3557
3558 gboolean
3559 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3560 {
3561         gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3562
3563         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3564                     result ? "match, returning TRUE" : "don't match, returning FALSE");
3565         return result;
3566
3567 }
3568
3569 gboolean
3570 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3571 {
3572 #ifndef DISABLE_DESKTOP_LOADER
3573         const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3574         if (vmap) {
3575                 if (!vmap->framework_facade_assembly) {
3576                         /* 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. */
3577                         gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3578                         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");
3579                         return result;
3580                 } else {
3581                         /* For facades, the name and public key token should
3582                          * match, but the version doesn't matter. */
3583                         gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3584                         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");
3585                         return result;
3586                 }
3587         }
3588 #endif
3589         return FALSE;
3590 }
3591
3592 MonoAssembly*
3593 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
3594                                                                   const char       *basedir, 
3595                                                                   MonoImageOpenStatus *status,
3596                                                                   gboolean refonly)
3597 {
3598         MonoAssembly *result;
3599         char *fullpath, *filename;
3600         MonoAssemblyName maped_aname;
3601         MonoAssemblyName maped_name_pp;
3602         int ext_index;
3603         const char *ext;
3604         int len;
3605
3606         aname = mono_assembly_remap_version (aname, &maped_aname);
3607
3608         /* Reflection only assemblies don't get assembly binding */
3609         if (!refonly)
3610                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3611         
3612         result = mono_assembly_loaded_full (aname, refonly);
3613         if (result)
3614                 return result;
3615
3616         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3617         if (result) {
3618                 result->in_gac = FALSE;
3619                 return result;
3620         }
3621
3622         /* Currently we retrieve the loaded corlib for reflection 
3623          * only requests, like a common reflection only assembly 
3624          */
3625         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3626                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3627         }
3628
3629         MonoAssemblyCandidatePredicate predicate = NULL;
3630         void* predicate_ud = NULL;
3631 #if !defined(DISABLE_DESKTOP_LOADER)
3632         if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3633                 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3634                 predicate_ud = aname;
3635         }
3636 #endif
3637
3638         len = strlen (aname->name);
3639         for (ext_index = 0; ext_index < 2; ext_index ++) {
3640                 ext = ext_index == 0 ? ".dll" : ".exe";
3641                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3642                         filename = g_strdup (aname->name);
3643                         /* Don't try appending .dll/.exe if it already has one of those extensions */
3644                         ext_index++;
3645                 } else {
3646                         filename = g_strconcat (aname->name, ext, NULL);
3647                 }
3648
3649                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3650                 if (result) {
3651                         g_free (filename);
3652                         return result;
3653                 }
3654
3655                 if (basedir) {
3656                         fullpath = g_build_filename (basedir, filename, NULL);
3657                         result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3658                         g_free (fullpath);
3659                         if (result) {
3660                                 result->in_gac = FALSE;
3661                                 g_free (filename);
3662                                 return result;
3663                         }
3664                 }
3665
3666                 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3667                 if (result)
3668                         result->in_gac = FALSE;
3669                 g_free (filename);
3670                 if (result)
3671                         return result;
3672         }
3673
3674         return result;
3675 }
3676
3677 MonoAssembly*
3678 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3679 {
3680         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3681
3682         if (!result) {
3683                 /* Try a postload search hook */
3684                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3685                 result = prevent_reference_assembly_from_running (result, refonly);
3686         }
3687         return result;
3688 }
3689
3690 /**
3691  * mono_assembly_load_full:
3692  * \param aname A MonoAssemblyName with the assembly name to load.
3693  * \param basedir A directory to look up the assembly at.
3694  * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3695  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3696  *
3697  * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3698  * attempts to load the assembly from that directory before probing the standard locations.
3699  *
3700  * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no 
3701  * assembly binding takes place.
3702  *
3703  * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3704  * value pointed by \p status is updated with an error code.
3705  */
3706 MonoAssembly*
3707 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3708 {
3709         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3710 }
3711
3712 /**
3713  * mono_assembly_load:
3714  * \param aname A MonoAssemblyName with the assembly name to load.
3715  * \param basedir A directory to look up the assembly at.
3716  * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3717  *
3718  * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3719  * attempts to load the assembly from that directory before probing the standard locations.
3720  *
3721  * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3722  * value pointed by \p status is updated with an error code.
3723  */
3724 MonoAssembly*
3725 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3726 {
3727         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3728 }
3729
3730 /**
3731  * mono_assembly_loaded_full:
3732  * \param aname an assembly to look for.
3733  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3734  *
3735  * This is used to determine if the specified assembly has been loaded
3736  * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3737  * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3738  */
3739 MonoAssembly*
3740 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3741 {
3742         MonoAssembly *res;
3743         MonoAssemblyName maped_aname;
3744
3745         aname = mono_assembly_remap_version (aname, &maped_aname);
3746
3747         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3748
3749         return res;
3750 }
3751
3752 /**
3753  * mono_assembly_loaded:
3754  * \param aname an assembly to look for.
3755  *
3756  * This is used to determine if the specified assembly has been loaded
3757  
3758  * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3759  * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3760  */
3761 MonoAssembly*
3762 mono_assembly_loaded (MonoAssemblyName *aname)
3763 {
3764         return mono_assembly_loaded_full (aname, FALSE);
3765 }
3766
3767 void
3768 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3769 {
3770         if (assembly == NULL || assembly == REFERENCE_MISSING)
3771                 return;
3772
3773         if (assembly_is_dynamic (assembly)) {
3774                 int i;
3775                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3776                 for (i = 0; i < dynimg->image.module_count; ++i)
3777                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3778                 mono_dynamic_image_release_gc_roots (dynimg);
3779         }
3780 }
3781
3782 /*
3783  * Returns whether mono_assembly_close_finish() must be called as
3784  * well.  See comment for mono_image_close_except_pools() for why we
3785  * unload in two steps.
3786  */
3787 gboolean
3788 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3789 {
3790         GSList *tmp;
3791         g_return_val_if_fail (assembly != NULL, FALSE);
3792
3793         if (assembly == REFERENCE_MISSING)
3794                 return FALSE;
3795
3796         /* Might be 0 already */
3797         if (InterlockedDecrement (&assembly->ref_count) > 0)
3798                 return FALSE;
3799
3800         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3801
3802         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3803
3804         mono_debug_close_image (assembly->image);
3805
3806         mono_assemblies_lock ();
3807         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3808         mono_assemblies_unlock ();
3809
3810         assembly->image->assembly = NULL;
3811
3812         if (!mono_image_close_except_pools (assembly->image))
3813                 assembly->image = NULL;
3814
3815         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3816                 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3817                 mono_assembly_name_free (fname);
3818                 g_free (fname);
3819         }
3820         g_slist_free (assembly->friend_assembly_names);
3821         g_free (assembly->basedir);
3822
3823         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3824
3825         return TRUE;
3826 }
3827
3828 void
3829 mono_assembly_close_finish (MonoAssembly *assembly)
3830 {
3831         g_assert (assembly && assembly != REFERENCE_MISSING);
3832
3833         if (assembly->image)
3834                 mono_image_close_finish (assembly->image);
3835
3836         if (assembly_is_dynamic (assembly)) {
3837                 g_free ((char*)assembly->aname.culture);
3838         } else {
3839                 g_free (assembly);
3840         }
3841 }
3842
3843 /**
3844  * mono_assembly_close:
3845  * \param assembly the assembly to release.
3846  *
3847  * This method releases a reference to the \p assembly.  The assembly is
3848  * only released when all the outstanding references to it are released.
3849  */
3850 void
3851 mono_assembly_close (MonoAssembly *assembly)
3852 {
3853         if (mono_assembly_close_except_image_pools (assembly))
3854                 mono_assembly_close_finish (assembly);
3855 }
3856
3857 /**
3858  * mono_assembly_load_module:
3859  */
3860 MonoImage*
3861 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3862 {
3863         MonoError error;
3864         MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3865         mono_error_assert_ok (&error);
3866         return result;
3867 }
3868
3869 MONO_API MonoImage*
3870 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3871 {
3872         return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3873 }
3874
3875
3876 /**
3877  * mono_assembly_foreach:
3878  * \param func function to invoke for each assembly loaded
3879  * \param user_data data passed to the callback
3880  *
3881  * Invokes the provided \p func callback for each assembly loaded into
3882  * the runtime.   The first parameter passed to the callback  is the
3883  * \c MonoAssembly*, and the second parameter is the \p user_data.
3884  *
3885  * This is done for all assemblies loaded in the runtime, not just
3886  * those loaded in the current application domain.
3887  */
3888 void
3889 mono_assembly_foreach (GFunc func, gpointer user_data)
3890 {
3891         GList *copy;
3892
3893         /*
3894          * We make a copy of the list to avoid calling the callback inside the 
3895          * lock, which could lead to deadlocks.
3896          */
3897         mono_assemblies_lock ();
3898         copy = g_list_copy (loaded_assemblies);
3899         mono_assemblies_unlock ();
3900
3901         g_list_foreach (loaded_assemblies, func, user_data);
3902
3903         g_list_free (copy);
3904 }
3905
3906 /**
3907  * mono_assemblies_cleanup:
3908  *
3909  * Free all resources used by this module.
3910  */
3911 void
3912 mono_assemblies_cleanup (void)
3913 {
3914         GSList *l;
3915
3916         mono_os_mutex_destroy (&assemblies_mutex);
3917         mono_os_mutex_destroy (&assembly_binding_mutex);
3918
3919         for (l = loaded_assembly_bindings; l; l = l->next) {
3920                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3921
3922                 mono_assembly_binding_info_free (info);
3923                 g_free (info);
3924         }
3925         g_slist_free (loaded_assembly_bindings);
3926
3927         free_assembly_load_hooks ();
3928         free_assembly_search_hooks ();
3929         free_assembly_preload_hooks ();
3930 }
3931
3932 /*LOCKING takes the assembly_binding lock*/
3933 void
3934 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3935 {
3936         GSList **iter;
3937
3938         mono_assembly_binding_lock ();
3939         iter = &loaded_assembly_bindings;
3940         while (*iter) {
3941                 GSList *l = *iter;
3942                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3943
3944                 if (info->domain_id == domain_id) {
3945                         *iter = l->next;
3946                         mono_assembly_binding_info_free (info);
3947                         g_free (info);
3948                         g_slist_free_1 (l);
3949                 } else {
3950                         iter = &l->next;
3951                 }
3952         }
3953         mono_assembly_binding_unlock ();
3954 }
3955
3956 /*
3957  * Holds the assembly of the application, for
3958  * System.Diagnostics.Process::MainModule
3959  */
3960 static MonoAssembly *main_assembly=NULL;
3961
3962 /**
3963  * mono_assembly_set_main:
3964  */
3965 void
3966 mono_assembly_set_main (MonoAssembly *assembly)
3967 {
3968         main_assembly = assembly;
3969 }
3970
3971 /**
3972  * mono_assembly_get_main:
3973  *
3974  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3975  */
3976 MonoAssembly *
3977 mono_assembly_get_main (void)
3978 {
3979         return (main_assembly);
3980 }
3981
3982 /**
3983  * mono_assembly_get_image:
3984  * \param assembly The assembly to retrieve the image from
3985  *
3986  * \returns the \c MonoImage associated with this assembly.
3987  */
3988 MonoImage*
3989 mono_assembly_get_image (MonoAssembly *assembly)
3990 {
3991         return assembly->image;
3992 }
3993
3994 /**
3995  * mono_assembly_get_name:
3996  * \param assembly The assembly to retrieve the name from
3997  *
3998  * The returned name's lifetime is the same as \p assembly's.
3999  *
4000  * \returns the \c MonoAssemblyName associated with this assembly.
4001  */
4002 MonoAssemblyName *
4003 mono_assembly_get_name (MonoAssembly *assembly)
4004 {
4005         return &assembly->aname;
4006 }
4007
4008 /**
4009  * mono_register_bundled_assemblies:
4010  */
4011 void
4012 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4013 {
4014         bundles = assemblies;
4015 }
4016
4017 #define MONO_DECLSEC_FORMAT_10          0x3C
4018 #define MONO_DECLSEC_FORMAT_20          0x2E
4019 #define MONO_DECLSEC_FIELD              0x53
4020 #define MONO_DECLSEC_PROPERTY           0x54
4021
4022 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4023 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4024 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4025 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4026 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4027
4028 static gboolean
4029 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4030 {
4031         int len;
4032         switch (*p++) {
4033         case MONO_DECLSEC_PROPERTY:
4034                 break;
4035         case MONO_DECLSEC_FIELD:
4036         default:
4037                 *abort_decoding = TRUE;
4038                 return FALSE;
4039                 break;
4040         }
4041
4042         if (*p++ != MONO_TYPE_BOOLEAN) {
4043                 *abort_decoding = TRUE;
4044                 return FALSE;
4045         }
4046                 
4047         /* property name length */
4048         len = mono_metadata_decode_value (p, &p);
4049
4050         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4051                 p += len;
4052                 return *p;
4053         }
4054         p += len + 1;
4055
4056         *resp = p;
4057         return FALSE;
4058 }
4059
4060 static gboolean
4061 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4062 {
4063         int i, j, num, len, params_len;
4064
4065         if (*p == MONO_DECLSEC_FORMAT_10) {
4066                 gsize read, written;
4067                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4068                 if (res) {
4069                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4070                         g_free (res);
4071                         return found;
4072                 }
4073                 return FALSE;
4074         }
4075         if (*p++ != MONO_DECLSEC_FORMAT_20)
4076                 return FALSE;
4077
4078         /* number of encoded permission attributes */
4079         num = mono_metadata_decode_value (p, &p);
4080         for (i = 0; i < num; ++i) {
4081                 gboolean is_valid = FALSE;
4082                 gboolean abort_decoding = FALSE;
4083
4084                 /* attribute name length */
4085                 len =  mono_metadata_decode_value (p, &p);
4086
4087                 /* We don't really need to fully decode the type. Comparing the name is enough */
4088                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4089
4090                 p += len;
4091
4092                 /*size of the params table*/
4093                 params_len =  mono_metadata_decode_value (p, &p);
4094                 if (is_valid) {
4095                         const char *params_end = p + params_len;
4096                         
4097                         /* number of parameters */
4098                         len = mono_metadata_decode_value (p, &p);
4099         
4100                         for (j = 0; j < len; ++j) {
4101                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4102                                         return TRUE;
4103                                 if (abort_decoding)
4104                                         break;
4105                         }
4106                         p = params_end;
4107                 } else {
4108                         p += params_len;
4109                 }
4110         }
4111         
4112         return FALSE;
4113 }
4114
4115
4116 gboolean
4117 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4118 {
4119         MonoTableInfo *t;       
4120         guint32 cols [MONO_DECL_SECURITY_SIZE];
4121         const char *blob;
4122         int i, len;
4123
4124         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4125                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4126
4127         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4128
4129         for (i = 0; i < t->rows; ++i) {
4130                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4131                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4132                         continue;
4133                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4134                         continue;
4135
4136                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4137                 len = mono_metadata_decode_blob_size (blob, &blob);
4138                 if (!len)
4139                         continue;
4140
4141                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4142                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4143                         return TRUE;
4144                 }
4145         }
4146
4147         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
4148         return FALSE;
4149 }