wrong error number
[mono.git] / mono / metadata / process.c
index 3832f82de664317bcc891578825a72de6428a3cb..ade650b4c5462ab1ffd666bde06db5ed5195a479 100644 (file)
 #include <mono/metadata/image.h>
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/exception.h>
+#include <mono/utils/strenc.h>
 #include <mono/io-layer/io-layer.h>
+/* FIXME: fix this code to not depend so much on the inetrnals */
+#include <mono/metadata/class-internals.h>
 
 #undef DEBUG
 
@@ -203,7 +206,8 @@ static gpointer process_get_versioninfo_block (gpointer data,
        data=((gunichar2 *)data)+(unicode_chars (block->key)+1);
 
        /* align on a 32-bit boundary */
-       data=(gpointer)(((unsigned)data+3) & (~3));
+       data=(gpointer)((char *)data + 3);
+       data=(gpointer)((char *)data - (GPOINTER_TO_INT(data) & 3));
        
        return(data);
 }
@@ -305,7 +309,9 @@ static gpointer process_read_string_block (MonoObject *filever,
                gunichar2 *value;
                
                /* align on a 32-bit boundary */
-               data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
+               data_ptr=(gpointer)((char *)data_ptr + 3);
+               data_ptr=(gpointer)((char *)data_ptr -
+                   (GPOINTER_TO_INT(data_ptr) & 3));
 
                data_ptr=process_get_versioninfo_block (data_ptr, &block);
                if(block.data_len==0) {
@@ -323,10 +329,11 @@ static gpointer process_read_string_block (MonoObject *filever,
                value=(gunichar2 *)data_ptr;
                /* Skip over the value */
                data_ptr=((gunichar2 *)data_ptr)+block.value_len;
-               
+
                if(store==TRUE) {
                        if(!memcmp (block.key, &comments_key,
                                    unicode_bytes (block.key))) {
+
                                process_set_field_string (filever, "comments", value, unicode_chars (value));
                        } else if (!memcmp (block.key, &compname_key,
                                            unicode_bytes (block.key))) {
@@ -382,18 +389,9 @@ static gpointer process_read_stringtable_block (MonoObject *filever,
                                                guint16 data_len)
 {
        version_data block;
+       gchar *language;
        guint16 string_len=36;  /* length of the StringFileInfo block */
 
-       /* Specifies language-neutral unicode string block */
-       guchar uni_key[]= {'0', '\0', '0', '\0', '0', '\0', '0', '\0',
-                          '0', '\0', '4', '\0', 'b', '\0', '0', '\0',
-                          '\0', '\0'
-       };
-       guchar uni_key_uc[]= {'0', '\0', '0', '\0', '0', '\0', '0', '\0',
-                             '0', '\0', '4', '\0', 'B', '\0', '0', '\0',
-                             '\0', '\0'
-       };
-       
        /* data_ptr is pointing at an array of StringTable blocks,
         * with total length (not including alignment padding) of
         * data_len.
@@ -401,7 +399,9 @@ static gpointer process_read_stringtable_block (MonoObject *filever,
 
        while(string_len<data_len) {
                /* align on a 32-bit boundary */
-               data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
+               data_ptr=(gpointer)((char *)data_ptr + 3);
+               data_ptr=(gpointer)((char *)data_ptr -
+                   (GPOINTER_TO_INT(data_ptr) & 3));
 
                data_ptr=process_get_versioninfo_block (data_ptr, &block);
                if(block.data_len==0) {
@@ -415,9 +415,10 @@ static gpointer process_read_stringtable_block (MonoObject *filever,
                        return(NULL);
                }
                string_len=string_len+block.data_len;
-       
-               if(!memcmp (block.key, &uni_key, unicode_bytes (block.key)) ||
-                  !memcmp (block.key, &uni_key_uc, unicode_bytes (block.key))) {
+
+               language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL);
+               g_strdown (language);
+               if (!strcmp (language, "007f04b0") || !strcmp (language, "000004b0")) {
                        /* Got the one we're interested in */
                        process_set_field_string_utf8 (filever, "language",
                                                       "Language Neutral");
@@ -433,6 +434,7 @@ static gpointer process_read_stringtable_block (MonoObject *filever,
                                                            block.data_len,
                                                            FALSE);
                }
+               g_free (language);
 
                if(data_ptr==NULL) {
                        /* Child block hit padding */
@@ -518,7 +520,7 @@ static void process_get_fileversion (MonoObject *filever, MonoImage *image)
                return;
        }
        
-       data=mono_cli_rva_map (image->image_info,
+       data=mono_image_rva_map (image,
                               version_info->rde_data_offset);
        if(data==NULL) {
                return;
@@ -569,7 +571,9 @@ static void process_get_fileversion (MonoObject *filever, MonoImage *image)
         */
        while(data_len > 0) {
                /* align on a 32-bit boundary */
-               data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
+               data_ptr=(gpointer)((char *)data_ptr + 3);
+               data_ptr=(gpointer)((char *)data_ptr -
+                   (GPOINTER_TO_INT(data_ptr) & 3));
 
                data_ptr=process_get_versioninfo_block (data_ptr, &block);
                if(block.data_len==0) {
@@ -616,6 +620,7 @@ static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
        MonoObject *item, *filever;
        MonoDomain *domain=mono_domain_get ();
        gchar *modulename;
+       const char* filename;
        
        /* Build a System.Diagnostics.ProcessModule with the data.
         * Leave BaseAddress and EntryPointAddress set to NULL,
@@ -637,13 +642,14 @@ static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
        g_message (G_GNUC_PRETTY_FUNCTION ": recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d], ModuleName [%s]", ass->image->name, ass->aname.major, ass->aname.minor, ass->aname.build, ass->aname.revision, ass->image->name);
 #endif
 
-       process_get_fileversion (filever, ass->image);
+       process_get_fileversion (filever, mono_assembly_get_image (ass));
 
-       process_set_field_string_utf8 (filever, "filename", ass->image->name);
-       process_set_field_string_utf8 (item, "filename", ass->image->name);
+       filename = mono_image_get_filename (mono_assembly_get_image (ass));
+       process_set_field_string_utf8 (filever, "filename", filename);
+       process_set_field_string_utf8 (item, "filename", filename);
        process_set_field_object (item, "version_info", filever);
 
-       modulename=g_path_get_basename (ass->image->name);
+       modulename=g_path_get_basename (filename);
        process_set_field_string_utf8 (item, "modulename", modulename);
        g_free (modulename);
 
@@ -686,7 +692,7 @@ MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject
        mono_assembly_foreach (process_scan_modules, modules_list);
 
        /* Build a MonoArray out of modules_list */
-       arr=mono_array_new (mono_domain_get (), mono_defaults.object_class,
+       arr=mono_array_new (mono_domain_get (), mono_get_object_class (),
                            modules_list->len);
        
        for(i=0; i<modules_list->len; i++) {
@@ -722,17 +728,72 @@ void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoO
        }
        
        process_get_fileversion (this, image);
-       process_set_field_string_utf8 (this, "filename", image->name);
+       process_set_field_string_utf8 (this, "filename", mono_image_get_filename (image));
        
        mono_image_close (image);
 }
 
-MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
+/* Only used when UseShellExecute is false */
+static gchar *
+quote_path (const gchar *path)
+{
+       gchar *res = g_shell_quote (path);
+#ifdef PLATFORM_WIN32
+       {
+       gchar *q = res;
+       while (*q) {
+               if (*q == '\'')
+                       *q = '\"';
+               q++;
+       }
+       }
+#endif
+       return res;
+}
+
+/* Only used when UseShellExecute is false */
+static gboolean
+complete_path (const gunichar2 *appname, gchar **completed)
+{
+       gchar *utf8app;
+       gchar *found;
+
+       utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
+       if (g_path_is_absolute (utf8app)) {
+               *completed = quote_path (utf8app);
+               g_free (utf8app);
+               return TRUE;
+       }
+
+       if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
+               *completed = quote_path (utf8app);
+               g_free (utf8app);
+               return TRUE;
+       }
+       
+       found = g_find_program_in_path (utf8app);
+       if (found == NULL) {
+               *completed = NULL;
+               g_free (utf8app);
+               return FALSE;
+       }
+
+       *completed = quote_path (found);
+       g_free (found);
+       g_free (utf8app);
+       return TRUE;
+}
+
+MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *appname, MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
 {
        gboolean ret;
        gunichar2 *dir;
        STARTUPINFO startinfo={0};
        PROCESS_INFORMATION procinfo;
+       gunichar2 *shell_path = NULL;
+       gchar *env_vars = NULL;
+       gboolean free_shell_path = TRUE;
+       gchar *newcmd, *tmp;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -742,6 +803,104 @@ MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd
        startinfo.hStdOutput=stdout_handle;
        startinfo.hStdError=stderr_handle;
        
+       if (process_info->use_shell) {
+               const gchar *spath;
+               const gchar *shell_args;
+#ifdef PLATFORM_WIN32
+               spath = g_getenv ("COMSPEC");
+               shell_args = "/c %s";
+#else
+               spath = g_getenv ("SHELL");
+               shell_args = "-c %s";
+#endif
+               if (spath != NULL) {
+                       gint dummy;
+                       gchar *quoted;
+
+                       shell_path = mono_unicode_from_external (spath, &dummy);
+                       tmp = mono_string_to_utf8 (cmd);
+                       quoted = g_shell_quote (tmp);
+#ifdef PLATFORM_WIN32
+                       {
+                               gchar *q = quoted;
+                               while (*q) {
+                                       if (*q == '\'')
+                                               *q = '\"';
+                                       q++;
+                               }
+                       }
+#endif
+                       newcmd = g_strdup_printf (shell_args, quoted);
+                       g_free (quoted);
+                       g_free (tmp);
+                       cmd = mono_string_new (mono_domain_get (), newcmd);
+                       g_free (newcmd);
+               }
+       } else {
+               gchar *spath = NULL;
+               shell_path = mono_string_chars (appname);
+               complete_path (shell_path, &spath);
+               if (spath == NULL) {
+                       process_info->pid = -ERROR_FILE_NOT_FOUND;
+                       return FALSE;
+               }
+#ifdef PLATFORM_WIN32
+               /* Seems like our CreateProcess does not work as the windows one.
+                * This hack is needed to deal with paths containing spaces */
+               shell_path = NULL;
+               free_shell_path = FALSE;
+               tmp = mono_string_to_utf8 (cmd);
+               newcmd = g_strdup_printf ("%s %s", spath, tmp);
+               cmd = mono_string_new_wrapper (newcmd);
+               g_free (newcmd);
+               g_free (tmp);
+#else
+               shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL);
+#endif
+               g_free (spath);
+       }
+
+       if (process_info->env_keys != NULL) {
+               gint i, len; 
+               MonoString *ms;
+               MonoString *key, *value;
+               gunichar2 *str, *ptr;
+               gunichar2 *equals16;
+
+               for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
+                       ms = mono_array_get (process_info->env_values, MonoString *, i);
+                       if (ms == NULL)
+                               continue;
+
+                       len += mono_string_length (ms) * sizeof (gunichar2);
+                       ms = mono_array_get (process_info->env_keys, MonoString *, i);
+                       len += mono_string_length (ms) * sizeof (gunichar2);
+                       len += 2 * sizeof (gunichar2);
+               }
+
+               equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
+               ptr = str = g_new0 (gunichar2, len + 1);
+               for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
+                       value = mono_array_get (process_info->env_values, MonoString *, i);
+                       if (value == NULL)
+                               continue;
+
+                       key = mono_array_get (process_info->env_keys, MonoString *, i);
+                       memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
+                       ptr += mono_string_length (key);
+
+                       memcpy (ptr, equals16, sizeof (gunichar2));
+                       ptr++;
+
+                       memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
+                       ptr += mono_string_length (value);
+                       ptr++;
+               }
+
+               g_free (equals16);
+               env_vars = (gchar *) str;
+       }
+       
        /* The default dir name is "".  Turn that into NULL to mean
         * "current directory"
         */
@@ -751,11 +910,17 @@ MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd
                dir=mono_string_chars (dirname);
        }
        
-       ret=CreateProcess (NULL, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, NULL, dir, &startinfo, &procinfo);
+       ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
+
+       g_free (env_vars);
+       if (free_shell_path)
+               g_free (shell_path);
 
        if(ret) {
                process_info->process_handle=procinfo.hProcess;
-               process_info->thread_handle=procinfo.hThread;
+               /*process_info->thread_handle=procinfo.hThread;*/
+               process_info->thread_handle=NULL;
+               CloseHandle(procinfo.hThread);
                process_info->pid=procinfo.dwProcessId;
                process_info->tid=procinfo.dwThreadId;
        } else {
@@ -773,11 +938,10 @@ MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObjec
 
        if(ms<0) {
                /* Wait forever */
-               ret=WaitForSingleObject (process, INFINITE);
+               ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
        } else {
-               ret=WaitForSingleObject (process, ms);
+               ret=WaitForSingleObjectEx (process, ms, TRUE);
        }
-       
        if(ret==WAIT_OBJECT_0) {
                return(TRUE);
        } else {
@@ -888,7 +1052,7 @@ MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
        }
        
        count=needed/sizeof(guint32);
-       procs=mono_array_new (mono_domain_get (), mono_defaults.int_class,
+       procs=mono_array_new (mono_domain_get (), mono_get_int32_class (),
                              count);
        for(i=0; i<count; i++) {
                mono_array_set (procs, guint32, i, pids[i]);
@@ -934,3 +1098,14 @@ MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE
 
        return(ret);
 }
+
+MonoBoolean
+ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
+
+       return TerminateProcess (process, -sig);
+}
+