Merge pull request #2590 from esdrubal/wcf_req
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Authors:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2012 Xamarin Inc
12  */
13 #undef ASSEMBLY_LOAD_DEBUG
14 #include <config.h>
15 #include <glib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #ifdef HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_UTIME_H
28 #include <utime.h>
29 #else
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
32 #endif
33 #endif
34
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/reflection-internals.h>
59 #include <mono/utils/mono-uri.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-path.h>
62 #include <mono/utils/mono-stdlib.h>
63 #include <mono/utils/mono-io-portability.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/utils/atomic.h>
66 #include <mono/utils/mono-memory-model.h>
67 #include <mono/utils/mono-threads.h>
68 #ifdef HOST_WIN32
69 #include <direct.h>
70 #endif
71
72 /*
73  * This is the version number of the corlib-runtime interface. When
74  * making changes to this interface (by changing the layout
75  * of classes the runtime knows about, changing icall signature or
76  * semantics etc), increment this variable. Also increment the
77  * pair of this variable in mscorlib in:
78  *       mcs/class/corlib/System/Environment.cs
79  *
80  * Changes which are already detected at runtime, like the addition
81  * of icalls, do not require an increment.
82  */
83 #define MONO_CORLIB_VERSION 140
84
85 typedef struct
86 {
87         int runtime_count;
88         int assemblybinding_count;
89         MonoDomain *domain;
90         gchar *filename;
91 } RuntimeConfig;
92
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
95
96 static gboolean no_exec = FALSE;
97
98 static MonoAssembly *
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100                               gchar **assemblies_path,
101                               gpointer user_data);
102
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
105                                                          gpointer user_data);
106
107 static void
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
109
110 static void
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
112
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
115
116 static char *
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
118
119 static MonoLoadFunc load_function = NULL;
120
121 void
122 mono_install_runtime_load (MonoLoadFunc func)
123 {
124         load_function = func;
125 }
126
127 MonoDomain*
128 mono_runtime_load (const char *filename, const char *runtime_version)
129 {
130         g_assert (load_function);
131         return load_function (filename, runtime_version);
132 }
133
134 /**
135  * mono_runtime_set_no_exec:
136  *
137  * Instructs the runtime to operate in static mode, i.e. avoid/do not
138  * allow managed code execution. This is useful for running the AOT
139  * compiler on platforms which allow full-aot execution only.  This
140  * should be called before mono_runtime_init ().
141  */
142 void
143 mono_runtime_set_no_exec (gboolean val)
144 {
145         no_exec = val;
146 }
147
148 /**
149  * mono_runtime_get_no_exec:
150  *
151  * If true, then the runtime will not allow managed code execution.
152  */
153 gboolean
154 mono_runtime_get_no_exec (void)
155 {
156         return no_exec;
157 }
158
159 static void
160 create_domain_objects (MonoDomain *domain)
161 {
162         MonoError error;
163         MonoDomain *old_domain = mono_domain_get ();
164         MonoString *arg;
165         MonoVTable *string_vt;
166         MonoClassField *string_empty_fld;
167
168         if (domain != old_domain) {
169                 mono_thread_push_appdomain_ref (domain);
170                 mono_domain_set_internal_with_options (domain, FALSE);
171         }
172
173         /*
174          * Initialize String.Empty. This enables the removal of
175          * the static cctor of the String class.
176          */
177         string_vt = mono_class_vtable (domain, mono_defaults.string_class);
178         string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
179         g_assert (string_empty_fld);
180         mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
181
182         /*
183          * Create an instance early since we can't do it when there is no memory.
184          */
185         arg = mono_string_new (domain, "Out of memory");
186         domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
187
188         /* 
189          * These two are needed because the signal handlers might be executing on
190          * an alternate stack, and Boehm GC can't handle that.
191          */
192         arg = mono_string_new (domain, "A null value was found where an object instance was required");
193         domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
194         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
195         domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
196
197         /*The ephemeron tombstone i*/
198         domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
199         mono_error_assert_ok (&error);
200
201         if (domain != old_domain) {
202                 mono_thread_pop_appdomain_ref ();
203                 mono_domain_set_internal_with_options (old_domain, FALSE);
204         }
205
206         /* 
207          * This class is used during exception handling, so initialize it here, to prevent
208          * stack overflows while handling stack overflows.
209          */
210         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
211 }
212
213 /**
214  * mono_runtime_init:
215  * @domain: domain returned by mono_init ()
216  *
217  * Initialize the core AppDomain: this function will run also some
218  * IL initialization code, so it needs the execution engine to be fully 
219  * operational.
220  *
221  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
222  * we know the entry_assembly.
223  *
224  */
225 void
226 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
227                    MonoThreadAttachCB attach_cb)
228 {
229         MonoError error;
230         MonoAppDomainSetup *setup;
231         MonoAppDomain *ad;
232         MonoClass *klass;
233
234         mono_portability_helpers_init ();
235         
236         mono_gc_base_init ();
237         mono_monitor_init ();
238         mono_marshal_init ();
239
240         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
241         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
242         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
243         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
244         mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
245         mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
246         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
247         mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
248
249         mono_thread_init (start_cb, attach_cb);
250
251         klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
252         setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, &error);
253         mono_error_raise_exception (&error); /* FIXME don't raise here */
254
255         klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
256         ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, &error);
257         mono_error_raise_exception (&error); /* FIXME don't raise here */
258         ad->data = domain;
259         domain->domain = ad;
260         domain->setup = setup;
261
262         mono_thread_attach (domain);
263
264         mono_type_initialization_init ();
265
266         if (!mono_runtime_get_no_exec ())
267                 create_domain_objects (domain);
268
269         /* GC init has to happen after thread init */
270         mono_gc_init ();
271
272         /* contexts use GC handles, so they must be initialized after the GC */
273         mono_context_init (domain);
274         mono_context_set (domain->default_context);
275
276 #ifndef DISABLE_SOCKETS
277         mono_network_init ();
278 #endif
279         
280         mono_console_init ();
281         mono_attach_init ();
282
283         mono_locks_tracer_init ();
284
285         /* mscorlib is loaded before we install the load hook */
286         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
287
288         return;
289 }
290
291 static int
292 mono_get_corlib_version (void)
293 {
294         MonoClass *klass;
295         MonoClassField *field;
296         MonoObject *value;
297
298         klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
299         mono_class_init (klass);
300         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
301         if (!field)
302                 return -1;
303         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
304                 return -1;
305         value = mono_field_get_value_object (mono_domain_get (), field, NULL);
306         return *(gint32*)((gchar*)value + sizeof (MonoObject));
307 }
308
309 /**
310  * mono_check_corlib_version
311  *
312  * Checks that the corlib that is loaded matches the version of this runtime.
313  *
314  * Returns: NULL if the runtime will work with the corlib, or a g_malloc
315  * allocated string with the error otherwise.
316  */
317 const char*
318 mono_check_corlib_version (void)
319 {
320         int version = mono_get_corlib_version ();
321         if (version != MONO_CORLIB_VERSION)
322                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
323         else
324                 return NULL;
325 }
326
327 /**
328  * mono_context_init:
329  * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
330  *
331  * Initializes the @domain's default System.Runtime.Remoting's Context.
332  */
333 void
334 mono_context_init (MonoDomain *domain)
335 {
336         MonoError error;
337         MonoClass *klass;
338         MonoAppContext *context;
339
340         klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
341         context = (MonoAppContext *) mono_object_new_pinned (domain, klass, &error);
342         mono_error_raise_exception (&error); /* FIXME don't raise here */
343         context->domain_id = domain->domain_id;
344         context->context_id = 0;
345         ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
346         domain->default_context = context;
347 }
348
349 /**
350  * mono_runtime_cleanup:
351  * @domain: unused.
352  *
353  * Internal routine.
354  *
355  * This must not be called while there are still running threads executing
356  * managed code.
357  */
358 void
359 mono_runtime_cleanup (MonoDomain *domain)
360 {
361         mono_attach_cleanup ();
362
363         /* This ends up calling any pending pending (for at most 2 seconds) */
364         mono_gc_cleanup ();
365
366         mono_thread_cleanup ();
367
368 #ifndef DISABLE_SOCKETS
369         mono_network_cleanup ();
370 #endif
371         mono_marshal_cleanup ();
372
373         mono_type_initialization_cleanup ();
374
375         mono_monitor_cleanup ();
376 }
377
378 static MonoDomainFunc quit_function = NULL;
379
380 void
381 mono_install_runtime_cleanup (MonoDomainFunc func)
382 {
383         quit_function = func;
384 }
385
386 void
387 mono_runtime_quit ()
388 {
389         if (quit_function != NULL)
390                 quit_function (mono_get_root_domain (), NULL);
391 }
392
393 /**
394  * mono_domain_create_appdomain:
395  * @friendly_name: The friendly name of the appdomain to create
396  * @configuration_file: The configuration file to initialize the appdomain with
397  * 
398  * Returns a MonoDomain initialized with the appdomain
399  */
400 MonoDomain *
401 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
402 {
403         MonoError error;
404         MonoAppDomain *ad;
405         MonoAppDomainSetup *setup;
406         MonoClass *klass;
407
408         klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
409         setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
410         mono_error_raise_exception (&error); /* FIXME don't raise here */
411         setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
412
413         ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
414         mono_error_raise_exception (&error); /* FIXME don't raise here */
415
416         return mono_domain_from_appdomain (ad);
417 }
418
419 /**
420  * mono_domain_set_config:
421  * @domain: MonoDomain initialized with the appdomain we want to change
422  * @base_dir: new base directory for the appdomain
423  * @config_file_name: path to the new configuration for the app domain
424  *
425  * Used to set the system configuration for an appdomain
426  *
427  * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: 
428  * Error Initializing the configuration system. ---> System.ArgumentException: 
429  * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
430  */
431 void
432 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
433 {
434         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
435         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
436 }
437
438 static MonoAppDomainSetup*
439 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
440 {
441         MonoError error;
442         MonoDomain *caller_domain = mono_domain_get ();
443         MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
444         MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, &error);
445         mono_error_raise_exception (&error); /* FIXME don't raise here */
446
447         mono_domain_set_internal (domain);
448
449         MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
450         MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
451         MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
452         MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
453         MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
454         MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
455         MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
456         MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
457         MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
458         MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
459         copy->publisher_policy = setup->publisher_policy;
460         copy->path_changed = setup->path_changed;
461         copy->loader_optimization = setup->loader_optimization;
462         copy->disallow_binding_redirects = setup->disallow_binding_redirects;
463         copy->disallow_code_downloads = setup->disallow_code_downloads;
464         MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
465         copy->disallow_appbase_probe = setup->disallow_appbase_probe;
466         MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
467         MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
468         MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
469
470         mono_domain_set_internal (caller_domain);
471
472         return copy;
473 }
474
475 static MonoAppDomain *
476 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
477 {
478         MonoClass *adclass;
479         MonoAppDomain *ad;
480         MonoDomain *data;
481         char *shadow_location;
482
483         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
484
485         /* FIXME: pin all those objects */
486         data = mono_domain_create();
487
488         ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
489         if (!mono_error_ok (error)) return NULL;
490         ad->data = data;
491         data->domain = ad;
492         data->friendly_name = g_strdup (friendly_name);
493
494         mono_profiler_appdomain_name (data, data->friendly_name);
495
496         if (!setup->application_base) {
497                 /* Inherit from the root domain since MS.NET does this */
498                 MonoDomain *root = mono_get_root_domain ();
499                 if (root->setup->application_base) {
500                         MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
501                         mono_error_assert_ok (error); /* FIXME don't swallow the error */
502                         MONO_OBJECT_SETREF (setup, application_base, s);
503                 }
504         }
505
506         mono_context_init (data);
507
508         data->setup = copy_app_domain_setup (data, setup);
509         mono_domain_set_options_from_config (data);
510         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
511
512 #ifndef DISABLE_SHADOW_COPY
513         /*FIXME, guard this for when the debugger is not running */
514         shadow_location = get_shadow_assembly_location_base (data, error);
515         if (!mono_error_ok (error))
516                 return NULL;
517
518         g_free (shadow_location);
519 #endif
520
521         create_domain_objects (data);
522
523         return ad;
524 }
525
526 /**
527  * mono_domain_has_type_resolve:
528  * @domain: application domains being looked up
529  *
530  * Returns: TRUE if the AppDomain.TypeResolve field has been
531  * set.
532  */
533 gboolean
534 mono_domain_has_type_resolve (MonoDomain *domain)
535 {
536         static MonoClassField *field = NULL;
537         MonoObject *o;
538
539         if (field == NULL) {
540                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
541                 g_assert (field);
542         }
543
544         /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
545         if (!domain->domain)
546                 return FALSE;
547
548         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
549         return o != NULL;
550 }
551
552 /**
553  * mono_domain_try_type_resolve:
554  * @domain: application domainwhere the name where the type is going to be resolved
555  * @name: the name of the type to resolve or NULL.
556  * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
557  *
558  * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
559  * the assembly that matches name.
560  *
561  * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
562  *
563  * Returns: A MonoReflectionAssembly or NULL if not found
564  */
565 MonoReflectionAssembly *
566 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
567 {
568         MonoError error;
569         MonoReflectionAssembly *ret;
570         MonoClass *klass;
571         void *params [1];
572         static MonoMethod *method = NULL;
573
574         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
575
576         if (method == NULL) {
577                 klass = domain->domain->mbr.obj.vtable->klass;
578                 g_assert (klass);
579
580                 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
581                 if (method == NULL) {
582                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
583                         return NULL;
584                 }
585         }
586
587         if (name)
588                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
589         else
590                 *params = tb;
591
592         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
593         mono_error_raise_exception (&error); /* FIXME don't raise here */
594
595         return ret;
596 }
597
598 /**
599  * mono_domain_owns_vtable_slot:
600  *
601  *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
602  */
603 gboolean
604 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
605 {
606         gboolean res;
607
608         mono_domain_lock (domain);
609         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
610         mono_domain_unlock (domain);
611         return res;
612 }
613
614 /**
615  * mono_domain_set:
616  * @domain: domain
617  * @force: force setting.
618  *
619  * Set the current appdomain to @domain. If @force is set, set it even
620  * if it is being unloaded.
621  *
622  * Returns:
623  *   TRUE on success;
624  *   FALSE if the domain is unloaded
625  */
626 gboolean
627 mono_domain_set (MonoDomain *domain, gboolean force)
628 {
629         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
630                 return FALSE;
631
632         mono_domain_set_internal (domain);
633
634         return TRUE;
635 }
636
637 MonoObject *
638 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
639 {
640         MonoDomain *add;
641         MonoObject *o;
642         char *str;
643
644         MONO_CHECK_ARG_NULL (name, NULL);
645
646         g_assert (ad);
647         add = ad->data;
648         g_assert (add);
649
650         str = mono_string_to_utf8 (name);
651
652         mono_domain_lock (add);
653
654         if (!strcmp (str, "APPBASE"))
655                 o = (MonoObject *)add->setup->application_base;
656         else if (!strcmp (str, "APP_CONFIG_FILE"))
657                 o = (MonoObject *)add->setup->configuration_file;
658         else if (!strcmp (str, "DYNAMIC_BASE"))
659                 o = (MonoObject *)add->setup->dynamic_base;
660         else if (!strcmp (str, "APP_NAME"))
661                 o = (MonoObject *)add->setup->application_name;
662         else if (!strcmp (str, "CACHE_BASE"))
663                 o = (MonoObject *)add->setup->cache_path;
664         else if (!strcmp (str, "PRIVATE_BINPATH"))
665                 o = (MonoObject *)add->setup->private_bin_path;
666         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
667                 o = (MonoObject *)add->setup->private_bin_path_probe;
668         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
669                 o = (MonoObject *)add->setup->shadow_copy_directories;
670         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
671                 o = (MonoObject *)add->setup->shadow_copy_files;
672         else 
673                 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
674
675         mono_domain_unlock (add);
676         g_free (str);
677
678         if (!o)
679                 return NULL;
680
681         return o;
682 }
683
684 void
685 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
686 {
687         MonoDomain *add;
688
689         MONO_CHECK_ARG_NULL (name,);
690
691         g_assert (ad);
692         add = ad->data;
693         g_assert (add);
694
695         mono_domain_lock (add);
696
697         mono_g_hash_table_insert (add->env, name, data);
698
699         mono_domain_unlock (add);
700 }
701
702 MonoAppDomainSetup *
703 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
704 {
705         g_assert (ad);
706         g_assert (ad->data);
707
708         return ad->data->setup;
709 }
710
711 MonoString *
712 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
713 {
714         g_assert (ad);
715         g_assert (ad->data);
716
717         return mono_string_new (ad->data, ad->data->friendly_name);
718 }
719
720 MonoAppDomain *
721 ves_icall_System_AppDomain_getCurDomain ()
722 {
723         MonoDomain *add = mono_domain_get ();
724
725         return add->domain;
726 }
727
728 MonoAppDomain *
729 ves_icall_System_AppDomain_getRootDomain ()
730 {
731         MonoDomain *root = mono_get_root_domain ();
732
733         return root->domain;
734 }
735
736 MonoBoolean
737 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
738 {
739         MonoDomain *domain = mono_domain_get ();
740
741         return domain->throw_unobserved_task_exceptions;
742 }
743
744 static char*
745 get_attribute_value (const gchar **attribute_names, 
746                      const gchar **attribute_values, 
747                      const char *att_name)
748 {
749         int n;
750         for (n = 0; attribute_names [n] != NULL; n++) {
751                 if (strcmp (attribute_names [n], att_name) == 0)
752                         return g_strdup (attribute_values [n]);
753         }
754         return NULL;
755 }
756
757 static void
758 start_element (GMarkupParseContext *context, 
759                const gchar         *element_name,
760                const gchar        **attribute_names,
761                const gchar        **attribute_values,
762                gpointer             user_data,
763                GError             **error)
764 {
765         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
766         
767         if (strcmp (element_name, "runtime") == 0) {
768                 runtime_config->runtime_count++;
769                 return;
770         }
771
772         if (strcmp (element_name, "assemblyBinding") == 0) {
773                 runtime_config->assemblybinding_count++;
774                 return;
775         }
776
777         if (runtime_config->runtime_count != 1)
778                 return;
779
780         if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
781                 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
782
783                 if (value && g_ascii_strcasecmp (value, "true") == 0)
784                         runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
785         }
786
787         if (runtime_config->assemblybinding_count != 1)
788                 return;
789
790         if (strcmp (element_name, "probing") != 0)
791                 return;
792
793         g_free (runtime_config->domain->private_bin_path);
794         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
795         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
796                 g_free (runtime_config->domain->private_bin_path);
797                 runtime_config->domain->private_bin_path = NULL;
798                 return;
799         }
800 }
801
802 static void
803 end_element (GMarkupParseContext *context,
804              const gchar         *element_name,
805              gpointer             user_data,
806              GError             **error)
807 {
808         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
809         if (strcmp (element_name, "runtime") == 0)
810                 runtime_config->runtime_count--;
811         else if (strcmp (element_name, "assemblyBinding") == 0)
812                 runtime_config->assemblybinding_count--;
813 }
814
815 static void
816 parse_error   (GMarkupParseContext *context, GError *error, gpointer user_data)
817 {
818         RuntimeConfig *state = (RuntimeConfig *)user_data;
819         const gchar *msg;
820         const gchar *filename;
821
822         filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
823         msg = error && error->message ? error->message : "";
824         g_warning ("Error parsing %s: %s", filename, msg);
825 }
826
827 static const GMarkupParser
828 mono_parser = {
829         start_element,
830         end_element,
831         NULL,
832         NULL,
833         parse_error
834 };
835
836 void
837 mono_domain_set_options_from_config (MonoDomain *domain)
838 {
839         MonoError error;
840         gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
841         gsize len;
842         GMarkupParseContext *context;
843         RuntimeConfig runtime_config;
844         gint offset;
845         
846         if (!domain || !domain->setup || !domain->setup->configuration_file)
847                 return;
848
849         config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
850         if (!mono_error_ok (&error)) {
851                 mono_error_cleanup (&error);
852                 goto free_and_out;
853         }
854
855         config_file_path = mono_portability_find_file (config_file_name, TRUE);
856         if (!config_file_path)
857                 config_file_path = config_file_name;
858
859         if (!g_file_get_contents (config_file_path, &text, &len, NULL))
860                 goto free_and_out;
861
862         runtime_config.runtime_count = 0;
863         runtime_config.assemblybinding_count = 0;
864         runtime_config.domain = domain;
865         runtime_config.filename = config_file_path;
866         
867         offset = 0;
868         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
869                 offset = 3; /* Skip UTF-8 BOM */
870
871         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
872         if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
873                 g_markup_parse_context_end_parse (context, NULL);
874         g_markup_parse_context_free (context);
875
876   free_and_out:
877         g_free (text);
878         if (config_file_name != config_file_path)
879                 g_free (config_file_name);
880         g_free (config_file_path);
881 }
882
883 MonoAppDomain *
884 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
885 {
886 #ifdef DISABLE_APPDOMAINS
887         mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
888         return NULL;
889 #else
890         MonoError error;
891         char *fname;
892         MonoAppDomain *ad;
893
894         fname = mono_string_to_utf8 (friendly_name);
895         ad = mono_domain_create_appdomain_internal (fname, setup, &error);
896
897         g_free (fname);
898
899         mono_error_raise_exception (&error);
900
901         return ad;
902 #endif
903 }
904
905 MonoArray *
906 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
907 {
908         MonoError error;
909         MonoDomain *domain = ad->data; 
910         MonoAssembly* ass;
911         static MonoClass *System_Reflection_Assembly;
912         MonoArray *res;
913         GSList *tmp;
914         int i;
915         GPtrArray *assemblies;
916
917         mono_error_init (&error);
918         
919         if (!System_Reflection_Assembly)
920                 System_Reflection_Assembly = mono_class_from_name (
921                         mono_defaults.corlib, "System.Reflection", "Assembly");
922
923         /* 
924          * Make a copy of the list of assemblies because we can't hold the assemblies
925          * lock while creating objects etc.
926          */
927         assemblies = g_ptr_array_new ();
928         /* Need to skip internal assembly builders created by remoting */
929         mono_domain_assemblies_lock (domain);
930         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
931                 ass = (MonoAssembly *)tmp->data;
932                 if (refonly != ass->ref_only)
933                         continue;
934                 if (ass->corlib_internal)
935                         continue;
936                 g_ptr_array_add (assemblies, ass);
937         }
938         mono_domain_assemblies_unlock (domain);
939
940         res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
941         for (i = 0; i < assemblies->len; ++i) {
942                 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
943                 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
944                 if (!mono_error_ok (&error))
945                         goto leave;
946                 mono_array_setref (res, i, ass_obj);
947         }
948
949 leave:
950         g_ptr_array_free (assemblies, TRUE);
951         if (!mono_error_ok (&error))
952                 mono_error_set_pending_exception (&error);
953         return res;
954 }
955
956 MonoReflectionAssembly *
957 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
958 {
959         MonoError error;
960         MonoReflectionAssembly *ret;
961         MonoClass *klass;
962         MonoMethod *method;
963         MonoBoolean isrefonly;
964         gpointer params [3];
965
966         if (mono_runtime_get_no_exec ())
967                 return NULL;
968
969         g_assert (domain != NULL && fname != NULL);
970
971         klass = domain->domain->mbr.obj.vtable->klass;
972         g_assert (klass);
973         
974         method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
975         if (method == NULL) {
976                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
977                 return NULL;
978         }
979
980         isrefonly = refonly ? 1 : 0;
981         params [0] = fname;
982         if (requesting) {
983                 params[1] = mono_assembly_get_object_checked (domain, requesting, &error);
984                 if (!mono_error_ok (&error))
985                         mono_error_raise_exception (&error); /* FIXME don't raise here */
986         } else
987                 params [1] = NULL;
988         params [2] = &isrefonly;
989
990         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
991         mono_error_raise_exception (&error); /* FIXME don't raise here */
992
993         return ret;
994 }
995
996 MonoAssembly *
997 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
998                                                                           gboolean refonly)
999 {
1000         MonoReflectionAssembly *assembly;
1001         MonoDomain *domain = mono_domain_get ();
1002         char *aname_str;
1003         MonoString *str;
1004
1005         aname_str = mono_stringify_assembly_name (aname);
1006
1007         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1008         str = mono_string_new (domain, aname_str);
1009         if (!str) {
1010                 g_free (aname_str);
1011                 return NULL;
1012         }
1013         assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
1014         g_free (aname_str);
1015
1016         if (assembly)
1017                 return assembly->assembly;
1018         else
1019                 return NULL;
1020 }
1021         
1022 /*
1023  * LOCKING: assumes assemblies_lock in the domain is already locked.
1024  */
1025 static void
1026 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1027 {
1028         gint i;
1029         GSList *tmp;
1030         gboolean destroy_ht = FALSE;
1031
1032         if (!ass->aname.name)
1033                 return;
1034
1035         if (!ht) {
1036                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1037                 destroy_ht = TRUE;
1038         }
1039
1040         /* FIXME: handle lazy loaded assemblies */
1041         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1042                 g_hash_table_insert (ht, tmp->data, tmp->data);
1043         }
1044         if (!g_hash_table_lookup (ht, ass)) {
1045                 mono_assembly_addref (ass);
1046                 g_hash_table_insert (ht, ass, ass);
1047                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1048                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1049         }
1050
1051         if (ass->image->references) {
1052                 for (i = 0; ass->image->references [i] != NULL; i++) {
1053                         if (ass->image->references [i] != REFERENCE_MISSING)
1054                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1055                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1056                                 }
1057                 }
1058         }
1059         if (destroy_ht)
1060                 g_hash_table_destroy (ht);
1061 }
1062
1063 static void
1064 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1065 {
1066         static MonoClassField *assembly_load_field;
1067         static MonoMethod *assembly_load_method;
1068         MonoError error;
1069         MonoDomain *domain = mono_domain_get ();
1070         MonoReflectionAssembly *ref_assembly;
1071         MonoClass *klass;
1072         gpointer load_value;
1073         void *params [1];
1074
1075         if (!domain->domain)
1076                 /* This can happen during startup */
1077                 return;
1078 #ifdef ASSEMBLY_LOAD_DEBUG
1079         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1080 #endif
1081         klass = domain->domain->mbr.obj.vtable->klass;
1082
1083         mono_domain_assemblies_lock (domain);
1084         add_assemblies_to_domain (domain, assembly, NULL);
1085         mono_domain_assemblies_unlock (domain);
1086
1087         if (assembly_load_field == NULL) {
1088                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1089                 g_assert (assembly_load_field);
1090         }
1091
1092         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1093         if (load_value == NULL) {
1094                 /* No events waiting to be triggered */
1095                 return;
1096         }
1097
1098         ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1099         mono_error_assert_ok (&error);
1100
1101         if (assembly_load_method == NULL) {
1102                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1103                 g_assert (assembly_load_method);
1104         }
1105
1106         *params = ref_assembly;
1107
1108         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1109         mono_error_raise_exception (&error); /* FIXME don't raise here */
1110 }
1111
1112 /*
1113  * LOCKING: Acquires the domain assemblies lock.
1114  */
1115 static void
1116 set_domain_search_path (MonoDomain *domain)
1117 {
1118         MonoError error;
1119         MonoAppDomainSetup *setup;
1120         gchar **tmp;
1121         gchar *search_path = NULL;
1122         gint i;
1123         gint npaths = 0;
1124         gchar **pvt_split = NULL;
1125         GError *gerror = NULL;
1126         gint appbaselen = -1;
1127
1128         /* 
1129          * We use the low-level domain assemblies lock, since this is called from
1130          * assembly loads hooks, which means this thread might hold the loader lock.
1131          */
1132         mono_domain_assemblies_lock (domain);
1133
1134         if (!domain->setup) {
1135                 mono_domain_assemblies_unlock (domain);
1136                 return;
1137         }
1138
1139         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1140                 mono_domain_assemblies_unlock (domain);
1141                 return;
1142         }
1143         setup = domain->setup;
1144         if (!setup->application_base) {
1145                 mono_domain_assemblies_unlock (domain);
1146                 return; /* Must set application base to get private path working */
1147         }
1148
1149         npaths++;
1150         
1151         if (setup->private_bin_path) {
1152                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1153                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1154                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1155                         mono_error_cleanup (&error);
1156                         mono_domain_assemblies_unlock (domain);
1157                         return;
1158                 }
1159         }
1160         
1161         if (domain->private_bin_path) {
1162                 if (search_path == NULL)
1163                         search_path = domain->private_bin_path;
1164                 else {
1165                         gchar *tmp2 = search_path;
1166                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1167                         g_free (tmp2);
1168                 }
1169         }
1170         
1171         if (search_path) {
1172                 /*
1173                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1174                  * directories relative to ApplicationBase separated by semicolons (see
1175                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1176                  * The loop below copes with the fact that some Unix applications may use ':' (or
1177                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1178                  * ';' for the subsequent split.
1179                  *
1180                  * The issue was reported in bug #81446
1181                  */
1182
1183 #ifndef TARGET_WIN32
1184                 gint slen;
1185
1186                 slen = strlen (search_path);
1187                 for (i = 0; i < slen; i++)
1188                         if (search_path [i] == ':')
1189                                 search_path [i] = ';';
1190 #endif
1191                 
1192                 pvt_split = g_strsplit (search_path, ";", 1000);
1193                 g_free (search_path);
1194                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1195         }
1196
1197         if (!npaths) {
1198                 if (pvt_split)
1199                         g_strfreev (pvt_split);
1200                 /*
1201                  * Don't do this because the first time is called, the domain
1202                  * setup is not finished.
1203                  *
1204                  * domain->search_path = g_malloc (sizeof (char *));
1205                  * domain->search_path [0] = NULL;
1206                 */
1207                 mono_domain_assemblies_unlock (domain);
1208                 return;
1209         }
1210
1211         if (domain->search_path)
1212                 g_strfreev (domain->search_path);
1213
1214         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1215         tmp [npaths] = NULL;
1216
1217         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1218         if (!mono_error_ok (&error)) {
1219                 mono_error_cleanup (&error);
1220                 g_strfreev (pvt_split);
1221                 g_free (tmp);
1222
1223                 mono_domain_assemblies_unlock (domain);
1224                 return;
1225         }
1226
1227         domain->search_path = tmp;
1228
1229         /* FIXME: is this needed? */
1230         if (strncmp (*tmp, "file://", 7) == 0) {
1231                 gchar *file = *tmp;
1232                 gchar *uri = *tmp;
1233                 gchar *tmpuri;
1234
1235                 if (uri [7] != '/')
1236                         uri = g_strdup_printf ("file:///%s", uri + 7);
1237
1238                 tmpuri = uri;
1239                 uri = mono_escape_uri_string (tmpuri);
1240                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1241                 g_free (uri);
1242
1243                 if (tmpuri != file)
1244                         g_free (tmpuri);
1245
1246                 if (gerror != NULL) {
1247                         g_warning ("%s\n", gerror->message);
1248                         g_error_free (gerror);
1249                         *tmp = file;
1250                 } else {
1251                         g_free (file);
1252                 }
1253         }
1254
1255         for (i = 1; pvt_split && i < npaths; i++) {
1256                 if (g_path_is_absolute (pvt_split [i - 1])) {
1257                         tmp [i] = g_strdup (pvt_split [i - 1]);
1258                 } else {
1259                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1260                 }
1261
1262                 if (strchr (tmp [i], '.')) {
1263                         gchar *reduced;
1264                         gchar *freeme;
1265
1266                         reduced = mono_path_canonicalize (tmp [i]);
1267                         if (appbaselen == -1)
1268                                 appbaselen = strlen (tmp [0]);
1269
1270                         if (strncmp (tmp [0], reduced, appbaselen)) {
1271                                 g_free (reduced);
1272                                 g_free (tmp [i]);
1273                                 tmp [i] = g_strdup ("");
1274                                 continue;
1275                         }
1276
1277                         freeme = tmp [i];
1278                         tmp [i] = reduced;
1279                         g_free (freeme);
1280                 }
1281         }
1282         
1283         if (setup->private_bin_path_probe != NULL) {
1284                 g_free (tmp [0]);
1285                 tmp [0] = g_strdup ("");
1286         }
1287                 
1288         domain->setup->path_changed = FALSE;
1289
1290         g_strfreev (pvt_split);
1291
1292         mono_domain_assemblies_unlock (domain);
1293 }
1294
1295 #ifdef DISABLE_SHADOW_COPY
1296 gboolean
1297 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1298 {
1299         return FALSE;
1300 }
1301
1302 char *
1303 mono_make_shadow_copy (const char *filename, MonoError *error)
1304 {
1305         mono_error_init (error);
1306         return (char *) filename;
1307 }
1308 #else
1309 static gboolean
1310 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1311 {
1312         guint16 *orig, *dest;
1313         gboolean copy_result;
1314         
1315         strcpy (src + srclen - tail_len, extension);
1316
1317         if (IS_PORTABILITY_CASE) {
1318                 gchar *file = mono_portability_find_file (src, TRUE);
1319
1320                 if (file == NULL)
1321                         return TRUE;
1322
1323                 g_free (file);
1324         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1325                 return TRUE;
1326         }
1327
1328         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1329
1330         strcpy (target + targetlen - tail_len, extension);
1331         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1332         
1333         DeleteFile (dest);
1334         copy_result = CopyFile (orig, dest, FALSE);
1335
1336         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1337          * overwritten when updated in their original locations. */
1338         if (copy_result)
1339                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1340
1341         g_free (orig);
1342         g_free (dest);
1343         
1344         return copy_result;
1345 }
1346
1347 static gint32 
1348 get_cstring_hash (const char *str)
1349 {
1350         int len, i;
1351         const char *p;
1352         gint32 h = 0;
1353         
1354         if (!str || !str [0])
1355                 return 0;
1356                 
1357         len = strlen (str);
1358         p = str;
1359         for (i = 0; i < len; i++) {
1360                 h = (h << 5) - h + *p;
1361                 p++;
1362         }
1363         
1364         return h;
1365 }
1366
1367 /*
1368  * Returned memory is malloc'd. Called must free it 
1369  */
1370 static char *
1371 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1372 {
1373         MonoAppDomainSetup *setup;
1374         char *cache_path, *appname;
1375         char *userdir;
1376         char *location;
1377
1378         mono_error_init (error);
1379         
1380         setup = domain->setup;
1381         if (setup->cache_path != NULL && setup->application_name != NULL) {
1382                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1383                 return_val_if_nok (error, NULL);
1384
1385 #ifndef TARGET_WIN32
1386                 {
1387                         gint i;
1388                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1389                                 if (cache_path [i] == '\\')
1390                                         cache_path [i] = '/';
1391                 }
1392 #endif
1393
1394                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1395                 if (!mono_error_ok (error)) {
1396                         g_free (cache_path);
1397                         return NULL;
1398                 }
1399
1400                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1401                 g_free (appname);
1402                 g_free (cache_path);
1403         } else {
1404                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1405                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1406                 g_free (userdir);
1407         }
1408         return location;
1409 }
1410
1411 static char *
1412 get_shadow_assembly_location (const char *filename, MonoError *error)
1413 {
1414         gint32 hash = 0, hash2 = 0;
1415         char name_hash [9];
1416         char path_hash [30];
1417         char *bname = g_path_get_basename (filename);
1418         char *dirname = g_path_get_dirname (filename);
1419         char *location, *tmploc;
1420         MonoDomain *domain = mono_domain_get ();
1421
1422         mono_error_init (error);
1423         
1424         hash = get_cstring_hash (bname);
1425         hash2 = get_cstring_hash (dirname);
1426         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1427         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1428         tmploc = get_shadow_assembly_location_base (domain, error);
1429         if (!mono_error_ok (error)) {
1430                 g_free (bname);
1431                 g_free (dirname);
1432                 return NULL;
1433         }
1434
1435         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1436         g_free (tmploc);
1437         g_free (bname);
1438         g_free (dirname);
1439         return location;
1440 }
1441
1442 static gboolean
1443 ensure_directory_exists (const char *filename)
1444 {
1445 #ifdef HOST_WIN32
1446         gchar *dir_utf8 = g_path_get_dirname (filename);
1447         gunichar2 *p;
1448         gunichar2 *dir_utf16 = NULL;
1449         int retval;
1450         
1451         if (!dir_utf8 || !dir_utf8 [0])
1452                 return FALSE;
1453
1454         dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1455         g_free (dir_utf8);
1456
1457         if (!dir_utf16)
1458                 return FALSE;
1459
1460         p = dir_utf16;
1461
1462         /* make life easy and only use one directory seperator */
1463         while (*p != '\0')
1464         {
1465                 if (*p == '/')
1466                         *p = '\\';
1467                 p++;
1468         }
1469
1470         p = dir_utf16;
1471
1472         /* get past C:\ )*/
1473         while (*p++ != '\\')    
1474         {
1475         }
1476
1477         while (1) {
1478                 BOOL bRet = FALSE;
1479                 p = wcschr (p, '\\');
1480                 if (p)
1481                         *p = '\0';
1482                 retval = _wmkdir (dir_utf16);
1483                 if (retval != 0 && errno != EEXIST) {
1484                         g_free (dir_utf16);
1485                         return FALSE;
1486                 }
1487                 if (!p)
1488                         break;
1489                 *p++ = '\\';
1490         }
1491         
1492         g_free (dir_utf16);
1493         return TRUE;
1494 #else
1495         char *p;
1496         gchar *dir = g_path_get_dirname (filename);
1497         int retval;
1498         struct stat sbuf;
1499         
1500         if (!dir || !dir [0]) {
1501                 g_free (dir);
1502                 return FALSE;
1503         }
1504         
1505         if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1506                 g_free (dir);
1507                 return TRUE;
1508         }
1509         
1510         p = dir;
1511         while (*p == '/')
1512                 p++;
1513
1514         while (1) {
1515                 p = strchr (p, '/');
1516                 if (p)
1517                         *p = '\0';
1518                 retval = mkdir (dir, 0777);
1519                 if (retval != 0 && errno != EEXIST) {
1520                         g_free (dir);
1521                         return FALSE;
1522                 }
1523                 if (!p)
1524                         break;
1525                 *p++ = '/';
1526         }
1527         
1528         g_free (dir);
1529         return TRUE;
1530 #endif
1531 }
1532
1533 static gboolean
1534 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1535 {
1536         struct stat sbuf_dest;
1537         gchar *stat_src;
1538         gchar *real_src = mono_portability_find_file (src, TRUE);
1539
1540         if (!real_src)
1541                 stat_src = (gchar*)src;
1542         else
1543                 stat_src = real_src;
1544
1545         if (stat (stat_src, sbuf_src) == -1) {
1546                 time_t tnow = time (NULL);
1547
1548                 if (real_src)
1549                         g_free (real_src);
1550
1551                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1552                 sbuf_src->st_mtime = tnow;
1553                 sbuf_src->st_atime = tnow;
1554                 return TRUE;
1555         }
1556
1557         if (real_src)
1558                 g_free (real_src);
1559
1560         if (stat (dest, &sbuf_dest) == -1)
1561                 return TRUE;
1562         
1563         if (sbuf_src->st_size == sbuf_dest.st_size &&
1564             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1565                 return FALSE;
1566
1567         return TRUE;
1568 }
1569
1570 static gboolean
1571 shadow_copy_create_ini (const char *shadow, const char *filename)
1572 {
1573         char *dir_name;
1574         char *ini_file;
1575         guint16 *u16_ini;
1576         gboolean result;
1577         guint32 n;
1578         HANDLE *handle;
1579         gchar *full_path;
1580
1581         dir_name = g_path_get_dirname (shadow);
1582         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1583         g_free (dir_name);
1584         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1585                 g_free (ini_file);
1586                 return TRUE;
1587         }
1588
1589         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1590         g_free (ini_file);
1591         if (!u16_ini) {
1592                 return FALSE;
1593         }
1594         handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1595                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1596         g_free (u16_ini);
1597         if (handle == INVALID_HANDLE_VALUE) {
1598                 return FALSE;
1599         }
1600
1601         full_path = mono_path_resolve_symlinks (filename);
1602         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1603         g_free (full_path);
1604         CloseHandle (handle);
1605         return result;
1606 }
1607
1608 gboolean
1609 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1610 {
1611         MonoError error;
1612         MonoAppDomainSetup *setup;
1613         gchar *all_dirs;
1614         gchar **dir_ptr;
1615         gchar **directories;
1616         gchar *shadow_status_string;
1617         gchar *base_dir;
1618         gboolean shadow_enabled;
1619         gboolean found = FALSE;
1620
1621         if (domain == NULL)
1622                 return FALSE;
1623
1624         setup = domain->setup;
1625         if (setup == NULL || setup->shadow_copy_files == NULL)
1626                 return FALSE;
1627
1628         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1629         if (!mono_error_ok (&error)) {
1630                 mono_error_cleanup (&error);
1631                 return FALSE;
1632         }
1633         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1634         g_free (shadow_status_string);
1635
1636         if (!shadow_enabled)
1637                 return FALSE;
1638
1639         if (setup->shadow_copy_directories == NULL)
1640                 return TRUE;
1641
1642         /* Is dir_name a shadow_copy destination already? */
1643         base_dir = get_shadow_assembly_location_base (domain, &error);
1644         if (!mono_error_ok (&error)) {
1645                 mono_error_cleanup (&error);
1646                 return FALSE;
1647         }
1648
1649         if (strstr (dir_name, base_dir)) {
1650                 g_free (base_dir);
1651                 return TRUE;
1652         }
1653         g_free (base_dir);
1654
1655         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1656         if (!mono_error_ok (&error)) {
1657                 mono_error_cleanup (&error);
1658                 return FALSE;
1659         }
1660
1661         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1662         dir_ptr = directories;
1663         while (*dir_ptr) {
1664                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1665                         found = TRUE;
1666                         break;
1667                 }
1668                 dir_ptr++;
1669         }
1670         g_strfreev (directories);
1671         g_free (all_dirs);
1672         return found;
1673 }
1674
1675 /*
1676 This function raises exceptions so it can cause as sorts of nasty stuff if called
1677 while holding a lock.
1678 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1679 or NULL if source file not found.
1680 FIXME bubble up the error instead of raising it here
1681 */
1682 char *
1683 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1684 {
1685         MonoError error;
1686         gchar *sibling_source, *sibling_target;
1687         gint sibling_source_len, sibling_target_len;
1688         guint16 *orig, *dest;
1689         guint32 attrs;
1690         char *shadow;
1691         gboolean copy_result;
1692         struct stat src_sbuf;
1693         struct utimbuf utbuf;
1694         char *dir_name = g_path_get_dirname (filename);
1695         MonoDomain *domain = mono_domain_get ();
1696         char *shadow_dir;
1697
1698         mono_error_init (oerror);
1699
1700         set_domain_search_path (domain);
1701
1702         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1703                 g_free (dir_name);
1704                 return (char *) filename;
1705         }
1706
1707         /* Is dir_name a shadow_copy destination already? */
1708         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1709         if (!mono_error_ok (&error)) {
1710                 mono_error_cleanup (&error);
1711                 g_free (dir_name);
1712                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1713                 return NULL;
1714         }
1715
1716         if (strstr (dir_name, shadow_dir)) {
1717                 g_free (shadow_dir);
1718                 g_free (dir_name);
1719                 return (char *) filename;
1720         }
1721         g_free (shadow_dir);
1722         g_free (dir_name);
1723
1724         shadow = get_shadow_assembly_location (filename, &error);
1725         if (!mono_error_ok (&error)) {
1726                 mono_error_cleanup (&error);
1727                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1728                 return NULL;
1729         }
1730
1731         if (ensure_directory_exists (shadow) == FALSE) {
1732                 g_free (shadow);
1733                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1734                 return NULL;
1735         }       
1736
1737         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1738                 return (char*) shadow;
1739
1740         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1741         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1742         DeleteFile (dest);
1743
1744         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1745          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1746          * and not have it runtime error" */
1747         attrs = GetFileAttributes (orig);
1748         if (attrs == INVALID_FILE_ATTRIBUTES) {
1749                 g_free (shadow);
1750                 return (char *)filename;
1751         }
1752
1753         copy_result = CopyFile (orig, dest, FALSE);
1754
1755         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1756          * overwritten when updated in their original locations. */
1757         if (copy_result)
1758                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1759
1760         g_free (dest);
1761         g_free (orig);
1762
1763         if (copy_result == FALSE) {
1764                 g_free (shadow);
1765
1766                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1767                 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1768                         return NULL; /* file not found, shadow copy failed */
1769
1770                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1771                 return NULL;
1772         }
1773
1774         /* attempt to copy .mdb, .config if they exist */
1775         sibling_source = g_strconcat (filename, ".config", NULL);
1776         sibling_source_len = strlen (sibling_source);
1777         sibling_target = g_strconcat (shadow, ".config", NULL);
1778         sibling_target_len = strlen (sibling_target);
1779         
1780         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1781         if (copy_result == TRUE)
1782                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1783         
1784         g_free (sibling_source);
1785         g_free (sibling_target);
1786         
1787         if (copy_result == FALSE)  {
1788                 g_free (shadow);
1789                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1790                 return NULL;
1791         }
1792
1793         /* Create a .ini file containing the original assembly location */
1794         if (!shadow_copy_create_ini (shadow, filename)) {
1795                 g_free (shadow);
1796                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1797                 return NULL;
1798         }
1799
1800         utbuf.actime = src_sbuf.st_atime;
1801         utbuf.modtime = src_sbuf.st_mtime;
1802         utime (shadow, &utbuf);
1803         
1804         return shadow;
1805 }
1806 #endif /* DISABLE_SHADOW_COPY */
1807
1808 MonoDomain *
1809 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1810 {
1811         if (appdomain == NULL)
1812                 return NULL;
1813         
1814         return appdomain->data;
1815 }
1816
1817 static gboolean
1818 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1819                                         const gchar *path3, const gchar *path4,
1820                                         gboolean refonly, gboolean is_private)
1821 {
1822         gchar *fullpath;
1823         gboolean found = FALSE;
1824         
1825         *assembly = NULL;
1826         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1827
1828         if (IS_PORTABILITY_SET) {
1829                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1830                 if (new_fullpath) {
1831                         g_free (fullpath);
1832                         fullpath = new_fullpath;
1833                         found = TRUE;
1834                 }
1835         } else
1836                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1837         
1838         if (found)
1839                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1840
1841         g_free (fullpath);
1842         return (*assembly != NULL);
1843 }
1844
1845 static MonoAssembly *
1846 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1847 {
1848         MonoAssembly *result = NULL;
1849         gchar **path;
1850         gchar *filename;
1851         const gchar *local_culture;
1852         gint len;
1853         gboolean is_private = FALSE;
1854
1855         if (!culture || *culture == '\0') {
1856                 local_culture = "";
1857         } else {
1858                 local_culture = culture;
1859         }
1860
1861         filename =  g_strconcat (name, ".dll", NULL);
1862         len = strlen (filename);
1863
1864         for (path = search_path; *path; path++) {
1865                 if (**path == '\0') {
1866                         is_private = TRUE;
1867                         continue; /* Ignore empty ApplicationBase */
1868                 }
1869
1870                 /* See test cases in bug #58992 and bug #57710 */
1871                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1872                 strcpy (filename + len - 4, ".dll");
1873                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1874                         break;
1875
1876                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1877                 strcpy (filename + len - 4, ".exe");
1878                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1879                         break;
1880
1881                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1882                 strcpy (filename + len - 4, ".dll");
1883                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1884                         break;
1885
1886                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1887                 strcpy (filename + len - 4, ".exe");
1888                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1889                         break;
1890         }
1891
1892         g_free (filename);
1893         return result;
1894 }
1895
1896 /*
1897  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1898  * and then from assemblies_path if any.
1899  * LOCKING: This is called from the assembly loading code, which means the caller
1900  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1901  */
1902 static MonoAssembly *
1903 mono_domain_assembly_preload (MonoAssemblyName *aname,
1904                               gchar **assemblies_path,
1905                               gpointer user_data)
1906 {
1907         MonoDomain *domain = mono_domain_get ();
1908         MonoAssembly *result = NULL;
1909         gboolean refonly = GPOINTER_TO_UINT (user_data);
1910
1911         set_domain_search_path (domain);
1912
1913         if (domain->search_path && domain->search_path [0] != NULL) {
1914                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1915         }
1916
1917         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1918                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1919         }
1920
1921         return result;
1922 }
1923
1924 /*
1925  * Check whenever a given assembly was already loaded in the current appdomain.
1926  */
1927 static MonoAssembly *
1928 mono_domain_assembly_search (MonoAssemblyName *aname,
1929                                                          gpointer user_data)
1930 {
1931         MonoDomain *domain = mono_domain_get ();
1932         GSList *tmp;
1933         MonoAssembly *ass;
1934         gboolean refonly = GPOINTER_TO_UINT (user_data);
1935
1936         mono_domain_assemblies_lock (domain);
1937         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1938                 ass = (MonoAssembly *)tmp->data;
1939                 /* Dynamic assemblies can't match here in MS.NET */
1940                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1941                         continue;
1942
1943                 mono_domain_assemblies_unlock (domain);
1944                 return ass;
1945         }
1946         mono_domain_assemblies_unlock (domain);
1947
1948         return NULL;
1949 }
1950
1951 MonoReflectionAssembly *
1952 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1953 {
1954         MonoError error;
1955         MonoReflectionAssembly *result;
1956         MonoDomain *domain = mono_domain_get ();
1957         char *name, *filename;
1958         MonoImageOpenStatus status = MONO_IMAGE_OK;
1959         MonoAssembly *ass;
1960
1961         if (fname == NULL) {
1962                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1963                 mono_set_pending_exception (exc);
1964                 return NULL;
1965         }
1966                 
1967         name = filename = mono_string_to_utf8 (fname);
1968         
1969         ass = mono_assembly_open_full (filename, &status, refOnly);
1970         
1971         if (!ass) {
1972                 MonoException *exc;
1973
1974                 if (status == MONO_IMAGE_IMAGE_INVALID)
1975                         exc = mono_get_exception_bad_image_format2 (NULL, fname);
1976                 else
1977                         exc = mono_get_exception_file_not_found2 (NULL, fname);
1978                 g_free (name);
1979                 mono_set_pending_exception (exc);
1980                 return NULL;
1981         }
1982
1983         g_free (name);
1984
1985         result = mono_assembly_get_object_checked (domain, ass, &error);
1986         if (!result)
1987                 mono_error_set_pending_exception (&error);
1988         return result;
1989 }
1990
1991 MonoReflectionAssembly *
1992 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
1993                                             MonoArray *raw_assembly,
1994                                             MonoArray *raw_symbol_store, MonoObject *evidence,
1995                                             MonoBoolean refonly)
1996 {
1997         MonoError error;
1998         MonoAssembly *ass;
1999         MonoReflectionAssembly *refass = NULL;
2000         MonoDomain *domain = ad->data;
2001         MonoImageOpenStatus status;
2002         guint32 raw_assembly_len = mono_array_length (raw_assembly);
2003         MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2004
2005         if (!image) {
2006                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2007                 return NULL;
2008         }
2009
2010         if (raw_symbol_store != NULL)
2011                 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2012
2013         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2014
2015
2016         if (!ass) {
2017                 mono_image_close (image);
2018                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2019                 return NULL; 
2020         }
2021
2022         refass = mono_assembly_get_object_checked (domain, ass, &error);
2023         if (!refass)
2024                 mono_error_set_pending_exception (&error);
2025         else
2026                 MONO_OBJECT_SETREF (refass, evidence, evidence);
2027         return refass;
2028 }
2029
2030 MonoReflectionAssembly *
2031 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2032 {
2033         MonoError error;
2034         MonoDomain *domain = ad->data; 
2035         MonoImageOpenStatus status = MONO_IMAGE_OK;
2036         MonoAssembly *ass;
2037         MonoAssemblyName aname;
2038         MonoReflectionAssembly *refass = NULL;
2039         gchar *name;
2040         gboolean parsed;
2041
2042         g_assert (assRef);
2043
2044         name = mono_string_to_utf8 (assRef);
2045         parsed = mono_assembly_name_parse (name, &aname);
2046         g_free (name);
2047
2048         if (!parsed) {
2049                 /* This is a parse error... */
2050                 if (!refOnly)
2051                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2052                 return refass;
2053         }
2054
2055         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2056         mono_assembly_name_free (&aname);
2057
2058         if (!ass) {
2059                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2060                 if (!refOnly)
2061                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2062                 else
2063                         refass = NULL;
2064                 if (!refass) {
2065                         return NULL;
2066                 }
2067         }
2068
2069         if (refass == NULL)
2070                 refass = mono_assembly_get_object_checked (domain, ass, &error);
2071
2072         if (refass == NULL)
2073                 mono_error_set_pending_exception (&error);
2074         else
2075                 MONO_OBJECT_SETREF (refass, evidence, evidence);
2076         return refass;
2077 }
2078
2079 void
2080 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2081 {
2082         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2083
2084         if (NULL == domain) {
2085                 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2086                 mono_set_pending_exception (exc);
2087                 return;
2088         }
2089         
2090         if (domain == mono_get_root_domain ()) {
2091                 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2092                 return;
2093         }
2094
2095         /* 
2096          * Unloading seems to cause problems when running NUnit/NAnt, hence
2097          * this workaround.
2098          */
2099         if (g_getenv ("MONO_NO_UNLOAD"))
2100                 return;
2101 #ifdef __native_client__
2102         return;
2103 #endif
2104
2105         mono_domain_unload (domain);
2106 }
2107
2108 gboolean
2109 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2110 {
2111         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2112
2113         if (!domain)
2114                 return TRUE;
2115
2116         return mono_domain_is_unloading (domain);
2117 }
2118
2119 void
2120 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2121 {
2122         mono_unhandled_exception ((MonoObject*) exc);
2123 }
2124
2125 gint32
2126 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
2127                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
2128 {
2129         MonoError error;
2130         MonoImage *image;
2131         MonoMethod *method;
2132
2133         g_assert (refass);
2134         image = refass->assembly->image;
2135         g_assert (image);
2136
2137         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2138
2139         if (!method)
2140                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2141
2142         if (!args)
2143                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2144
2145         return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2146 }
2147
2148 gint32 
2149 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2150 {
2151         return ad->data->domain_id;
2152 }
2153
2154 MonoAppDomain * 
2155 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2156 {
2157         MonoDomain *old_domain = mono_domain_get();
2158
2159         if (!mono_domain_set (ad->data, FALSE)) {
2160                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2161                 return NULL;
2162         }
2163
2164         return old_domain->domain;
2165 }
2166
2167 MonoAppDomain * 
2168 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2169 {
2170         MonoDomain *current_domain = mono_domain_get ();
2171         MonoDomain *domain = mono_domain_get_by_id (domainid);
2172
2173         if (!domain || !mono_domain_set (domain, FALSE)) {
2174                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2175                 return NULL;
2176         }
2177
2178         return current_domain->domain;
2179 }
2180
2181 void
2182 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2183 {
2184         mono_thread_push_appdomain_ref (ad->data);
2185 }
2186
2187 void
2188 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2189 {
2190         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2191
2192         if (!domain) {
2193                 /* 
2194                  * Raise an exception to prevent the managed code from executing a pop
2195                  * later.
2196                  */
2197                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2198                 return;
2199         }
2200
2201         mono_thread_push_appdomain_ref (domain);
2202 }
2203
2204 void
2205 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2206 {
2207         mono_thread_pop_appdomain_ref ();
2208 }
2209
2210 MonoAppContext * 
2211 ves_icall_System_AppDomain_InternalGetContext ()
2212 {
2213         return mono_context_get ();
2214 }
2215
2216 MonoAppContext * 
2217 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2218 {
2219         return mono_domain_get ()->default_context;
2220 }
2221
2222 MonoAppContext * 
2223 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2224 {
2225         MonoAppContext *old_context = mono_context_get ();
2226
2227         mono_context_set (mc);
2228
2229         return old_context;
2230 }
2231
2232 MonoString *
2233 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2234 {
2235         MonoDomain* mono_root_domain = mono_get_root_domain ();
2236         mono_domain_lock (mono_root_domain);
2237         if (process_guid_set) {
2238                 mono_domain_unlock (mono_root_domain);
2239                 MonoError error;
2240                 MonoString *res = NULL;
2241                 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2242                 mono_error_raise_exception (&error);
2243                 return res;
2244         }
2245         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2246         process_guid_set = TRUE;
2247         mono_domain_unlock (mono_root_domain);
2248         return newguid;
2249 }
2250
2251 gboolean
2252 mono_domain_is_unloading (MonoDomain *domain)
2253 {
2254         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2255                 return TRUE;
2256         else
2257                 return FALSE;
2258 }
2259
2260 static void
2261 clear_cached_vtable (MonoVTable *vtable)
2262 {
2263         MonoClass *klass = vtable->klass;
2264         MonoDomain *domain = vtable->domain;
2265         MonoClassRuntimeInfo *runtime_info;
2266         void *data;
2267
2268         runtime_info = klass->runtime_info;
2269         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2270                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2271         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2272                 mono_gc_free_fixed (data);
2273 }
2274
2275 static G_GNUC_UNUSED void
2276 zero_static_data (MonoVTable *vtable)
2277 {
2278         MonoClass *klass = vtable->klass;
2279         void *data;
2280
2281         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2282                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2283 }
2284
2285 typedef struct unload_data {
2286         gboolean done;
2287         MonoDomain *domain;
2288         char *failure_reason;
2289         gint32 refcount;
2290 } unload_data;
2291
2292 static void
2293 unload_data_unref (unload_data *data)
2294 {
2295         gint32 count;
2296         do {
2297                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2298                 g_assert (count >= 1 && count <= 2);
2299                 if (count == 1) {
2300                         g_free (data);
2301                         return;
2302                 }
2303         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2304 }
2305
2306 static void
2307 deregister_reflection_info_roots_from_list (MonoImage *image)
2308 {
2309         GSList *list = image->reflection_info_unregister_classes;
2310
2311         while (list) {
2312                 MonoClass *klass = (MonoClass *)list->data;
2313
2314                 mono_class_free_ref_info (klass);
2315
2316                 list = list->next;
2317         }
2318
2319         image->reflection_info_unregister_classes = NULL;
2320 }
2321
2322 static void
2323 deregister_reflection_info_roots (MonoDomain *domain)
2324 {
2325         GSList *list;
2326
2327         mono_domain_assemblies_lock (domain);
2328         for (list = domain->domain_assemblies; list; list = list->next) {
2329                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2330                 MonoImage *image = assembly->image;
2331                 int i;
2332
2333                 /*
2334                  * No need to take the image lock here since dynamic images are appdomain bound and
2335                  * at this point the mutator is gone.  Taking the image lock here would mean
2336                  * promoting it from a simple lock to a complex lock, which we better avoid if
2337                  * possible.
2338                  */
2339                 if (image_is_dynamic (image))
2340                         deregister_reflection_info_roots_from_list (image);
2341
2342                 for (i = 0; i < image->module_count; ++i) {
2343                         MonoImage *module = image->modules [i];
2344                         if (module && image_is_dynamic (module))
2345                                 deregister_reflection_info_roots_from_list (module);
2346                 }
2347         }
2348         mono_domain_assemblies_unlock (domain);
2349 }
2350
2351 static guint32 WINAPI
2352 unload_thread_main (void *arg)
2353 {
2354         MonoError error;
2355         unload_data *data = (unload_data*)arg;
2356         MonoDomain *domain = data->domain;
2357         MonoThread *thread;
2358         int i;
2359
2360         /* Have to attach to the runtime so shutdown can wait for this thread */
2361         /* Force it to be attached to avoid racing during shutdown. */
2362         thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2363         mono_error_raise_exception (&error); /* FIXME don't raise here */
2364
2365         /* 
2366          * FIXME: Abort our parent thread last, so we can return a failure 
2367          * indication if aborting times out.
2368          */
2369         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2370                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2371                 goto failure;
2372         }
2373
2374         if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2375                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2376                 goto failure;
2377         }
2378
2379         /* Finalize all finalizable objects in the doomed appdomain */
2380         if (!mono_domain_finalize (domain, -1)) {
2381                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2382                 goto failure;
2383         }
2384
2385         /* Clear references to our vtables in class->runtime_info.
2386          * We also hold the loader lock because we're going to change
2387          * class->runtime_info.
2388          */
2389
2390         mono_loader_lock (); //FIXME why do we need the loader lock here?
2391         mono_domain_lock (domain);
2392 #ifdef HAVE_SGEN_GC
2393         /*
2394          * We need to make sure that we don't have any remsets
2395          * pointing into static data of the to-be-freed domain because
2396          * at the next collections they would be invalid.  So what we
2397          * do is we first zero all static data and then do a minor
2398          * collection.  Because all references in the static data will
2399          * now be null we won't do any unnecessary copies and after
2400          * the collection there won't be any more remsets.
2401          */
2402         for (i = 0; i < domain->class_vtable_array->len; ++i)
2403                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2404         mono_gc_collect (0);
2405 #endif
2406         for (i = 0; i < domain->class_vtable_array->len; ++i)
2407                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2408         deregister_reflection_info_roots (domain);
2409
2410         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2411
2412         mono_domain_unlock (domain);
2413         mono_loader_unlock ();
2414
2415         mono_threads_clear_cached_culture (domain);
2416
2417         domain->state = MONO_APPDOMAIN_UNLOADED;
2418
2419         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2420
2421         /* remove from the handle table the items related to this domain */
2422         mono_gchandle_free_domain (domain);
2423
2424         mono_domain_free (domain, FALSE);
2425
2426         mono_gc_collect (mono_gc_max_generation ());
2427
2428         mono_atomic_store_release (&data->done, TRUE);
2429         unload_data_unref (data);
2430         mono_thread_detach (thread);
2431         return 0;
2432
2433 failure:
2434         mono_atomic_store_release (&data->done, TRUE);
2435         unload_data_unref (data);
2436         mono_thread_detach (thread);
2437         return 1;
2438 }
2439
2440 /*
2441  * mono_domain_unload:
2442  * @domain: The domain to unload
2443  *
2444  *  Unloads an appdomain. Follows the process outlined in the comment
2445  *  for mono_domain_try_unload.
2446  */
2447 void
2448 mono_domain_unload (MonoDomain *domain)
2449 {
2450         MonoObject *exc = NULL;
2451         mono_domain_try_unload (domain, &exc);
2452         if (exc)
2453                 mono_raise_exception ((MonoException*)exc);
2454 }
2455
2456 static guint32
2457 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2458 {
2459         guint32 result;
2460
2461         MONO_PREPARE_BLOCKING;
2462         result = WaitForSingleObjectEx (handle, timeout, alertable);
2463         MONO_FINISH_BLOCKING;
2464
2465         return result;
2466 }
2467
2468 /*
2469  * mono_domain_unload:
2470  * @domain: The domain to unload
2471  * @exc: Exception information
2472  *
2473  *  Unloads an appdomain. Follows the process outlined in:
2474  *  http://blogs.gotdotnet.com/cbrumme
2475  *
2476  *  If doing things the 'right' way is too hard or complex, we do it the 
2477  *  'simple' way, which means do everything needed to avoid crashes and
2478  *  memory leaks, but not much else.
2479  *
2480  *  It is required to pass a valid reference to the exc argument, upon return
2481  *  from this function *exc will be set to the exception thrown, if any.
2482  *
2483  *  If this method is not called from an icall (embedded scenario for instance),
2484  *  it must not be called with any managed frames on the stack, since the unload
2485  *  process could end up trying to abort the current thread.
2486  */
2487 void
2488 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2489 {
2490         MonoError error;
2491         HANDLE thread_handle;
2492         MonoAppDomainState prev_state;
2493         MonoMethod *method;
2494         unload_data *thread_data;
2495         MonoNativeThreadId tid;
2496         MonoDomain *caller_domain = mono_domain_get ();
2497         char *name;
2498
2499         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2500
2501         /* Atomically change our state to UNLOADING */
2502         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2503                 MONO_APPDOMAIN_UNLOADING_START,
2504                 MONO_APPDOMAIN_CREATED);
2505         if (prev_state != MONO_APPDOMAIN_CREATED) {
2506                 switch (prev_state) {
2507                 case MONO_APPDOMAIN_UNLOADING_START:
2508                 case MONO_APPDOMAIN_UNLOADING:
2509                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2510                         return;
2511                 case MONO_APPDOMAIN_UNLOADED:
2512                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2513                         return;
2514                 default:
2515                         g_warning ("Invalid appdomain state %d", prev_state);
2516                         g_assert_not_reached ();
2517                 }
2518         }
2519
2520         mono_domain_set (domain, FALSE);
2521         /* Notify OnDomainUnload listeners */
2522         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2523         g_assert (method);
2524
2525         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2526
2527         if (!mono_error_ok (&error)) {
2528                 if (*exc)
2529                         mono_error_cleanup (&error);
2530                 else
2531                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2532         }
2533
2534         if (*exc) {
2535                 /* Roll back the state change */
2536                 domain->state = MONO_APPDOMAIN_CREATED;
2537                 mono_domain_set (caller_domain, FALSE);
2538                 return;
2539         }
2540         mono_domain_set (caller_domain, FALSE);
2541
2542         thread_data = g_new0 (unload_data, 1);
2543         thread_data->domain = domain;
2544         thread_data->failure_reason = NULL;
2545         thread_data->done = FALSE;
2546         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2547
2548         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2549         domain->state = MONO_APPDOMAIN_UNLOADING;
2550         /* 
2551          * First we create a separate thread for unloading, since
2552          * we might have to abort some threads, including the current one.
2553          */
2554         thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2555         if (thread_handle == NULL)
2556                 return;
2557         name = g_strdup_printf ("Unload thread for domain %x", domain);
2558         mono_thread_info_set_name (tid, name);
2559         mono_thread_info_resume (tid);
2560         g_free (name);
2561
2562         /* Wait for the thread */       
2563         while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2564                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2565                         /* The unload thread tries to abort us */
2566                         /* The icall wrapper will execute the abort */
2567                         CloseHandle (thread_handle);
2568                         unload_data_unref (thread_data);
2569                         return;
2570                 }
2571         }
2572         CloseHandle (thread_handle);
2573
2574         if (thread_data->failure_reason) {
2575                 /* Roll back the state change */
2576                 domain->state = MONO_APPDOMAIN_CREATED;
2577
2578                 g_warning ("%s", thread_data->failure_reason);
2579
2580                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2581
2582                 g_free (thread_data->failure_reason);
2583                 thread_data->failure_reason = NULL;
2584         }
2585
2586         unload_data_unref (thread_data);
2587 }