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