2007-07-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / appdomain.c
index 20e4521e7b6df8e4fe084c594a4d8da85277af30..020a47cc97be23da621f02b5ea9e8539d36e3558 100644 (file)
 #include <config.h>
 #include <glib.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include <mono/os/gc_wrapper.h>
 
 #include <mono/utils/mono-logger.h>
 #include <mono/utils/mono-path.h>
 #include <mono/utils/mono-stdlib.h>
+#ifdef PLATFORM_WIN32
+#include <direct.h>
+#endif
 
-#define MONO_CORLIB_VERSION 54
+#define MONO_CORLIB_VERSION 58
 
 CRITICAL_SECTION mono_delegate_section;
 
@@ -627,9 +635,10 @@ add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
 
        if (ass->image->references) {
                for (i = 0; ass->image->references [i] != NULL; i++) {
-                       if (!g_hash_table_lookup (ht, ass->image->references [i])) {
-                               add_assemblies_to_domain (domain, ass->image->references [i], ht);
-                       }
+                       if (ass->image->references [i] != REFERENCE_MISSING)
+                               if (!g_hash_table_lookup (ht, ass->image->references [i])) {
+                                       add_assemblies_to_domain (domain, ass->image->references [i], ht);
+                               }
                }
        }
        if (destroy_ht)
@@ -796,41 +805,201 @@ set_domain_search_path (MonoDomain *domain)
        g_strfreev (pvt_split);
 }
 
