* docs.make, Makefile.am: Build mono-file-formats{.tree,.zip},
[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  * (C) 2001 Ximian, Inc.  http://www.ximian.com
8  *
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_PATH 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 = rindex (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 = rindex (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 #else
567         char buf [4096];
568         int  s;
569         char *str;
570
571         /* Linux style */
572         s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
573
574         if (s != -1){
575                 buf [s] = 0;
576                 set_dirs (buf);
577                 return;
578         }
579
580         /* Solaris 10 style */
581         str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
582         s = readlink (str, buf, sizeof (buf)-1);
583         g_free (str);
584         if (s != -1){
585                 buf [s] = 0;
586                 set_dirs (buf);
587                 return;
588         } 
589         fallback ();
590 #endif
591 }
592
593 /**
594  * mono_assemblies_init:
595  *
596  *  Initialize global variables used by this module.
597  */
598 void
599 mono_assemblies_init (void)
600 {
601         /*
602          * Initialize our internal paths if we have not been initialized yet.
603          * This happens when embedders use Mono.
604          */
605         if (mono_assembly_getrootdir () == NULL)
606                 mono_set_rootdir ();
607
608         check_path_env ();
609         check_extra_gac_path_env ();
610
611         InitializeCriticalSection (&assemblies_mutex);
612 }
613
614 gboolean
615 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
616 {
617         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
618         guint32 cols [MONO_ASSEMBLY_SIZE];
619
620         if (!t->rows)
621                 return FALSE;
622
623         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
624
625         aname->hash_len = 0;
626         aname->hash_value = NULL;
627         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
628         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
629         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
630         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
631         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
632         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
633         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
634         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
635         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
636                 guchar* token = g_malloc (8);
637                 gchar* encoded;
638                 const gchar* pkey;
639                 int len;
640
641                 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
642                 len = mono_metadata_decode_blob_size (pkey, &pkey);
643                 aname->public_key = (guchar*)pkey;
644
645                 mono_digest_get_public_token (token, aname->public_key, len);
646                 encoded = encode_public_tok (token, 8);
647                 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
648
649                 g_free (encoded);
650                 g_free (token);
651         }
652         else {
653                 aname->public_key = NULL;
654                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
655         }
656
657         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
658                 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
659         }
660         else
661                 aname->public_key = 0;
662
663         return TRUE;
664 }
665
666 /**
667  * mono_stringify_assembly_name:
668  * @aname: the assembly name.
669  *
670  * Convert @aname into its string format. The returned string is dynamically
671  * allocated and should be freed by the caller.
672  *
673  * Returns: a newly allocated string with a string representation of
674  * the assembly name.
675  */
676 char*
677 mono_stringify_assembly_name (MonoAssemblyName *aname)
678 {
679         return g_strdup_printf (
680                 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
681                 aname->name,
682                 aname->major, aname->minor, aname->build, aname->revision,
683                 aname->culture && *aname->culture? aname->culture: "neutral",
684                 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
685                 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
686 }
687
688 static gchar*
689 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
690 {
691         const gchar *public_tok;
692         int len;
693
694         public_tok = mono_metadata_blob_heap (image, key_index);
695         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
696
697         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
698                 guchar token [8];
699                 mono_digest_get_public_token (token, (guchar*)public_tok, len);
700                 return encode_public_tok (token, 8);
701         }
702
703         return encode_public_tok ((guchar*)public_tok, len);
704 }
705
706 /**
707  * mono_assembly_addref:
708  * @assemnly: the assembly to reference
709  *
710  * This routine increments the reference count on a MonoAssembly.
711  * The reference count is reduced every time the method mono_assembly_close() is
712  * invoked.
713  */
714 void
715 mono_assembly_addref (MonoAssembly *assembly)
716 {
717         InterlockedIncrement (&assembly->ref_count);
718 }
719
720 static MonoAssemblyName *
721 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
722 {
723         const MonoRuntimeInfo *current_runtime;
724         int pos, first, last;
725
726         if (aname->name == NULL) return aname;
727         current_runtime = mono_get_runtime_info ();
728
729         first = 0;
730         last = G_N_ELEMENTS (framework_assemblies) - 1;
731         
732         while (first <= last) {
733                 int res;
734                 pos = first + (last - first) / 2;
735                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
736                 if (res == 0) {
737                         const AssemblyVersionSet* vset;
738                         int index = framework_assemblies[pos].version_set_index;
739                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
740                         vset = &current_runtime->version_sets [index];
741
742                         if (aname->major == vset->major && aname->minor == vset->minor &&
743                                 aname->build == vset->build && aname->revision == vset->revision)
744                                 return aname;
745                 
746                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
747                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
748                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
749                                                         aname->name,
750                                                         aname->major, aname->minor, aname->build, aname->revision,
751                                                         vset->major, vset->minor, vset->build, vset->revision
752                                                         );
753                         
754                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
755                         dest_aname->major = vset->major;
756                         dest_aname->minor = vset->minor;
757                         dest_aname->build = vset->build;
758                         dest_aname->revision = vset->revision;
759                         return dest_aname;
760                 } else if (res < 0) {
761                         last = pos - 1;
762                 } else {
763                         first = pos + 1;
764                 }
765         }
766         return aname;
767 }
768
769 /*
770  * mono_assembly_get_assemblyref:
771  *
772  *   Fill out ANAME with the assembly name of the INDEXth assembly reference in IMAGE.
773  */
774 void
775 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
776 {
777         MonoTableInfo *t;
778         guint32 cols [MONO_ASSEMBLYREF_SIZE];
779         const char *hash;
780
781         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
782
783         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
784                 
785         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
786         aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
787         aname->hash_value = hash;
788         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
789         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
790         aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
791         aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
792         aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
793         aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
794         aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
795
796         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
797                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
798                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
799                 g_free (token);
800         } else {
801                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
802         }
803 }
804
805 void
806 mono_assembly_load_reference (MonoImage *image, int index)
807 {
808         MonoAssembly *reference;
809         MonoAssemblyName aname;
810         MonoImageOpenStatus status;
811
812         /*
813          * image->references is shared between threads, so we need to access
814          * it inside a critical section.
815          */
816         mono_assemblies_lock ();
817         if (!image->references) {
818                 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
819         
820                 image->references = g_new0 (MonoAssembly *, t->rows + 1);
821         }
822         reference = image->references [index];
823         mono_assemblies_unlock ();
824         if (reference)
825                 return;
826
827         mono_assembly_get_assemblyref (image, index, &aname);
828
829         if (image->assembly && image->assembly->ref_only) {
830                 /* We use the loaded corlib */
831                 if (!strcmp (aname.name, "mscorlib"))
832                         reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
833                 else {
834                         reference = mono_assembly_loaded_full (&aname, TRUE);
835                         if (!reference)
836                                 /* Try a postload search hook */
837                                 reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
838                 }
839
840                 /*
841                  * Here we must advice that the error was due to
842                  * a non loaded reference using the ReflectionOnly api
843                 */
844                 if (!reference)
845                         reference = REFERENCE_MISSING;
846         } else
847                 reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status);
848
849         if (reference == NULL){
850                 char *extra_msg = g_strdup ("");
851
852                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
853                         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 : "" );
854                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
855                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
856                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
857                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
858                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
859                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
860                 }
861                 
862                 g_warning ("The following assembly referenced from %s could not be loaded:\n"
863                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
864                                    "     Version:    %d.%d.%d.%d\n"
865                                    "     Public Key: %s\n%s",
866                                    image->name, aname.name, index,
867                                    aname.major, aname.minor, aname.build, aname.revision,
868                                    strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
869                 g_free (extra_msg);
870         }
871
872         mono_assemblies_lock ();
873         if (reference == NULL) {
874                 /* Flag as not found */
875                 reference = REFERENCE_MISSING;
876         }       
877
878         if (!image->references [index]) {
879                 if (reference != REFERENCE_MISSING){
880                         mono_assembly_addref (reference);
881                         if (image->assembly)
882                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n",
883                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
884                 } else {
885                         if (image->assembly)
886                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
887                                     image->assembly->aname.name, image->assembly);
888                 }
889                 
890                 image->references [index] = reference;
891         }
892         mono_assemblies_unlock ();
893
894         if (image->references [index] != reference) {
895                 /* Somebody loaded it before us */
896                 mono_assembly_close (reference);
897         }
898 }
899
900 void
901 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
902 {
903         /* This is a no-op now but it is part of the embedding API so we can't remove it */
904         *status = MONO_IMAGE_OK;
905 }
906
907 typedef struct AssemblyLoadHook AssemblyLoadHook;
908 struct AssemblyLoadHook {
909         AssemblyLoadHook *next;
910         MonoAssemblyLoadFunc func;
911         gpointer user_data;
912 };
913
914 AssemblyLoadHook *assembly_load_hook = NULL;
915
916 void
917 mono_assembly_invoke_load_hook (MonoAssembly *ass)
918 {
919         AssemblyLoadHook *hook;
920
921         for (hook = assembly_load_hook; hook; hook = hook->next) {
922                 hook->func (ass, hook->user_data);
923         }
924 }
925
926 void
927 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
928 {
929         AssemblyLoadHook *hook;
930         
931         g_return_if_fail (func != NULL);
932
933         hook = g_new0 (AssemblyLoadHook, 1);
934         hook->func = func;
935         hook->user_data = user_data;
936         hook->next = assembly_load_hook;
937         assembly_load_hook = hook;
938 }
939
940 static void
941 free_assembly_load_hooks (void)
942 {
943         AssemblyLoadHook *hook, *next;
944
945         for (hook = assembly_load_hook; hook; hook = next) {
946                 next = hook->next;
947                 g_free (hook);
948         }
949 }
950
951 typedef struct AssemblySearchHook AssemblySearchHook;
952 struct AssemblySearchHook {
953         AssemblySearchHook *next;
954         MonoAssemblySearchFunc func;
955         gboolean refonly;
956         gboolean postload;
957         gpointer user_data;
958 };
959
960 AssemblySearchHook *assembly_search_hook = NULL;
961
962 static MonoAssembly*
963 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload)
964 {
965         AssemblySearchHook *hook;
966
967         for (hook = assembly_search_hook; hook; hook = hook->next) {
968                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
969                         MonoAssembly *ass = hook->func (aname, hook->user_data);
970                         if (ass)
971                                 return ass;
972                 }
973         }
974
975         return NULL;
976 }
977
978 MonoAssembly*
979 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
980 {
981         return mono_assembly_invoke_search_hook_internal (aname, FALSE, FALSE);
982 }
983
984 static void
985 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
986 {
987         AssemblySearchHook *hook;
988         
989         g_return_if_fail (func != NULL);
990
991         hook = g_new0 (AssemblySearchHook, 1);
992         hook->func = func;
993         hook->user_data = user_data;
994         hook->refonly = refonly;
995         hook->postload = postload;
996         hook->next = assembly_search_hook;
997         assembly_search_hook = hook;
998 }
999
1000 void          
1001 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1002 {
1003         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1004 }       
1005
1006 static void
1007 free_assembly_search_hooks (void)
1008 {
1009         AssemblySearchHook *hook, *next;
1010
1011         for (hook = assembly_search_hook; hook; hook = next) {
1012                 next = hook->next;
1013                 g_free (hook);
1014         }
1015 }
1016
1017 void
1018 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1019 {
1020         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1021 }
1022
1023 void          
1024 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1025 {
1026         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1027 }       
1028
1029 void
1030 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1031 {
1032         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1033 }
1034
1035 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1036 struct AssemblyPreLoadHook {
1037         AssemblyPreLoadHook *next;
1038         MonoAssemblyPreLoadFunc func;
1039         gpointer user_data;
1040 };
1041
1042 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1043 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1044
1045 static MonoAssembly *
1046 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1047 {
1048         AssemblyPreLoadHook *hook;
1049         MonoAssembly *assembly;
1050
1051         for (hook = assembly_preload_hook; hook; hook = hook->next) {
1052                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1053                 if (assembly != NULL)
1054                         return assembly;
1055         }
1056
1057         return NULL;
1058 }
1059
1060 static MonoAssembly *
1061 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1062 {
1063         AssemblyPreLoadHook *hook;
1064         MonoAssembly *assembly;
1065
1066         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1067                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1068                 if (assembly != NULL)
1069                         return assembly;
1070         }
1071
1072         return NULL;
1073 }
1074
1075 void
1076 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1077 {
1078         AssemblyPreLoadHook *hook;
1079         
1080         g_return_if_fail (func != NULL);
1081
1082         hook = g_new0 (AssemblyPreLoadHook, 1);
1083         hook->func = func;
1084         hook->user_data = user_data;
1085         hook->next = assembly_preload_hook;
1086         assembly_preload_hook = hook;
1087 }
1088
1089 void
1090 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1091 {
1092         AssemblyPreLoadHook *hook;
1093         
1094         g_return_if_fail (func != NULL);
1095
1096         hook = g_new0 (AssemblyPreLoadHook, 1);
1097         hook->func = func;
1098         hook->user_data = user_data;
1099         hook->next = assembly_refonly_preload_hook;
1100         assembly_refonly_preload_hook = hook;
1101 }
1102
1103 static void
1104 free_assembly_preload_hooks (void)
1105 {
1106         AssemblyPreLoadHook *hook, *next;
1107
1108         for (hook = assembly_preload_hook; hook; hook = next) {
1109                 next = hook->next;
1110                 g_free (hook);
1111         }
1112
1113         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1114                 next = hook->next;
1115                 g_free (hook);
1116         }
1117 }
1118
1119 static gchar *
1120 absolute_dir (const gchar *filename)
1121 {
1122         gchar *cwd;
1123         gchar *mixed;
1124         gchar **parts;
1125         gchar *part;
1126         GList *list, *tmp;
1127         GString *result;
1128         gchar *res;
1129         gint i;
1130
1131         if (g_path_is_absolute (filename)) {
1132                 part = g_path_get_dirname (filename);
1133                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1134                 g_free (part);
1135                 return res;
1136         }
1137
1138         cwd = g_get_current_dir ();
1139         mixed = g_build_filename (cwd, filename, NULL);
1140         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1141         g_free (mixed);
1142         g_free (cwd);
1143
1144         list = NULL;
1145         for (i = 0; (part = parts [i]) != NULL; i++) {
1146                 if (!strcmp (part, "."))
1147                         continue;
1148
1149                 if (!strcmp (part, "..")) {
1150                         if (list && list->next) /* Don't remove root */
1151                                 list = g_list_delete_link (list, list);
1152                 } else {
1153                         list = g_list_prepend (list, part);
1154                 }
1155         }
1156
1157         result = g_string_new ("");
1158         list = g_list_reverse (list);
1159
1160         /* Ignores last data pointer, which should be the filename */
1161         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1162                 if (tmp->data)
1163                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1164                                                                 G_DIR_SEPARATOR);
1165         }
1166
1167         res = result->str;
1168         g_string_free (result, FALSE);
1169         g_list_free (list);
1170         g_strfreev (parts);
1171         if (*res == '\0') {
1172                 g_free (res);
1173                 return g_strdup (".");
1174         }
1175
1176         return res;
1177 }
1178
1179 /** 
1180  * mono_assembly_open_from_bundle:
1181  * @filename: Filename requested
1182  * @status: return value
1183  *
1184  * This routine tries to open the assembly specified by `filename' from the
1185  * defined bundles, if found, returns the MonoImage for it, if not found
1186  * returns NULL
1187  */
1188 MonoImage *
1189 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1190 {
1191         int i;
1192         char *name;
1193         MonoImage *image = NULL;
1194
1195         /*
1196          * we do a very simple search for bundled assemblies: it's not a general 
1197          * purpose assembly loading mechanism.
1198          */
1199
1200         if (!bundles)
1201                 return NULL;
1202
1203         name = g_path_get_basename (filename);
1204
1205         mono_assemblies_lock ();
1206         for (i = 0; !image && bundles [i]; ++i) {
1207                 if (strcmp (bundles [i]->name, name) == 0) {
1208                         image = mono_image_open_from_data_full ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly);
1209                         break;
1210                 }
1211         }
1212         mono_assemblies_unlock ();
1213         g_free (name);
1214         if (image) {
1215                 mono_image_addref (image);
1216                 return image;
1217         }
1218         return NULL;
1219 }
1220
1221 MonoAssembly *
1222 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1223 {
1224         MonoImage *image;
1225         MonoAssembly *ass;
1226         MonoImageOpenStatus def_status;
1227         gchar *fname;
1228         gchar *new_fname;
1229         
1230         g_return_val_if_fail (filename != NULL, NULL);
1231
1232         if (!status)
1233                 status = &def_status;
1234         *status = MONO_IMAGE_OK;
1235
1236         if (strncmp (filename, "file://", 7) == 0) {
1237                 GError *error = NULL;
1238                 gchar *uri = (gchar *) filename;
1239                 gchar *tmpuri;
1240
1241                 /*
1242                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1243                  * They also throw an IndexOutOfRangeException if "file://"
1244                  */
1245                 if (uri [7] != '/')
1246                         uri = g_strdup_printf ("file:///%s", uri + 7);
1247         
1248                 tmpuri = uri;
1249                 uri = mono_escape_uri_string (tmpuri);
1250                 fname = g_filename_from_uri (uri, NULL, &error);
1251                 g_free (uri);
1252
1253                 if (tmpuri != filename)
1254                         g_free (tmpuri);
1255
1256                 if (error != NULL) {
1257                         g_warning ("%s\n", error->message);
1258                         g_error_free (error);
1259                         fname = g_strdup (filename);
1260                 }
1261         } else {
1262                 fname = g_strdup (filename);
1263         }
1264
1265         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1266                         "Assembly Loader probing location: '%s'.", fname);
1267         new_fname = mono_make_shadow_copy (fname);
1268         if (new_fname && new_fname != fname) {
1269                 g_free (fname);
1270                 fname = new_fname;
1271                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1272                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1273         }
1274         
1275         image = NULL;
1276
1277         if (bundles != NULL)
1278                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1279
1280         if (!image)
1281                 image = mono_image_open_full (fname, status, refonly);
1282
1283         if (!image){
1284                 if (*status == MONO_IMAGE_OK)
1285                         *status = MONO_IMAGE_ERROR_ERRNO;
1286                 g_free (fname);
1287                 return NULL;
1288         }
1289
1290         if (image->assembly) {
1291                 /* Already loaded by another appdomain */
1292                 mono_assembly_invoke_load_hook (image->assembly);
1293                 mono_image_close (image);
1294                 g_free (fname);
1295                 return image->assembly;
1296         }
1297
1298         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1299
1300         if (ass) {
1301                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1302                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1303                 if (!refonly)
1304                         mono_config_for_assembly (ass->image);
1305         }
1306
1307         /* Clear the reference added by mono_image_open */
1308         mono_image_close (image);
1309         
1310         g_free (fname);
1311
1312         return ass;
1313 }
1314
1315 static void
1316 free_item (gpointer val, gpointer user_data)
1317 {
1318         g_free (val);
1319 }
1320
1321 /*
1322  * mono_assembly_load_friends:
1323  * @ass: an assembly
1324  *
1325  * Load the list of friend assemblies that are allowed to access
1326  * the assembly's internal types and members. They are stored as assembly
1327  * names in custom attributes.
1328  *
1329  * This is an internal method, we need this because when we load mscorlib
1330  * we do not have the mono_defaults.internals_visible_class loaded yet,
1331  * so we need to load these after we initialize the runtime. 
1332  *
1333  * LOCKING: Acquires the assemblies lock plus the loader lock.
1334  */
1335 void
1336 mono_assembly_load_friends (MonoAssembly* ass)
1337 {
1338         int i;
1339         MonoCustomAttrInfo* attrs;
1340         GSList *list;
1341
1342         if (ass->friend_assembly_names_inited)
1343                 return;
1344
1345         attrs = mono_custom_attrs_from_assembly (ass);
1346         if (!attrs) {
1347                 mono_assemblies_lock ();
1348                 ass->friend_assembly_names_inited = TRUE;
1349                 mono_assemblies_unlock ();
1350                 return;
1351         }
1352
1353         mono_assemblies_lock ();
1354         if (ass->friend_assembly_names_inited) {
1355                 mono_assemblies_unlock ();
1356                 return;
1357         }
1358         mono_assemblies_unlock ();
1359
1360         list = NULL;
1361         /* 
1362          * We build the list outside the assemblies lock, the worse that can happen
1363          * is that we'll need to free the allocated list.
1364          */
1365         for (i = 0; i < attrs->num_attrs; ++i) {
1366                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1367                 MonoAssemblyName *aname;
1368                 const gchar *data;
1369                 guint slen;
1370                 /* Do some sanity checking */
1371                 if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
1372                         continue;
1373                 if (attr->data_size < 4)
1374                         continue;
1375                 data = (const char*)attr->data;
1376                 /* 0xFF means null string, see custom attr format */
1377                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1378                         continue;
1379                 slen = mono_metadata_decode_value (data + 2, &data);
1380                 aname = g_new0 (MonoAssemblyName, 1);
1381                 /*g_print ("friend ass: %s\n", data);*/
1382                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1383                         list = g_slist_prepend (list, aname);
1384                 } else {
1385                         g_free (aname);
1386                 }
1387         }
1388         mono_custom_attrs_free (attrs);
1389
1390         mono_assemblies_lock ();
1391         if (ass->friend_assembly_names_inited) {
1392                 mono_assemblies_unlock ();
1393                 g_slist_foreach (list, free_item, NULL);
1394                 g_slist_free (list);
1395                 return;
1396         }
1397         ass->friend_assembly_names = list;
1398
1399         /* Because of the double checked locking pattern above */
1400         mono_memory_barrier ();
1401         ass->friend_assembly_names_inited = TRUE;
1402         mono_assemblies_unlock ();
1403 }
1404
1405 /**
1406  * mono_assembly_open:
1407  * @filename: Opens the assembly pointed out by this name
1408  * @status: where a status code can be returned
1409  *
1410  * mono_assembly_open opens the PE-image pointed by @filename, and
1411  * loads any external assemblies referenced by it.
1412  *
1413  * Return: a pointer to the MonoAssembly if @filename contains a valid
1414  * assembly or NULL on error.  Details about the error are stored in the
1415  * @status variable.
1416  */
1417 MonoAssembly *
1418 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1419 {
1420         return mono_assembly_open_full (filename, status, FALSE);
1421 }
1422
1423 MonoAssembly *
1424 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1425                               MonoImageOpenStatus *status, gboolean refonly)
1426 {
1427         MonoAssembly *ass, *ass2;
1428         char *base_dir;
1429
1430         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1431                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1432                 *status = MONO_IMAGE_IMAGE_INVALID;
1433                 return NULL;
1434         }
1435
1436 #if defined (PLATFORM_WIN32)
1437         {
1438                 gchar *tmp_fn;
1439                 int i;
1440
1441                 tmp_fn = g_strdup (fname);
1442                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1443                         if (tmp_fn [i] == '/')
1444                                 tmp_fn [i] = '\\';
1445                 }
1446
1447                 base_dir = absolute_dir (tmp_fn);
1448                 g_free (tmp_fn);
1449         }
1450 #else
1451         base_dir = absolute_dir (fname);
1452 #endif
1453
1454         /*
1455          * Create assembly struct, and enter it into the assembly cache
1456          */
1457         ass = g_new0 (MonoAssembly, 1);
1458         ass->basedir = base_dir;
1459         ass->ref_only = refonly;
1460         ass->image = image;
1461
1462         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1463
1464         mono_assembly_fill_assembly_name (image, &ass->aname);
1465
1466         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1467                 // MS.NET doesn't support loading other mscorlibs
1468                 g_free (ass);
1469                 g_free (base_dir);
1470                 mono_image_addref (mono_defaults.corlib);
1471                 *status = MONO_IMAGE_OK;
1472                 return mono_defaults.corlib->assembly;
1473         }
1474
1475         /* Add a non-temporary reference because of ass->image */
1476         mono_image_addref (image);
1477
1478         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);
1479
1480         /* 
1481          * The load hooks might take locks so we can't call them while holding the
1482          * assemblies lock.
1483          */
1484         if (ass->aname.name) {
1485                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE);
1486                 if (ass2) {
1487                         g_free (ass);
1488                         g_free (base_dir);
1489                         mono_image_close (image);
1490                         *status = MONO_IMAGE_OK;
1491                         return ass2;
1492                 }
1493         }
1494
1495         mono_assemblies_lock ();
1496
1497         if (image->assembly) {
1498                 /* 
1499                  * This means another thread has already loaded the assembly, but not yet
1500                  * called the load hooks so the search hook can't find the assembly.
1501                  */
1502                 mono_assemblies_unlock ();
1503                 ass2 = image->assembly;
1504                 g_free (ass);
1505                 g_free (base_dir);
1506                 mono_image_close (image);
1507                 *status = MONO_IMAGE_OK;
1508                 return ass2;
1509         }
1510
1511         image->assembly = ass;
1512
1513         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1514         mono_assemblies_unlock ();
1515
1516 #ifdef PLATFORM_WIN32
1517         if (image->is_module_handle)
1518                 mono_image_fixup_vtable (image);
1519 #endif
1520
1521         mono_assembly_invoke_load_hook (ass);
1522
1523         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1524         
1525         return ass;
1526 }
1527
1528 MonoAssembly *
1529 mono_assembly_load_from (MonoImage *image, const char *fname,
1530                          MonoImageOpenStatus *status)
1531 {
1532         return mono_assembly_load_from_full (image, fname, status, FALSE);
1533 }
1534
1535 /**
1536  * mono_assembly_name_free:
1537  * @aname: assembly name to free
1538  * 
1539  * Frees the provided assembly name object.
1540  * (it does not frees the object itself, only the name members).
1541  */
1542 void
1543 mono_assembly_name_free (MonoAssemblyName *aname)
1544 {
1545         if (aname == NULL)
1546                 return;
1547
1548         g_free ((void *) aname->name);
1549         g_free ((void *) aname->culture);
1550         g_free ((void *) aname->hash_value);
1551 }
1552
1553 static gboolean
1554 parse_public_key (const gchar *key, gchar** pubkey)
1555 {
1556         const gchar *pkey;
1557         gchar header [16], val, *arr;
1558         gint i, j, offset, bitlen, keylen, pkeylen;
1559         
1560         keylen = strlen (key) >> 1;
1561         if (keylen < 1)
1562                 return FALSE;
1563         
1564         val = g_ascii_xdigit_value (key [0]) << 4;
1565         val |= g_ascii_xdigit_value (key [1]);
1566         switch (val) {
1567                 case 0x00:
1568                         if (keylen < 13)
1569                                 return FALSE;
1570                         val = g_ascii_xdigit_value (key [24]);
1571                         val |= g_ascii_xdigit_value (key [25]);
1572                         if (val != 0x06)
1573                                 return FALSE;
1574                         pkey = key + 24;
1575                         break;
1576                 case 0x06:
1577                         pkey = key;
1578                         break;
1579                 default:
1580                         return FALSE;
1581         }
1582                 
1583         /* We need the first 16 bytes
1584         * to check whether this key is valid or not */
1585         pkeylen = strlen (pkey) >> 1;
1586         if (pkeylen < 16)
1587                 return FALSE;
1588                 
1589         for (i = 0, j = 0; i < 16; i++) {
1590                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
1591                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
1592         }
1593
1594         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
1595                         header [1] != 0x02 || /* Version (0x02) */
1596                         header [2] != 0x00 || /* Reserved (word) */
1597                         header [3] != 0x00 ||
1598                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
1599                 return FALSE;
1600
1601         /* Based on this length, we _should_ be able to know if the length is right */
1602         bitlen = read32 (header + 12) >> 3;
1603         if ((bitlen + 16 + 4) != pkeylen)
1604                 return FALSE;
1605                 
1606         /* Encode the size of the blob */
1607         offset = 0;
1608         if (keylen <= 127) {
1609                 arr = g_malloc (keylen + 1);
1610                 arr [offset++] = keylen;
1611         } else {
1612                 arr = g_malloc (keylen + 2);
1613                 arr [offset++] = 0x80; /* 10bs */
1614                 arr [offset++] = keylen;
1615         }
1616                 
1617         for (i = offset, j = 0; i < keylen + offset; i++) {
1618                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
1619                 arr [i] |= g_ascii_xdigit_value (key [j++]);
1620         }
1621         if (pubkey)
1622                 *pubkey = arr;
1623
1624         return TRUE;
1625 }
1626
1627 static gboolean
1628 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)
1629 {
1630         gint major, minor, build, revision;
1631         gint len;
1632         gint version_parts;
1633         gchar *pkey, *pkeyptr, *encoded, tok [8];
1634
1635         memset (aname, 0, sizeof (MonoAssemblyName));
1636
1637         if (version) {
1638                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
1639                 if (version_parts < 2 || version_parts > 4)
1640                         return FALSE;
1641
1642                 /* FIXME: we should set build & revision to -1 (instead of 0)
1643                 if these are not set in the version string. That way, later on,
1644                 we can still determine if these were specified. */
1645                 aname->major = major;
1646                 aname->minor = minor;
1647                 if (version_parts >= 3)
1648                         aname->build = build;
1649                 else
1650                         aname->build = 0;
1651                 if (version_parts == 4)
1652                         aname->revision = revision;
1653                 else
1654                         aname->revision = 0;
1655         }
1656         
1657         aname->flags = flags;
1658         aname->name = g_strdup (name);
1659         
1660         if (culture) {
1661                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
1662                         aname->culture = g_strdup ("");
1663                 else
1664                         aname->culture = g_strdup (culture);
1665         }
1666         
1667         if (token && strncmp (token, "null", 4) != 0) {
1668                 char *lower;
1669
1670                 /* the constant includes the ending NULL, hence the -1 */
1671                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
1672                         mono_assembly_name_free (aname);
1673                         return FALSE;
1674                 }
1675                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1676                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1677                 g_free (lower);
1678         }
1679
1680         if (key) {
1681                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) {
1682                         mono_assembly_name_free (aname);
1683                         return FALSE;
1684                 }
1685                 
1686                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
1687                 // We also need to generate the key token
1688                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
1689                 encoded = encode_public_tok ((guchar*) tok, 8);
1690                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1691                 g_free (encoded);
1692
1693                 if (save_public_key)
1694                         aname->public_key = (guint8*) pkey;
1695                 else
1696                         g_free (pkey);
1697         }
1698
1699         return TRUE;
1700 }
1701
1702 static gboolean
1703 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
1704 {
1705         gchar **parts;
1706         gboolean res;
1707         
1708         parts = g_strsplit (dirname, "_", 3);
1709         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
1710                 g_strfreev (parts);
1711                 return FALSE;
1712         }
1713         
1714         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE);
1715         g_strfreev (parts);
1716         return res;
1717 }
1718
1719 gboolean
1720 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
1721 {
1722         gchar *dllname;
1723         gchar *version = NULL;
1724         gchar *culture = NULL;
1725         gchar *token = NULL;
1726         gchar *key = NULL;
1727         gchar *retargetable = NULL;
1728         gboolean res;
1729         gchar *value;
1730         gchar **parts;
1731         gchar **tmp;
1732         gboolean version_defined;
1733         gboolean token_defined;
1734         guint32 flags = 0;
1735
1736         if (!is_version_defined)
1737                 is_version_defined = &version_defined;
1738         *is_version_defined = FALSE;
1739         if (!is_token_defined)
1740                 is_token_defined = &token_defined;
1741         *is_token_defined = FALSE;
1742         
1743         parts = tmp = g_strsplit (name, ",", 6);
1744         if (!tmp || !*tmp) {
1745                 g_strfreev (tmp);
1746                 return FALSE;
1747         }
1748
1749         dllname = g_strstrip (*tmp);
1750         
1751         tmp++;
1752
1753         while (*tmp) {
1754                 value = g_strstrip (*tmp);
1755                 if (!g_ascii_strncasecmp (value, "Version=", 8)) {
1756                         *is_version_defined = TRUE;
1757                         version = g_strstrip (value + 8);
1758                         if (strlen (version) == 0) {
1759                                 goto cleanup_and_fail;
1760                         }
1761                         tmp++;
1762                         continue;
1763                 }
1764
1765                 if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
1766                         culture = g_strstrip (value + 8);
1767                         if (strlen (culture) == 0) {
1768                                 goto cleanup_and_fail;
1769                         }
1770                         tmp++;
1771                         continue;
1772                 }
1773
1774                 if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
1775                         *is_token_defined = TRUE;
1776                         token = g_strstrip (value + 15);
1777                         if (strlen (token) == 0) {
1778                                 goto cleanup_and_fail;
1779                         }
1780                         tmp++;
1781                         continue;
1782                 }
1783
1784                 if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) {
1785                         key = g_strstrip (value + 10);
1786                         if (strlen (key) == 0) {
1787                                 goto cleanup_and_fail;
1788                         }
1789                         tmp++;
1790                         continue;
1791                 }
1792
1793                 if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) {
1794                         retargetable = g_strstrip (value + 13);
1795                         if (strlen (retargetable) == 0) {
1796                                 goto cleanup_and_fail;
1797                         }
1798                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
1799                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
1800                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
1801                                 goto cleanup_and_fail;
1802                         }
1803                         tmp++;
1804                         continue;
1805                 }
1806
1807                 if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) {
1808                         /* this is ignored for now, until we can change MonoAssemblyName */
1809                         tmp++;
1810                         continue;
1811                 }
1812
1813                 g_strfreev (parts);
1814                 return FALSE;
1815         }
1816
1817         /* if retargetable flag is set, then we must have a fully qualified name */
1818         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
1819                 goto cleanup_and_fail;
1820         }
1821
1822         res = build_assembly_name (dllname, version, culture, token, key, flags,
1823                 aname, save_public_key);
1824         g_strfreev (parts);
1825         return res;
1826
1827 cleanup_and_fail:
1828         g_strfreev (parts);
1829         return FALSE;
1830 }
1831
1832 /**
1833  * mono_assembly_name_parse:
1834  * @name: name to parse
1835  * @aname: the destination assembly name
1836  * 
1837  * Parses an assembly qualified type name and assigns the name,
1838  * version, culture and token to the provided assembly name object.
1839  *
1840  * Returns: true if the name could be parsed.
1841  */
1842 gboolean
1843 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
1844 {
1845         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
1846 }
1847
1848 static MonoAssembly*
1849 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
1850 {
1851         gchar *fullpath = NULL;
1852         GDir *dirhandle;
1853         const char* direntry;
1854         MonoAssemblyName gac_aname;
1855         gint major=-1, minor=0, build=0, revision=0;
1856         gboolean exact_version;
1857         
1858         dirhandle = g_dir_open (basepath, 0, NULL);
1859         if (!dirhandle)
1860                 return NULL;
1861                 
1862         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
1863
1864         while ((direntry = g_dir_read_name (dirhandle))) {
1865                 gboolean match = TRUE;
1866                 
1867                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
1868                         continue;
1869                 
1870                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
1871                         match = FALSE;
1872                         
1873                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
1874                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
1875                         match = FALSE;
1876                 
1877                 if (match) {
1878                         if (exact_version) {
1879                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
1880                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
1881                         }
1882                         else if (gac_aname.major < major)
1883                                 match = FALSE;
1884                         else if (gac_aname.major == major) {
1885                                 if (gac_aname.minor < minor)
1886                                         match = FALSE;
1887                                 else if (gac_aname.minor == minor) {
1888                                         if (gac_aname.build < build)
1889                                                 match = FALSE;
1890                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
1891                                                 match = FALSE; 
1892                                 }
1893                         }
1894                 }
1895                 
1896                 if (match) {
1897                         major = gac_aname.major;
1898                         minor = gac_aname.minor;
1899                         build = gac_aname.build;
1900                         revision = gac_aname.revision;
1901                         g_free (fullpath);
1902                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
1903                 }
1904
1905                 mono_assembly_name_free (&gac_aname);
1906         }
1907         
1908         g_dir_close (dirhandle);
1909         
1910         if (fullpath == NULL)
1911                 return NULL;
1912         else {
1913                 MonoAssembly *res = mono_assembly_open (fullpath, status);
1914                 g_free (fullpath);
1915                 return res;
1916         }
1917 }
1918
1919 MonoAssembly*
1920 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
1921 {
1922         MonoAssembly *res;
1923         MonoAssemblyName *aname, base_name, maped_aname;
1924         gchar *fullname, *gacpath;
1925         gchar **paths;
1926
1927         memset (&base_name, 0, sizeof (MonoAssemblyName));
1928         aname = &base_name;
1929
1930         if (!mono_assembly_name_parse (name, aname))
1931                 return NULL;
1932
1933         /* 
1934          * If no specific version has been requested, make sure we load the
1935          * correct version for system assemblies.
1936          */ 
1937         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
1938                 aname = mono_assembly_remap_version (aname, &maped_aname);
1939         
1940         res = mono_assembly_loaded (aname);
1941         if (res) {
1942                 mono_assembly_name_free (aname);
1943                 return res;
1944         }
1945
1946         res = invoke_assembly_preload_hook (aname, assemblies_path);
1947         if (res) {
1948                 res->in_gac = FALSE;
1949                 mono_assembly_name_free (aname);
1950                 return res;
1951         }
1952
1953         fullname = g_strdup_printf ("%s.dll", aname->name);
1954
1955         if (extra_gac_paths) {
1956                 paths = extra_gac_paths;
1957                 while (!res && *paths) {
1958                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
1959                         res = probe_for_partial_name (gacpath, fullname, aname, status);
1960                         g_free (gacpath);
1961                         paths++;
1962                 }
1963         }
1964
1965         if (res) {
1966                 res->in_gac = TRUE;
1967                 g_free (fullname);
1968                 mono_assembly_name_free (aname);
1969                 return res;
1970         }
1971
1972         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
1973         res = probe_for_partial_name (gacpath, fullname, aname, status);
1974         g_free (gacpath);
1975
1976         if (res)
1977                 res->in_gac = TRUE;
1978         else {
1979                 MonoDomain *domain = mono_domain_get ();
1980                 MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
1981                 if (refasm)
1982                         res = refasm->assembly;
1983         }
1984         
1985         g_free (fullname);
1986         mono_assembly_name_free (aname);
1987
1988         return res;
1989 }
1990
1991 static MonoImage*
1992 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
1993 {
1994         MonoImage *image;
1995         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
1996         gchar **paths;
1997         gint32 len;
1998
1999         if (strstr (aname->name, ".dll")) {
2000                 len = strlen (aname->name) - 4;
2001                 name = g_malloc (len);
2002                 strncpy (name, aname->name, len);
2003         } else
2004                 name = g_strdup (aname->name);
2005         
2006         if (aname->culture)
2007                 culture = g_utf8_strdown (aname->culture, -1);
2008         else
2009                 culture = g_strdup ("");
2010         
2011         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2012         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2013         g_free (name);
2014         g_free (culture);
2015         
2016         filename = g_strconcat (pname, ".dll", NULL);
2017         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2018         g_free (pname);
2019         g_free (version);
2020         g_free (filename);
2021
2022         image = NULL;
2023         if (extra_gac_paths) {
2024                 paths = extra_gac_paths;
2025                 while (!image && *paths) {
2026                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2027                                         "lib", "mono", "gac", subpath, NULL);
2028                         image = mono_image_open (fullpath, NULL);
2029                         g_free (fullpath);
2030                         paths++;
2031                 }
2032         }
2033
2034         if (image) {
2035                 g_free (subpath);
2036                 return image;
2037         }
2038
2039         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2040                         "mono", "gac", subpath, NULL);
2041         image = mono_image_open (fullpath, NULL);
2042         g_free (subpath);
2043         g_free (fullpath);
2044         
2045         return image;
2046 }
2047
2048 static MonoAssemblyName*
2049 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2050 {
2051         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2052         dest_name->major = info->new_version.major;
2053         dest_name->minor = info->new_version.minor;
2054         dest_name->build = info->new_version.build;
2055         dest_name->revision = info->new_version.revision;
2056         
2057         return dest_name;
2058 }
2059
2060 /* LOCKING: Assumes that we are already locked */
2061 static MonoAssemblyBindingInfo*
2062 search_binding_loaded (MonoAssemblyName *aname)
2063 {
2064         GSList *tmp;
2065
2066         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2067                 MonoAssemblyBindingInfo *info = tmp->data;
2068                 if (assembly_binding_maps_name (info, aname))
2069                         return info;
2070         }
2071
2072         return NULL;
2073 }
2074
2075 static MonoAssemblyName*
2076 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2077 {
2078         MonoAssemblyBindingInfo *info, *info2;
2079         MonoImage *ppimage;
2080
2081         if (aname->public_key_token [0] == 0)
2082                 return aname;
2083
2084         mono_loader_lock ();
2085         info = search_binding_loaded (aname);
2086         mono_loader_unlock ();
2087         if (info) {
2088                 if (!check_policy_versions (info, aname))
2089                         return aname;
2090                 
2091                 mono_assembly_bind_version (info, aname, dest_name);
2092                 return dest_name;
2093         }
2094
2095         info = g_new0 (MonoAssemblyBindingInfo, 1);
2096         info->major = aname->major;
2097         info->minor = aname->minor;
2098         
2099         ppimage = mono_assembly_load_publisher_policy (aname);
2100         if (ppimage) {
2101                 get_publisher_policy_info (ppimage, aname, info);
2102                 mono_image_close (ppimage);
2103         }
2104
2105         /* Define default error value if needed */
2106         if (!info->is_valid) {
2107                 info->name = g_strdup (aname->name);
2108                 info->culture = g_strdup (aname->culture);
2109                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2110         }
2111         
2112         mono_loader_lock ();
2113         info2 = search_binding_loaded (aname);
2114         if (info2) {
2115                 /* This binding was added by another thread 
2116                  * before us */
2117                 mono_assembly_binding_info_free (info);
2118                 g_free (info);
2119                 
2120                 info = info2;
2121         } else
2122                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2123                 
2124         mono_loader_unlock ();
2125         
2126         if (!info->is_valid || !check_policy_versions (info, aname))
2127                 return aname;
2128
2129         mono_assembly_bind_version (info, aname, dest_name);
2130         return dest_name;
2131 }
2132
2133 /**
2134  * mono_assembly_load_from_gac
2135  *
2136  * @aname: The assembly name object
2137  */
2138 static MonoAssembly*
2139 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2140 {
2141         MonoAssembly *result = NULL;
2142         gchar *name, *version, *culture, *fullpath, *subpath;
2143         gint32 len;
2144         gchar **paths;
2145         char *pubtok;
2146
2147         if (aname->public_key_token [0] == 0) {
2148                 return NULL;
2149         }
2150
2151         if (strstr (aname->name, ".dll")) {
2152                 len = strlen (filename) - 4;
2153                 name = g_malloc (len);
2154                 strncpy (name, aname->name, len);
2155         } else {
2156                 name = g_strdup (aname->name);
2157         }
2158
2159         if (aname->culture) {
2160                 culture = g_utf8_strdown (aname->culture, -1);
2161         } else {
2162                 culture = g_strdup ("");
2163         }
2164
2165         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2166         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
2167                         aname->minor, aname->build, aname->revision,
2168                         culture, pubtok);
2169         g_free (pubtok);
2170         
2171         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
2172         g_free (name);
2173         g_free (version);
2174         g_free (culture);
2175
2176         if (extra_gac_paths) {
2177                 paths = extra_gac_paths;
2178                 while (!result && *paths) {
2179                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
2180                         result = mono_assembly_open_full (fullpath, status, refonly);
2181                         g_free (fullpath);
2182                         paths++;
2183                 }
2184         }
2185
2186         if (result) {
2187                 result->in_gac = TRUE;
2188                 g_free (subpath);
2189                 return result;
2190         }
2191
2192         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2193                         "mono", "gac", subpath, NULL);
2194         result = mono_assembly_open_full (fullpath, status, refonly);
2195         g_free (fullpath);
2196
2197         if (result)
2198                 result->in_gac = TRUE;
2199         
2200         g_free (subpath);
2201
2202         return result;
2203 }
2204
2205
2206 MonoAssembly*
2207 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
2208 {
2209         char *corlib_file;
2210
2211         if (corlib) {
2212                 /* g_print ("corlib already loaded\n"); */
2213                 return corlib;
2214         }
2215         
2216         if (assemblies_path) {
2217                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
2218                 if (corlib)
2219                         return corlib;
2220         }
2221
2222         /* Load corlib from mono/<version> */
2223         
2224         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
2225         if (assemblies_path) {
2226                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
2227                 if (corlib) {
2228                         g_free (corlib_file);
2229                         return corlib;
2230                 }
2231         }
2232         corlib = load_in_path (corlib_file, default_path, status, FALSE);
2233         g_free (corlib_file);
2234
2235         return corlib;
2236 }
2237
2238 MonoAssembly*
2239 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
2240                                                                   const char       *basedir, 
2241                                                                   MonoImageOpenStatus *status,
2242                                                                   gboolean refonly)
2243 {
2244         MonoAssembly *result;
2245         char *fullpath, *filename;
2246         MonoAssemblyName maped_aname, maped_name_pp;
2247         int ext_index;
2248         const char *ext;
2249         int len;
2250
2251         aname = mono_assembly_remap_version (aname, &maped_aname);
2252         
2253         /* Reflection only assemblies don't get assembly binding */
2254         if (!refonly)
2255                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
2256         
2257         result = mono_assembly_loaded_full (aname, refonly);
2258         if (result)
2259                 return result;
2260
2261         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
2262         if (result) {
2263                 result->in_gac = FALSE;
2264                 return result;
2265         }
2266
2267         /* Currently we retrieve the loaded corlib for reflection 
2268          * only requests, like a common reflection only assembly 
2269          */
2270         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
2271                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
2272         }
2273
2274         len = strlen (aname->name);
2275         for (ext_index = 0; ext_index < 2; ext_index ++) {
2276                 ext = ext_index == 0 ? ".dll" : ".exe";
2277                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
2278                         filename = g_strdup (aname->name);
2279                         /* Don't try appending .dll/.exe if it already has one of those extensions */
2280                         ext_index++;
2281                 } else {
2282                         filename = g_strconcat (aname->name, ext, NULL);
2283                 }
2284
2285                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
2286                 if (result) {
2287                         g_free (filename);
2288                         return result;
2289                 }
2290
2291                 if (basedir) {
2292                         fullpath = g_build_filename (basedir, filename, NULL);
2293                         result = mono_assembly_open_full (fullpath, status, refonly);
2294                         g_free (fullpath);
2295                         if (result) {
2296                                 result->in_gac = FALSE;
2297                                 g_free (filename);
2298                                 return result;
2299                         }
2300                 }
2301
2302                 result = load_in_path (filename, default_path, status, refonly);
2303                 if (result)
2304                         result->in_gac = FALSE;
2305                 g_free (filename);
2306                 if (result)
2307                         return result;
2308         }
2309
2310         return result;
2311 }
2312
2313 /**
2314  * mono_assembly_load_full:
2315  * @aname: A MonoAssemblyName with the assembly name to load.
2316  * @basedir: A directory to look up the assembly at.
2317  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2318  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
2319  *
2320  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2321  * attempts to load the assembly from that directory before probing the standard locations.
2322  *
2323  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
2324  * assembly binding takes place.
2325  *
2326  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2327  * value pointed by status is updated with an error code.
2328  */
2329 MonoAssembly*
2330 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
2331 {
2332         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
2333         
2334         if (!result)
2335                 /* Try a postload search hook */
2336                 result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
2337         return result;
2338 }
2339
2340 /**
2341  * mono_assembly_load:
2342  * @aname: A MonoAssemblyName with the assembly name to load.
2343  * @basedir: A directory to look up the assembly at.
2344  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2345  *
2346  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2347  * attempts to load the assembly from that directory before probing the standard locations.
2348  *
2349  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2350  * value pointed by status is updated with an error code.
2351  */
2352 MonoAssembly*
2353 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
2354 {
2355         return mono_assembly_load_full (aname, basedir, status, FALSE);
2356 }
2357         
2358 MonoAssembly*
2359 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
2360 {
2361         MonoAssembly *res;
2362         MonoAssemblyName maped_aname;
2363
2364         aname = mono_assembly_remap_version (aname, &maped_aname);
2365
2366         res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
2367
2368         return res;
2369 }
2370
2371 /**
2372  * mono_assembly_loaded:
2373  * @aname: an assembly to look for.
2374  *
2375  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
2376  * a MonoAssembly that matches the MonoAssemblyName specified.
2377  */
2378 MonoAssembly*
2379 mono_assembly_loaded (MonoAssemblyName *aname)
2380 {
2381         return mono_assembly_loaded_full (aname, FALSE);
2382 }
2383
2384 /**
2385  * mono_assembly_close:
2386  * @assembly: the assembly to release.
2387  *
2388  * This method releases a reference to the @assembly.  The assembly is
2389  * only released when all the outstanding references to it are released.
2390  */
2391 void
2392 mono_assembly_close (MonoAssembly *assembly)
2393 {
2394         GSList *tmp;
2395         g_return_if_fail (assembly != NULL);
2396
2397         if (assembly == REFERENCE_MISSING)
2398                 return;
2399         
2400         /* Might be 0 already */
2401         if (InterlockedDecrement (&assembly->ref_count) > 0)
2402                 return;
2403
2404         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
2405
2406         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
2407
2408         mono_debug_close_image (assembly->image);
2409
2410         mono_assemblies_lock ();
2411         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
2412         mono_assemblies_unlock ();
2413
2414         assembly->image->assembly = NULL;
2415
2416         mono_image_close (assembly->image);
2417
2418         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
2419                 MonoAssemblyName *fname = tmp->data;
2420                 mono_assembly_name_free (fname);
2421                 g_free (fname);
2422         }
2423         g_slist_free (assembly->friend_assembly_names);
2424         g_free (assembly->basedir);
2425         if (assembly->dynamic) {
2426                 g_free ((char*)assembly->aname.culture);
2427         } else {
2428                 g_free (assembly);
2429         }
2430
2431         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
2432 }
2433
2434 MonoImage*
2435 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
2436 {
2437         return mono_image_load_file_for_image (assembly->image, idx);
2438 }
2439
2440 void
2441 mono_assembly_foreach (GFunc func, gpointer user_data)
2442 {
2443         GList *copy;
2444
2445         /*
2446          * We make a copy of the list to avoid calling the callback inside the 
2447          * lock, which could lead to deadlocks.
2448          */
2449         mono_assemblies_lock ();
2450         copy = g_list_copy (loaded_assemblies);
2451         mono_assemblies_unlock ();
2452
2453         g_list_foreach (loaded_assemblies, func, user_data);
2454
2455         g_list_free (copy);
2456 }
2457
2458 /**
2459  * mono_assemblies_cleanup:
2460  *
2461  * Free all resources used by this module.
2462  */
2463 void
2464 mono_assemblies_cleanup (void)
2465 {
2466         GSList *l;
2467
2468         DeleteCriticalSection (&assemblies_mutex);
2469
2470         for (l = loaded_assembly_bindings; l; l = l->next) {
2471                 MonoAssemblyBindingInfo *info = l->data;
2472
2473                 mono_assembly_binding_info_free (info);
2474                 g_free (info);
2475         }
2476         g_slist_free (loaded_assembly_bindings);
2477
2478         free_assembly_load_hooks ();
2479         free_assembly_search_hooks ();
2480         free_assembly_preload_hooks ();
2481 }
2482
2483 /*
2484  * Holds the assembly of the application, for
2485  * System.Diagnostics.Process::MainModule
2486  */
2487 static MonoAssembly *main_assembly=NULL;
2488
2489 void
2490 mono_assembly_set_main (MonoAssembly *assembly)
2491 {
2492         main_assembly = assembly;
2493 }
2494
2495 /**
2496  * mono_assembly_get_main:
2497  *
2498  * Returns: the assembly for the application, the first assembly that is loaded by the VM
2499  */
2500 MonoAssembly *
2501 mono_assembly_get_main (void)
2502 {
2503         return (main_assembly);
2504 }
2505
2506 /**
2507  * mono_assembly_get_image:
2508  * @assembly: The assembly to retrieve the image from
2509  *
2510  * Returns: the MonoImage associated with this assembly.
2511  */
2512 MonoImage*
2513 mono_assembly_get_image (MonoAssembly *assembly)
2514 {
2515         return assembly->image;
2516 }
2517
2518 void
2519 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
2520 {
2521         bundles = assemblies;
2522 }
2523
2524 #define MONO_DECLSEC_FORMAT_20          0x2E
2525 #define MONO_DECLSEC_FIELD              0x53
2526 #define MONO_DECLSEC_PROPERTY           0x54
2527
2528 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
2529 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
2530 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
2531 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
2532
2533 static gboolean
2534 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
2535 {
2536         int len;
2537         switch (*p++) {
2538         case MONO_DECLSEC_PROPERTY:
2539                 break;
2540         case MONO_DECLSEC_FIELD:
2541         default:
2542                 *abort_decoding = TRUE;
2543                 return FALSE;
2544                 break;
2545         }
2546
2547         if (*p++ != MONO_TYPE_BOOLEAN) {
2548                 *abort_decoding = TRUE;
2549                 return FALSE;
2550         }
2551                 
2552         /* property name length */
2553         len = mono_metadata_decode_value (p, &p);
2554
2555         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
2556                 p += len;
2557                 return *p;
2558         }
2559         p += len + 1;
2560
2561         *resp = p;
2562         return FALSE;
2563 }
2564
2565 static gboolean
2566 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
2567 {
2568         int i, j, num, len, params_len;
2569
2570         if (*p++ != MONO_DECLSEC_FORMAT_20)
2571                 return FALSE;
2572
2573         /* number of encoded permission attributes */
2574         num = mono_metadata_decode_value (p, &p);
2575         for (i = 0; i < num; ++i) {
2576                 gboolean is_valid = FALSE;
2577                 gboolean abort_decoding = FALSE;
2578
2579                 /* attribute name length */
2580                 len =  mono_metadata_decode_value (p, &p);
2581
2582                 /* We don't really need to fully decode the type. Comparing the name is enough */
2583                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
2584
2585                 p += len;
2586
2587                 /*size of the params table*/
2588                 params_len =  mono_metadata_decode_value (p, &p);
2589                 if (is_valid) {
2590                         const char *params_end = p + params_len;
2591                         
2592                         /* number of parameters */
2593                         len = mono_metadata_decode_value (p, &p);
2594         
2595                         for (j = 0; j < len; ++j) {
2596                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
2597                                         return TRUE;
2598                                 if (abort_decoding)
2599                                         break;
2600                         }
2601                         p = params_end;
2602                 } else {
2603                         p += params_len;
2604                 }
2605         }
2606         
2607         return FALSE;
2608 }
2609
2610
2611 gboolean
2612 mono_assembly_has_skip_verification (MonoAssembly *assembly)
2613 {
2614         MonoTableInfo *t;       
2615         guint32 cols [MONO_DECL_SECURITY_SIZE];
2616         const char *blob;
2617         int i, len;
2618
2619         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
2620                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
2621
2622         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
2623
2624         for (i = 0; i < t->rows; ++i) {
2625                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
2626                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
2627                         continue;
2628                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
2629                         continue;
2630
2631                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
2632                 len = mono_metadata_decode_blob_size (blob, &blob);
2633                 if (!len)
2634                         continue;
2635
2636                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
2637                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
2638                         return TRUE;
2639                 }
2640         }
2641
2642         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
2643         return FALSE;
2644 }