2004-05-03 Gonzalo Paniagua Javier <gonzalo@ximian.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  * TODO:
10  *   Implement big-endian versions of the reading routines.
11  */
12 #include <config.h>
13 #include <stdio.h>
14 #include <glib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include "assembly.h"
19 #include "image.h"
20 #include "cil-coff.h"
21 #include "rawbuffer.h"
22 #ifdef WITH_BUNDLE
23 #include "mono-bundle.h"
24 #endif
25 #include <mono/metadata/loader.h>
26 #include <mono/metadata/tabledefs.h>
27 #include <mono/io-layer/io-layer.h>
28 #include <mono/utils/mono-uri.h>
29 #include <mono/metadata/mono-config.h>
30 #include <mono/utils/mono-digest.h>
31
32 /* the default search path is just MONO_ASSEMBLIES */
33 static const char*
34 default_path [] = {
35         MONO_ASSEMBLIES,
36         NULL
37 };
38
39 static char **assemblies_path = NULL;
40
41 /*
42  * keeps track of loaded assemblies
43  */
44 static GList *loaded_assemblies = NULL;
45 static MonoAssembly *corlib;
46
47 /* This protects loaded_assemblies and image->references */
48 static CRITICAL_SECTION assemblies_mutex;
49
50 /* A hastable of thread->assembly list mappings */
51 static GHashTable *assemblies_loading;
52
53 static gboolean allow_user_gac = FALSE;
54
55 #ifdef PLATFORM_WIN32
56
57 static void
58 init_default_path (void)
59 {
60         int i;
61
62         default_path [0] = g_strdup (MONO_ASSEMBLIES);
63         for (i = strlen (MONO_ASSEMBLIES) - 1; i >= 0; i--) {
64                 if (default_path [0][i] == '/')
65                         ((char*) default_path [0])[i] = '\\';
66         }
67 }
68 #endif
69
70
71 static gchar*
72 encode_public_tok (const guchar *token, gint32 len)
73 {
74         static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
75         gchar *res;
76         int i;
77
78         res = g_malloc (len * 2 + 1);
79         for (i = 0; i < len; i++) {
80                 res [i * 2] = allowed [token [i] >> 4];
81                 res [i * 2 + 1] = allowed [token [i] & 0xF];
82         }
83         res [len * 2] = 0;
84         return res;
85 }
86
87 static void
88 check_env (void) {
89         const char *path;
90         char **splitted;
91         
92         path = getenv ("MONO_PATH");
93         if (!path)
94                 return;
95         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
96         if (assemblies_path)
97                 g_strfreev (assemblies_path);
98         assemblies_path = splitted;
99 }
100
101 static gboolean
102 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
103 {
104         if (!l->name || !r->name)
105                 return FALSE;
106
107         if (strcmp (l->name, r->name))
108                 return FALSE;
109
110         /*
111          * simply compare names until some other issues are resolved
112          * (version info not getting set correctly for custom
113          * attributes).
114          */
115         /*
116         if (l->major != r->major || l->minor != r->minor ||
117                         l->build != r->build || l->revision != r->revision)
118                 return FALSE;
119
120         if (!l->public_tok_value && !r->public_tok_value)
121                 return TRUE;
122
123         if ((l->public_tok_value && !r->public_tok_value) || (!l->public_tok_value && r->public_tok_value))
124                 return FALSE;
125
126         if (strcmp (l->public_tok_value, r->public_tok_value))
127                 return FALSE;
128         */
129         return TRUE;
130 }
131
132 /* assemblies_mutex must be held by the caller */
133 static MonoAssembly*
134 search_loaded (MonoAssemblyName* aname)
135 {
136         GList *tmp;
137         MonoAssembly *ass;
138         GList *loading;
139         
140         for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
141                 ass = tmp->data;
142                 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
143                 if (!mono_assembly_names_equal (aname, &ass->aname))
144                         continue;
145                 /* g_print ("success\n"); */
146
147                 return ass;
148         }
149
150         /*
151          * The assembly might be under load by this thread. In this case, it is
152          * safe to return an incomplete instance to prevent loops.
153          */
154         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
155         for (tmp = loading; tmp; tmp = tmp->next) {
156                 ass = tmp->data;
157                 if (!mono_assembly_names_equal (aname, &ass->aname))
158                         continue;
159
160                 return ass;
161         }
162
163         return NULL;
164 }
165
166 static MonoAssembly *
167 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
168 {
169         int i;
170         char *fullpath;
171         MonoAssembly *result;
172
173         for (i = 0; search_path [i]; ++i) {
174                 fullpath = g_build_filename (search_path [i], basename, NULL);
175                 result = mono_assembly_open (fullpath, status);
176                 g_free (fullpath);
177                 if (result)
178                         return result;
179         }
180         return NULL;
181 }
182
183 /**
184  * mono_assembly_setrootdir:
185  * @root_dir: The pathname of the root directory where we will locate assemblies
186  *
187  * This routine sets the internal default root directory for looking up
188  * assemblies.  This is used by Windows installations to compute dynamically
189  * the place where the Mono assemblies are located.
190  *
191  */
192 void
193 mono_assembly_setrootdir (const char *root_dir)
194 {
195         /*
196          * Override the MONO_ASSEMBLIES directory configured at compile time.
197          */
198         /* Leak if called more than once */
199         default_path [0] = g_strdup (root_dir);
200 }
201
202 /**
203  * mono_assemblies_init:
204  *
205  *  Initialize global variables used by this module.
206  */
207 void
208 mono_assemblies_init (void)
209 {
210 #ifdef PLATFORM_WIN32
211         init_default_path ();
212 #endif
213
214         check_env ();
215
216         InitializeCriticalSection (&assemblies_mutex);
217
218         assemblies_loading = g_hash_table_new (NULL, NULL);
219 }
220
221 gboolean
222 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
223 {
224         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
225         guint32 cols [MONO_ASSEMBLY_SIZE];
226
227         if (!t->rows)
228                 return FALSE;
229
230         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
231
232         aname->hash_len = 0;
233         aname->hash_value = NULL;
234         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
235         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
236         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
237         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
238         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
239         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
240         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
241         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
242         if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
243                 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
244         else
245                 aname->public_key = 0;
246
247         return TRUE;
248 }
249
250 static gchar*
251 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
252 {
253         const gchar *public_tok;
254         int len;
255
256         public_tok = mono_metadata_blob_heap (image, key_index);
257         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
258
259         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
260                 gchar token [8];
261                 mono_digest_get_public_token (token, public_tok, len);
262                 return encode_public_tok (token, 8);
263         }
264
265         return encode_public_tok (public_tok, len);
266 }
267
268 void
269 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
270 {
271         MonoTableInfo *t;
272         guint32 cols [MONO_ASSEMBLYREF_SIZE];
273         const char *hash;
274         int i;
275         MonoAssembly **references = NULL;
276
277         *status = MONO_IMAGE_OK;
278         
279         /*
280          * image->references is shared between threads, so we need to access
281          * it inside a critical section.
282          */
283         EnterCriticalSection (&assemblies_mutex);
284         references = image->references;
285         LeaveCriticalSection (&assemblies_mutex);
286         if (references)
287                 return;
288
289         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
290
291         references = g_new0 (MonoAssembly *, t->rows + 1);
292
293         /*
294          * Load any assemblies this image references
295          */
296         for (i = 0; i < t->rows; i++) {
297                 MonoAssemblyName aname;
298
299                 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
300                 
301                 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
302                 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
303                 aname.hash_value = hash;
304                 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
305                 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
306                 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
307                 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
308                 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
309                 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
310                 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
311
312                 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
313                         aname.public_tok_value = assemblyref_public_tok (image,
314                                         cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
315                 } else {
316                         aname.public_tok_value = NULL;
317                 } 
318
319                 references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
320
321                 if (references [i] == NULL){
322                         int j;
323
324                         /*
325                         ** Temporary work around: any System.* which are 3300 build, will get
326                         ** remapped, this is to keep old applications running that might have
327                         ** been linked against our 5000 API, before we were strongnamed, and
328                         ** hence were labeled as 3300 builds by reflection.c
329                         */
330                         if (aname.build == 3300 && strncmp (aname.name, "System", 6) == 0){
331                                 aname.build = 5000;
332                                 
333                                 references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
334                         }
335                         if (references [i] != NULL){
336                                 if (getenv ("MONO_SILENT_WARNING") == NULL)
337                                         g_printerr ("Compat mode: the request from %s to load %s was remapped (http://www.go-mono.com/remap.html)\n",
338                                                  image->name, aname.name);
339                                 
340                         } else {
341                         
342                                 for (j = 0; j < i; j++)
343                                         mono_assembly_close (references [j]);
344                                 g_free (references);
345                                 
346                                 g_warning ("Could not find assembly %s, references from %s (assemblyref_index=%d)\n"
347                                            "     Major/Minor: %d,%d\n"
348                                            "     Build:       %d,%d\n"
349                                            "     Token:       %s\n",
350                                            aname.name, image->name, i,
351                                            aname.major, aname.minor, aname.build, aname.revision,
352                                            aname.public_tok_value);
353                                 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
354                                 return;
355                         }
356                 }
357
358                 /* 
359                  * This check is disabled since lots of people seem to have an older
360                  * corlib which triggers this.
361                  */
362                 /* 
363                 if (image->references [i]->image == image)
364                         g_error ("Error: Assembly %s references itself", image->name);
365                 */
366         }
367         references [i] = NULL;
368
369         /* resolve assembly references for modules */
370         t = &image->tables [MONO_TABLE_MODULEREF];
371         for (i = 0; i < t->rows; i++){
372                 if (image->modules [i]) {
373                         image->modules [i]->assembly = image->assembly;
374                         mono_assembly_load_references (image->modules [i], status);
375                 }
376         }
377
378         EnterCriticalSection (&assemblies_mutex);
379         if (!image->references)
380                 image->references = references;
381         LeaveCriticalSection (&assemblies_mutex);
382
383         if (image->references != references) {
384                 /* Somebody loaded it before us */
385                 for (i = 0; i < t->rows; i++)
386                         mono_assembly_close (references [i]);
387                 g_free (references);
388         }
389 }
390
391 typedef struct AssemblyLoadHook AssemblyLoadHook;
392 struct AssemblyLoadHook {
393         AssemblyLoadHook *next;
394         MonoAssemblyLoadFunc func;
395         gpointer user_data;
396 };
397
398 AssemblyLoadHook *assembly_load_hook = NULL;
399
400 void
401 mono_assembly_invoke_load_hook (MonoAssembly *ass)
402 {
403         AssemblyLoadHook *hook;
404
405         for (hook = assembly_load_hook; hook; hook = hook->next) {
406                 hook->func (ass, hook->user_data);
407         }
408 }
409
410 void
411 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
412 {
413         AssemblyLoadHook *hook;
414         
415         g_return_if_fail (func != NULL);
416
417         hook = g_new0 (AssemblyLoadHook, 1);
418         hook->func = func;
419         hook->user_data = user_data;
420         hook->next = assembly_load_hook;
421         assembly_load_hook = hook;
422 }
423
424 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
425 struct AssemblyPreLoadHook {
426         AssemblyPreLoadHook *next;
427         MonoAssemblyPreLoadFunc func;
428         gpointer user_data;
429 };
430
431 AssemblyPreLoadHook *assembly_preload_hook = NULL;
432
433 static MonoAssembly *
434 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
435 {
436         AssemblyPreLoadHook *hook;
437         MonoAssembly *assembly;
438
439         for (hook = assembly_preload_hook; hook; hook = hook->next) {
440                 assembly = hook->func (aname, assemblies_path, hook->user_data);
441                 if (assembly != NULL)
442                         return assembly;
443         }
444
445         return NULL;
446 }
447
448 void
449 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
450 {
451         AssemblyPreLoadHook *hook;
452         
453         g_return_if_fail (func != NULL);
454
455         hook = g_new0 (AssemblyPreLoadHook, 1);
456         hook->func = func;
457         hook->user_data = user_data;
458         hook->next = assembly_preload_hook;
459         assembly_preload_hook = hook;
460 }
461
462 static gchar *
463 absolute_dir (const gchar *filename)
464 {
465         gchar *cwd;
466         gchar *mixed;
467         gchar **parts;
468         gchar *part;
469         GList *list, *tmp;
470         GString *result;
471         gchar *res;
472         gint i;
473
474         if (g_path_is_absolute (filename))
475                 return g_path_get_dirname (filename);
476
477         cwd = g_get_current_dir ();
478         mixed = g_build_filename (cwd, filename, NULL);
479         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
480         g_free (mixed);
481         g_free (cwd);
482
483         list = NULL;
484         for (i = 0; (part = parts [i]) != NULL; i++) {
485                 if (!strcmp (part, "."))
486                         continue;
487
488                 if (!strcmp (part, "..")) {
489                         if (list && list->next) /* Don't remove root */
490                                 list = g_list_delete_link (list, list);
491                 } else {
492                         list = g_list_prepend (list, part);
493                 }
494         }
495
496         result = g_string_new ("");
497         list = g_list_reverse (list);
498
499         /* Ignores last data pointer, which should be the filename */
500         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
501                 if (tmp->data)
502                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
503                                                                 G_DIR_SEPARATOR);
504         
505         res = result->str;
506         g_string_free (result, FALSE);
507         g_list_free (list);
508         g_strfreev (parts);
509         if (*res == '\0') {
510                 g_free (res);
511                 return g_strdup (".");
512         }
513
514         return res;
515 }
516
517 static MonoImage*
518 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
519 {
520         MonoImage *image = NULL;
521 #ifdef WITH_BUNDLE
522         int i;
523         char *name = g_path_get_basename (filename);
524         char *dot = strrchr (name, '.');
525         GList *tmp;
526         MonoAssembly *ass;
527         
528         if (dot)
529                 *dot = 0;
530         /* we do a very simple search for bundled assemblies: it's not a general 
531          * purpose assembly loading mechanism.
532          */
533         EnterCriticalSection (&assemblies_mutex);
534         for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
535                 ass = tmp->data;
536                 if (!ass->aname.name)
537                         continue;
538                 if (strcmp (name, ass->aname.name))
539                         continue;
540                 image = ass->image;
541                 break;
542         }
543
544         for (i = 0; !image && bundled_assemblies [i]; ++i) {
545                 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
546                         image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
547                         break;
548                 }
549         }
550         LeaveCriticalSection (&assemblies_mutex);
551         g_free (name);
552         if (image) {
553                 mono_image_addref (image);
554                 return image;
555         }
556 #endif
557         EnterCriticalSection (&assemblies_mutex);
558         image = mono_image_open (filename, status);
559         LeaveCriticalSection (&assemblies_mutex);
560         
561         return image;
562 }
563
564 /**
565  * mono_assembly_open:
566  * @filename: Opens the assembly pointed out by this name
567  * @status: where a status code can be returned
568  *
569  * mono_assembly_open opens the PE-image pointed by @filename, and
570  * loads any external assemblies referenced by it.
571  *
572  * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
573  * it. 
574  */
575 MonoAssembly *
576 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
577 {
578         MonoImage *image;
579         MonoAssembly *ass;
580         MonoImageOpenStatus def_status;
581         gchar *fname;
582         
583         g_return_val_if_fail (filename != NULL, NULL);
584
585         if (!status)
586                 status = &def_status;
587         *status = MONO_IMAGE_OK;
588
589         if (strncmp (filename, "file://", 7) == 0) {
590                 GError *error = NULL;
591                 gchar *uri = (gchar *) filename;
592                 gchar *tmpuri;
593
594                 /*
595                  * MS allows file://c:/... and fails on file://localhost/c:/... 
596                  * They also throw an IndexOutOfRangeException if "file://"
597                  */
598                 if (uri [7] != '/')
599                         uri = g_strdup_printf ("file:///%s", uri + 7);
600         
601                 tmpuri = uri;
602                 uri = mono_escape_uri_string (tmpuri);
603                 fname = g_filename_from_uri (uri, NULL, &error);
604                 g_free (uri);
605
606                 if (tmpuri != filename)
607                         g_free (tmpuri);
608
609                 if (error != NULL) {
610                         g_warning ("%s\n", error->message);
611                         g_error_free (error);
612                         fname = g_strdup (filename);
613                 }
614         } else {
615                 fname = g_strdup (filename);
616         }
617
618         /* g_print ("file loading %s\n", fname); */
619         image = do_mono_assembly_open (fname, status);
620
621         if (!image){
622                 *status = MONO_IMAGE_ERROR_ERRNO;
623                 g_free (fname);
624                 return NULL;
625         }
626
627         ass = mono_assembly_load_from (image, fname, status);
628
629         mono_config_for_assembly (ass->image);
630
631         g_free (fname);
632
633         return ass;
634 }
635
636 MonoAssembly *
637 mono_assembly_load_from (MonoImage *image, const char*fname, 
638                          MonoImageOpenStatus *status)
639 {
640         MonoAssembly *ass, *ass2;
641         char *base_dir;
642         GList *loading;
643
644 #if defined (PLATFORM_WIN32)
645         {
646                 gchar *tmp_fn;
647                 int i;
648
649                 tmp_fn = g_strdup (fname);
650                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
651                         if (tmp_fn [i] == '/')
652                                 tmp_fn [i] = '\\';
653                 }
654
655                 base_dir = absolute_dir (tmp_fn);
656                 g_free (tmp_fn);
657         }
658 #else
659         base_dir = absolute_dir (fname);
660 #endif
661
662         /*
663          * To avoid deadlocks and scalability problems, we load assemblies outside
664          * the assembly lock. This means that multiple threads might try to load
665          * the same assembly at the same time. The first one to load it completely
666          * "wins", the other threads free their copy and use the one loaded by
667          * the winning thread.
668          */
669
670         /*
671          * Create assembly struct, and enter it into the assembly cache
672          */
673         ass = g_new0 (MonoAssembly, 1);
674         ass->basedir = base_dir;
675         ass->image = image;
676
677         mono_assembly_fill_assembly_name (image, &ass->aname);
678
679         /* 
680          * Atomically search the loaded list and add ourselves to it if necessary.
681          */
682         EnterCriticalSection (&assemblies_mutex);
683         if (ass->aname.name)
684                 /* avoid loading the same assembly twice for now... */
685                 if ((ass2 = search_loaded (&ass->aname))) {
686                         g_free (ass);
687                         g_free (base_dir);
688                         mono_image_close (image);
689                         *status = MONO_IMAGE_OK;
690                         LeaveCriticalSection (&assemblies_mutex);
691                         return ass2;
692                 }
693         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
694         loading = g_list_prepend (loading, ass);
695         g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
696         LeaveCriticalSection (&assemblies_mutex);
697
698         image->assembly = ass;
699
700         /*
701          * We load referenced assemblies outside the lock to prevent deadlocks
702          * with regards to preload hooks.
703          */
704         mono_assembly_load_references (image, status);
705
706         EnterCriticalSection (&assemblies_mutex);
707
708         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
709         loading = g_list_remove (loading, ass);
710         if (loading == NULL)
711                 /* Prevent memory leaks */
712                 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
713         else
714                 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
715         if (*status != MONO_IMAGE_OK) {
716                 LeaveCriticalSection (&assemblies_mutex);
717                 mono_assembly_close (ass);
718                 return NULL;
719         }
720
721         if (ass->aname.name) {
722                 ass2 = search_loaded (&ass->aname);
723                 if (ass2) {
724                         /* Somebody else has loaded the assembly before us */
725                         LeaveCriticalSection (&assemblies_mutex);
726                         mono_assembly_close (ass);
727                         return ass2;
728                 }
729         }
730
731         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
732         LeaveCriticalSection (&assemblies_mutex);
733
734         mono_assembly_invoke_load_hook (ass);
735
736         return ass;
737 }
738
739 /**
740  * mono_assembly_load_from_gac
741  *
742  * @aname: The assembly name object
743  */
744 static MonoAssembly*
745 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status)
746 {
747         MonoAssembly *result = NULL;
748         gchar *name, *version, *fullpath;
749         gint32 len;
750
751         if (!aname->public_tok_value) {
752                 return NULL;
753         }
754
755         if (strstr (aname->name, ".dll")) {
756                 len = strlen (filename) - 4;
757                 name = g_malloc (len);
758                 strncpy (name, aname->name, len);
759         } else {
760                 name = g_strdup (aname->name);
761         }
762
763         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
764                         aname->minor, aname->build, aname->revision,
765                         aname->culture == NULL ? "" : aname->culture,
766                         aname->public_tok_value);
767         
768         fullpath = g_build_path (G_DIR_SEPARATOR_S, MONO_ASSEMBLIES, "mono", "gac",
769                         name, version, filename, NULL);
770         result = mono_assembly_open (fullpath, status);
771
772         g_free (fullpath);
773
774         if (!result && allow_user_gac) {
775                 fullpath = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".mono", "gac",
776                                 name, version, filename, NULL);
777                 result = mono_assembly_open (fullpath, status);
778                 g_free (fullpath);
779         }
780
781         if (result)
782                 result->in_gac = TRUE;
783         
784         g_free (name);
785         g_free (version);
786
787         return result;
788 }
789
790         
791 MonoAssembly*
792 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
793 {
794         MonoAssembly *result;
795         char *fullpath, *filename;
796
797         result = invoke_assembly_preload_hook (aname, assemblies_path);
798         if (result)
799                 return result;
800         /* g_print ("loading %s\n", aname->name); */
801         /* special case corlib */
802         if (strcmp (aname->name, "mscorlib") == 0) {
803                 if (corlib) {
804                         /* g_print ("corlib already loaded\n"); */
805                         return corlib;
806                 }
807                 /* g_print ("corlib load\n"); */
808                 if (assemblies_path) {
809                         corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
810                         if (corlib)
811                                 return corlib;
812                 }
813                 corlib = load_in_path ("mscorlib.dll", default_path, status);
814                 return corlib;
815         }
816         result = search_loaded (aname);
817
818         if (result)
819                 return result;
820         /* g_print ("%s not found in cache\n", aname->name); */
821         if (strstr (aname->name, ".dll"))
822                 filename = g_strdup (aname->name);
823         else
824                 filename = g_strconcat (aname->name, ".dll", NULL);
825
826         result = mono_assembly_load_from_gac (aname, filename, status);
827         if (result) {
828                 g_free (filename);
829                 return result;
830         }
831
832         if (basedir) {
833                 fullpath = g_build_filename (basedir, filename, NULL);
834                 result = mono_assembly_open (fullpath, status);
835                 g_free (fullpath);
836                 if (result) {
837                         result->in_gac = FALSE;
838                         g_free (filename);
839                         return result;
840                 }
841         }
842         if (assemblies_path) {
843                 result = load_in_path (filename, (const char**)assemblies_path, status);
844                 if (result) {
845                         result->in_gac = FALSE;
846                         g_free (filename);
847                         return result;
848                 }
849         }
850         result = load_in_path (filename, default_path, status);
851         
852         if (result)
853                 result->in_gac = FALSE;
854         g_free (filename);
855         return result;
856 }
857
858 MonoAssembly*
859 mono_assembly_loaded (MonoAssemblyName *aname)
860 {
861         MonoAssembly *res;
862
863         EnterCriticalSection (&assemblies_mutex);
864         res = search_loaded (aname);
865         LeaveCriticalSection (&assemblies_mutex);
866
867         return res;
868 }
869
870 void
871 mono_assembly_close (MonoAssembly *assembly)
872 {
873         MonoImage *image;
874         int i;
875         
876         g_return_if_fail (assembly != NULL);
877
878         EnterCriticalSection (&assemblies_mutex);
879         if (--assembly->ref_count != 0) {
880                 LeaveCriticalSection (&assemblies_mutex);
881                 return;
882         }
883         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
884         LeaveCriticalSection (&assemblies_mutex);
885         image = assembly->image;
886         if (image->references) {
887                 for (i = 0; image->references [i] != NULL; i++)
888                         mono_image_close (image->references [i]->image);
889                 g_free (image->references);
890         }
891
892         mono_image_close (assembly->image);
893
894         g_free (assembly->basedir);
895         g_free (assembly);
896 }
897
898 MonoImage*
899 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
900 {
901         MonoImageOpenStatus status;
902         MonoImage *module;
903
904         module = mono_image_load_file_for_image (assembly->image, idx);
905         if (module)
906                 mono_assembly_load_references (module, &status);
907
908         return module;
909 }
910
911 void
912 mono_assembly_foreach (GFunc func, gpointer user_data)
913 {
914         GList *copy;
915
916         /*
917      * We make a copy of the list to avoid calling the callback inside the 
918          * lock, which could lead to deadlocks.
919          */
920         EnterCriticalSection (&assemblies_mutex);
921         copy = g_list_copy (loaded_assemblies);
922         LeaveCriticalSection (&assemblies_mutex);
923
924         g_list_foreach (loaded_assemblies, func, user_data);
925
926         g_list_free (copy);
927 }
928
929 /* Holds the assembly of the application, for
930  * System.Diagnostics.Process::MainModule
931  */
932 static MonoAssembly *main_assembly=NULL;
933
934 void
935 mono_assembly_set_main (MonoAssembly *assembly)
936 {
937         main_assembly=assembly;
938 }
939
940 MonoAssembly *
941 mono_assembly_get_main (void)
942 {
943         return(main_assembly);
944 }
945
946 void
947 mono_assembly_allow_user_gac (gboolean allow)
948 {
949         allow_user_gac = allow;
950 }
951