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