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