2005-08-20 Carlos Alberto Cortez <calberto.cortez@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 "cil-coff.h"
19 #include "rawbuffer.h"
20 #include <mono/metadata/loader.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/domain-internals.h>
25 #include <mono/io-layer/io-layer.h>
26 #include <mono/utils/mono-uri.h>
27 #include <mono/metadata/mono-config.h>
28 #include <mono/utils/mono-digest.h>
29 #include <mono/utils/mono-logger.h>
30 #ifdef PLATFORM_WIN32
31 #include <mono/os/util.h>
32 #ifdef _MSC_VER
33         /* not used on Windows - see mono_set_rootdir () */
34         #define MONO_ASSEMBLIES         NULL
35 #endif
36 #endif
37
38 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
39 typedef struct  {
40         const char* assembly_name;
41         guint8 version_set_index;
42 } AssemblyVersionMap;
43
44 /* the default search path is just MONO_ASSEMBLIES */
45 static const char*
46 default_path [] = {
47         MONO_ASSEMBLIES,
48         NULL
49 };
50
51 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
52 static char **assemblies_path = NULL;
53
54 /* Contains the list of directories that point to auxiliary GACs */
55 static char **extra_gac_paths = NULL;
56
57 /* The list of system assemblies what will be remapped to the running
58  * runtime version. WARNING: this list must be sorted.
59  */
60 static const AssemblyVersionMap framework_assemblies [] = {
61         {"Accessibility", 0},
62         {"Commons.Xml.Relaxng", 0},
63         {"I18N", 0},
64         {"I18N.CJK", 0},
65         {"I18N.MidEast", 0},
66         {"I18N.Other", 0},
67         {"I18N.Rare", 0},
68         {"I18N.West", 0},
69         {"Microsoft.VisualBasic", 1},
70         {"Microsoft.VisualC", 1},
71         {"Mono.Cairo", 0},
72         {"Mono.CompilerServices.SymbolWriter", 0},
73         {"Mono.Data", 0},
74         {"Mono.Data.SqliteClient", 0},
75         {"Mono.Data.SybaseClient", 0},
76         {"Mono.Data.Tds", 0},
77         {"Mono.Data.TdsClient", 0},
78         {"Mono.GetOptions", 0},
79         {"Mono.Http", 0},
80         {"Mono.Posix", 0},
81         {"Mono.Security", 0},
82         {"Mono.Security.Win32", 0},
83         {"Mono.Xml.Ext", 0},
84         {"Novell.Directory.Ldap", 0},
85         {"Npgsql", 0},
86         {"PEAPI", 0},
87         {"System", 0},
88         {"System.Configuration.Install", 0},
89         {"System.Data", 0},
90         {"System.Data.OracleClient", 0},
91         {"System.Data.SqlXml", 0},
92         {"System.Design", 0},
93         {"System.DirectoryServices", 0},
94         {"System.Drawing", 0},
95         {"System.Drawing.Design", 0},
96         {"System.EnterpriseServices", 0},
97         {"System.Management", 0},
98         {"System.Messaging", 0},
99         {"System.Runtime.Remoting", 0},
100         {"System.Runtime.Serialization.Formatters.Soap", 0},
101         {"System.Security", 0},
102         {"System.ServiceProcess", 0},
103         {"System.Web", 0},
104         {"System.Web.Mobile", 0},
105         {"System.Web.Services", 0},
106         {"System.Windows.Forms", 0},
107         {"System.Xml", 0},
108         {"mscorlib", 0}
109 };
110
111 /*
112  * keeps track of loaded assemblies
113  */
114 static GList *loaded_assemblies = NULL;
115 static MonoAssembly *corlib;
116
117 /* This protects loaded_assemblies and image->references */
118 static CRITICAL_SECTION assemblies_mutex;
119
120 /* A hastable of thread->assembly list mappings */
121 static GHashTable *assemblies_loading;
122
123 /* A hashtable of reflection only load thread->assemblies mappings */
124 static GHashTable *assemblies_refonly_loading;
125
126 /* If defined, points to the bundled assembly information */
127 const MonoBundledAssembly **bundles;
128
129 /* Reflection only private hook functions */
130 static MonoAssembly* mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname);
131
132 /* Loaded assembly binding info */
133 static GSList *loaded_assembly_bindings = NULL;
134
135 static gchar*
136 encode_public_tok (const guchar *token, gint32 len)
137 {
138         const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
139         gchar *res;
140         int i;
141
142         res = g_malloc (len * 2 + 1);
143         for (i = 0; i < len; i++) {
144                 res [i * 2] = allowed [token [i] >> 4];
145                 res [i * 2 + 1] = allowed [token [i] & 0xF];
146         }
147         res [len * 2] = 0;
148         return res;
149 }
150
151 static void
152 check_path_env (void)
153 {
154         const char *path;
155         char **splitted;
156         
157         path = g_getenv ("MONO_PATH");
158         if (!path)
159                 return;
160
161         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
162         if (assemblies_path)
163                 g_strfreev (assemblies_path);
164         assemblies_path = splitted;
165         if (g_getenv ("MONO_DEBUG") == NULL)
166                 return;
167
168         while (*splitted) {
169                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
170                         g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
171
172                 splitted++;
173         }
174 }
175
176 static void
177 check_extra_gac_path_env (void) {
178         const char *path;
179         char **splitted;
180         
181         path = g_getenv ("MONO_GAC_PREFIX");
182         if (!path)
183                 return;
184
185         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
186         if (extra_gac_paths)
187                 g_strfreev (extra_gac_paths);
188         extra_gac_paths = splitted;
189         if (g_getenv ("MONO_DEBUG") == NULL)
190                 return;
191
192         while (*splitted) {
193                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
194                         g_warning ("'%s' in MONO_GAC_PATH doesn't exist or has wrong permissions.", *splitted);
195
196                 splitted++;
197         }
198 }
199
200 static gboolean
201 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
202 {
203         if (strcmp (info->name, aname->name))
204                 return FALSE;
205
206         if (info->major != aname->major || info->minor != aname->minor)
207                 return FALSE;
208
209         if ((info->culture != NULL) != (aname->culture != NULL))
210                 return FALSE;
211         
212         if (info->culture && strcmp (info->culture, aname->culture))
213                 return FALSE;
214         
215         if (strcmp ((const char *)info->public_key_token, (const char *)aname->public_key_token))
216                 return FALSE;
217
218         return TRUE;
219 }
220
221 static void
222 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
223 {
224         g_free (info->name);
225         g_free (info->culture);
226 }
227
228 static void
229 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
230 {
231         MonoTableInfo *t;
232         guint32 cols [MONO_MANIFEST_SIZE];
233         const gchar *filename;
234         gchar *subpath, *fullpath;
235
236         t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
237         /* MS Impl. accepts policy assemblies with more than
238          * one manifest resource, and only takes the first one */
239         if (t->rows < 1) {
240                 binding_info->is_valid = FALSE;
241                 return;
242         }
243         
244         mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
245         if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
246                 binding_info->is_valid = FALSE;
247                 return;
248         }
249         
250         filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
251         g_assert (filename != NULL);
252         
253         subpath = g_path_get_dirname (image->name);
254         fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
255         mono_config_parse_publisher_policy (fullpath, binding_info);
256         g_free (subpath);
257         g_free (fullpath);
258         
259         /* Define the optional elements/attributes before checking */
260         if (!binding_info->culture)
261                 binding_info->culture = g_strdup ("");
262         
263         /* Check that the most important elements/attributes exist */
264         if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
265                         !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
266                 mono_assembly_binding_info_free (binding_info);
267                 binding_info->is_valid = FALSE;
268                 return;
269         }
270
271         binding_info->is_valid = TRUE;
272 }
273
274 static int
275 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
276 {
277         if (v->major > aname->major)
278                 return 1;
279         else if (v->major < aname->major)
280                 return -1;
281
282         if (v->minor > aname->minor)
283                 return 1;
284         else if (v->minor < aname->minor)
285                 return -1;
286
287         if (v->build > aname->build)
288                 return 1;
289         else if (v->build < aname->build)
290                 return -1;
291
292         if (v->revision > aname->revision)
293                 return 1;
294         else if (v->revision < aname->revision)
295                 return -1;
296
297         return 0;
298 }
299
300 static gboolean
301 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
302 {
303         if (!info->is_valid)
304                 return FALSE;
305         
306         /* If has_old_version_top doesn't exist, we don't have an interval */
307         if (!info->has_old_version_top) {
308                 if (compare_versions (&info->old_version_bottom, name) == 0)
309                         return TRUE;
310
311                 return FALSE;
312         }
313
314         /* Check that the version defined by name is valid for the interval */
315         if (compare_versions (&info->old_version_top, name) < 0)
316                 return FALSE;
317
318         /* We should be greater or equal than the small version */
319         if (compare_versions (&info->old_version_bottom, name) > 0)
320                 return FALSE;
321
322         return TRUE;
323 }
324
325 gboolean
326 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
327 {
328         if (!l->name || !r->name)
329                 return FALSE;
330
331         if (strcmp (l->name, r->name))
332                 return FALSE;
333
334         if (l->culture && r->culture && strcmp (l->culture, r->culture))
335                 return FALSE;
336
337         if (l->major != r->major || l->minor != r->minor ||
338                         l->build != r->build || l->revision != r->revision)
339                 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)))
340                         return FALSE;
341
342         if (!l->public_key_token [0] || !r->public_key_token [0])
343                 return TRUE;
344
345         if (strcmp (l->public_key_token, r->public_key_token))
346                 return FALSE;
347
348         return TRUE;
349 }
350
351 static MonoAssembly*
352 search_loaded (MonoAssemblyName* aname, gboolean refonly)
353 {
354         GList *tmp;
355         MonoAssembly *ass;
356         GList *loading;
357
358         ass = refonly ? mono_assembly_refonly_invoke_search_hook (aname) : mono_assembly_invoke_search_hook (aname);
359         if (ass)
360                 return ass;
361         
362         /*
363          * The assembly might be under load by this thread. In this case, it is
364          * safe to return an incomplete instance to prevent loops.
365          */
366         loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, GetCurrentThread ());
367         for (tmp = loading; tmp; tmp = tmp->next) {
368                 ass = tmp->data;
369                 if (!mono_assembly_names_equal (aname, &ass->aname))
370                         continue;
371
372                 return ass;
373         }
374
375         return NULL;
376 }
377
378 static MonoAssembly *
379 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
380 {
381         int i;
382         char *fullpath;
383         MonoAssembly *result;
384
385         for (i = 0; search_path [i]; ++i) {
386                 fullpath = g_build_filename (search_path [i], basename, NULL);
387                 result = mono_assembly_open_full (fullpath, status, refonly);
388                 g_free (fullpath);
389                 if (result)
390                         return result;
391         }
392         return NULL;
393 }
394
395 /**
396  * mono_assembly_setrootdir:
397  * @root_dir: The pathname of the root directory where we will locate assemblies
398  *
399  * This routine sets the internal default root directory for looking up
400  * assemblies.  This is used by Windows installations to compute dynamically
401  * the place where the Mono assemblies are located.
402  *
403  */
404 void
405 mono_assembly_setrootdir (const char *root_dir)
406 {
407         /*
408          * Override the MONO_ASSEMBLIES directory configured at compile time.
409          */
410         /* Leak if called more than once */
411         default_path [0] = g_strdup (root_dir);
412 }
413
414 G_CONST_RETURN gchar *
415 mono_assembly_getrootdir (void)
416 {
417         return default_path [0];
418 }
419
420 /**
421  * mono_assemblies_init:
422  *
423  *  Initialize global variables used by this module.
424  */
425 void
426 mono_assemblies_init (void)
427 {
428 #ifdef PLATFORM_WIN32
429         mono_set_rootdir ();
430 #endif
431
432         check_path_env ();
433         check_extra_gac_path_env ();
434
435         InitializeCriticalSection (&assemblies_mutex);
436
437         assemblies_loading = g_hash_table_new (NULL, NULL);
438         assemblies_refonly_loading = g_hash_table_new (NULL, NULL);
439 }
440
441 gboolean
442 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
443 {
444         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
445         guint32 cols [MONO_ASSEMBLY_SIZE];
446
447         if (!t->rows)
448                 return FALSE;
449
450         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
451
452         aname->hash_len = 0;
453         aname->hash_value = NULL;
454         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
455         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
456         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
457         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
458         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
459         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
460         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
461         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
462         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
463                 gchar* token = g_malloc (8);
464                 gchar* encoded;
465                 int len;
466
467                 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
468                 len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
469
470                 mono_digest_get_public_token (token, aname->public_key, len);
471                 encoded = encode_public_tok (token, 8);
472                 g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
473
474                 g_free (encoded);
475                 g_free (token);
476         }
477         else {
478                 aname->public_key = NULL;
479                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
480         }
481
482         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
483                 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
484         }
485         else
486                 aname->public_key = 0;
487
488         return TRUE;
489 }
490
491 static gchar*
492 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
493 {
494         const gchar *public_tok;
495         int len;
496
497         public_tok = mono_metadata_blob_heap (image, key_index);
498         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
499
500         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
501                 gchar token [8];
502                 mono_digest_get_public_token (token, public_tok, len);
503                 return encode_public_tok (token, 8);
504         }
505
506         return encode_public_tok (public_tok, len);
507 }
508
509 void
510 mono_assembly_addref (MonoAssembly *assembly)
511 {
512         InterlockedIncrement (&assembly->ref_count);
513 }
514
515 static MonoAssemblyName *
516 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
517 {
518         const MonoRuntimeInfo *current_runtime;
519         int pos, first, last;
520
521         if (aname->name == NULL) return aname;
522         current_runtime = mono_get_runtime_info ();
523
524         first = 0;
525         last = G_N_ELEMENTS (framework_assemblies) - 1;
526         
527         while (first <= last) {
528                 int res;
529                 pos = first + (last - first) / 2;
530                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
531                 if (res == 0) {
532                         const AssemblyVersionSet* vset;
533                         int index = framework_assemblies[pos].version_set_index;
534                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
535                         vset = &current_runtime->version_sets [index];
536
537                         if (aname->major == vset->major && aname->minor == vset->minor &&
538                                 aname->build == vset->build && aname->revision == vset->revision)
539                                 return aname;
540                 
541                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
542                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
543                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
544                                                         aname->name,
545                                                         aname->major, aname->minor, aname->build, aname->revision,
546                                                         vset->major, vset->minor, vset->build, vset->revision
547                                                         );
548                         
549                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
550                         dest_aname->major = vset->major;
551                         dest_aname->minor = vset->minor;
552                         dest_aname->build = vset->build;
553                         dest_aname->revision = vset->revision;
554                         return dest_aname;
555                 } else if (res < 0) {
556                         last = pos - 1;
557                 } else {
558                         first = pos + 1;
559                 }
560         }
561         return aname;
562 }
563
564 void
565 mono_assembly_load_reference (MonoImage *image, int index)
566 {
567         MonoTableInfo *t;
568         guint32 cols [MONO_ASSEMBLYREF_SIZE];
569         const char *hash;
570         MonoAssembly *reference;
571         MonoAssemblyName aname;
572         MonoImageOpenStatus status;
573
574         /*
575          * image->references is shared between threads, so we need to access
576          * it inside a critical section.
577          */
578         EnterCriticalSection (&assemblies_mutex);
579         reference = image->references [index];
580         LeaveCriticalSection (&assemblies_mutex);
581         if (reference)
582                 return;
583
584         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
585
586         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
587                 
588         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
589         aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
590         aname.hash_value = hash;
591         aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
592         aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
593         aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
594         aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
595         aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
596         aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
597         aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
598
599         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
600                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
601                 g_strlcpy (aname.public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
602                 g_free (token);
603         } else {
604                 memset (aname.public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
605         }
606
607         if (image->assembly->ref_only) {
608                 /* We use the loaded corlib */
609                 if (!strcmp (aname.name, "mscorlib"))
610                         reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
611                 else
612                         reference = mono_assembly_loaded_full (&aname, TRUE);
613                 /*
614                  * Here we must advice that the error was due to
615                  * a non loaded reference using the ReflectionOnly api
616                 */
617                 if (!reference)
618                         reference = (gpointer)-1;
619         } else
620                 reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
621
622         if (reference == NULL){
623                 char *extra_msg = g_strdup ("");
624
625                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
626                         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);
627                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
628                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
629                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
630                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
631                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
632                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
633                 }
634                 
635                 g_warning ("The following assembly referenced from %s could not be loaded:\n"
636                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
637                                    "     Version:    %d.%d.%d.%d\n"
638                                    "     Public Key: %s\n%s",
639                                    image->name, aname.name, index,
640                                    aname.major, aname.minor, aname.build, aname.revision,
641                                    strlen(aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
642                 g_free (extra_msg);
643         }
644
645         EnterCriticalSection (&assemblies_mutex);
646         if (reference == NULL) {
647                 /* Flag as not found */
648                 reference = (gpointer)-1;
649         } else {
650                 mono_assembly_addref (reference);
651         }       
652
653         if (!image->references [index])
654                 image->references [index] = reference;
655         LeaveCriticalSection (&assemblies_mutex);
656
657         if (image->references [index] != reference) {
658                 /* Somebody loaded it before us */
659                 mono_assembly_close (reference);
660         }
661 }
662
663 void
664 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
665 {
666         MonoTableInfo *t;
667         int i;
668
669         *status = MONO_IMAGE_OK;
670
671         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
672         
673         image->references = g_new0 (MonoAssembly *, t->rows + 1);
674
675         /* resolve assembly references for modules */
676         for (i = 0; i < image->module_count; i++){
677                 if (image->modules [i]) {
678                         image->modules [i]->assembly = image->assembly;
679                         mono_assembly_load_references (image->modules [i], status);
680                 }
681         }
682 }
683
684 typedef struct AssemblyLoadHook AssemblyLoadHook;
685 struct AssemblyLoadHook {
686         AssemblyLoadHook *next;
687         MonoAssemblyLoadFunc func;
688         gpointer user_data;
689 };
690
691 AssemblyLoadHook *assembly_load_hook = NULL;
692
693 void
694 mono_assembly_invoke_load_hook (MonoAssembly *ass)
695 {
696         AssemblyLoadHook *hook;
697
698         for (hook = assembly_load_hook; hook; hook = hook->next) {
699                 hook->func (ass, hook->user_data);
700         }
701 }
702
703 void
704 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
705 {
706         AssemblyLoadHook *hook;
707         
708         g_return_if_fail (func != NULL);
709
710         hook = g_new0 (AssemblyLoadHook, 1);
711         hook->func = func;
712         hook->user_data = user_data;
713         hook->next = assembly_load_hook;
714         assembly_load_hook = hook;
715 }
716
717 typedef struct AssemblySearchHook AssemblySearchHook;
718 struct AssemblySearchHook {
719         AssemblySearchHook *next;
720         MonoAssemblySearchFunc func;
721         gpointer user_data;
722 };
723
724 AssemblySearchHook *assembly_search_hook = NULL;
725 static AssemblySearchHook *assembly_refonly_search_hook = NULL;
726
727 MonoAssembly*
728 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
729 {
730         AssemblySearchHook *hook;
731
732         for (hook = assembly_search_hook; hook; hook = hook->next) {
733                 MonoAssembly *ass = hook->func (aname, hook->user_data);
734                 if (ass)
735                         return ass;
736         }
737
738         return NULL;
739 }
740
741 static MonoAssembly*
742 mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname)
743 {
744         AssemblySearchHook *hook;
745
746         for (hook = assembly_refonly_search_hook; hook; hook = hook->next) {
747                 MonoAssembly *ass = hook->func (aname, hook->user_data);
748                 if (ass)
749                         return ass;
750         }
751
752         return NULL;
753 }
754
755 void          
756 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
757 {
758         AssemblySearchHook *hook;
759         
760         g_return_if_fail (func != NULL);
761
762         hook = g_new0 (AssemblySearchHook, 1);
763         hook->func = func;
764         hook->user_data = user_data;
765         hook->next = assembly_search_hook;
766         assembly_search_hook = hook;
767 }       
768
769 void
770 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
771 {
772         AssemblySearchHook *hook;
773
774         g_return_if_fail (func != NULL);
775
776         hook = g_new0 (AssemblySearchHook, 1);
777         hook->func = func;
778         hook->user_data = user_data;
779         hook->next = assembly_refonly_search_hook;
780         assembly_refonly_search_hook = hook;
781 }
782
783 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
784 struct AssemblyPreLoadHook {
785         AssemblyPreLoadHook *next;
786         MonoAssemblyPreLoadFunc func;
787         gpointer user_data;
788 };
789
790 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
791 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
792
793 static MonoAssembly *
794 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
795 {
796         AssemblyPreLoadHook *hook;
797         MonoAssembly *assembly;
798
799         for (hook = assembly_preload_hook; hook; hook = hook->next) {
800                 assembly = hook->func (aname, assemblies_path, hook->user_data);
801                 if (assembly != NULL)
802                         return assembly;
803         }
804
805         return NULL;
806 }
807
808 static MonoAssembly *
809 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
810 {
811         AssemblyPreLoadHook *hook;
812         MonoAssembly *assembly;
813
814         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
815                 assembly = hook->func (aname, assemblies_path, hook->user_data);
816                 if (assembly != NULL)
817                         return assembly;
818         }
819
820         return NULL;
821 }
822
823 void
824 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
825 {
826         AssemblyPreLoadHook *hook;
827         
828         g_return_if_fail (func != NULL);
829
830         hook = g_new0 (AssemblyPreLoadHook, 1);
831         hook->func = func;
832         hook->user_data = user_data;
833         hook->next = assembly_preload_hook;
834         assembly_preload_hook = hook;
835 }
836
837 void
838 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
839 {
840         AssemblyPreLoadHook *hook;
841         
842         g_return_if_fail (func != NULL);
843
844         hook = g_new0 (AssemblyPreLoadHook, 1);
845         hook->func = func;
846         hook->user_data = user_data;
847         hook->next = assembly_refonly_preload_hook;
848         assembly_refonly_preload_hook = hook;
849 }
850
851 static gchar *
852 absolute_dir (const gchar *filename)
853 {
854         gchar *cwd;
855         gchar *mixed;
856         gchar **parts;
857         gchar *part;
858         GList *list, *tmp;
859         GString *result;
860         gchar *res;
861         gint i;
862
863         if (g_path_is_absolute (filename))
864                 return g_path_get_dirname (filename);
865
866         cwd = g_get_current_dir ();
867         mixed = g_build_filename (cwd, filename, NULL);
868         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
869         g_free (mixed);
870         g_free (cwd);
871
872         list = NULL;
873         for (i = 0; (part = parts [i]) != NULL; i++) {
874                 if (!strcmp (part, "."))
875                         continue;
876
877                 if (!strcmp (part, "..")) {
878                         if (list && list->next) /* Don't remove root */
879                                 list = g_list_delete_link (list, list);
880                 } else {
881                         list = g_list_prepend (list, part);
882                 }
883         }
884
885         result = g_string_new ("");
886         list = g_list_reverse (list);
887
888         /* Ignores last data pointer, which should be the filename */
889         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
890                 if (tmp->data)
891                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
892                                                                 G_DIR_SEPARATOR);
893         
894         res = result->str;
895         g_string_free (result, FALSE);
896         g_list_free (list);
897         g_strfreev (parts);
898         if (*res == '\0') {
899                 g_free (res);
900                 return g_strdup (".");
901         }
902
903         return res;
904 }
905
906 /** 
907  * mono_assembly_open_from_bundle:
908  * @filename: Filename requested
909  * @status: return value
910  *
911  * This routine tries to open the assembly specified by `filename' from the
912  * defined bundles, if found, returns the MonoImage for it, if not found
913  * returns NULL
914  */
915 static MonoImage *
916 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
917 {
918         int i;
919         char *name = g_path_get_basename (filename);
920         MonoImage *image = NULL;
921
922         /*
923          * we do a very simple search for bundled assemblies: it's not a general 
924          * purpose assembly loading mechanism.
925          */
926         EnterCriticalSection (&assemblies_mutex);
927         for (i = 0; !image && bundles [i]; ++i) {
928                 if (strcmp (bundles [i]->name, name) == 0) {
929                         image = mono_image_open_from_data_full ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly);
930                         break;
931                 }
932         }
933         LeaveCriticalSection (&assemblies_mutex);
934         g_free (name);
935         if (image) {
936                 mono_image_addref (image);
937                 return image;
938         }
939         return NULL;
940 }
941
942 static MonoImage*
943 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
944 {
945         MonoImage *image = NULL;
946
947         if (bundles != NULL){
948                 image = mono_assembly_open_from_bundle (filename, status, refonly);
949
950                 if (image != NULL)
951                         return image;
952         }
953         EnterCriticalSection (&assemblies_mutex);
954         image = mono_image_open_full (filename, status, refonly);
955         LeaveCriticalSection (&assemblies_mutex);
956
957         return image;
958 }
959
960 MonoAssembly *
961 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
962 {
963         MonoImage *image;
964         MonoAssembly *ass;
965         MonoImageOpenStatus def_status;
966         gchar *fname;
967         
968         g_return_val_if_fail (filename != NULL, NULL);
969
970         if (!status)
971                 status = &def_status;
972         *status = MONO_IMAGE_OK;
973
974         if (strncmp (filename, "file://", 7) == 0) {
975                 GError *error = NULL;
976                 gchar *uri = (gchar *) filename;
977                 gchar *tmpuri;
978
979                 /*
980                  * MS allows file://c:/... and fails on file://localhost/c:/... 
981                  * They also throw an IndexOutOfRangeException if "file://"
982                  */
983                 if (uri [7] != '/')
984                         uri = g_strdup_printf ("file:///%s", uri + 7);
985         
986                 tmpuri = uri;
987                 uri = mono_escape_uri_string (tmpuri);
988                 fname = g_filename_from_uri (uri, NULL, &error);
989                 g_free (uri);
990
991                 if (tmpuri != filename)
992                         g_free (tmpuri);
993
994                 if (error != NULL) {
995                         g_warning ("%s\n", error->message);
996                         g_error_free (error);
997                         fname = g_strdup (filename);
998                 }
999         } else {
1000                 fname = g_strdup (filename);
1001         }
1002
1003         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1004                         "Assembly Loader probing location: '%s'.", filename);
1005         image = do_mono_assembly_open (fname, status, refonly);
1006
1007         if (!image){
1008                 *status = MONO_IMAGE_ERROR_ERRNO;
1009                 g_free (fname);
1010                 return NULL;
1011         }
1012
1013         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1014
1015         if (ass) {
1016                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1017                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1018                 if (!refonly)
1019                         mono_config_for_assembly (ass->image);
1020         }
1021
1022         g_free (fname);
1023
1024         return ass;
1025 }
1026
1027 /**
1028  * mono_assembly_open:
1029  * @filename: Opens the assembly pointed out by this name
1030  * @status: where a status code can be returned
1031  *
1032  * mono_assembly_open opens the PE-image pointed by @filename, and
1033  * loads any external assemblies referenced by it.
1034  *
1035  * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
1036  * it. 
1037  */
1038 MonoAssembly *
1039 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1040 {
1041         return mono_assembly_open_full (filename, status, FALSE);
1042 }
1043
1044 MonoAssembly *
1045 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1046                          MonoImageOpenStatus *status, gboolean refonly)
1047 {
1048         MonoAssembly *ass, *ass2;
1049         char *base_dir;
1050         GList *loading;
1051         GHashTable *ass_loading;
1052
1053 #if defined (PLATFORM_WIN32)
1054         {
1055                 gchar *tmp_fn;
1056                 int i;
1057
1058                 tmp_fn = g_strdup (fname);
1059                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1060                         if (tmp_fn [i] == '/')
1061                                 tmp_fn [i] = '\\';
1062                 }
1063
1064                 base_dir = absolute_dir (tmp_fn);
1065                 g_free (tmp_fn);
1066         }
1067 #else
1068         base_dir = absolute_dir (fname);
1069 #endif
1070
1071         /*
1072          * To avoid deadlocks and scalability problems, we load assemblies outside
1073          * the assembly lock. This means that multiple threads might try to load
1074          * the same assembly at the same time. The first one to load it completely
1075          * "wins", the other threads free their copy and use the one loaded by
1076          * the winning thread.
1077          */
1078
1079         /*
1080          * Create assembly struct, and enter it into the assembly cache
1081          */
1082         ass = g_new0 (MonoAssembly, 1);
1083         ass->basedir = base_dir;
1084         ass->ref_only = refonly;
1085         ass->image = image;
1086         ass->ref_count = 1;
1087
1088         mono_assembly_fill_assembly_name (image, &ass->aname);
1089
1090         /* 
1091          * Atomically search the loaded list and add ourselves to it if necessary.
1092          */
1093         EnterCriticalSection (&assemblies_mutex);
1094         if (ass->aname.name) {
1095                 /* avoid loading the same assembly twice for now... */
1096                 ass2 = search_loaded (&ass->aname, refonly);
1097                 if (ass2) {
1098                         g_free (ass);
1099                         g_free (base_dir);
1100                         mono_image_close (image);
1101                         *status = MONO_IMAGE_OK;
1102                         LeaveCriticalSection (&assemblies_mutex);
1103                         return ass2;
1104                 }
1105         }
1106         ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading;
1107         loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
1108         loading = g_list_prepend (loading, ass);
1109         g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
1110         LeaveCriticalSection (&assemblies_mutex);
1111
1112         image->assembly = ass;
1113
1114         mono_assembly_load_references (image, status);
1115
1116         EnterCriticalSection (&assemblies_mutex);
1117
1118         loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
1119         loading = g_list_remove (loading, ass);
1120         if (loading == NULL)
1121                 /* Prevent memory leaks */
1122                 g_hash_table_remove (ass_loading, GetCurrentThread ());
1123         else
1124                 g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
1125         if (*status != MONO_IMAGE_OK) {
1126                 LeaveCriticalSection (&assemblies_mutex);
1127                 mono_assembly_close (ass);
1128                 return NULL;
1129         }
1130
1131         if (ass->aname.name) {
1132                 ass2 = search_loaded (&ass->aname, refonly);
1133                 if (ass2) {
1134                         /* Somebody else has loaded the assembly before us */
1135                         LeaveCriticalSection (&assemblies_mutex);
1136                         mono_assembly_close (ass);
1137                         return ass2;
1138                 }
1139         }
1140
1141         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1142         LeaveCriticalSection (&assemblies_mutex);
1143
1144         mono_assembly_invoke_load_hook (ass);
1145
1146         return ass;
1147 }
1148
1149 MonoAssembly *
1150 mono_assembly_load_from (MonoImage *image, const char *fname,
1151                          MonoImageOpenStatus *status)
1152 {
1153         return mono_assembly_load_from_full (image, fname, status, FALSE);
1154 }
1155
1156 /**
1157 * mono_assembly_name_free:
1158 * @aname: assembly name to free
1159
1160 * Frees the provided assembly name object.
1161 * (it does not frees the object itself, only the name members).
1162 */
1163 void
1164 mono_assembly_name_free (MonoAssemblyName *aname)
1165 {
1166         if (aname == NULL)
1167                 return;
1168
1169         g_free ((void *) aname->name);
1170         g_free ((void *) aname->culture);
1171         g_free ((void *) aname->hash_value);
1172 }
1173
1174 static gboolean
1175 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, MonoAssemblyName *aname)
1176 {
1177         gint major, minor, build, revision;
1178
1179         memset (aname, 0, sizeof (MonoAssemblyName));
1180
1181         if (version) {
1182                 if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
1183                         return FALSE;
1184
1185                 aname->major = major;
1186                 aname->minor = minor;
1187                 aname->build = build;
1188                 aname->revision = revision;
1189         }
1190         
1191         aname->name = g_strdup (name);
1192         
1193         if (culture) {
1194                 if (g_strcasecmp (culture, "neutral") == 0)
1195                         aname->culture = g_strdup ("");
1196                 else
1197                         aname->culture = g_strdup (culture);
1198         }
1199         
1200         if (token && strncmp (token, "null", 4) != 0)
1201                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1202         
1203         return TRUE;
1204 }
1205
1206 static gboolean
1207 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
1208 {
1209         gchar **parts;
1210         gboolean res;
1211         
1212         parts = g_strsplit (dirname, "_", 3);
1213         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
1214                 g_strfreev (parts);
1215                 return FALSE;
1216         }
1217         
1218         res = build_assembly_name (name, parts[0], parts[1], parts[2], aname);
1219         g_strfreev (parts);
1220         return res;
1221 }
1222
1223 /**
1224 * mono_assembly_name_parse:
1225 * @name: name to parse
1226 * @aname: the destination assembly name
1227 * Returns: true if the name could be parsed.
1228
1229 * Parses an assembly qualified type name and assigns the name,
1230 * version, culture and token to the provided assembly name object.
1231 */
1232 gboolean
1233 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
1234 {
1235         gchar *dllname;
1236         gchar *version = NULL;
1237         gchar *culture = NULL;
1238         gchar *token = NULL;
1239         gboolean res;
1240         gchar *value;
1241         gchar **parts;
1242         gchar **tmp;
1243
1244         parts = tmp = g_strsplit (name, ",", 4);
1245         if (!tmp || !*tmp) {
1246                 g_strfreev (tmp);
1247                 return FALSE;
1248         }
1249
1250         dllname = g_strstrip (*tmp);
1251         
1252         tmp++;
1253
1254         while (*tmp) {
1255                 value = g_strstrip (*tmp);
1256                 if (!g_ascii_strncasecmp (value, "Version=", 8)) {
1257                         version = g_strstrip (value + 8);
1258                         tmp++;
1259                         continue;
1260                 }
1261
1262                 if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
1263                         culture = g_strstrip (value + 8);
1264                         tmp++;
1265                         continue;
1266                 }
1267
1268                 if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
1269                         token = g_strstrip (value + 15);
1270                         tmp++;
1271                         continue;
1272                 }
1273                 
1274                 g_strfreev (parts);
1275                 return FALSE;
1276         }
1277
1278         res = build_assembly_name (dllname, version, culture, token, aname);
1279         g_strfreev (parts);
1280         return res;
1281 }
1282
1283 static MonoAssembly*
1284 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
1285 {
1286         gchar *fullpath = NULL;
1287         GDir *dirhandle;
1288         const char* direntry;
1289         MonoAssemblyName gac_aname;
1290         gint major=-1, minor=0, build=0, revision=0;
1291         gboolean exact_version;
1292         
1293         dirhandle = g_dir_open (basepath, 0, NULL);
1294         if (!dirhandle)
1295                 return NULL;
1296                 
1297         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
1298
1299         while ((direntry = g_dir_read_name (dirhandle))) {
1300                 gboolean match = TRUE;
1301                 
1302                 parse_assembly_directory_name (aname->name, direntry, &gac_aname);
1303                 
1304                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
1305                         match = FALSE;
1306                         
1307                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
1308                                 strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0)
1309                         match = FALSE;
1310                 
1311                 if (match) {
1312                         if (exact_version) {
1313                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
1314                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
1315                         }
1316                         else if (gac_aname.major < major)
1317                                 match = FALSE;
1318                         else if (gac_aname.major == major) {
1319                                 if (gac_aname.minor < minor)
1320                                         match = FALSE;
1321                                 else if (gac_aname.minor == minor) {
1322                                         if (gac_aname.build < build)
1323                                                 match = FALSE;
1324                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
1325                                                 match = FALSE; 
1326                                 }
1327                         }
1328                 }
1329                 
1330                 if (match) {
1331                         major = gac_aname.major;
1332                         minor = gac_aname.minor;
1333                         build = gac_aname.build;
1334                         revision = gac_aname.revision;
1335                         g_free (fullpath);
1336                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
1337                 }
1338
1339                 mono_assembly_name_free (&gac_aname);
1340         }
1341         
1342         g_dir_close (dirhandle);
1343         
1344         if (fullpath == NULL)
1345                 return NULL;
1346         else {
1347                 MonoAssembly *res = mono_assembly_open (fullpath, status);
1348                 g_free (fullpath);
1349                 return res;
1350         }
1351 }
1352
1353 MonoAssembly*
1354 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
1355 {
1356         MonoAssembly *res;
1357         MonoAssemblyName *aname, base_name, maped_aname;
1358         gchar *fullname, *gacpath;
1359         gchar **paths;
1360
1361         memset (&base_name, 0, sizeof (MonoAssemblyName));
1362         aname = &base_name;
1363
1364         if (!mono_assembly_name_parse (name, aname))
1365                 return NULL;
1366
1367         /* 
1368          * If no specific version has been requested, make sure we load the
1369          * correct version for system assemblies.
1370          */ 
1371         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
1372                 aname = mono_assembly_remap_version (aname, &maped_aname);
1373         
1374         res = mono_assembly_loaded (aname);
1375         if (res) {
1376                 mono_assembly_name_free (aname);
1377                 return res;
1378         }
1379
1380         res = invoke_assembly_preload_hook (aname, assemblies_path);
1381         if (res) {
1382                 res->in_gac = FALSE;
1383                 mono_assembly_name_free (aname);
1384                 return res;
1385         }
1386
1387         fullname = g_strdup_printf ("%s.dll", aname->name);
1388
1389         if (extra_gac_paths) {
1390                 paths = extra_gac_paths;
1391                 while (!res && *paths) {
1392                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
1393                         res = probe_for_partial_name (gacpath, fullname, aname, status);
1394                         g_free (gacpath);
1395                         paths++;
1396                 }
1397         }
1398
1399         if (res) {
1400                 res->in_gac = TRUE;
1401                 g_free (fullname);
1402                 mono_assembly_name_free (aname);
1403                 return res;
1404         }
1405
1406         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
1407         res = probe_for_partial_name (gacpath, fullname, aname, status);
1408         g_free (gacpath);
1409
1410         if (res)
1411                 res->in_gac = TRUE;
1412
1413         g_free (fullname);
1414         mono_assembly_name_free (aname);
1415
1416         return res;
1417 }
1418
1419 static MonoImage*
1420 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
1421 {
1422         MonoImage *image;
1423         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
1424         gchar **paths;
1425         gint32 len;
1426
1427         if (strstr (aname->name, ".dll")) {
1428                 len = strlen (aname->name) - 4;
1429                 name = g_malloc (len);
1430                 strncpy (name, aname->name, len);
1431         } else
1432                 name = g_strdup (aname->name);
1433         
1434         if (aname->culture) {
1435                 culture = g_strdup (aname->culture);
1436                 g_strdown (culture);
1437         } else
1438                 culture = g_strdup ("");
1439         
1440         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
1441         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
1442         g_free (name);
1443         g_free (culture);
1444         
1445         filename = g_strconcat (pname, ".dll", NULL);
1446         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
1447         g_free (pname);
1448         g_free (version);
1449         g_free (filename);
1450
1451         image = NULL;
1452         if (extra_gac_paths) {
1453                 paths = extra_gac_paths;
1454                 while (!image && *paths) {
1455                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
1456                                         "lib", "mono", "gac", subpath, NULL);
1457                         image = mono_image_open (fullpath, NULL);
1458                         g_free (fullpath);
1459                         paths++;
1460                 }
1461         }
1462
1463         if (image) {
1464                 g_free (subpath);
1465                 return image;
1466         }
1467
1468         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
1469                         "mono", "gac", subpath, NULL);
1470         image = mono_image_open (fullpath, NULL);
1471         g_free (subpath);
1472         g_free (fullpath);
1473         
1474         return image;
1475 }
1476
1477 static MonoAssemblyName*
1478 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
1479 {
1480         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
1481         dest_name->major = info->new_version.major;
1482         dest_name->minor = info->new_version.minor;
1483         dest_name->build = info->new_version.build;
1484         dest_name->revision = info->new_version.revision;
1485         
1486         return dest_name;
1487 }
1488
1489 /* LOCKING: Assumes that we are already locked */
1490 static MonoAssemblyBindingInfo*
1491 search_binding_loaded (MonoAssemblyName *aname)
1492 {
1493         GSList *tmp;
1494
1495         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
1496                 MonoAssemblyBindingInfo *info = tmp->data;
1497                 if (assembly_binding_maps_name (info, aname))
1498                         return info;
1499         }
1500
1501         return NULL;
1502 }
1503
1504 static MonoAssemblyName*
1505 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
1506 {
1507         MonoAssemblyBindingInfo *info, *info2;
1508         MonoImage *ppimage;
1509
1510         if (aname->public_key_token [0] == 0)
1511                 return aname;
1512
1513         mono_loader_lock ();
1514         info = search_binding_loaded (aname);
1515         mono_loader_unlock ();
1516         if (info) {
1517                 if (!check_policy_versions (info, aname))
1518                         return aname;
1519                 
1520                 mono_assembly_bind_version (info, aname, dest_name);
1521                 return dest_name;
1522         }
1523
1524         info = g_new0 (MonoAssemblyBindingInfo, 1);
1525         info->major = aname->major;
1526         info->minor = aname->minor;
1527         
1528         ppimage = mono_assembly_load_publisher_policy (aname);
1529         if (ppimage) {
1530                 get_publisher_policy_info (ppimage, aname, info);
1531                 mono_image_close (ppimage);
1532         }
1533
1534         /* Define default error value if needed */
1535         if (!info->is_valid) {
1536                 info->name = g_strdup (aname->name);
1537                 info->culture = g_strdup (aname->culture);
1538                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1539         }
1540         
1541         mono_loader_lock ();
1542         info2 = search_binding_loaded (aname);
1543         if (info2) {
1544                 /* This binding was added by another thread 
1545                  * before us */
1546                 mono_assembly_binding_info_free (info);
1547                 g_free (info);
1548                 
1549                 info = info2;
1550         } else
1551                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
1552                 
1553         mono_loader_unlock ();
1554         
1555         if (!info->is_valid || !check_policy_versions (info, aname))
1556                 return aname;
1557
1558         mono_assembly_bind_version (info, aname, dest_name);
1559         return dest_name;
1560 }
1561
1562 /**
1563  * mono_assembly_load_from_gac
1564  *
1565  * @aname: The assembly name object
1566  */
1567 static MonoAssembly*
1568 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
1569 {
1570         MonoAssembly *result = NULL;
1571         gchar *name, *version, *culture, *fullpath, *subpath;
1572         gint32 len;
1573         gchar **paths;
1574
1575         if (aname->public_key_token [0] == 0) {
1576                 return NULL;
1577         }
1578
1579         if (strstr (aname->name, ".dll")) {
1580                 len = strlen (filename) - 4;
1581                 name = g_malloc (len);
1582                 strncpy (name, aname->name, len);
1583         } else {
1584                 name = g_strdup (aname->name);
1585         }
1586
1587         if (aname->culture) {
1588                 culture = g_strdup (aname->culture);
1589                 g_strdown (culture);
1590         } else {
1591                 culture = g_strdup ("");
1592         }
1593
1594         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
1595                         aname->minor, aname->build, aname->revision,
1596                         culture, aname->public_key_token);
1597         
1598         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
1599         g_free (name);
1600         g_free (version);
1601         g_free (culture);
1602
1603         if (extra_gac_paths) {
1604                 paths = extra_gac_paths;
1605                 while (!result && *paths) {
1606                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
1607                         result = mono_assembly_open_full (fullpath, status, refonly);
1608                         g_free (fullpath);
1609                         paths++;
1610                 }
1611         }
1612
1613         if (result) {
1614                 result->in_gac = TRUE;
1615                 g_free (subpath);
1616                 return result;
1617         }
1618
1619         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
1620                         "mono", "gac", subpath, NULL);
1621         result = mono_assembly_open_full (fullpath, status, refonly);
1622         g_free (fullpath);
1623
1624         if (result)
1625                 result->in_gac = TRUE;
1626         
1627         g_free (subpath);
1628
1629         return result;
1630 }
1631
1632
1633 MonoAssembly*
1634 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
1635 {
1636         char *corlib_file;
1637
1638         if (corlib) {
1639                 /* g_print ("corlib already loaded\n"); */
1640                 return corlib;
1641         }
1642         
1643         if (assemblies_path) {
1644                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
1645                 if (corlib)
1646                         return corlib;
1647         }
1648
1649         /* Load corlib from mono/<version> */
1650         
1651         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
1652         if (assemblies_path) {
1653                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
1654                 if (corlib) {
1655                         g_free (corlib_file);
1656                         return corlib;
1657                 }
1658         }
1659         corlib = load_in_path (corlib_file, default_path, status, FALSE);
1660         g_free (corlib_file);
1661
1662         return corlib;
1663 }
1664
1665
1666 MonoAssembly*
1667 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
1668 {
1669         MonoAssembly *result;
1670         char *fullpath, *filename;
1671         MonoAssemblyName maped_aname, maped_name_pp;
1672         int ext_index;
1673         const char *ext;
1674
1675         aname = mono_assembly_remap_version (aname, &maped_aname);
1676         
1677         /* Reflection only assemblies don't get assembly binding */
1678         if (!refonly)
1679                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
1680         
1681         result = mono_assembly_loaded_full (aname, refonly);
1682         if (result)
1683                 return result;
1684
1685         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
1686         if (result) {
1687                 result->in_gac = FALSE;
1688                 return result;
1689         }
1690
1691         /* Currently we retrieve the loaded corlib for reflection 
1692          * only requests, like a common reflection only assembly 
1693          */
1694         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
1695                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
1696         }
1697
1698         for (ext_index = 0; ext_index < 2; ext_index ++) {
1699                 ext = ext_index == 0 ? ".dll" : ".exe";
1700                 if (strstr (aname->name, ".dll"))
1701                         filename = g_strdup (aname->name);
1702                 else
1703                         filename = g_strconcat (aname->name, ext, NULL);
1704
1705                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
1706                 if (result) {
1707                         g_free (filename);
1708                         return result;
1709                 }
1710
1711                 if (basedir) {
1712                         fullpath = g_build_filename (basedir, filename, NULL);
1713                         result = mono_assembly_open_full (fullpath, status, refonly);
1714                         g_free (fullpath);
1715                         if (result) {
1716                                 result->in_gac = FALSE;
1717                                 g_free (filename);
1718                                 return result;
1719                         }
1720                 }
1721
1722                 result = load_in_path (filename, default_path, status, refonly);
1723                 if (result)
1724                         result->in_gac = FALSE;
1725                 g_free (filename);
1726                 if (result)
1727                         return result;
1728         }
1729
1730         return NULL;
1731 }
1732
1733 MonoAssembly*
1734 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
1735 {
1736         return mono_assembly_load_full (aname, basedir, status, FALSE);
1737 }
1738         
1739 MonoAssembly*
1740 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
1741 {
1742         MonoAssembly *res;
1743         MonoAssemblyName maped_aname;
1744
1745         aname = mono_assembly_remap_version (aname, &maped_aname);
1746
1747         EnterCriticalSection (&assemblies_mutex);
1748         res = search_loaded (aname, refonly);
1749         LeaveCriticalSection (&assemblies_mutex);
1750
1751         return res;
1752 }
1753
1754 MonoAssembly*
1755 mono_assembly_loaded (MonoAssemblyName *aname)
1756 {
1757         return mono_assembly_loaded_full (aname, FALSE);
1758 }
1759
1760 void
1761 mono_assembly_close (MonoAssembly *assembly)
1762 {
1763         g_return_if_fail (assembly != NULL);
1764
1765         if (InterlockedDecrement (&assembly->ref_count))
1766                 return;
1767         
1768         EnterCriticalSection (&assemblies_mutex);
1769         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
1770         LeaveCriticalSection (&assemblies_mutex);
1771         /* assemblies belong to domains, so the domain code takes care of unloading the
1772          * referenced assemblies
1773          */
1774
1775         mono_image_close (assembly->image);
1776
1777         g_free (assembly->basedir);
1778         if (!assembly->dynamic)
1779                 g_free (assembly);
1780 }
1781
1782 MonoImage*
1783 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
1784 {
1785         MonoImageOpenStatus status;
1786         MonoImage *module;
1787
1788         module = mono_image_load_file_for_image (assembly->image, idx);
1789         if (module)
1790                 mono_assembly_load_references (module, &status);
1791
1792         return module;
1793 }
1794
1795 void
1796 mono_assembly_foreach (GFunc func, gpointer user_data)
1797 {
1798         GList *copy;
1799
1800         /*
1801          * We make a copy of the list to avoid calling the callback inside the 
1802          * lock, which could lead to deadlocks.
1803          */
1804         EnterCriticalSection (&assemblies_mutex);
1805         copy = g_list_copy (loaded_assemblies);
1806         LeaveCriticalSection (&assemblies_mutex);
1807
1808         g_list_foreach (loaded_assemblies, func, user_data);
1809
1810         g_list_free (copy);
1811 }
1812
1813 /*
1814  * Holds the assembly of the application, for
1815  * System.Diagnostics.Process::MainModule
1816  */
1817 static MonoAssembly *main_assembly=NULL;
1818
1819 void
1820 mono_assembly_set_main (MonoAssembly *assembly)
1821 {
1822         main_assembly=assembly;
1823 }
1824
1825 MonoAssembly *
1826 mono_assembly_get_main (void)
1827 {
1828         return(main_assembly);
1829 }
1830
1831 MonoImage*
1832 mono_assembly_get_image (MonoAssembly *assembly)
1833 {
1834         return assembly->image;
1835 }
1836
1837 void
1838 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
1839 {
1840         bundles = assemblies;
1841 }