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