Fix some small memory leaks.
[mono.git] / mono / metadata / assembly.c
1 /*
2  * assembly.c: Routines for loading assemblies.
3  * 
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  */
10 #include <config.h>
11 #include <stdio.h>
12 #include <glib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include "assembly.h"
17 #include "image.h"
18 #include "object-internals.h"
19 #include <mono/metadata/loader.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/metadata-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/domain-internals.h>
25 #include <mono/metadata/mono-endian.h>
26 #include <mono/metadata/mono-debug.h>
27 #include <mono/io-layer/io-layer.h>
28 #include <mono/utils/mono-uri.h>
29 #include <mono/metadata/mono-config.h>
30 #include <mono/utils/mono-digest.h>
31 #include <mono/utils/mono-logger-internal.h>
32 #include <mono/utils/mono-path.h>
33 #include <mono/metadata/reflection.h>
34 #include <mono/metadata/coree.h>
35
36 #ifndef HOST_WIN32
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <sys/stat.h>
40 #endif
41
42 #ifdef PLATFORM_MACOSX
43 #include <mach-o/dyld.h>
44 #endif
45
46 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
47 typedef struct  {
48         const char* assembly_name;
49         guint8 version_set_index;
50 } AssemblyVersionMap;
51
52 /* the default search path is empty, the first slot is replaced with the computed value */
53 static const char*
54 default_path [] = {
55         NULL,
56         NULL
57 };
58
59 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
60 static char **assemblies_path = NULL;
61
62 /* Contains the list of directories that point to auxiliary GACs */
63 static char **extra_gac_paths = NULL;
64
65 #ifndef DISABLE_ASSEMBLY_REMAPPING
66 /* The list of system assemblies what will be remapped to the running
67  * runtime version. WARNING: this list must be sorted.
68  */
69 static const AssemblyVersionMap framework_assemblies [] = {
70         {"Accessibility", 0},
71         {"Commons.Xml.Relaxng", 0},
72         {"I18N", 0},
73         {"I18N.CJK", 0},
74         {"I18N.MidEast", 0},
75         {"I18N.Other", 0},
76         {"I18N.Rare", 0},
77         {"I18N.West", 0},
78         {"Microsoft.VisualBasic", 1},
79         {"Microsoft.VisualC", 1},
80         {"Mono.Cairo", 0},
81         {"Mono.CompilerServices.SymbolWriter", 0},
82         {"Mono.Data", 0},
83         {"Mono.Data.SybaseClient", 0},
84         {"Mono.Data.Tds", 0},
85         {"Mono.Data.TdsClient", 0},
86         {"Mono.GetOptions", 0},
87         {"Mono.Http", 0},
88         {"Mono.Posix", 0},
89         {"Mono.Security", 0},
90         {"Mono.Security.Win32", 0},
91         {"Mono.Xml.Ext", 0},
92         {"Novell.Directory.Ldap", 0},
93         {"Npgsql", 0},
94         {"PEAPI", 0},
95         {"System", 0},
96         {"System.ComponentModel.DataAnnotations", 2},
97         {"System.Configuration", 0},
98         {"System.Configuration.Install", 0},
99         {"System.Core", 2},
100         {"System.Data", 0},
101         {"System.Data.Linq", 2},
102         {"System.Data.OracleClient", 0},
103         {"System.Data.SqlXml", 0},
104         {"System.Design", 0},
105         {"System.DirectoryServices", 0},
106         {"System.Drawing", 0},
107         {"System.Drawing.Design", 0},
108         {"System.EnterpriseServices", 0},
109         {"System.Management", 0},
110         {"System.Messaging", 0},
111         {"System.Runtime.Remoting", 0},
112         {"System.Runtime.Serialization.Formatters.Soap", 0},
113         {"System.Security", 0},
114         {"System.ServiceProcess", 0},
115         {"System.Web", 0},
116         {"System.Web.Abstractions", 2},
117         {"System.Web.Mobile", 0},
118         {"System.Web.Routing", 2},
119         {"System.Web.Services", 0},
120         {"System.Windows.Forms", 0},
121         {"System.Xml", 0},
122         {"mscorlib", 0}
123 };
124 #endif
125
126 /*
127  * keeps track of loaded assemblies
128  */
129 static GList *loaded_assemblies = NULL;
130 static MonoAssembly *corlib;
131
132 #if defined(__native_client__)
133
134 /* On Native Client, allow mscorlib to be loaded from memory  */
135 /* instead of loaded off disk.  If these are not set, default */
136 /* mscorlib loading will take place                           */
137
138 /* NOTE: If mscorlib data is passed to mono in this way then */
139 /* it needs to remain allocated during the use of mono.      */
140
141 static void *corlibData = NULL;
142 static size_t corlibSize = 0;
143
144 void
145 mono_set_corlib_data (void *data, size_t size)
146 {
147   corlibData = data;
148   corlibSize = size;
149 }
150
151 #endif
152
153 /* This protects loaded_assemblies and image->references */
154 #define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex)
155 #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
156 static CRITICAL_SECTION assemblies_mutex;
157
158 /* If defined, points to the bundled assembly information */
159 const MonoBundledAssembly **bundles;
160
161 /* Loaded assembly binding info */
162 static GSList *loaded_assembly_bindings = NULL;
163
164 static MonoAssembly*
165 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload);
166 static MonoBoolean
167 mono_assembly_is_in_gac (const gchar *filanem);
168
169 static gchar*
170 encode_public_tok (const guchar *token, gint32 len)
171 {
172         const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
173         gchar *res;
174         int i;
175
176         res = g_malloc (len * 2 + 1);
177         for (i = 0; i < len; i++) {
178                 res [i * 2] = allowed [token [i] >> 4];
179                 res [i * 2 + 1] = allowed [token [i] & 0xF];
180         }
181         res [len * 2] = 0;
182         return res;
183 }
184
185 /**
186  * mono_public_tokens_are_equal:
187  * @pubt1: first public key token
188  * @pubt2: second public key token
189  *
190  * Compare two public key tokens and return #TRUE is they are equal and #FALSE
191  * otherwise.
192  */
193 gboolean
194 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
195 {
196         return memcmp (pubt1, pubt2, 16) == 0;
197 }
198
199 static void
200 check_path_env (void)
201 {
202         const char *path;
203         char **splitted, **dest;
204         
205         path = g_getenv ("MONO_PATH");
206         if (!path)
207                 return;
208
209         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
210         if (assemblies_path)
211                 g_strfreev (assemblies_path);
212         assemblies_path = dest = splitted;
213         while (*splitted){
214                 if (**splitted)
215                         *dest++ = *splitted;
216                 splitted++;
217         }
218         *dest = *splitted;
219         
220         if (g_getenv ("MONO_DEBUG") == NULL)
221                 return;
222
223         splitted = assemblies_path;
224         while (*splitted) {
225                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
226                         g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
227
228                 splitted++;
229         }
230 }
231
232 static void
233 check_extra_gac_path_env (void) {
234         const char *path;
235         char **splitted, **dest;
236         
237         path = g_getenv ("MONO_GAC_PREFIX");
238         if (!path)
239                 return;
240
241         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
242         if (extra_gac_paths)
243                 g_strfreev (extra_gac_paths);
244         extra_gac_paths = dest = splitted;
245         while (*splitted){
246                 if (**splitted)
247                         *dest++ = *splitted;
248                 splitted++;
249         }
250         *dest = *splitted;
251         
252         if (g_getenv ("MONO_DEBUG") == NULL)
253                 return;
254
255         while (*splitted) {
256                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
257                         g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
258
259                 splitted++;
260         }
261 }
262
263 static gboolean
264 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
265 {
266         if (!info || !info->name)
267                 return FALSE;
268
269         if (strcmp (info->name, aname->name))
270                 return FALSE;
271
272         if (info->major != aname->major || info->minor != aname->minor)
273                 return FALSE;
274
275         if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0])) 
276                 return FALSE;
277         
278         if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
279                 return FALSE;
280         
281         if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
282                 return FALSE;
283
284         return TRUE;
285 }
286
287 static void
288 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
289 {
290         if (!info)
291                 return;
292
293         g_free (info->name);
294         g_free (info->culture);
295 }
296
297 static void
298 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
299 {
300         MonoTableInfo *t;
301         guint32 cols [MONO_MANIFEST_SIZE];
302         const gchar *filename;
303         gchar *subpath, *fullpath;
304
305         t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
306         /* MS Impl. accepts policy assemblies with more than
307          * one manifest resource, and only takes the first one */
308         if (t->rows < 1) {
309                 binding_info->is_valid = FALSE;
310                 return;
311         }
312         
313         mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
314         if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
315                 binding_info->is_valid = FALSE;
316                 return;
317         }
318         
319         filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
320         g_assert (filename != NULL);
321         
322         subpath = g_path_get_dirname (image->name);
323         fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
324         mono_config_parse_publisher_policy (fullpath, binding_info);
325         g_free (subpath);
326         g_free (fullpath);
327         
328         /* Define the optional elements/attributes before checking */
329         if (!binding_info->culture)
330                 binding_info->culture = g_strdup ("");
331         
332         /* Check that the most important elements/attributes exist */
333         if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
334                         !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
335                 mono_assembly_binding_info_free (binding_info);
336                 binding_info->is_valid = FALSE;
337                 return;
338         }
339
340         binding_info->is_valid = TRUE;
341 }
342
343 static int
344 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
345 {
346         if (v->major > aname->major)
347                 return 1;
348         else if (v->major < aname->major)
349                 return -1;
350
351         if (v->minor > aname->minor)
352                 return 1;
353         else if (v->minor < aname->minor)
354                 return -1;
355
356         if (v->build > aname->build)
357                 return 1;
358         else if (v->build < aname->build)
359                 return -1;
360
361         if (v->revision > aname->revision)
362                 return 1;
363         else if (v->revision < aname->revision)
364                 return -1;
365
366         return 0;
367 }
368
369 static gboolean
370 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
371 {
372         if (!info->is_valid)
373                 return FALSE;
374         
375         /* If has_old_version_top doesn't exist, we don't have an interval */
376         if (!info->has_old_version_top) {
377                 if (compare_versions (&info->old_version_bottom, name) == 0)
378                         return TRUE;
379
380                 return FALSE;
381         }
382
383         /* Check that the version defined by name is valid for the interval */
384         if (compare_versions (&info->old_version_top, name) < 0)
385                 return FALSE;
386
387         /* We should be greater or equal than the small version */
388         if (compare_versions (&info->old_version_bottom, name) > 0)
389                 return FALSE;
390
391         return TRUE;
392 }
393
394 /**
395  * mono_assembly_names_equal:
396  * @l: first assembly
397  * @r: second assembly.
398  *
399  * Compares two MonoAssemblyNames and returns whether they are equal.
400  *
401  * This compares the names, the cultures, the release version and their
402  * public tokens.
403  *
404  * Returns: TRUE if both assembly names are equal.
405  */
406 gboolean
407 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
408 {
409         if (!l->name || !r->name)
410                 return FALSE;
411
412         if (strcmp (l->name, r->name))
413                 return FALSE;
414
415         if (l->culture && r->culture && strcmp (l->culture, r->culture))
416                 return FALSE;
417
418         if (l->major != r->major || l->minor != r->minor ||
419                         l->build != r->build || l->revision != r->revision)
420                 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)))
421                         return FALSE;
422
423         if (!l->public_key_token [0] || !r->public_key_token [0])
424                 return TRUE;
425
426         if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
427                 return FALSE;
428
429         return TRUE;
430 }
431
432 static MonoAssembly *
433 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
434 {
435         int i;
436         char *fullpath;
437         MonoAssembly *result;
438
439         for (i = 0; search_path [i]; ++i) {
440                 fullpath = g_build_filename (search_path [i], basename, NULL);
441                 result = mono_assembly_open_full (fullpath, status, refonly);
442                 g_free (fullpath);
443                 if (result)
444                         return result;
445         }
446         return NULL;
447 }
448
449 /**
450  * mono_assembly_setrootdir:
451  * @root_dir: The pathname of the root directory where we will locate assemblies
452  *
453  * This routine sets the internal default root directory for looking up
454  * assemblies.
455  *
456  * This is used by Windows installations to compute dynamically the
457  * place where the Mono assemblies are located.
458  *
459  */
460 void
461 mono_assembly_setrootdir (const char *root_dir)
462 {
463         /*
464          * Override the MONO_ASSEMBLIES directory configured at compile time.
465          */
466         /* Leak if called more than once */
467         default_path [0] = g_strdup (root_dir);
468 }
469
470 /**
471  * mono_assembly_getrootdir:
472  * 
473  * Obtains the root directory used for looking up assemblies.
474  *
475  * Returns: a string with the directory, this string should not be freed.
476  */
477 G_CONST_RETURN gchar *
478 mono_assembly_getrootdir (void)
479 {
480         return default_path [0];
481 }
482
483 /**
484  * mono_set_dirs:
485  * @assembly_dir: the base directory for assemblies
486  * @config_dir: the base directory for configuration files
487  *
488  * This routine is used internally and by developers embedding
489  * the runtime into their own applications.
490  *
491  * There are a number of cases to consider: Mono as a system-installed
492  * package that is available on the location preconfigured or Mono in
493  * a relocated location.
494  *
495  * If you are using a system-installed Mono, you can pass NULL
496  * to both parameters.  If you are not, you should compute both
497  * directory values and call this routine.
498  *
499  * The values for a given PREFIX are:
500  *
501  *    assembly_dir: PREFIX/lib
502  *    config_dir:   PREFIX/etc
503  *
504  * Notice that embedders that use Mono in a relocated way must
505  * compute the location at runtime, as they will be in control
506  * of where Mono is installed.
507  */
508 void
509 mono_set_dirs (const char *assembly_dir, const char *config_dir)
510 {
511 #if defined (MONO_ASSEMBLIES)
512         if (assembly_dir == NULL)
513                 assembly_dir = MONO_ASSEMBLIES;
514 #endif
515 #if defined (MONO_CFG_DIR)
516         if (config_dir == NULL)
517                 config_dir = MONO_CFG_DIR;
518 #endif
519         mono_assembly_setrootdir (assembly_dir);
520         mono_set_config_dir (config_dir);
521 }
522
523 #ifndef HOST_WIN32
524
525 static char *
526 compute_base (char *path)
527 {
528         char *p = strrchr (path, '/');
529         if (p == NULL)
530                 return NULL;
531
532         /* Not a well known Mono executable, we are embedded, cant guess the base  */
533         if (strcmp (p, "/mono") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet"))
534                 return NULL;
535             
536         *p = 0;
537         p = strrchr (path, '/');
538         if (p == NULL)
539                 return NULL;
540         
541         if (strcmp (p, "/bin") != 0)
542                 return NULL;
543         *p = 0;
544         return path;
545 }
546
547 static void
548 fallback (void)
549 {
550         mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR);
551 }
552
553 static void
554 set_dirs (char *exe)
555 {
556         char *base;
557         char *config, *lib, *mono;
558         struct stat buf;
559         
560         /*
561          * Only /usr prefix is treated specially
562          */
563         if (strncmp (exe, MONO_BINDIR, strlen (MONO_BINDIR)) == 0 || (base = compute_base (exe)) == NULL){
564                 fallback ();
565                 return;
566         }
567
568         config = g_build_filename (base, "etc", NULL);
569         lib = g_build_filename (base, "lib", NULL);
570         mono = g_build_filename (lib, "mono/1.0", NULL);
571         if (stat (mono, &buf) == -1)
572                 fallback ();
573         else {
574                 mono_set_dirs (lib, config);
575         }
576         
577         g_free (config);
578         g_free (lib);
579         g_free (mono);
580 }
581
582 #endif /* HOST_WIN32 */
583
584 /**
585  * mono_set_rootdir:
586  *
587  * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
588  * this auto-detects the prefix where Mono was installed. 
589  */
590 void
591 mono_set_rootdir (void)
592 {
593 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
594         gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
595
596 #ifdef HOST_WIN32
597         name = mono_get_module_file_name ((HMODULE) &__ImageBase);
598 #else
599         {
600                 /* 
601                  * _NSGetExecutablePath may return -1 to indicate buf is not large
602                  *  enough, but we ignore that case to avoid having to do extra dynamic
603                  *  allocation for the path and hope that 4096 is enough - this is 
604                  *  ok in the Linux/Solaris case below at least...
605                  */
606                 
607                 gchar buf[4096];
608                 guint buf_size = sizeof (buf);
609  
610                 if (_NSGetExecutablePath (buf, &buf_size) == 0)
611                         name = g_strdup (buf);
612  
613                 if (name == NULL) {
614                         fallback ();
615                         return;
616                 }
617
618                 name = mono_path_resolve_symlinks (name);
619         }
620 #endif
621
622         resolvedname = mono_path_resolve_symlinks (name);
623
624         bindir = g_path_get_dirname (resolvedname);
625         installdir = g_path_get_dirname (bindir);
626         root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
627
628         config = g_build_filename (root, "..", "etc", NULL);
629 #ifdef HOST_WIN32
630         mono_set_dirs (root, config);
631 #else
632         if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
633                 mono_set_dirs (root, config);
634         else
635                 fallback ();
636 #endif
637
638         g_free (config);
639         g_free (root);
640         g_free (installdir);
641         g_free (bindir);
642         g_free (name);
643         g_free (resolvedname);
644 #elif defined(DISABLE_MONO_AUTODETECTION)
645         fallback ();
646 #else
647         char buf [4096];
648         int  s;
649         char *str;
650
651         /* Linux style */
652         s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
653
654         if (s != -1){
655                 buf [s] = 0;
656                 set_dirs (buf);
657                 return;
658         }
659
660         /* Solaris 10 style */
661         str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
662         s = readlink (str, buf, sizeof (buf)-1);
663         g_free (str);
664         if (s != -1){
665                 buf [s] = 0;
666                 set_dirs (buf);
667                 return;
668         } 
669         fallback ();
670 #endif
671 }
672
673 /**
674  * mono_assemblies_init:
675  *
676  *  Initialize global variables used by this module.
677  */
678 void
679 mono_assemblies_init (void)
680 {
681         /*
682          * Initialize our internal paths if we have not been initialized yet.
683          * This happens when embedders use Mono.
684          */
685         if (mono_assembly_getrootdir () == NULL)
686                 mono_set_rootdir ();
687
688         check_path_env ();
689         check_extra_gac_path_env ();
690
691         InitializeCriticalSection (&assemblies_mutex);
692 }
693
694 gboolean
695 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
696 {
697         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
698         guint32 cols [MONO_ASSEMBLY_SIZE];
699
700         if (!t->rows)
701                 return FALSE;
702
703         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
704
705         aname->hash_len = 0;
706         aname->hash_value = NULL;
707         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
708         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
709         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
710         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
711         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
712         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
713         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
714         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
715         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
716                 guchar* token = g_malloc (8);
717                 gchar* encoded;
718                 const gchar* pkey;
719                 int len;
720
721                 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
722                 len = mono_metadata_decode_blob_size (pkey, &pkey);
723                 aname->public_key = (guchar*)pkey;
724
725                 mono_digest_get_public_token (token, aname->public_key, len);
726                 encoded = encode_public_tok (token, 8);
727                 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
728
729                 g_free (encoded);
730                 g_free (token);
731         }
732         else {
733                 aname->public_key = NULL;
734                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
735         }
736
737         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
738                 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
739         }
740         else
741                 aname->public_key = 0;
742
743         return TRUE;
744 }
745
746 /**
747  * mono_stringify_assembly_name:
748  * @aname: the assembly name.
749  *
750  * Convert @aname into its string format. The returned string is dynamically
751  * allocated and should be freed by the caller.
752  *
753  * Returns: a newly allocated string with a string representation of
754  * the assembly name.
755  */
756 char*
757 mono_stringify_assembly_name (MonoAssemblyName *aname)
758 {
759         const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
760
761         return g_strdup_printf (
762                 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
763                 quote, aname->name, quote,
764                 aname->major, aname->minor, aname->build, aname->revision,
765                 aname->culture && *aname->culture? aname->culture: "neutral",
766                 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
767                 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
768 }
769
770 static gchar*
771 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
772 {
773         const gchar *public_tok;
774         int len;
775
776         public_tok = mono_metadata_blob_heap (image, key_index);
777         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
778
779         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
780                 guchar token [8];
781                 mono_digest_get_public_token (token, (guchar*)public_tok, len);
782                 return encode_public_tok (token, 8);
783         }
784
785         return encode_public_tok ((guchar*)public_tok, len);
786 }
787
788 /**
789  * mono_assembly_addref:
790  * @assemnly: the assembly to reference
791  *
792  * This routine increments the reference count on a MonoAssembly.
793  * The reference count is reduced every time the method mono_assembly_close() is
794  * invoked.
795  */
796 void
797 mono_assembly_addref (MonoAssembly *assembly)
798 {
799         InterlockedIncrement (&assembly->ref_count);
800 }
801
802 #ifndef DISABLE_ASSEMBLY_REMAPPING
803 static MonoAssemblyName *
804 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
805 {
806         const MonoRuntimeInfo *current_runtime;
807         int pos, first, last;
808
809         if (aname->name == NULL) return aname;
810         current_runtime = mono_get_runtime_info ();
811
812         first = 0;
813         last = G_N_ELEMENTS (framework_assemblies) - 1;
814         
815         while (first <= last) {
816                 int res;
817                 pos = first + (last - first) / 2;
818                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
819                 if (res == 0) {
820                         const AssemblyVersionSet* vset;
821                         int index = framework_assemblies[pos].version_set_index;
822                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
823                         vset = &current_runtime->version_sets [index];
824
825                         if (aname->major == vset->major && aname->minor == vset->minor &&
826                                 aname->build == vset->build && aname->revision == vset->revision)
827                                 return aname;
828                 
829                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
830                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
831                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
832                                                         aname->name,
833                                                         aname->major, aname->minor, aname->build, aname->revision,
834                                                         vset->major, vset->minor, vset->build, vset->revision
835                                                         );
836                         
837                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
838                         dest_aname->major = vset->major;
839                         dest_aname->minor = vset->minor;
840                         dest_aname->build = vset->build;
841                         dest_aname->revision = vset->revision;
842                         return dest_aname;
843                 } else if (res < 0) {
844                         last = pos - 1;
845                 } else {
846                         first = pos + 1;
847                 }
848         }
849         return aname;
850 }
851 #endif
852
853 /*
854  * mono_assembly_get_assemblyref:
855  *
856  *   Fill out ANAME with the assembly name of the INDEXth assembly reference in IMAGE.
857  */
858 void
859 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
860 {
861         MonoTableInfo *t;
862         guint32 cols [MONO_ASSEMBLYREF_SIZE];
863         const char *hash;
864
865         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
866
867         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
868                 
869         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
870         aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
871         aname->hash_value = hash;
872         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
873         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
874         aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
875         aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
876         aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
877         aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
878         aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
879
880         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
881                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
882                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
883                 g_free (token);
884         } else {
885                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
886         }
887 }
888
889 void
890 mono_assembly_load_reference (MonoImage *image, int index)
891 {
892         MonoAssembly *reference;
893         MonoAssemblyName aname;
894         MonoImageOpenStatus status;
895
896         /*
897          * image->references is shared between threads, so we need to access
898          * it inside a critical section.
899          */
900         mono_assemblies_lock ();
901         if (!image->references) {
902                 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
903         
904                 image->references = g_new0 (MonoAssembly *, t->rows + 1);
905         }
906         reference = image->references [index];
907         mono_assemblies_unlock ();
908         if (reference)
909                 return;
910
911         mono_assembly_get_assemblyref (image, index, &aname);
912
913         if (image->assembly && image->assembly->ref_only) {
914                 /* We use the loaded corlib */
915                 if (!strcmp (aname.name, "mscorlib"))
916                         reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
917                 else {
918                         reference = mono_assembly_loaded_full (&aname, TRUE);
919                         if (!reference)
920                                 /* Try a postload search hook */
921                                 reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
922                 }
923
924                 /*
925                  * Here we must advice that the error was due to
926                  * a non loaded reference using the ReflectionOnly api
927                 */
928                 if (!reference)
929                         reference = REFERENCE_MISSING;
930         } else
931                 reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status);
932
933         if (reference == NULL){
934                 char *extra_msg;
935
936                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
937                         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 : "" );
938                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
939                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
940                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
941                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
942                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
943                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
944                 } else {
945                         extra_msg = g_strdup ("");
946                 }
947                 
948                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
949                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
950                                    "     Version:    %d.%d.%d.%d\n"
951                                    "     Public Key: %s\n%s",
952                                    image->name, aname.name, index,
953                                    aname.major, aname.minor, aname.build, aname.revision,
954                                    strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
955                 g_free (extra_msg);
956         }
957
958         mono_assemblies_lock ();
959         if (reference == NULL) {
960                 /* Flag as not found */
961                 reference = REFERENCE_MISSING;
962         }       
963
964         if (!image->references [index]) {
965                 if (reference != REFERENCE_MISSING){
966                         mono_assembly_addref (reference);
967                         if (image->assembly)
968                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d",
969                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
970                 } else {
971                         if (image->assembly)
972                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
973                                     image->assembly->aname.name, image->assembly);
974                 }
975                 
976                 image->references [index] = reference;
977         }
978         mono_assemblies_unlock ();
979
980         if (image->references [index] != reference) {
981                 /* Somebody loaded it before us */
982                 mono_assembly_close (reference);
983         }
984 }
985
986 void
987 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
988 {
989         /* This is a no-op now but it is part of the embedding API so we can't remove it */
990         *status = MONO_IMAGE_OK;
991 }
992
993 typedef struct AssemblyLoadHook AssemblyLoadHook;
994 struct AssemblyLoadHook {
995         AssemblyLoadHook *next;
996         MonoAssemblyLoadFunc func;
997         gpointer user_data;
998 };
999
1000 AssemblyLoadHook *assembly_load_hook = NULL;
1001
1002 void
1003 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1004 {
1005         AssemblyLoadHook *hook;
1006
1007         for (hook = assembly_load_hook; hook; hook = hook->next) {
1008                 hook->func (ass, hook->user_data);
1009         }
1010 }
1011
1012 void
1013 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1014 {
1015         AssemblyLoadHook *hook;
1016         
1017         g_return_if_fail (func != NULL);
1018
1019         hook = g_new0 (AssemblyLoadHook, 1);
1020         hook->func = func;
1021         hook->user_data = user_data;
1022         hook->next = assembly_load_hook;
1023         assembly_load_hook = hook;
1024 }
1025
1026 static void
1027 free_assembly_load_hooks (void)
1028 {
1029         AssemblyLoadHook *hook, *next;
1030
1031         for (hook = assembly_load_hook; hook; hook = next) {
1032                 next = hook->next;
1033                 g_free (hook);
1034         }
1035 }
1036
1037 typedef struct AssemblySearchHook AssemblySearchHook;
1038 struct AssemblySearchHook {
1039         AssemblySearchHook *next;
1040         MonoAssemblySearchFunc func;
1041         gboolean refonly;
1042         gboolean postload;
1043         gpointer user_data;
1044 };
1045
1046 AssemblySearchHook *assembly_search_hook = NULL;
1047
1048 static MonoAssembly*
1049 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload)
1050 {
1051         AssemblySearchHook *hook;
1052
1053         for (hook = assembly_search_hook; hook; hook = hook->next) {
1054                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1055                         MonoAssembly *ass = hook->func (aname, hook->user_data);
1056                         if (ass)
1057                                 return ass;
1058                 }
1059         }
1060
1061         return NULL;
1062 }
1063
1064 MonoAssembly*
1065 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1066 {
1067         return mono_assembly_invoke_search_hook_internal (aname, FALSE, FALSE);
1068 }
1069
1070 static void
1071 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1072 {
1073         AssemblySearchHook *hook;
1074         
1075         g_return_if_fail (func != NULL);
1076
1077         hook = g_new0 (AssemblySearchHook, 1);
1078         hook->func = func;
1079         hook->user_data = user_data;
1080         hook->refonly = refonly;
1081         hook->postload = postload;
1082         hook->next = assembly_search_hook;
1083         assembly_search_hook = hook;
1084 }
1085
1086 void          
1087 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1088 {
1089         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1090 }       
1091
1092 static void
1093 free_assembly_search_hooks (void)
1094 {
1095         AssemblySearchHook *hook, *next;
1096
1097         for (hook = assembly_search_hook; hook; hook = next) {
1098                 next = hook->next;
1099                 g_free (hook);
1100         }
1101 }
1102
1103 void
1104 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1105 {
1106         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1107 }
1108
1109 void          
1110 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1111 {
1112         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1113 }       
1114
1115 void
1116 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1117 {
1118         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1119 }
1120
1121 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1122 struct AssemblyPreLoadHook {
1123         AssemblyPreLoadHook *next;
1124         MonoAssemblyPreLoadFunc func;
1125         gpointer user_data;
1126 };
1127
1128 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1129 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1130
1131 static MonoAssembly *
1132 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1133 {
1134         AssemblyPreLoadHook *hook;
1135         MonoAssembly *assembly;
1136
1137         for (hook = assembly_preload_hook; hook; hook = hook->next) {
1138                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1139                 if (assembly != NULL)
1140                         return assembly;
1141         }
1142
1143         return NULL;
1144 }
1145
1146 static MonoAssembly *
1147 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1148 {
1149         AssemblyPreLoadHook *hook;
1150         MonoAssembly *assembly;
1151
1152         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1153                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1154                 if (assembly != NULL)
1155                         return assembly;
1156         }
1157
1158         return NULL;
1159 }
1160
1161 void
1162 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1163 {
1164         AssemblyPreLoadHook *hook;
1165         
1166         g_return_if_fail (func != NULL);
1167
1168         hook = g_new0 (AssemblyPreLoadHook, 1);
1169         hook->func = func;
1170         hook->user_data = user_data;
1171         hook->next = assembly_preload_hook;
1172         assembly_preload_hook = hook;
1173 }
1174
1175 void
1176 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1177 {
1178         AssemblyPreLoadHook *hook;
1179         
1180         g_return_if_fail (func != NULL);
1181
1182         hook = g_new0 (AssemblyPreLoadHook, 1);
1183         hook->func = func;
1184         hook->user_data = user_data;
1185         hook->next = assembly_refonly_preload_hook;
1186         assembly_refonly_preload_hook = hook;
1187 }
1188
1189 static void
1190 free_assembly_preload_hooks (void)
1191 {
1192         AssemblyPreLoadHook *hook, *next;
1193
1194         for (hook = assembly_preload_hook; hook; hook = next) {
1195                 next = hook->next;
1196                 g_free (hook);
1197         }
1198
1199         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1200                 next = hook->next;
1201                 g_free (hook);
1202         }
1203 }
1204
1205 static gchar *
1206 absolute_dir (const gchar *filename)
1207 {
1208         gchar *cwd;
1209         gchar *mixed;
1210         gchar **parts;
1211         gchar *part;
1212         GList *list, *tmp;
1213         GString *result;
1214         gchar *res;
1215         gint i;
1216
1217         if (g_path_is_absolute (filename)) {
1218                 part = g_path_get_dirname (filename);
1219                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1220                 g_free (part);
1221                 return res;
1222         }
1223
1224         cwd = g_get_current_dir ();
1225         mixed = g_build_filename (cwd, filename, NULL);
1226         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1227         g_free (mixed);
1228         g_free (cwd);
1229
1230         list = NULL;
1231         for (i = 0; (part = parts [i]) != NULL; i++) {
1232                 if (!strcmp (part, "."))
1233                         continue;
1234
1235                 if (!strcmp (part, "..")) {
1236                         if (list && list->next) /* Don't remove root */
1237                                 list = g_list_delete_link (list, list);
1238                 } else {
1239                         list = g_list_prepend (list, part);
1240                 }
1241         }
1242
1243         result = g_string_new ("");
1244         list = g_list_reverse (list);
1245
1246         /* Ignores last data pointer, which should be the filename */
1247         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1248                 if (tmp->data)
1249                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1250                                                                 G_DIR_SEPARATOR);
1251         }
1252
1253         res = result->str;
1254         g_string_free (result, FALSE);
1255         g_list_free (list);
1256         g_strfreev (parts);
1257         if (*res == '\0') {
1258                 g_free (res);
1259                 return g_strdup (".");
1260         }
1261
1262         return res;
1263 }
1264
1265 /** 
1266  * mono_assembly_open_from_bundle:
1267  * @filename: Filename requested
1268  * @status: return value
1269  *
1270  * This routine tries to open the assembly specified by `filename' from the
1271  * defined bundles, if found, returns the MonoImage for it, if not found
1272  * returns NULL
1273  */
1274 MonoImage *
1275 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1276 {
1277         int i;
1278         char *name;
1279         MonoImage *image = NULL;
1280
1281         /*
1282          * we do a very simple search for bundled assemblies: it's not a general 
1283          * purpose assembly loading mechanism.
1284          */
1285
1286         if (!bundles)
1287                 return NULL;
1288
1289         name = g_path_get_basename (filename);
1290
1291         mono_assemblies_lock ();
1292         for (i = 0; !image && bundles [i]; ++i) {
1293                 if (strcmp (bundles [i]->name, name) == 0) {
1294                         image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1295                         break;
1296                 }
1297         }
1298         mono_assemblies_unlock ();
1299         g_free (name);
1300         if (image) {
1301                 mono_image_addref (image);
1302                 return image;
1303         }
1304         return NULL;
1305 }
1306
1307 MonoAssembly *
1308 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1309 {
1310         MonoImage *image;
1311         MonoAssembly *ass;
1312         MonoImageOpenStatus def_status;
1313         gchar *fname;
1314         gchar *new_fname;
1315         
1316         g_return_val_if_fail (filename != NULL, NULL);
1317
1318         if (!status)
1319                 status = &def_status;
1320         *status = MONO_IMAGE_OK;
1321
1322         if (strncmp (filename, "file://", 7) == 0) {
1323                 GError *error = NULL;
1324                 gchar *uri = (gchar *) filename;
1325                 gchar *tmpuri;
1326
1327                 /*
1328                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1329                  * They also throw an IndexOutOfRangeException if "file://"
1330                  */
1331                 if (uri [7] != '/')
1332                         uri = g_strdup_printf ("file:///%s", uri + 7);
1333         
1334                 tmpuri = uri;
1335                 uri = mono_escape_uri_string (tmpuri);
1336                 fname = g_filename_from_uri (uri, NULL, &error);
1337                 g_free (uri);
1338
1339                 if (tmpuri != filename)
1340                         g_free (tmpuri);
1341
1342                 if (error != NULL) {
1343                         g_warning ("%s\n", error->message);
1344                         g_error_free (error);
1345                         fname = g_strdup (filename);
1346                 }
1347         } else {
1348                 fname = g_strdup (filename);
1349         }
1350
1351         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1352                         "Assembly Loader probing location: '%s'.", fname);
1353
1354         new_fname = NULL;
1355         if (!mono_assembly_is_in_gac (fname))
1356                 new_fname = mono_make_shadow_copy (fname);
1357         if (new_fname && new_fname != fname) {
1358                 g_free (fname);
1359                 fname = new_fname;
1360                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1361                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1362         }
1363         
1364         image = NULL;
1365
1366         if (bundles != NULL)
1367                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1368
1369         if (!image)
1370                 image = mono_image_open_full (fname, status, refonly);
1371
1372         if (!image){
1373                 if (*status == MONO_IMAGE_OK)
1374                         *status = MONO_IMAGE_ERROR_ERRNO;
1375                 g_free (fname);
1376                 return NULL;
1377         }
1378
1379         if (image->assembly) {
1380                 /* Already loaded by another appdomain */
1381                 mono_assembly_invoke_load_hook (image->assembly);
1382                 mono_image_close (image);
1383                 g_free (fname);
1384                 return image->assembly;
1385         }
1386
1387         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1388
1389         if (ass) {
1390                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1391                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1392                 if (!refonly)
1393                         mono_config_for_assembly (ass->image);
1394         }
1395
1396         /* Clear the reference added by mono_image_open */
1397         mono_image_close (image);
1398         
1399         g_free (fname);
1400
1401         return ass;
1402 }
1403
1404 static void
1405 free_item (gpointer val, gpointer user_data)
1406 {
1407         g_free (val);
1408 }
1409
1410 /*
1411  * mono_assembly_load_friends:
1412  * @ass: an assembly
1413  *
1414  * Load the list of friend assemblies that are allowed to access
1415  * the assembly's internal types and members. They are stored as assembly
1416  * names in custom attributes.
1417  *
1418  * This is an internal method, we need this because when we load mscorlib
1419  * we do not have the mono_defaults.internals_visible_class loaded yet,
1420  * so we need to load these after we initialize the runtime. 
1421  *
1422  * LOCKING: Acquires the assemblies lock plus the loader lock.
1423  */
1424 void
1425 mono_assembly_load_friends (MonoAssembly* ass)
1426 {
1427         int i;
1428         MonoCustomAttrInfo* attrs;
1429         GSList *list;
1430
1431         if (ass->friend_assembly_names_inited)
1432                 return;
1433
1434         attrs = mono_custom_attrs_from_assembly (ass);
1435         if (!attrs) {
1436                 mono_assemblies_lock ();
1437                 ass->friend_assembly_names_inited = TRUE;
1438                 mono_assemblies_unlock ();
1439                 return;
1440         }
1441
1442         mono_assemblies_lock ();
1443         if (ass->friend_assembly_names_inited) {
1444                 mono_assemblies_unlock ();
1445                 return;
1446         }
1447         mono_assemblies_unlock ();
1448
1449         list = NULL;
1450         /* 
1451          * We build the list outside the assemblies lock, the worse that can happen
1452          * is that we'll need to free the allocated list.
1453          */
1454         for (i = 0; i < attrs->num_attrs; ++i) {
1455                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1456                 MonoAssemblyName *aname;
1457                 const gchar *data;
1458                 guint slen;
1459                 /* Do some sanity checking */
1460                 if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
1461                         continue;
1462                 if (attr->data_size < 4)
1463                         continue;
1464                 data = (const char*)attr->data;
1465                 /* 0xFF means null string, see custom attr format */
1466                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1467                         continue;
1468                 slen = mono_metadata_decode_value (data + 2, &data);
1469                 aname = g_new0 (MonoAssemblyName, 1);
1470                 /*g_print ("friend ass: %s\n", data);*/
1471                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1472                         list = g_slist_prepend (list, aname);
1473                 } else {
1474                         g_free (aname);
1475                 }
1476         }
1477         mono_custom_attrs_free (attrs);
1478
1479         mono_assemblies_lock ();
1480         if (ass->friend_assembly_names_inited) {
1481                 mono_assemblies_unlock ();
1482                 g_slist_foreach (list, free_item, NULL);
1483                 g_slist_free (list);
1484                 return;
1485         }
1486         ass->friend_assembly_names = list;
1487
1488         /* Because of the double checked locking pattern above */
1489         mono_memory_barrier ();
1490         ass->friend_assembly_names_inited = TRUE;
1491         mono_assemblies_unlock ();
1492 }
1493
1494 /**
1495  * mono_assembly_open:
1496  * @filename: Opens the assembly pointed out by this name
1497  * @status: where a status code can be returned
1498  *
1499  * mono_assembly_open opens the PE-image pointed by @filename, and
1500  * loads any external assemblies referenced by it.
1501  *
1502  * Return: a pointer to the MonoAssembly if @filename contains a valid
1503  * assembly or NULL on error.  Details about the error are stored in the
1504  * @status variable.
1505  */
1506 MonoAssembly *
1507 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1508 {
1509         return mono_assembly_open_full (filename, status, FALSE);
1510 }
1511
1512 MonoAssembly *
1513 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1514                               MonoImageOpenStatus *status, gboolean refonly)
1515 {
1516         MonoAssembly *ass, *ass2;
1517         char *base_dir;
1518
1519         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1520                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1521                 *status = MONO_IMAGE_IMAGE_INVALID;
1522                 return NULL;
1523         }
1524
1525 #if defined (HOST_WIN32)
1526         {
1527                 gchar *tmp_fn;
1528                 int i;
1529
1530                 tmp_fn = g_strdup (fname);
1531                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1532                         if (tmp_fn [i] == '/')
1533                                 tmp_fn [i] = '\\';
1534                 }
1535
1536                 base_dir = absolute_dir (tmp_fn);
1537                 g_free (tmp_fn);
1538         }
1539 #else
1540         base_dir = absolute_dir (fname);
1541 #endif
1542
1543         /*
1544          * Create assembly struct, and enter it into the assembly cache
1545          */
1546         ass = g_new0 (MonoAssembly, 1);
1547         ass->basedir = base_dir;
1548         ass->ref_only = refonly;
1549         ass->image = image;
1550
1551         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1552
1553         mono_assembly_fill_assembly_name (image, &ass->aname);
1554
1555         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1556                 // MS.NET doesn't support loading other mscorlibs
1557                 g_free (ass);
1558                 g_free (base_dir);
1559                 mono_image_addref (mono_defaults.corlib);
1560                 *status = MONO_IMAGE_OK;
1561                 return mono_defaults.corlib->assembly;
1562         }
1563
1564         /* Add a non-temporary reference because of ass->image */
1565         mono_image_addref (image);
1566
1567         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);
1568
1569         /* 
1570          * The load hooks might take locks so we can't call them while holding the
1571          * assemblies lock.
1572          */
1573         if (ass->aname.name) {
1574                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE);
1575                 if (ass2) {
1576                         g_free (ass);
1577                         g_free (base_dir);
1578                         mono_image_close (image);
1579                         *status = MONO_IMAGE_OK;
1580                         return ass2;
1581                 }
1582         }
1583
1584         mono_assemblies_lock ();
1585
1586         if (image->assembly) {
1587                 /* 
1588                  * This means another thread has already loaded the assembly, but not yet
1589                  * called the load hooks so the search hook can't find the assembly.
1590                  */
1591                 mono_assemblies_unlock ();
1592                 ass2 = image->assembly;
1593                 g_free (ass);
1594                 g_free (base_dir);
1595                 mono_image_close (image);
1596                 *status = MONO_IMAGE_OK;
1597                 return ass2;
1598         }
1599
1600         image->assembly = ass;
1601
1602         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1603         mono_assemblies_unlock ();
1604
1605 #ifdef HOST_WIN32
1606         if (image->is_module_handle)
1607                 mono_image_fixup_vtable (image);
1608 #endif
1609
1610         mono_assembly_invoke_load_hook (ass);
1611
1612         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1613         
1614         return ass;
1615 }
1616
1617 MonoAssembly *
1618 mono_assembly_load_from (MonoImage *image, const char *fname,
1619                          MonoImageOpenStatus *status)
1620 {
1621         return mono_assembly_load_from_full (image, fname, status, FALSE);
1622 }
1623
1624 /**
1625  * mono_assembly_name_free:
1626  * @aname: assembly name to free
1627  * 
1628  * Frees the provided assembly name object.
1629  * (it does not frees the object itself, only the name members).
1630  */
1631 void
1632 mono_assembly_name_free (MonoAssemblyName *aname)
1633 {
1634         if (aname == NULL)
1635                 return;
1636
1637         g_free ((void *) aname->name);
1638         g_free ((void *) aname->culture);
1639         g_free ((void *) aname->hash_value);
1640 }
1641
1642 static gboolean
1643 parse_public_key (const gchar *key, gchar** pubkey)
1644 {
1645         const gchar *pkey;
1646         gchar header [16], val, *arr;
1647         gint i, j, offset, bitlen, keylen, pkeylen;
1648         
1649         keylen = strlen (key) >> 1;
1650         if (keylen < 1)
1651                 return FALSE;
1652         
1653         val = g_ascii_xdigit_value (key [0]) << 4;
1654         val |= g_ascii_xdigit_value (key [1]);
1655         switch (val) {
1656                 case 0x00:
1657                         if (keylen < 13)
1658                                 return FALSE;
1659                         val = g_ascii_xdigit_value (key [24]);
1660                         val |= g_ascii_xdigit_value (key [25]);
1661                         if (val != 0x06)
1662                                 return FALSE;
1663                         pkey = key + 24;
1664                         break;
1665                 case 0x06:
1666                         pkey = key;
1667                         break;
1668                 default:
1669                         return FALSE;
1670         }
1671                 
1672         /* We need the first 16 bytes
1673         * to check whether this key is valid or not */
1674         pkeylen = strlen (pkey) >> 1;
1675         if (pkeylen < 16)
1676                 return FALSE;
1677                 
1678         for (i = 0, j = 0; i < 16; i++) {
1679                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
1680                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
1681         }
1682
1683         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
1684                         header [1] != 0x02 || /* Version (0x02) */
1685                         header [2] != 0x00 || /* Reserved (word) */
1686                         header [3] != 0x00 ||
1687                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
1688                 return FALSE;
1689
1690         /* Based on this length, we _should_ be able to know if the length is right */
1691         bitlen = read32 (header + 12) >> 3;
1692         if ((bitlen + 16 + 4) != pkeylen)
1693                 return FALSE;
1694
1695         /* parsing is OK and the public key itself is not requested back */
1696         if (!pubkey)
1697                 return TRUE;
1698                 
1699         /* Encode the size of the blob */
1700         offset = 0;
1701         if (keylen <= 127) {
1702                 arr = g_malloc (keylen + 1);
1703                 arr [offset++] = keylen;
1704         } else {
1705                 arr = g_malloc (keylen + 2);
1706                 arr [offset++] = 0x80; /* 10bs */
1707                 arr [offset++] = keylen;
1708         }
1709                 
1710         for (i = offset, j = 0; i < keylen + offset; i++) {
1711                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
1712                 arr [i] |= g_ascii_xdigit_value (key [j++]);
1713         }
1714
1715         *pubkey = arr;
1716
1717         return TRUE;
1718 }
1719
1720 static gboolean
1721 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)
1722 {
1723         gint major, minor, build, revision;
1724         gint len;
1725         gint version_parts;
1726         gchar *pkey, *pkeyptr, *encoded, tok [8];
1727
1728         memset (aname, 0, sizeof (MonoAssemblyName));
1729
1730         if (version) {
1731                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
1732                 if (version_parts < 2 || version_parts > 4)
1733                         return FALSE;
1734
1735                 /* FIXME: we should set build & revision to -1 (instead of 0)
1736                 if these are not set in the version string. That way, later on,
1737                 we can still determine if these were specified. */
1738                 aname->major = major;
1739                 aname->minor = minor;
1740                 if (version_parts >= 3)
1741                         aname->build = build;
1742                 else
1743                         aname->build = 0;
1744                 if (version_parts == 4)
1745                         aname->revision = revision;
1746                 else
1747                         aname->revision = 0;
1748         }
1749         
1750         aname->flags = flags;
1751         aname->arch = arch;
1752         aname->name = g_strdup (name);
1753         
1754         if (culture) {
1755                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
1756                         aname->culture = g_strdup ("");
1757                 else
1758                         aname->culture = g_strdup (culture);
1759         }
1760         
1761         if (token && strncmp (token, "null", 4) != 0) {
1762                 char *lower;
1763
1764                 /* the constant includes the ending NULL, hence the -1 */
1765                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
1766                         mono_assembly_name_free (aname);
1767                         return FALSE;
1768                 }
1769                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1770                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1771                 g_free (lower);
1772         }
1773
1774         if (key) {
1775                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) {
1776                         mono_assembly_name_free (aname);
1777                         return FALSE;
1778                 }
1779                 
1780                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
1781                 // We also need to generate the key token
1782                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
1783                 encoded = encode_public_tok ((guchar*) tok, 8);
1784                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1785                 g_free (encoded);
1786
1787                 if (save_public_key)
1788                         aname->public_key = (guint8*) pkey;
1789                 else
1790                         g_free (pkey);
1791         }
1792
1793         return TRUE;
1794 }
1795
1796 static gboolean
1797 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
1798 {
1799         gchar **parts;
1800         gboolean res;
1801         
1802         parts = g_strsplit (dirname, "_", 3);
1803         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
1804                 g_strfreev (parts);
1805                 return FALSE;
1806         }
1807         
1808         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
1809         g_strfreev (parts);
1810         return res;
1811 }
1812
1813 gboolean
1814 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
1815 {
1816         gchar *dllname;
1817         gchar *version = NULL;
1818         gchar *culture = NULL;
1819         gchar *token = NULL;
1820         gchar *key = NULL;
1821         gchar *retargetable = NULL;
1822         gboolean res;
1823         gchar *value;
1824         gchar **parts;
1825         gchar **tmp;
1826         gboolean version_defined;
1827         gboolean token_defined;
1828         guint32 flags = 0;
1829         guint32 arch = PROCESSOR_ARCHITECTURE_NONE;
1830
1831         if (!is_version_defined)
1832                 is_version_defined = &version_defined;
1833         *is_version_defined = FALSE;
1834         if (!is_token_defined)
1835                 is_token_defined = &token_defined;
1836         *is_token_defined = FALSE;
1837         
1838         parts = tmp = g_strsplit (name, ",", 6);
1839         if (!tmp || !*tmp) {
1840                 g_strfreev (tmp);
1841                 return FALSE;
1842         }
1843
1844         dllname = g_strstrip (*tmp);
1845         
1846         tmp++;
1847
1848         while (*tmp) {
1849                 value = g_strstrip (*tmp);
1850                 if (!g_ascii_strncasecmp (value, "Version=", 8)) {
1851                         *is_version_defined = TRUE;
1852                         version = g_strstrip (value + 8);
1853                         if (strlen (version) == 0) {
1854                                 goto cleanup_and_fail;
1855                         }
1856                         tmp++;
1857                         continue;
1858                 }
1859
1860                 if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
1861                         culture = g_strstrip (value + 8);
1862                         if (strlen (culture) == 0) {
1863                                 goto cleanup_and_fail;
1864                         }
1865                         tmp++;
1866                         continue;
1867                 }
1868
1869                 if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
1870                         *is_token_defined = TRUE;
1871                         token = g_strstrip (value + 15);
1872                         if (strlen (token) == 0) {
1873                                 goto cleanup_and_fail;
1874                         }
1875                         tmp++;
1876                         continue;
1877                 }
1878
1879                 if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) {
1880                         key = g_strstrip (value + 10);
1881                         if (strlen (key) == 0) {
1882                                 goto cleanup_and_fail;
1883                         }
1884                         tmp++;
1885                         continue;
1886                 }
1887
1888                 if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) {
1889                         retargetable = g_strstrip (value + 13);
1890                         if (strlen (retargetable) == 0) {
1891                                 goto cleanup_and_fail;
1892                         }
1893                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
1894                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
1895                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
1896                                 goto cleanup_and_fail;
1897                         }
1898                         tmp++;
1899                         continue;
1900                 }
1901
1902                 if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) {
1903                         char *s = g_strstrip (value + 22);
1904                         if (!g_ascii_strcasecmp (s, "None"))
1905                                 arch = PROCESSOR_ARCHITECTURE_NONE;
1906                         else if (!g_ascii_strcasecmp (s, "MSIL"))
1907                                 arch = PROCESSOR_ARCHITECTURE_MSIL;
1908                         else if (!g_ascii_strcasecmp (s, "X86"))
1909                                 arch = PROCESSOR_ARCHITECTURE_X86;
1910                         else if (!g_ascii_strcasecmp (s, "IA64"))
1911                                 arch = PROCESSOR_ARCHITECTURE_IA64;
1912                         else if (!g_ascii_strcasecmp (s, "AMD64"))
1913                                 arch = PROCESSOR_ARCHITECTURE_AMD64;
1914                         else
1915                                 goto cleanup_and_fail;
1916                         tmp++;
1917                         continue;
1918                 }
1919
1920                 g_strfreev (parts);
1921                 return FALSE;
1922         }
1923
1924         /* if retargetable flag is set, then we must have a fully qualified name */
1925         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
1926                 goto cleanup_and_fail;
1927         }
1928
1929         res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
1930                 aname, save_public_key);
1931         g_strfreev (parts);
1932         return res;
1933
1934 cleanup_and_fail:
1935         g_strfreev (parts);
1936         return FALSE;
1937 }
1938
1939 /**
1940  * mono_assembly_name_parse:
1941  * @name: name to parse
1942  * @aname: the destination assembly name
1943  * 
1944  * Parses an assembly qualified type name and assigns the name,
1945  * version, culture and token to the provided assembly name object.
1946  *
1947  * Returns: true if the name could be parsed.
1948  */
1949 gboolean
1950 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
1951 {
1952         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
1953 }
1954
1955 /**
1956  * mono_assembly_name_new:
1957  * @name: name to parse
1958  *
1959  * Allocate a new MonoAssemblyName and fill its values from the
1960  * passed @name.
1961  *
1962  * Returns: a newly allocated structure or NULL if there was any failure.
1963  */
1964 MonoAssemblyName*
1965 mono_assembly_name_new (const char *name)
1966 {
1967         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
1968         if (mono_assembly_name_parse (name, aname))
1969                 return aname;
1970         g_free (aname);
1971         return NULL;
1972 }
1973
1974 const char*
1975 mono_assembly_name_get_name (MonoAssemblyName *aname)
1976 {
1977         return aname->name;
1978 }
1979
1980 const char*
1981 mono_assembly_name_get_culture (MonoAssemblyName *aname)
1982 {
1983         return aname->culture;
1984 }
1985
1986 mono_byte*
1987 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
1988 {
1989         if (aname->public_key_token [0])
1990                 return aname->public_key_token;
1991         return NULL;
1992 }
1993
1994 uint16_t
1995 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
1996 {
1997         if (minor)
1998                 *minor = aname->minor;
1999         if (build)
2000                 *build = aname->build;
2001         if (revision)
2002                 *revision = aname->revision;
2003         return aname->major;
2004 }
2005
2006 static MonoAssembly*
2007 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2008 {
2009         gchar *fullpath = NULL;
2010         GDir *dirhandle;
2011         const char* direntry;
2012         MonoAssemblyName gac_aname;
2013         gint major=-1, minor=0, build=0, revision=0;
2014         gboolean exact_version;
2015         
2016         dirhandle = g_dir_open (basepath, 0, NULL);
2017         if (!dirhandle)
2018                 return NULL;
2019                 
2020         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2021
2022         while ((direntry = g_dir_read_name (dirhandle))) {
2023                 gboolean match = TRUE;
2024                 
2025                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2026                         continue;
2027                 
2028                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2029                         match = FALSE;
2030                         
2031                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2032                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2033                         match = FALSE;
2034                 
2035                 if (match) {
2036                         if (exact_version) {
2037                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2038                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2039                         }
2040                         else if (gac_aname.major < major)
2041                                 match = FALSE;
2042                         else if (gac_aname.major == major) {
2043                                 if (gac_aname.minor < minor)
2044                                         match = FALSE;
2045                                 else if (gac_aname.minor == minor) {
2046                                         if (gac_aname.build < build)
2047                                                 match = FALSE;
2048                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2049                                                 match = FALSE; 
2050                                 }
2051                         }
2052                 }
2053                 
2054                 if (match) {
2055                         major = gac_aname.major;
2056                         minor = gac_aname.minor;
2057                         build = gac_aname.build;
2058                         revision = gac_aname.revision;
2059                         g_free (fullpath);
2060                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2061                 }
2062
2063                 mono_assembly_name_free (&gac_aname);
2064         }
2065         
2066         g_dir_close (dirhandle);
2067         
2068         if (fullpath == NULL)
2069                 return NULL;
2070         else {
2071                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2072                 g_free (fullpath);
2073                 return res;
2074         }
2075 }
2076
2077 MonoAssembly*
2078 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2079 {
2080         MonoAssembly *res;
2081         MonoAssemblyName *aname, base_name;
2082 #ifndef DISABLE_ASSEMBLY_REMAPPING
2083         MonoAssemblyName maped_aname;
2084 #endif
2085         gchar *fullname, *gacpath;
2086         gchar **paths;
2087
2088         memset (&base_name, 0, sizeof (MonoAssemblyName));
2089         aname = &base_name;
2090
2091         if (!mono_assembly_name_parse (name, aname))
2092                 return NULL;
2093
2094 #ifndef DISABLE_ASSEMBLY_REMAPPING
2095         /* 
2096          * If no specific version has been requested, make sure we load the
2097          * correct version for system assemblies.
2098          */ 
2099         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2100                 aname = mono_assembly_remap_version (aname, &maped_aname);
2101 #endif
2102         
2103         res = mono_assembly_loaded (aname);
2104         if (res) {
2105                 mono_assembly_name_free (aname);
2106                 return res;
2107         }
2108
2109         res = invoke_assembly_preload_hook (aname, assemblies_path);
2110         if (res) {
2111                 res->in_gac = FALSE;
2112                 mono_assembly_name_free (aname);
2113                 return res;
2114         }
2115
2116         fullname = g_strdup_printf ("%s.dll", aname->name);
2117
2118         if (extra_gac_paths) {
2119                 paths = extra_gac_paths;
2120                 while (!res && *paths) {
2121                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2122                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2123                         g_free (gacpath);
2124                         paths++;
2125                 }
2126         }
2127
2128         if (res) {
2129                 res->in_gac = TRUE;
2130                 g_free (fullname);
2131                 mono_assembly_name_free (aname);
2132                 return res;
2133         }
2134
2135         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2136         res = probe_for_partial_name (gacpath, fullname, aname, status);
2137         g_free (gacpath);
2138
2139         if (res)
2140                 res->in_gac = TRUE;
2141         else {
2142                 MonoDomain *domain = mono_domain_get ();
2143                 MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
2144                 if (refasm)
2145                         res = refasm->assembly;
2146         }
2147         
2148         g_free (fullname);
2149         mono_assembly_name_free (aname);
2150
2151         return res;
2152 }
2153
2154 static MonoBoolean
2155 mono_assembly_is_in_gac (const gchar *filename)
2156 {
2157         const gchar *rootdir;
2158         gchar *gp;
2159         gchar **paths;
2160
2161         if (filename == NULL)
2162                 return FALSE;
2163
2164         for (paths = extra_gac_paths; paths && *paths; paths++) {
2165                 if (strstr (*paths, filename) != *paths)
2166                         continue;
2167
2168                 gp = (gchar *) (filename + strlen (*paths));
2169                 if (*gp != G_DIR_SEPARATOR)
2170                         continue;
2171                 gp++;
2172                 if (strncmp (gp, "lib", 3))
2173                         continue;
2174                 gp += 3;
2175                 if (*gp != G_DIR_SEPARATOR)
2176                         continue;
2177                 gp++;
2178                 if (strncmp (gp, "mono", 4))
2179                         continue;
2180                 gp += 4;
2181                 if (*gp != G_DIR_SEPARATOR)
2182                         continue;
2183                 gp++;
2184                 if (strncmp (gp, "gac", 3))
2185                         continue;
2186                 gp += 3;
2187                 if (*gp != G_DIR_SEPARATOR)
2188                         continue;
2189
2190                 return TRUE;
2191         }
2192
2193         rootdir = mono_assembly_getrootdir ();
2194         if (strstr (filename, rootdir) != filename)
2195                 return FALSE;
2196
2197         gp = (gchar *) (filename + strlen (rootdir));
2198         if (*gp != G_DIR_SEPARATOR)
2199                 return FALSE;
2200         gp++;
2201         if (strncmp (gp, "mono", 4))
2202                 return FALSE;
2203         gp += 4;
2204         if (*gp != G_DIR_SEPARATOR)
2205                 return FALSE;
2206         gp++;
2207         if (strncmp (gp, "gac", 3))
2208                 return FALSE;
2209         gp += 3;
2210         if (*gp != G_DIR_SEPARATOR)
2211                 return FALSE;
2212         return TRUE;
2213 }
2214
2215 static MonoImage*
2216 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2217 {
2218         MonoImage *image;
2219         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2220         gchar **paths;
2221         gint32 len;
2222
2223         if (strstr (aname->name, ".dll")) {
2224                 len = strlen (aname->name) - 4;
2225                 name = g_malloc (len);
2226                 strncpy (name, aname->name, len);
2227         } else
2228                 name = g_strdup (aname->name);
2229         
2230         if (aname->culture)
2231                 culture = g_utf8_strdown (aname->culture, -1);
2232         else
2233                 culture = g_strdup ("");
2234         
2235         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2236         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2237         g_free (name);
2238         g_free (culture);
2239         
2240         filename = g_strconcat (pname, ".dll", NULL);
2241         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2242         g_free (pname);
2243         g_free (version);
2244         g_free (filename);
2245
2246         image = NULL;
2247         if (extra_gac_paths) {
2248                 paths = extra_gac_paths;
2249                 while (!image && *paths) {
2250                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2251                                         "lib", "mono", "gac", subpath, NULL);
2252                         image = mono_image_open (fullpath, NULL);
2253                         g_free (fullpath);
2254                         paths++;
2255                 }
2256         }
2257
2258         if (image) {
2259                 g_free (subpath);
2260                 return image;
2261         }
2262
2263         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2264                         "mono", "gac", subpath, NULL);
2265         image = mono_image_open (fullpath, NULL);
2266         g_free (subpath);
2267         g_free (fullpath);
2268         
2269         return image;
2270 }
2271
2272 static MonoAssemblyName*
2273 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2274 {
2275         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2276         dest_name->major = info->new_version.major;
2277         dest_name->minor = info->new_version.minor;
2278         dest_name->build = info->new_version.build;
2279         dest_name->revision = info->new_version.revision;
2280         
2281         return dest_name;
2282 }
2283
2284 /* LOCKING: Assumes that we are already locked */
2285 static MonoAssemblyBindingInfo*
2286 search_binding_loaded (MonoAssemblyName *aname)
2287 {
2288         GSList *tmp;
2289
2290         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2291                 MonoAssemblyBindingInfo *info = tmp->data;
2292                 if (assembly_binding_maps_name (info, aname))
2293                         return info;
2294         }
2295
2296         return NULL;
2297 }
2298
2299 static inline gboolean
2300 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2301 {
2302         if (left->major != right->major || left->minor != right->minor ||
2303             left->build != right->build || left->revision != right->revision)
2304                 return FALSE;
2305
2306         return TRUE;
2307 }
2308
2309 static inline gboolean
2310 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2311 {
2312         if (left->has_old_version_bottom != right->has_old_version_bottom)
2313                 return FALSE;
2314
2315         if (left->has_old_version_top != right->has_old_version_top)
2316                 return FALSE;
2317
2318         if (left->has_new_version != right->has_new_version)
2319                 return FALSE;
2320
2321         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2322                 return FALSE;
2323
2324         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2325                 return FALSE;
2326
2327         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2328                 return FALSE;
2329
2330         return TRUE;
2331 }
2332
2333 /* LOCKING: assumes all the necessary locks are held */
2334 static void
2335 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2336 {
2337         MonoAssemblyBindingInfo *info_copy;
2338         GSList *tmp;
2339         MonoAssemblyBindingInfo *info_tmp;
2340         MonoDomain *domain = (MonoDomain*)user_data;
2341
2342         if (!domain)
2343                 return;
2344
2345         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2346                 info_tmp = tmp->data;
2347                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2348                         return;
2349         }
2350
2351         info_copy = mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2352         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2353         if (info->name)
2354                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2355         if (info->culture)
2356                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2357
2358         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2359 }
2360
2361 static inline gboolean
2362 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2363 {
2364         if (!info->has_old_version_bottom)
2365                 return FALSE;
2366
2367         if (info->old_version_bottom.major > aname->major || info->old_version_bottom.minor > aname->minor)
2368                 return FALSE;
2369
2370         if (info->has_old_version_top && (info->old_version_top.major < aname->major || info->old_version_top.minor < aname->minor))
2371                 return FALSE;
2372
2373         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2374         info->major = aname->major;
2375         info->minor = aname->minor;
2376
2377         return TRUE;
2378 }
2379
2380 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2381 static MonoAssemblyBindingInfo*
2382 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2383 {
2384         MonoAssemblyBindingInfo *info;
2385         GSList *list;
2386
2387         if (!domain->assembly_bindings)
2388                 return NULL;
2389
2390         info = NULL;
2391         for (list = domain->assembly_bindings; list; list = list->next) {
2392                 info = list->data;
2393                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2394                         break;
2395                 info = NULL;
2396         }
2397
2398         if (info) {
2399                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2400                     info->has_new_version && assembly_binding_maps_name (info, aname))
2401                         info->is_valid = TRUE;
2402                 else
2403                         info->is_valid = FALSE;
2404         }
2405
2406         return info;
2407 }
2408
2409 static MonoAssemblyName*
2410 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2411 {
2412         MonoAssemblyBindingInfo *info, *info2;
2413         MonoImage *ppimage;
2414         MonoDomain *domain;
2415
2416         if (aname->public_key_token [0] == 0)
2417                 return aname;
2418
2419         domain = mono_domain_get ();
2420         mono_loader_lock ();
2421         info = search_binding_loaded (aname);
2422         if (!info) {
2423                 mono_domain_lock (domain);
2424                 info = get_per_domain_assembly_binding_info (domain, aname);
2425                 mono_domain_unlock (domain);
2426         }
2427
2428         mono_loader_unlock ();
2429         if (info) {
2430                 if (!check_policy_versions (info, aname))
2431                         return aname;
2432                 
2433                 mono_assembly_bind_version (info, aname, dest_name);
2434                 return dest_name;
2435         }
2436
2437         if (domain && domain->setup && domain->setup->configuration_file) {
2438                 mono_domain_lock (domain);
2439                 if (!domain->assembly_bindings_parsed) {
2440                         gchar *domain_config_file = mono_string_to_utf8 (domain->setup->configuration_file);
2441
2442                         mono_config_parse_assembly_bindings (domain_config_file, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2443                         domain->assembly_bindings_parsed = TRUE;
2444                         g_free (domain_config_file);
2445                 }
2446                 mono_domain_unlock (domain);
2447
2448                 mono_loader_lock ();
2449                 mono_domain_lock (domain);
2450                 info = get_per_domain_assembly_binding_info (domain, aname);
2451                 mono_domain_unlock (domain);
2452                 mono_loader_unlock ();
2453         }
2454
2455         if (!info) {
2456                 info = g_new0 (MonoAssemblyBindingInfo, 1);
2457                 info->major = aname->major;
2458                 info->minor = aname->minor;
2459         }
2460
2461         if (!info->is_valid) {
2462                 ppimage = mono_assembly_load_publisher_policy (aname);
2463                 if (ppimage) {
2464                         get_publisher_policy_info (ppimage, aname, info);
2465                         mono_image_close (ppimage);
2466                 }
2467         }
2468
2469         /* Define default error value if needed */
2470         if (!info->is_valid) {
2471                 info->name = g_strdup (aname->name);
2472                 info->culture = g_strdup (aname->culture);
2473                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2474         }
2475         
2476         mono_loader_lock ();
2477         info2 = search_binding_loaded (aname);
2478         if (info2) {
2479                 /* This binding was added by another thread 
2480                  * before us */
2481                 mono_assembly_binding_info_free (info);
2482                 g_free (info);
2483                 
2484                 info = info2;
2485         } else
2486                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2487                 
2488         mono_loader_unlock ();
2489         
2490         if (!info->is_valid || !check_policy_versions (info, aname))
2491                 return aname;
2492
2493         mono_assembly_bind_version (info, aname, dest_name);
2494         return dest_name;
2495 }
2496
2497 /**
2498  * mono_assembly_load_from_gac
2499  *
2500  * @aname: The assembly name object
2501  */
2502 static MonoAssembly*
2503 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2504 {
2505         MonoAssembly *result = NULL;
2506         gchar *name, *version, *culture, *fullpath, *subpath;
2507         gint32 len;
2508         gchar **paths;
2509         char *pubtok;
2510
2511         if (aname->public_key_token [0] == 0) {
2512                 return NULL;
2513         }
2514
2515         if (strstr (aname->name, ".dll")) {
2516                 len = strlen (filename) - 4;
2517                 name = g_malloc (len);
2518                 strncpy (name, aname->name, len);
2519         } else {
2520                 name = g_strdup (aname->name);
2521         }
2522
2523         if (aname->culture) {
2524                 culture = g_utf8_strdown (aname->culture, -1);
2525         } else {
2526                 culture = g_strdup ("");
2527         }
2528
2529         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2530         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
2531                         aname->minor, aname->build, aname->revision,
2532                         culture, pubtok);
2533         g_free (pubtok);
2534         
2535         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
2536         g_free (name);
2537         g_free (version);
2538         g_free (culture);
2539
2540         if (extra_gac_paths) {
2541                 paths = extra_gac_paths;
2542                 while (!result && *paths) {
2543                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
2544                         result = mono_assembly_open_full (fullpath, status, refonly);
2545                         g_free (fullpath);
2546                         paths++;
2547                 }
2548         }
2549
2550         if (result) {
2551                 result->in_gac = TRUE;
2552                 g_free (subpath);
2553                 return result;
2554         }
2555
2556         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2557                         "mono", "gac", subpath, NULL);
2558         result = mono_assembly_open_full (fullpath, status, refonly);
2559         g_free (fullpath);
2560
2561         if (result)
2562                 result->in_gac = TRUE;
2563         
2564         g_free (subpath);
2565
2566         return result;
2567 }
2568
2569 MonoAssembly*
2570 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
2571 {
2572         char *corlib_file;
2573         MonoAssemblyName *aname;
2574
2575         if (corlib) {
2576                 /* g_print ("corlib already loaded\n"); */
2577                 return corlib;
2578         }
2579
2580 #if defined(__native_client__)
2581         if (corlibData != NULL && corlibSize != 0) {
2582                 int status = 0;
2583                 /* First "FALSE" instructs mono not to make a copy. */
2584                 /* Second "FALSE" says this is not just a ref.      */
2585                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
2586                 if (image == NULL || status != 0)
2587                         g_print("mono_image_open_from_data_full failed: %d\n", status);
2588                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
2589                 if (corlib == NULL || status != 0)
2590                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
2591                 if (corlib)
2592                         return corlib;
2593         }
2594 #endif
2595
2596         aname = mono_assembly_name_new ("mscorlib.dll");
2597         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
2598         mono_assembly_name_free (aname);
2599         g_free (aname);
2600         if (corlib != NULL)
2601                 return corlib;
2602
2603         if (assemblies_path) {
2604                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
2605                 if (corlib)
2606                         return corlib;
2607         }
2608
2609         /* Load corlib from mono/<version> */
2610         
2611         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
2612         if (assemblies_path) {
2613                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
2614                 if (corlib) {
2615                         g_free (corlib_file);
2616                         return corlib;
2617                 }
2618         }
2619         corlib = load_in_path (corlib_file, default_path, status, FALSE);
2620         g_free (corlib_file);
2621
2622         return corlib;
2623 }
2624
2625 MonoAssembly*
2626 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
2627                                                                   const char       *basedir, 
2628                                                                   MonoImageOpenStatus *status,
2629                                                                   gboolean refonly)
2630 {
2631         MonoAssembly *result;
2632         char *fullpath, *filename;
2633 #ifndef DISABLE_ASSEMBLY_REMAPPING
2634         MonoAssemblyName maped_aname;
2635 #endif
2636         MonoAssemblyName maped_name_pp;
2637         int ext_index;
2638         const char *ext;
2639         int len;
2640
2641 #ifndef DISABLE_ASSEMBLY_REMAPPING
2642         aname = mono_assembly_remap_version (aname, &maped_aname);
2643 #endif
2644         
2645         /* Reflection only assemblies don't get assembly binding */
2646         if (!refonly)
2647                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
2648         
2649         result = mono_assembly_loaded_full (aname, refonly);
2650         if (result)
2651                 return result;
2652
2653         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
2654         if (result) {
2655                 result->in_gac = FALSE;
2656                 return result;
2657         }
2658
2659         /* Currently we retrieve the loaded corlib for reflection 
2660          * only requests, like a common reflection only assembly 
2661          */
2662         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
2663                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
2664         }
2665
2666         len = strlen (aname->name);
2667         for (ext_index = 0; ext_index < 2; ext_index ++) {
2668                 ext = ext_index == 0 ? ".dll" : ".exe";
2669                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
2670                         filename = g_strdup (aname->name);
2671                         /* Don't try appending .dll/.exe if it already has one of those extensions */
2672                         ext_index++;
2673                 } else {
2674                         filename = g_strconcat (aname->name, ext, NULL);
2675                 }
2676
2677                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
2678                 if (result) {
2679                         g_free (filename);
2680                         return result;
2681                 }
2682
2683                 if (basedir) {
2684                         fullpath = g_build_filename (basedir, filename, NULL);
2685                         result = mono_assembly_open_full (fullpath, status, refonly);
2686                         g_free (fullpath);
2687                         if (result) {
2688                                 result->in_gac = FALSE;
2689                                 g_free (filename);
2690                                 return result;
2691                         }
2692                 }
2693
2694                 result = load_in_path (filename, default_path, status, refonly);
2695                 if (result)
2696                         result->in_gac = FALSE;
2697                 g_free (filename);
2698                 if (result)
2699                         return result;
2700         }
2701
2702         return result;
2703 }
2704
2705 /**
2706  * mono_assembly_load_full:
2707  * @aname: A MonoAssemblyName with the assembly name to load.
2708  * @basedir: A directory to look up the assembly at.
2709  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2710  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
2711  *
2712  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2713  * attempts to load the assembly from that directory before probing the standard locations.
2714  *
2715  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
2716  * assembly binding takes place.
2717  *
2718  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2719  * value pointed by status is updated with an error code.
2720  */
2721 MonoAssembly*
2722 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
2723 {
2724         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
2725         
2726         if (!result)
2727                 /* Try a postload search hook */
2728                 result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
2729         return result;
2730 }
2731
2732 /**
2733  * mono_assembly_load:
2734  * @aname: A MonoAssemblyName with the assembly name to load.
2735  * @basedir: A directory to look up the assembly at.
2736  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2737  *
2738  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2739  * attempts to load the assembly from that directory before probing the standard locations.
2740  *
2741  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2742  * value pointed by status is updated with an error code.
2743  */
2744 MonoAssembly*
2745 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
2746 {
2747         return mono_assembly_load_full (aname, basedir, status, FALSE);
2748 }
2749         
2750 MonoAssembly*
2751 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
2752 {
2753         MonoAssembly *res;
2754 #ifndef DISABLE_ASSEMBLY_REMAPPING
2755         MonoAssemblyName maped_aname;
2756
2757         aname = mono_assembly_remap_version (aname, &maped_aname);
2758 #endif
2759
2760         res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
2761
2762         return res;
2763 }
2764
2765 /**
2766  * mono_assembly_loaded:
2767  * @aname: an assembly to look for.
2768  *
2769  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
2770  * a MonoAssembly that matches the MonoAssemblyName specified.
2771  */
2772 MonoAssembly*
2773 mono_assembly_loaded (MonoAssemblyName *aname)
2774 {
2775         return mono_assembly_loaded_full (aname, FALSE);
2776 }
2777
2778 /*
2779  * Returns whether mono_assembly_close_finish() must be called as
2780  * well.  See comment for mono_image_close_except_pools() for why we
2781  * unload in two steps.
2782  */
2783 gboolean
2784 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
2785 {
2786         GSList *tmp;
2787         g_return_val_if_fail (assembly != NULL, FALSE);
2788
2789         if (assembly == REFERENCE_MISSING)
2790                 return FALSE;
2791
2792         /* Might be 0 already */
2793         if (InterlockedDecrement (&assembly->ref_count) > 0)
2794                 return FALSE;
2795
2796         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
2797
2798         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
2799
2800         mono_debug_close_image (assembly->image);
2801
2802         mono_assemblies_lock ();
2803         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
2804         mono_assemblies_unlock ();
2805
2806         assembly->image->assembly = NULL;
2807
2808         if (!mono_image_close_except_pools (assembly->image))
2809                 assembly->image = NULL;
2810
2811         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
2812                 MonoAssemblyName *fname = tmp->data;
2813                 mono_assembly_name_free (fname);
2814                 g_free (fname);
2815         }
2816         g_slist_free (assembly->friend_assembly_names);
2817         g_free (assembly->basedir);
2818
2819         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
2820
2821         return TRUE;
2822 }
2823
2824 void
2825 mono_assembly_close_finish (MonoAssembly *assembly)
2826 {
2827         g_assert (assembly && assembly != REFERENCE_MISSING);
2828
2829         if (assembly->image)
2830                 mono_image_close_finish (assembly->image);
2831
2832         if (assembly->dynamic) {
2833                 g_free ((char*)assembly->aname.culture);
2834         } else {
2835                 g_free (assembly);
2836         }
2837 }
2838
2839 /**
2840  * mono_assembly_close:
2841  * @assembly: the assembly to release.
2842  *
2843  * This method releases a reference to the @assembly.  The assembly is
2844  * only released when all the outstanding references to it are released.
2845  */
2846 void
2847 mono_assembly_close (MonoAssembly *assembly)
2848 {
2849         if (mono_assembly_close_except_image_pools (assembly))
2850                 mono_assembly_close_finish (assembly);
2851 }
2852
2853 MonoImage*
2854 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
2855 {
2856         return mono_image_load_file_for_image (assembly->image, idx);
2857 }
2858
2859 void
2860 mono_assembly_foreach (GFunc func, gpointer user_data)
2861 {
2862         GList *copy;
2863
2864         /*
2865          * We make a copy of the list to avoid calling the callback inside the 
2866          * lock, which could lead to deadlocks.
2867          */
2868         mono_assemblies_lock ();
2869         copy = g_list_copy (loaded_assemblies);
2870         mono_assemblies_unlock ();
2871
2872         g_list_foreach (loaded_assemblies, func, user_data);
2873
2874         g_list_free (copy);
2875 }
2876
2877 /**
2878  * mono_assemblies_cleanup:
2879  *
2880  * Free all resources used by this module.
2881  */
2882 void
2883 mono_assemblies_cleanup (void)
2884 {
2885         GSList *l;
2886
2887         DeleteCriticalSection (&assemblies_mutex);
2888
2889         for (l = loaded_assembly_bindings; l; l = l->next) {
2890                 MonoAssemblyBindingInfo *info = l->data;
2891
2892                 mono_assembly_binding_info_free (info);
2893                 g_free (info);
2894         }
2895         g_slist_free (loaded_assembly_bindings);
2896
2897         free_assembly_load_hooks ();
2898         free_assembly_search_hooks ();
2899         free_assembly_preload_hooks ();
2900 }
2901
2902 /*
2903  * Holds the assembly of the application, for
2904  * System.Diagnostics.Process::MainModule
2905  */
2906 static MonoAssembly *main_assembly=NULL;
2907
2908 void
2909 mono_assembly_set_main (MonoAssembly *assembly)
2910 {
2911         main_assembly = assembly;
2912 }
2913
2914 /**
2915  * mono_assembly_get_main:
2916  *
2917  * Returns: the assembly for the application, the first assembly that is loaded by the VM
2918  */
2919 MonoAssembly *
2920 mono_assembly_get_main (void)
2921 {
2922         return (main_assembly);
2923 }
2924
2925 /**
2926  * mono_assembly_get_image:
2927  * @assembly: The assembly to retrieve the image from
2928  *
2929  * Returns: the MonoImage associated with this assembly.
2930  */
2931 MonoImage*
2932 mono_assembly_get_image (MonoAssembly *assembly)
2933 {
2934         return assembly->image;
2935 }
2936
2937 void
2938 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
2939 {
2940         bundles = assemblies;
2941 }
2942
2943 #define MONO_DECLSEC_FORMAT_10          0x3C
2944 #define MONO_DECLSEC_FORMAT_20          0x2E
2945 #define MONO_DECLSEC_FIELD              0x53
2946 #define MONO_DECLSEC_PROPERTY           0x54
2947
2948 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
2949 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
2950 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
2951 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
2952 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
2953
2954 static gboolean
2955 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
2956 {
2957         int len;
2958         switch (*p++) {
2959         case MONO_DECLSEC_PROPERTY:
2960                 break;
2961         case MONO_DECLSEC_FIELD:
2962         default:
2963                 *abort_decoding = TRUE;
2964                 return FALSE;
2965                 break;
2966         }
2967
2968         if (*p++ != MONO_TYPE_BOOLEAN) {
2969                 *abort_decoding = TRUE;
2970                 return FALSE;
2971         }
2972                 
2973         /* property name length */
2974         len = mono_metadata_decode_value (p, &p);
2975
2976         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
2977                 p += len;
2978                 return *p;
2979         }
2980         p += len + 1;
2981
2982         *resp = p;
2983         return FALSE;
2984 }
2985
2986 static gboolean
2987 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
2988 {
2989         int i, j, num, len, params_len;
2990
2991         if (*p == MONO_DECLSEC_FORMAT_10) {
2992                 gsize read, written;
2993                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
2994                 if (res) {
2995                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
2996                         g_free (res);
2997                         return found;
2998                 }
2999                 return FALSE;
3000         }
3001         if (*p++ != MONO_DECLSEC_FORMAT_20)
3002                 return FALSE;
3003
3004         /* number of encoded permission attributes */
3005         num = mono_metadata_decode_value (p, &p);
3006         for (i = 0; i < num; ++i) {
3007                 gboolean is_valid = FALSE;
3008                 gboolean abort_decoding = FALSE;
3009
3010                 /* attribute name length */
3011                 len =  mono_metadata_decode_value (p, &p);
3012
3013                 /* We don't really need to fully decode the type. Comparing the name is enough */
3014                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3015
3016                 p += len;
3017
3018                 /*size of the params table*/
3019                 params_len =  mono_metadata_decode_value (p, &p);
3020                 if (is_valid) {
3021                         const char *params_end = p + params_len;
3022                         
3023                         /* number of parameters */
3024                         len = mono_metadata_decode_value (p, &p);
3025         
3026                         for (j = 0; j < len; ++j) {
3027                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3028                                         return TRUE;
3029                                 if (abort_decoding)
3030                                         break;
3031                         }
3032                         p = params_end;
3033                 } else {
3034                         p += params_len;
3035                 }
3036         }
3037         
3038         return FALSE;
3039 }
3040
3041
3042 gboolean
3043 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3044 {
3045         MonoTableInfo *t;       
3046         guint32 cols [MONO_DECL_SECURITY_SIZE];
3047         const char *blob;
3048         int i, len;
3049
3050         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3051                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3052
3053         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3054
3055         for (i = 0; i < t->rows; ++i) {
3056                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3057                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3058                         continue;
3059                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3060                         continue;
3061
3062                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3063                 len = mono_metadata_decode_blob_size (blob, &blob);
3064                 if (!len)
3065                         continue;
3066
3067                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3068                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3069                         return TRUE;
3070                 }
3071         }
3072
3073         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3074         return FALSE;
3075 }