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