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