forgot this
[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/domain-internals.h>
24 #include <mono/io-layer/io-layer.h>
25 #include <mono/utils/mono-uri.h>
26 #include <mono/metadata/mono-config.h>
27 #include <mono/utils/mono-digest.h>
28 #include <mono/utils/mono-logger.h>
29 #ifdef PLATFORM_WIN32
30 #include <mono/os/util.h>
31 #endif
32
33 /* the default search path is just MONO_ASSEMBLIES */
34 static const char*
35 default_path [] = {
36         MONO_ASSEMBLIES,
37         NULL
38 };
39
40 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
41 static char **assemblies_path = NULL;
42
43 /* Contains the list of directories that point to auxiliary GACs */
44 static char **extra_gac_paths = NULL;
45
46 /*
47  * keeps track of loaded assemblies
48  */
49 static GList *loaded_assemblies = NULL;
50 static MonoAssembly *corlib;
51
52 /* This protects loaded_assemblies and image->references */
53 static CRITICAL_SECTION assemblies_mutex;
54
55 /* A hastable of thread->assembly list mappings */
56 static GHashTable *assemblies_loading;
57
58 /* If defined, points to the bundled assembly information */
59 const MonoBundledAssembly **bundles;
60
61 static gchar*
62 encode_public_tok (const guchar *token, gint32 len)
63 {
64         const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
65         gchar *res;
66         int i;
67
68         res = g_malloc (len * 2 + 1);
69         for (i = 0; i < len; i++) {
70                 res [i * 2] = allowed [token [i] >> 4];
71                 res [i * 2 + 1] = allowed [token [i] & 0xF];
72         }
73         res [len * 2] = 0;
74         return res;
75 }
76
77 static void
78 check_path_env (void)
79 {
80         const char *path;
81         char **splitted;
82         
83         path = g_getenv ("MONO_PATH");
84         if (!path)
85                 return;
86
87         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
88         if (assemblies_path)
89                 g_strfreev (assemblies_path);
90         assemblies_path = splitted;
91         if (g_getenv ("MONO_DEBUG") == NULL)
92                 return;
93
94         while (*splitted) {
95                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
96                         g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
97
98                 splitted++;
99         }
100 }
101
102 static void
103 check_extra_gac_path_env (void) {
104         const char *path;
105         char **splitted;
106         
107         path = g_getenv ("MONO_GAC_PREFIX");
108         if (!path)
109                 return;
110
111         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
112         if (extra_gac_paths)
113                 g_strfreev (extra_gac_paths);
114         extra_gac_paths = splitted;
115         if (g_getenv ("MONO_DEBUG") == NULL)
116                 return;
117
118         while (*splitted) {
119                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
120                         g_warning ("'%s' in MONO_GAC_PATH doesn't exist or has wrong permissions.", *splitted);
121
122                 splitted++;
123         }
124 }
125
126 gboolean
127 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
128 {
129         if (!l->name || !r->name)
130                 return FALSE;
131
132         if (strcmp (l->name, r->name))
133                 return FALSE;
134
135         if (l->culture && r->culture && strcmp (l->culture, r->culture))
136                 return FALSE;
137
138         if (l->major != r->major || l->minor != r->minor ||
139                         l->build != r->build || l->revision != r->revision)
140                 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)))
141                         return FALSE;
142
143         if (!l->public_key_token [0] || !r->public_key_token [0])
144                 return TRUE;
145
146         if (strcmp (l->public_key_token, r->public_key_token))
147                 return FALSE;
148
149         return TRUE;
150 }
151
152 static MonoAssembly*
153 search_loaded (MonoAssemblyName* aname)
154 {
155         GList *tmp;
156         MonoAssembly *ass;
157         GList *loading;
158
159         ass = mono_assembly_invoke_search_hook (aname);
160         if (ass)
161                 return ass;
162         
163         /*
164          * The assembly might be under load by this thread. In this case, it is
165          * safe to return an incomplete instance to prevent loops.
166          */
167         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
168         for (tmp = loading; tmp; tmp = tmp->next) {
169                 ass = tmp->data;
170                 if (!mono_assembly_names_equal (aname, &ass->aname))
171                         continue;
172
173                 return ass;
174         }
175
176         return NULL;
177 }
178
179 static MonoAssembly *
180 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
181 {
182         int i;
183         char *fullpath;
184         MonoAssembly *result;
185
186         for (i = 0; search_path [i]; ++i) {
187                 fullpath = g_build_filename (search_path [i], basename, NULL);
188                 result = mono_assembly_open (fullpath, status);
189                 g_free (fullpath);
190                 if (result)
191                         return result;
192         }
193         return NULL;
194 }
195
196 /**
197  * mono_assembly_setrootdir:
198  * @root_dir: The pathname of the root directory where we will locate assemblies
199  *
200  * This routine sets the internal default root directory for looking up
201  * assemblies.  This is used by Windows installations to compute dynamically
202  * the place where the Mono assemblies are located.
203  *
204  */
205 void
206 mono_assembly_setrootdir (const char *root_dir)
207 {
208         /*
209          * Override the MONO_ASSEMBLIES directory configured at compile time.
210          */
211         /* Leak if called more than once */
212         default_path [0] = g_strdup (root_dir);
213 }
214
215 G_CONST_RETURN gchar *
216 mono_assembly_getrootdir (void)
217 {
218         return default_path [0];
219 }
220
221 /**
222  * mono_assemblies_init:
223  *
224  *  Initialize global variables used by this module.
225  */
226 void
227 mono_assemblies_init (void)
228 {
229 #ifdef PLATFORM_WIN32
230         mono_set_rootdir ();
231 #endif
232
233         check_path_env ();
234         check_extra_gac_path_env ();
235
236         InitializeCriticalSection (&assemblies_mutex);
237
238         assemblies_loading = g_hash_table_new (NULL, NULL);
239 }
240
241 gboolean
242 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
243 {
244         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
245         guint32 cols [MONO_ASSEMBLY_SIZE];
246
247         if (!t->rows)
248                 return FALSE;
249
250         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
251
252         aname->hash_len = 0;
253         aname->hash_value = NULL;
254         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
255         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
256         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
257         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
258         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
259         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
260         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
261         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
262         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
263                 gchar* token = g_malloc (8);
264                 gchar* encoded;
265                 int len;
266
267                 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
268                 len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
269
270                 mono_digest_get_public_token (token, aname->public_key, len);
271                 encoded = encode_public_tok (token, 8);
272                 g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
273
274                 g_free (encoded);
275                 g_free (token);
276         }
277         else {
278                 aname->public_key = NULL;
279                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
280         }
281
282         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
283                 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
284         }
285         else
286                 aname->public_key = 0;
287
288         return TRUE;
289 }
290
291 static gchar*
292 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
293 {
294         const gchar *public_tok;
295         int len;
296
297         public_tok = mono_metadata_blob_heap (image, key_index);
298         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
299
300         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
301                 gchar token [8];
302                 mono_digest_get_public_token (token, public_tok, len);
303                 return encode_public_tok (token, 8);
304         }
305
306         return encode_public_tok (public_tok, len);
307 }
308
309 void
310 mono_assembly_load_reference (MonoImage *image, int index)
311 {
312         MonoTableInfo *t;
313         guint32 cols [MONO_ASSEMBLYREF_SIZE];
314         const char *hash;
315         MonoAssembly *reference;
316         MonoAssemblyName aname;
317         MonoImageOpenStatus status;
318
319         /*
320          * image->references is shared between threads, so we need to access
321          * it inside a critical section.
322          */
323         EnterCriticalSection (&assemblies_mutex);
324         reference = image->references [index];
325         LeaveCriticalSection (&assemblies_mutex);
326         if (reference)
327                 return;
328
329         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
330
331         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
332                 
333         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
334         aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
335         aname.hash_value = hash;
336         aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
337         aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
338         aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
339         aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
340         aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
341         aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
342         aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
343
344         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
345                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
346                 g_strlcpy (aname.public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
347                 g_free (token);
348         } else {
349                 memset (aname.public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
350         } 
351
352         reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
353
354         if (reference == NULL){
355                 /*
356                 ** Temporary work around: any System.* which are 3300 build, will get
357                 ** remapped, this is to keep old applications running that might have
358                 ** been linked against our 5000 API, before we were strongnamed, and
359                 ** hence were labeled as 3300 builds by reflection.c
360                 */
361                 if (aname.build == 3300 && strncmp (aname.name, "System", 6) == 0){
362                         aname.build = 5000;
363                                 
364                         reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
365                 }
366                 if (reference != NULL){
367                         if (g_getenv ("MONO_SILENT_WARNING") == NULL)
368                                 g_printerr ("Compat mode: the request from %s to load %s was remapped (http://www.go-mono.com/remap.html)\n",
369                                                         image->name, aname.name);
370                         
371                 } else {
372                         char *extra_msg = g_strdup ("");
373
374                         if (status == MONO_IMAGE_ERROR_ERRNO) {
375                                 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
376                         } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
377                                 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
378                         } else if (status == MONO_IMAGE_IMAGE_INVALID) {
379                                 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
380                         }
381                         
382                         g_warning ("Could not find assembly %s, references from %s (assemblyref_index=%d)\n"
383                                            "     Major/Minor: %d,%d\n"
384                                            "     Build:       %d,%d\n"
385                                            "     Token:       %s\n%s",
386                                            aname.name, image->name, index,
387                                            aname.major, aname.minor, aname.build, aname.revision,
388                                            aname.public_key_token, extra_msg);
389                         g_free (extra_msg);
390                 }
391         }
392
393         if (reference == NULL)
394                 /* Flag as not found */
395                 reference = (gpointer)-1;
396
397         EnterCriticalSection (&assemblies_mutex);
398         if (!image->references [index])
399                 image->references [index] = reference;
400         LeaveCriticalSection (&assemblies_mutex);
401
402         if (image->references [index] != reference) {
403                 /* Somebody loaded it before us */
404                 mono_assembly_close (reference);
405         }
406 }
407
408 void
409 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
410 {
411         MonoTableInfo *t;
412         int i;
413
414         *status = MONO_IMAGE_OK;
415
416         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
417         
418         image->references = g_new0 (MonoAssembly *, t->rows + 1);
419
420         /* resolve assembly references for modules */
421         for (i = 0; i < image->module_count; i++){
422                 if (image->modules [i]) {
423                         image->modules [i]->assembly = image->assembly;
424                         mono_assembly_load_references (image->modules [i], status);
425                 }
426         }
427 }
428
429 typedef struct AssemblyLoadHook AssemblyLoadHook;
430 struct AssemblyLoadHook {
431         AssemblyLoadHook *next;
432         MonoAssemblyLoadFunc func;
433         gpointer user_data;
434 };
435
436 AssemblyLoadHook *assembly_load_hook = NULL;
437
438 void
439 mono_assembly_invoke_load_hook (MonoAssembly *ass)
440 {
441         AssemblyLoadHook *hook;
442
443         for (hook = assembly_load_hook; hook; hook = hook->next) {
444                 hook->func (ass, hook->user_data);
445         }
446 }
447
448 void
449 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
450 {
451         AssemblyLoadHook *hook;
452         
453         g_return_if_fail (func != NULL);
454
455         hook = g_new0 (AssemblyLoadHook, 1);
456         hook->func = func;
457         hook->user_data = user_data;
458         hook->next = assembly_load_hook;
459         assembly_load_hook = hook;
460 }
461
462 typedef struct AssemblySearchHook AssemblySearchHook;
463 struct AssemblySearchHook {
464         AssemblySearchHook *next;
465         MonoAssemblySearchFunc func;
466         gpointer user_data;
467 };
468
469 AssemblySearchHook *assembly_search_hook = NULL;
470
471 MonoAssembly*
472 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
473 {
474         AssemblySearchHook *hook;
475
476         for (hook = assembly_search_hook; hook; hook = hook->next) {
477                 MonoAssembly *ass = hook->func (aname, hook->user_data);
478                 if (ass)
479                         return ass;
480         }
481
482         return NULL;
483 }
484
485 void          
486 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
487 {
488         AssemblySearchHook *hook;
489         
490         g_return_if_fail (func != NULL);
491
492         hook = g_new0 (AssemblySearchHook, 1);
493         hook->func = func;
494         hook->user_data = user_data;
495         hook->next = assembly_search_hook;
496         assembly_search_hook = hook;
497 }       
498
499 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
500 struct AssemblyPreLoadHook {
501         AssemblyPreLoadHook *next;
502         MonoAssemblyPreLoadFunc func;
503         gpointer user_data;
504 };
505
506 AssemblyPreLoadHook *assembly_preload_hook = NULL;
507
508 static MonoAssembly *
509 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
510 {
511         AssemblyPreLoadHook *hook;
512         MonoAssembly *assembly;
513
514         for (hook = assembly_preload_hook; hook; hook = hook->next) {
515                 assembly = hook->func (aname, assemblies_path, hook->user_data);
516                 if (assembly != NULL)
517                         return assembly;
518         }
519
520         return NULL;
521 }
522
523 void
524 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
525 {
526         AssemblyPreLoadHook *hook;
527         
528         g_return_if_fail (func != NULL);
529
530         hook = g_new0 (AssemblyPreLoadHook, 1);
531         hook->func = func;
532         hook->user_data = user_data;
533         hook->next = assembly_preload_hook;
534         assembly_preload_hook = hook;
535 }
536
537 static gchar *
538 absolute_dir (const gchar *filename)
539 {
540         gchar *cwd;
541         gchar *mixed;
542         gchar **parts;
543         gchar *part;
544         GList *list, *tmp;
545         GString *result;
546         gchar *res;
547         gint i;
548
549         if (g_path_is_absolute (filename))
550                 return g_path_get_dirname (filename);
551
552         cwd = g_get_current_dir ();
553         mixed = g_build_filename (cwd, filename, NULL);
554         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
555         g_free (mixed);
556         g_free (cwd);
557
558         list = NULL;
559         for (i = 0; (part = parts [i]) != NULL; i++) {
560                 if (!strcmp (part, "."))
561                         continue;
562
563                 if (!strcmp (part, "..")) {
564                         if (list && list->next) /* Don't remove root */
565                                 list = g_list_delete_link (list, list);
566                 } else {
567                         list = g_list_prepend (list, part);
568                 }
569         }
570
571         result = g_string_new ("");
572         list = g_list_reverse (list);
573
574         /* Ignores last data pointer, which should be the filename */
575         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
576                 if (tmp->data)
577                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
578                                                                 G_DIR_SEPARATOR);
579         
580         res = result->str;
581         g_string_free (result, FALSE);
582         g_list_free (list);
583         g_strfreev (parts);
584         if (*res == '\0') {
585                 g_free (res);
586                 return g_strdup (".");
587         }
588
589         return res;
590 }
591
592 /** 
593  * mono_assembly_open_from_bundle:
594  * @filename: Filename requested
595  * @status: return value
596  *
597  * This routine tries to open the assembly specified by `filename' from the
598  * defined bundles, if found, returns the MonoImage for it, if not found
599  * returns NULL
600  */
601 static MonoImage *
602 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status)
603 {
604         int i;
605         char *name = g_path_get_basename (filename);
606         char *dot = strrchr (name, '.');
607         MonoImage *image = NULL;
608
609         /*
610          * we do a very simple search for bundled assemblies: it's not a general 
611          * purpose assembly loading mechanism.
612          */
613         EnterCriticalSection (&assemblies_mutex);
614         for (i = 0; !image && bundles [i]; ++i) {
615                 if (strcmp (bundles [i]->name, name) == 0) {
616                         image = mono_image_open_from_data ((char*)bundles [i]->data, bundles [i]->size, FALSE, status);
617                         break;
618                 }
619         }
620         LeaveCriticalSection (&assemblies_mutex);
621         g_free (name);
622         if (image) {
623                 mono_image_addref (image);
624                 return image;
625         }
626         return NULL;
627 }
628
629 static MonoImage*
630 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
631 {
632         MonoImage *image = NULL;
633
634         if (bundles != NULL){
635                 image = mono_assembly_open_from_bundle (filename, status);
636
637                 if (image != NULL)
638                         return image;
639         }
640         EnterCriticalSection (&assemblies_mutex);
641         image = mono_image_open (filename, status);
642         LeaveCriticalSection (&assemblies_mutex);
643
644         return image;
645 }
646
647 /**
648  * mono_assembly_open:
649  * @filename: Opens the assembly pointed out by this name
650  * @status: where a status code can be returned
651  *
652  * mono_assembly_open opens the PE-image pointed by @filename, and
653  * loads any external assemblies referenced by it.
654  *
655  * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
656  * it. 
657  */
658 MonoAssembly *
659 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
660 {
661         MonoImage *image;
662         MonoAssembly *ass;
663         MonoImageOpenStatus def_status;
664         gchar *fname;
665         
666         g_return_val_if_fail (filename != NULL, NULL);
667
668         if (!status)
669                 status = &def_status;
670         *status = MONO_IMAGE_OK;
671
672         if (strncmp (filename, "file://", 7) == 0) {
673                 GError *error = NULL;
674                 gchar *uri = (gchar *) filename;
675                 gchar *tmpuri;
676
677                 /*
678                  * MS allows file://c:/... and fails on file://localhost/c:/... 
679                  * They also throw an IndexOutOfRangeException if "file://"
680                  */
681                 if (uri [7] != '/')
682                         uri = g_strdup_printf ("file:///%s", uri + 7);
683         
684                 tmpuri = uri;
685                 uri = mono_escape_uri_string (tmpuri);
686                 fname = g_filename_from_uri (uri, NULL, &error);
687                 g_free (uri);
688
689                 if (tmpuri != filename)
690                         g_free (tmpuri);
691
692                 if (error != NULL) {
693                         g_warning ("%s\n", error->message);
694                         g_error_free (error);
695                         fname = g_strdup (filename);
696                 }
697         } else {
698                 fname = g_strdup (filename);
699         }
700
701         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
702                         "Assembly Loader probing location: '%s'.", filename);
703         image = do_mono_assembly_open (fname, status);
704
705         if (!image){
706                 *status = MONO_IMAGE_ERROR_ERRNO;
707                 g_free (fname);
708                 return NULL;
709         }
710
711         ass = mono_assembly_load_from (image, fname, status);
712
713         if (ass) {
714                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
715                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
716                 mono_config_for_assembly (ass->image);
717         }
718
719         g_free (fname);
720
721         return ass;
722 }
723
724 MonoAssembly *
725 mono_assembly_load_from (MonoImage *image, const char*fname, 
726                          MonoImageOpenStatus *status)
727 {
728         MonoAssembly *ass, *ass2;
729         char *base_dir;
730         GList *loading;
731
732 #if defined (PLATFORM_WIN32)
733         {
734                 gchar *tmp_fn;
735                 int i;
736
737                 tmp_fn = g_strdup (fname);
738                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
739                         if (tmp_fn [i] == '/')
740                                 tmp_fn [i] = '\\';
741                 }
742
743                 base_dir = absolute_dir (tmp_fn);
744                 g_free (tmp_fn);
745         }
746 #else
747         base_dir = absolute_dir (fname);
748 #endif
749
750         /*
751          * To avoid deadlocks and scalability problems, we load assemblies outside
752          * the assembly lock. This means that multiple threads might try to load
753          * the same assembly at the same time. The first one to load it completely
754          * "wins", the other threads free their copy and use the one loaded by
755          * the winning thread.
756          */
757
758         /*
759          * Create assembly struct, and enter it into the assembly cache
760          */
761         ass = g_new0 (MonoAssembly, 1);
762         ass->basedir = base_dir;
763         ass->image = image;
764
765         mono_assembly_fill_assembly_name (image, &ass->aname);
766
767         /* 
768          * Atomically search the loaded list and add ourselves to it if necessary.
769          */
770         EnterCriticalSection (&assemblies_mutex);
771         if (ass->aname.name)
772                 /* avoid loading the same assembly twice for now... */
773                 if ((ass2 = search_loaded (&ass->aname))) {
774                         g_free (ass);
775                         g_free (base_dir);
776                         mono_image_close (image);
777                         *status = MONO_IMAGE_OK;
778                         LeaveCriticalSection (&assemblies_mutex);
779                         return ass2;
780                 }
781         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
782         loading = g_list_prepend (loading, ass);
783         g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
784         LeaveCriticalSection (&assemblies_mutex);
785
786         image->assembly = ass;
787
788         mono_assembly_load_references (image, status);
789
790         EnterCriticalSection (&assemblies_mutex);
791
792         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
793         loading = g_list_remove (loading, ass);
794         if (loading == NULL)
795                 /* Prevent memory leaks */
796                 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
797         else
798                 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
799         if (*status != MONO_IMAGE_OK) {
800                 LeaveCriticalSection (&assemblies_mutex);
801                 mono_assembly_close (ass);
802                 return NULL;
803         }
804
805         if (ass->aname.name) {
806                 ass2 = search_loaded (&ass->aname);
807                 if (ass2) {
808                         /* Somebody else has loaded the assembly before us */
809                         LeaveCriticalSection (&assemblies_mutex);
810                         mono_assembly_close (ass);
811                         return ass2;
812                 }
813         }
814
815         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
816         LeaveCriticalSection (&assemblies_mutex);
817
818         mono_assembly_invoke_load_hook (ass);
819
820         return ass;
821 }
822
823 static MonoAssembly*
824 probe_for_partial_name (const char *basepath, const char *fullname, MonoImageOpenStatus *status)
825 {
826         MonoAssembly *res = NULL;
827         gchar *fullpath;
828         GDir *dirhandle;
829         const char* direntry;
830
831         dirhandle = g_dir_open (basepath, 0, NULL);
832         if (!dirhandle)
833                 return NULL;
834
835         while ((direntry = g_dir_read_name (dirhandle))) {
836                 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
837                 res = mono_assembly_open (fullpath, status);
838                 g_free (fullpath);
839                 if (res)
840                         break;
841         }
842         g_dir_close (dirhandle);
843
844         return res;
845 }
846
847 MonoAssembly*
848 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
849 {
850         MonoAssembly *res;
851         MonoAssemblyName aname;
852         gchar *fullname, *gacpath;
853         gchar **paths;
854
855         memset (&aname, 0, sizeof (MonoAssemblyName));
856         aname.name = name;
857
858         res = invoke_assembly_preload_hook (&aname, assemblies_path);
859         if (res) {
860                 res->in_gac = FALSE;
861                 return res;
862         }
863
864         res = mono_assembly_loaded (&aname);
865         if (res)
866                 return res;
867
868         fullname = g_strdup_printf ("%s.dll", name);
869
870         if (extra_gac_paths) {
871                 paths = extra_gac_paths;
872                 while (!res && *paths) {
873                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", name, NULL);
874                         res = probe_for_partial_name (gacpath, fullname, status);
875                         g_free (gacpath);
876                         paths++;
877                 }
878         }
879
880         if (res) {
881                 res->in_gac = TRUE;
882                 g_free (fullname);
883                 return res;
884                 
885         }
886
887         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", name, NULL);
888         res = probe_for_partial_name (gacpath, fullname, status);
889         g_free (gacpath);
890
891         if (res)
892                 res->in_gac = TRUE;
893
894         g_free (fullname);
895
896         return res;
897 }
898
899 /**
900  * mono_assembly_load_from_gac
901  *
902  * @aname: The assembly name object
903  */
904 static MonoAssembly*
905 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status)
906 {
907         MonoAssembly *result = NULL;
908         gchar *name, *version, *culture, *fullpath, *subpath;
909         gint32 len;
910         gchar **paths;
911
912         if (aname->public_key_token [0] == 0) {
913                 return NULL;
914         }
915
916         if (strstr (aname->name, ".dll")) {
917                 len = strlen (filename) - 4;
918                 name = g_malloc (len);
919                 strncpy (name, aname->name, len);
920         } else {
921                 name = g_strdup (aname->name);
922         }
923
924         if (aname->culture) {
925                 culture = g_strdup (aname->culture);
926                 g_strdown (culture);
927         } else {
928                 culture = g_strdup ("");
929         }
930
931         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
932                         aname->minor, aname->build, aname->revision,
933                         culture, aname->public_key_token);
934         
935         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
936         g_free (name);
937         g_free (version);
938         g_free (culture);
939
940         if (extra_gac_paths) {
941                 paths = extra_gac_paths;
942                 while (!result && *paths) {
943                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
944                         result = mono_assembly_open (fullpath, status);
945                         g_free (fullpath);
946                         paths++;
947                 }
948         }
949
950         if (result) {
951                 result->in_gac = TRUE;
952                 g_free (subpath);
953                 return result;
954         }
955
956         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
957                         "mono", "gac", subpath, NULL);
958         result = mono_assembly_open (fullpath, status);
959         g_free (fullpath);
960
961         if (result)
962                 result->in_gac = TRUE;
963         
964         g_free (subpath);
965
966         return result;
967 }
968
969         
970 MonoAssembly*
971 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
972 {
973         MonoAssembly *result;
974         char *fullpath, *filename;
975
976         result = invoke_assembly_preload_hook (aname, assemblies_path);
977         if (result) {
978                 result->in_gac = FALSE;
979                 return result;
980         }
981
982         result = mono_assembly_loaded (aname);
983         if (result)
984                 return result;
985
986         /* g_print ("loading %s\n", aname->name); */
987         /* special case corlib */
988         if (strcmp (aname->name, "mscorlib") == 0) {
989                 char *corlib_file;
990                 if (corlib) {
991                         /* g_print ("corlib already loaded\n"); */
992                         return corlib;
993                 }
994                 /* g_print ("corlib load\n"); */
995                 if (assemblies_path) {
996                         corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
997                         if (corlib)
998                                 return corlib;
999                 }
1000                 corlib = load_in_path ("mscorlib.dll", default_path, status);
1001
1002                 if (corlib)
1003                         return corlib;
1004         
1005                 /* Load corlib from mono/<version> */
1006                 
1007                 corlib_file = g_build_filename ("mono", mono_get_framework_version (), "mscorlib.dll", NULL);
1008                 if (assemblies_path) {
1009                         corlib = load_in_path (corlib_file, (const char**)assemblies_path, status);
1010                         if (corlib) {
1011                                 g_free (corlib_file);
1012                                 return corlib;
1013                         }
1014                 }
1015                 corlib = load_in_path (corlib_file, default_path, status);
1016                 g_free (corlib_file);
1017         
1018                 return corlib;
1019         }
1020
1021         if (strstr (aname->name, ".dll"))
1022                 filename = g_strdup (aname->name);
1023         else
1024                 filename = g_strconcat (aname->name, ".dll", NULL);
1025
1026         result = mono_assembly_load_from_gac (aname, filename, status);
1027         if (result) {
1028                 g_free (filename);
1029                 return result;
1030         }
1031
1032         if (basedir) {
1033                 fullpath = g_build_filename (basedir, filename, NULL);
1034                 result = mono_assembly_open (fullpath, status);
1035                 g_free (fullpath);
1036                 if (result) {
1037                         result->in_gac = FALSE;
1038                         g_free (filename);
1039                         return result;
1040                 }
1041         }
1042
1043         result = load_in_path (filename, default_path, status);
1044         if (result)
1045                 result->in_gac = FALSE;
1046         g_free (filename);
1047         return result;
1048 }
1049
1050 MonoAssembly*
1051 mono_assembly_loaded (MonoAssemblyName *aname)
1052 {
1053         MonoAssembly *res;
1054
1055         EnterCriticalSection (&assemblies_mutex);
1056         res = search_loaded (aname);
1057         LeaveCriticalSection (&assemblies_mutex);
1058
1059         return res;
1060 }
1061
1062 void
1063 mono_assembly_close (MonoAssembly *assembly)
1064 {
1065         MonoImage *image;
1066         int i;
1067         
1068         g_return_if_fail (assembly != NULL);
1069
1070         EnterCriticalSection (&assemblies_mutex);
1071         if (--assembly->ref_count != 0) {
1072                 LeaveCriticalSection (&assemblies_mutex);
1073                 return;
1074         }
1075         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
1076         LeaveCriticalSection (&assemblies_mutex);
1077         image = assembly->image;
1078         if (image->references) {
1079                 for (i = 0; image->references [i] != NULL; i++)
1080                         if (image->references [i] && (image->references [i] != (gpointer)-1))
1081                                 mono_image_close (image->references [i]->image);
1082                 g_free (image->references);
1083         }
1084
1085         mono_image_close (assembly->image);
1086
1087         g_free (assembly->basedir);
1088         g_free (assembly);
1089 }
1090
1091 MonoImage*
1092 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
1093 {
1094         MonoImageOpenStatus status;
1095         MonoImage *module;
1096
1097         module = mono_image_load_file_for_image (assembly->image, idx);
1098         if (module)
1099                 mono_assembly_load_references (module, &status);
1100
1101         return module;
1102 }
1103
1104 void
1105 mono_assembly_foreach (GFunc func, gpointer user_data)
1106 {
1107         GList *copy;
1108
1109         /*
1110          * We make a copy of the list to avoid calling the callback inside the 
1111          * lock, which could lead to deadlocks.
1112          */
1113         EnterCriticalSection (&assemblies_mutex);
1114         copy = g_list_copy (loaded_assemblies);
1115         LeaveCriticalSection (&assemblies_mutex);
1116
1117         g_list_foreach (loaded_assemblies, func, user_data);
1118
1119         g_list_free (copy);
1120 }
1121
1122 /*
1123  * Holds the assembly of the application, for
1124  * System.Diagnostics.Process::MainModule
1125  */
1126 static MonoAssembly *main_assembly=NULL;
1127
1128 void
1129 mono_assembly_set_main (MonoAssembly *assembly)
1130 {
1131         main_assembly=assembly;
1132 }
1133
1134 MonoAssembly *
1135 mono_assembly_get_main (void)
1136 {
1137         return(main_assembly);
1138 }
1139
1140 MonoImage*
1141 mono_assembly_get_image (MonoAssembly *assembly)
1142 {
1143         return assembly->image;
1144 }
1145
1146 void
1147 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
1148 {
1149         bundles = assemblies;
1150 }