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