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