+static gboolean
+shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
+{
+       guint16 *orig, *dest;
+       gboolean copy_result;
+       
+       strcpy (src + srclen - tail_len, extension);
+       if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
+               return TRUE;
+       orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
+
+       strcpy (target + targetlen - tail_len, extension);
+       dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
+       
+       copy_result = CopyFile (orig, dest, FALSE);
+       g_free (orig);
+       g_free (dest);
+       
+       return copy_result;
+}
+
+static gint32 
+get_cstring_hash (const char *str)
+{
+       int len, i;
+       const char *p;
+       gint32 h = 0;
+       
+       if (!str || !str [0])
+               return 0;
+               
+       len = strlen (str);
+       p = str;
+       for (i = 0; i < len; i++) {
+               h = (h << 5) - h + *p;
+               p++;
+       }
+       
+       return h;
+}
+
+static char *
+get_shadow_assembly_location (const char *filename)
+{
+       gint32 hash = 0, hash2 = 0;
+       guint32 ticks = GetTickCount ();
+       char name_hash [9];
+       char path_hash [30];
+       char *bname = g_path_get_basename (filename);
+       MonoDomain *domain = mono_domain_get ();
+       
+       hash = get_cstring_hash (bname);
+       hash2 = get_cstring_hash (g_path_get_dirname (filename));
+       g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
+       g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, ticks);
+       return g_build_filename (mono_string_to_utf8 (domain->setup->dynamic_base), 
+                                "assembly", 
+                                "shadow", 
+                                name_hash,
+                                path_hash,
+                                bname, 
+                                NULL);
+}
+
+static gboolean
+ensure_directory_exists (const char *filename)
+{
+#ifdef PLATFORM_WIN32
+       gchar *dir_utf8 = g_path_get_dirname (filename);
+       gunichar2 *p;
+       gunichar2 *dir_utf16 = NULL;
+       int retval;
+       
+       if (!dir_utf8 || !dir_utf8 [0])
+               return FALSE;
+
+       dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
+       g_free (dir_utf8);
+
+       if (!dir_utf16)
+               return FALSE;
+
+       p = dir_utf16;
+
+       /* make life easy and only use one directory seperator */
+       while (*p != '\0')
+       {
+               if (*p == '/')
+                       *p = '\\';
+               p++;
+       }
+
+       p = dir_utf16;
+
+       /* get past C:\ )*/
+       while (*p++ != '\\')    
+       {
+       }
+
+       while (1) {
+               BOOL bRet = FALSE;
+               p = wcschr (p, '\\');
+               if (p)
+                       *p = '\0';
+               retval = _wmkdir (dir_utf16);
+               if (retval != 0 && errno != EEXIST) {
+                       g_free (dir_utf16);
+                       return FALSE;
+               }
+               if (!p)
+                       break;
+               *p++ = '\\';
+       }
+       
+       g_free (dir_utf16);
+       return TRUE;
+#else
+       char *p;
+       gchar *dir = g_path_get_dirname (filename);
+       int retval;
+       
+       if (!dir || !dir [0])
+               return FALSE;
+
+       p = dir;
+       while (*p == '/')
+               p++;
+
+       while (1) {
+               p = strchr (p, '/');
+               if (p)
+                       *p = '\0';
+               retval = mkdir (dir, 0777);
+               if (retval != 0 && errno != EEXIST) {
+                       g_free (dir);
+                       return FALSE;
+               }
+               if (!p)
+                       break;
+               *p++ = '/';
+       }
+       
+       g_free (dir);
+       return TRUE;
+#endif
+}
+
 static char *
 make_shadow_copy (const char *filename)
 {
-       gchar *tmp;
+       gchar *sibling_source, *sibling_target;
+       gint sibling_source_len, sibling_target_len;
        guint16 *orig, *dest;
-       MonoDomain *domain = mono_domain_get ();
-       char *db;
-       int fd;
+       char *shadow;
        gboolean copy_result;
        MonoException *exc;
-
-       db = mono_string_to_utf8 (domain->setup->dynamic_base);
-       tmp = g_build_filename (db, "shadow-XXXXXX", NULL);
-       fd = mono_mkstemp (tmp);
-       if (fd == -1) {
-               exc = mono_get_exception_execution_engine ("Failed to create shadow copy (mkstemp).");
-               g_free (tmp);
-               g_free (db);
+       
+       shadow = get_shadow_assembly_location (filename);
+       if (ensure_directory_exists (shadow) == FALSE) {
+               exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
                mono_raise_exception (exc);
-       }
-       close (fd);
-       remove (tmp);
+       }       
+
        orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
-       dest = g_utf8_to_utf16 (tmp, strlen (tmp), NULL, NULL, NULL);
-       copy_result = CopyFile (orig, dest, TRUE);
+       dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
+       copy_result = CopyFile (orig, dest, FALSE);
        g_free (dest);
        g_free (orig);
-       g_free (db);
 
        if (copy_result == FALSE) {
-               g_free (tmp);
+               g_free (shadow);
                exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
                mono_raise_exception (exc);
        }
-       return tmp;
+
+       /* attempt to copy .mdb, .config if they exist */
+       sibling_source = g_strconcat (filename, ".config", NULL);
+       sibling_source_len = strlen (sibling_source);
+       sibling_target = g_strconcat (shadow, ".config", NULL);
+       sibling_target_len = strlen (sibling_target);
+       
+       copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
+       if (copy_result == TRUE)
+               copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
+       
+       g_free (sibling_source);
+       g_free (sibling_target);
+       
+       if (copy_result == FALSE)  {
+               g_free (shadow);
+               exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
+               mono_raise_exception (exc);
+       }
+       
+       return shadow;
 }
 
 static gboolean
@@ -984,7 +1153,7 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean re
                MonoException *exc;
 
                if (status == MONO_IMAGE_IMAGE_INVALID)
-                       exc = mono_get_exception_bad_image_format (name);
+                       exc = mono_get_exception_bad_image_format2 (NULL, fname);
                else
                        exc = mono_get_exception_file_not_found2 (NULL, fname);
                g_free (name);
@@ -998,9 +1167,9 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean re
 
 MonoReflectionAssembly *
 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
-                                                                                       MonoArray *raw_assembly,
-                                                                                       MonoArray *raw_symbol_store, MonoObject *evidence,
-                                                                                       MonoBoolean refonly)
+                                           MonoArray *raw_assembly,
+                                           MonoArray *raw_symbol_store, MonoObject *evidence,
+                                           MonoBoolean refonly)
 {
        MonoAssembly *ass;
        MonoReflectionAssembly *refass = NULL;
@@ -1403,6 +1572,9 @@ mono_domain_unload (MonoDomain *domain)
        thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, 0, &tid);
 #else
        thread_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
+       if (thread_handle == NULL) {
+               return;
+       }
        ResumeThread (thread_handle);
 #endif