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