From 251ec6e3e4c8552595c1e0ef735ca76573237565 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Wed, 10 Nov 2010 17:42:04 +0300
Subject: [PATCH 2/2] Fix environment table generation for child processes

---
 src/util/os_priority.c |  172 +++++++++++++++++++++++++++++-------------------
 1 files changed, 103 insertions(+), 69 deletions(-)

diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index 10beff4..45ad63d 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -115,7 +115,7 @@ GNUNET_OS_install_parent_control_handler (void *cls,
   if (control_pipe == NULL)
     return;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe to the scheduler\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe %d to the scheduler\n", control_pipe_end[0]);
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
 #endif
 }
@@ -358,75 +358,100 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
 }
 
 #if WINDOWS
-/**
- * Look through the @env_table and find its size (in bytes, excluding
- * all NULL-terminators) and item count.
- *
- * Use count + size + 1 to calculate the size of the envtable in memory
- *
- * @param env_table environment table, as returned by GetEnvironmentStrings()
- * @param count returned number of elements
- * @param size returned total length of the items
- * @return GNUNET_SYSERR on error, GNUNET_OK on success
- */
-int
-GetEnvTableSizeA (const char *env_table, size_t *count, size_t *size)
+char *
+CreateCustomEnvTable (char **vars)
 {
+  char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr;
   size_t tablesize = 0;
   size_t items_count = 0;
-  const char *ptr;
-  if (!env_table)
-    return GNUNET_SYSERR;
+  size_t n_found = 0, n_var;
+  char *index = NULL;
+  size_t c;
+  size_t var_len;
+  char *var;
+  char *val;
+  win32_env_table = GetEnvironmentStringsA ();
+  if (win32_env_table == NULL)
+    return NULL;
+  for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++);
+  n_var = c;
+  index = GNUNET_malloc (n_var);
+  for (c = 0; c < n_var; c++)
+    index[c] = 0;
   for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
   {
     size_t len = strlen (ptr);
-    tablesize += len;
-    ptr += len + 1;
+    int found = 0;
+    for (var_ptr = vars; *var_ptr; var_ptr++)
+    {
+      var = *var_ptr++;
+      val = *var_ptr;
+      var_len = strlen (var);
+      if (strncmp (var, ptr, var_len) == 0)
+      {
+        found = 1;
+        index[c] = 1;
+        tablesize += var_len + strlen (val) + 1;
+        break;
+      }
+    }
+    if (!found)
+      tablesize += len + 1;
+    ptr += len + 1; 
   }
-  if (count)
-    *count = items_count;
-  if (size)
-    *size = tablesize;
-  return GNUNET_OK;
-}
-
-char *
-CreateEnvTableA ()
-{
-  char *result = NULL;
-  size_t count, size;
-  const char *win32_env_table;
-  win32_env_table = GetEnvironmentStrings ();
-  if (win32_env_table == NULL || GNUNET_OK != GetEnvTableSizeA (win32_env_table, &count, &size))
-    return NULL;
-  result = GNUNET_malloc (count + size + 1);
-  if (result)
-    memcpy (result, win32_env_table, count + size + 1);
-  if (win32_env_table)
-    FreeEnvironmentStrings (win32_env_table);
-  return result;
-}
-
-char *
-AddToEnvTableA (char *env_table, const char *newvar)
-{
-  char *result = NULL, *ptr;
-  size_t count, size, new_var_size;
-  new_var_size = strlen (newvar);
-  if (env_table == NULL || GNUNET_OK != GetEnvTableSizeA ((const char *) env_table, &count, &size))
+  for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
   {
-    GNUNET_free (env_table);
-    return NULL;
+    var = *var_ptr++;
+    val = *var_ptr;
+    if (index[c] != 1)
+      n_found += strlen (var) + strlen (val) + 1;
+  }
+  result = GNUNET_malloc (tablesize + n_found + 1);
+  for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;)
+  {
+    size_t len = strlen (ptr);
+    int found = 0;
+    for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
+    {
+      var = *var_ptr++;
+      val = *var_ptr;
+      var_len = strlen (var);
+      if (strncmp (var, ptr, var_len) == 0)
+      {
+        found = 1;
+        break;
+      }
+    }
+    if (!found)
+    {
+      strcpy (result_ptr, ptr);
+      result_ptr += len + 1;
+    }
+    else
+    {
+      strcpy (result_ptr, var);
+      result_ptr += var_len;
+      strcpy (result_ptr, val);
+      result_ptr += strlen (val) + 1;
+    }
+    ptr += len + 1;
   }
-  result = GNUNET_malloc (count + 1 + size + new_var_size + 1);
-  if (result)
+  for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++)
   {
-    memcpy (result, win32_env_table, count + size);
-    ptr = result + count + size;
-    memcpy (ptr, newvar, new_var_size + 1);
-    ptr[new_var_size + 1] = 0;
+    var = *var_ptr++;
+    val = *var_ptr;
+    var_len = strlen (var);
+    if (index[c] != 1)
+    {
+      strcpy (result_ptr, var);
+      result_ptr += var_len;
+      strcpy (result_ptr, val);
+      result_ptr += strlen (val) + 1;
+    }
   }
-  GNUNET_free (env_table);
+  FreeEnvironmentStrings (win32_env_table);
+  GNUNET_free (index);
+  *result_ptr = 0;
   return result;
 }
 #endif
@@ -542,8 +567,8 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
   struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
-  char *env_buf;
   char *env_block = NULL;
+  char *our_env[3] = { NULL, NULL, NULL };
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
@@ -593,10 +618,12 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
 
-  env_block = CreateEnvTableA (env_block);
-  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
-  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
-  GNUNET_free (env_buf);
+  GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  GNUNET_asprintf (&our_env[1], "%d", control_pipe_read_end);
+  our_env[2] = NULL;
+  env_block = CreateCustomEnvTable (our_env);
+  GNUNET_free (our_env[0]);
+  GNUNET_free (our_env[1]);
 
   if (!CreateProcessA
       (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, env_block, NULL, &start,
@@ -612,6 +639,8 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->control_pipe = control_pipe;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started a child process, control pipe %d->%d\n", control_pipe_write_end, control_pipe_read_end);
+
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
@@ -755,7 +784,8 @@ GNUNET_OS_start_process_v (const int *lsocks,
   char non_const_filename[MAX_PATH +1];
   struct GNUNET_OS_Process *gnunet_proc = NULL;
   struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
-  char *env_buf = NULL, *env_block = NULL;
+  char *env_block = NULL;
+  char *our_env[3] = { NULL, NULL, NULL };
   HANDLE control_pipe_read_end, control_pipe_write_end;
 
   GNUNET_assert (lsocks == NULL);
@@ -819,10 +849,12 @@ GNUNET_OS_start_process_v (const int *lsocks,
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
   GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
 
-  env_block = CreateEnvTableA (env_block);
-  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
-  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
-  GNUNET_free (env_buf);
+  GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_NT_CONTROL_PIPE);
+  GNUNET_asprintf (&our_env[1], "%d", control_pipe_read_end);
+  our_env[2] = NULL;
+  env_block = CreateCustomEnvTable (our_env);
+  GNUNET_free (our_env[0]);
+  GNUNET_free (our_env[1]);
 
   if (!CreateProcessA
       (non_const_filename, cmd, NULL, NULL, TRUE,
@@ -834,6 +866,8 @@ GNUNET_OS_start_process_v (const int *lsocks,
       goto end;
     }
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started a child process, control pipe %d->%d\n", control_pipe_write_end, control_pipe_read_end);
+
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
-- 
1.7.3.1.msysgit.0

