This is an automated email from the git hooks/post-receive script.

x2go pushed a commit to branch master
in repository libx2goclient.

commit e1100f6544bda45fb0ab19525d53694f060dfb99
Author: Mihai Moldovan <io...@ionic.de>
Date:   Thu Jul 30 09:59:20 2020 +0200

    src/x2goclient-network-ssh.c: rename x2goclient_network_ssh_ptrarray_print 
() to x2goclient_network_ssh_gptrarray_to_string () and fully rework it.
    
    Instead of having it print out the result directly via g_log (and not
    having any control of the actual printing), make it return a boolean
    value indicating errors and a string as an output parameter.
    
    This way, callers can handle the string however they want.
    
    Additionally, pre-calculate the size of the resulting string (checking
    for size-based wrapping along the way) and copy data in chunks instead
    of using the old Shlemiel-The-Painter algorithm.
---
 src/x2goclient-network-ssh.c | 160 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 141 insertions(+), 19 deletions(-)

diff --git a/src/x2goclient-network-ssh.c b/src/x2goclient-network-ssh.c
index feab49c..f43a894 100644
--- a/src/x2goclient-network-ssh.c
+++ b/src/x2goclient-network-ssh.c
@@ -134,7 +134,7 @@ static gboolean x2goclient_network_ssh_kill_subprocesses 
(X2GoClientNetworkSSH *
 static gboolean x2goclient_network_ssh_parent_connect (X2GoClientNetwork 
*parent, GError **gerr);
 static gboolean x2goclient_network_ssh_fetch_openssh_version 
(X2GoClientNetworkSSH *self, GError **gerr);
 static void x2goclient_network_ssh_log_std_str (const gchar * const str, const 
gsize str_size, const _Bool select_stderr);
-static void x2goclient_network_ssh_ptrarray_print (GPtrArray * const arr, 
const gchar * const prelude);
+static gboolean x2goclient_network_ssh_gptrarray_to_string (GPtrArray * const 
arr, const gchar * const prelude, gchar ** const ret_str);
 
 
 static void x2goclient_network_ssh_class_init (X2GoClientNetworkSSHClass 
*klass) {
@@ -951,7 +951,21 @@ static gboolean x2goclient_network_ssh_parent_connect 
(X2GoClientNetwork *parent
   }
 
   if (ret) {
-    x2goclient_network_ssh_gptrarray_print (ssh_cmd, "Would try to connect 
via:");
+    gchar *ssh_cmd_str = NULL;
+    if (x2goclient_network_ssh_gptrarray_to_string (ssh_cmd, "Would try to 
connect via:", &ssh_cmd_str)) {
+      if (ssh_cmd_str) {
+        g_log (NULL, G_LOG_LEVEL_DEBUG, "%s", ssh_cmd_str);
+
+        g_free (ssh_cmd_str);
+        ssh_cmd_str = NULL;
+      }
+      else {
+        g_log (NULL, G_LOG_LEVEL_DEBUG, "Unable to print out OpenSSH client 
command, it was completely empty.");
+      }
+    }
+    else {
+      g_log (NULL, G_LOG_LEVEL_DEBUG, "Unable to print out OpenSSH client 
command, internal error (the string likely was too big).");
+    }
 
     g_log (NULL, G_LOG_LEVEL_DEBUG, "Launching!");
     GError *ssh_err = NULL;
@@ -1101,36 +1115,144 @@ static void x2goclient_network_ssh_log_std_str (const 
gchar * const str, const g
   }
 }
 
-static void x2goclient_network_ssh_gptrarray_print (GPtrArray * const arr, 
const gchar * const prelude) {
-  g_return_if_fail (arr);
+static gboolean x2goclient_network_ssh_gptrarray_to_string (GPtrArray * const 
arr, const gchar * const prelude, gchar ** const ret_str) {
+#define SIZE_LOW_WRAP(buffer_size, elem_size) ((G_MAXSIZE - (buffer_size)) < 
((elem_size)))
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (((arr) && (ret_str)), ret);
+
+  *(ret_str) = NULL;
 
-  /*
-   * Yeah, this is potentially slow, but there is no better way to use
-   * g_log ().
-   */
   gchar *tmp = NULL;
   const gchar *empty = "(NULL)";
+  const gsize empty_size = strlen (empty);
+
+  /* Account for terminating NULL. */
+  gsize size = 1;
+
+  /*
+   * First, calculate the total size.
+   *
+   * Calculating the size and printing will take two iterations, but that's
+   * still better than a lot of reallocations and data moves.
+   */
+  ret = TRUE;
   if (prelude) {
-    tmp = g_strdup (prelude);
+    const gsize elem_size = strlen (prelude);
+
+    if (SIZE_LOW_WRAP (size, elem_size)) {
+      ret = FALSE;
+    }
+    else {
+      size += elem_size;
+    }
   }
+  for (gsize i = 0; ((i < arr->len) && (ret)); ++i) {
+    const gchar *cur_entry = g_ptr_array_index (arr, i);
+
+    gsize additional_chars = 0;
+    /* Account for the potential additional chars " []". */
+    if ((0 == i) && (!(prelude))) {
+      /* No space character necessary if we don't have a prelude. */
+      additional_chars = 2;
+    }
+    else {
+      additional_chars = 3;
+    }
+
+    if (SIZE_LOW_WRAP (size, additional_chars)) {
+      ret = FALSE;
+      continue;
+    }
 
-  for (gsize i = 0; i < arr->len; ++i) {
-    gchar *tmp_new = NULL;
-    gchar *cur_entry = (gchar *)g_ptr_array_index (arr, i);
+    size += additional_chars;
 
+    gsize elem_size = 0;
     if (cur_entry) {
-      tmp_new = g_strdup_printf ("%s [%s]", tmp, cur_entry);
+      elem_size = strlen (cur_entry);
     }
     else {
-      tmp_new = g_strdup_printf ("%s [%s]", tmp, empty);
+      elem_size = empty_size;
     }
 
-    g_free (tmp);
+    if (SIZE_LOW_WRAP (size, elem_size)) {
+      ret = FALSE;
+      continue;
+    }
+
+    size += elem_size;
+  }
+
+  if (ret) {
+    /* Now allocate enough space. */
+    *(ret_str) = tmp = g_new0 (gchar, size);
+
+    gsize tmp_size = size,
+          written_size = 0;
+
+    /*
+     * *(ret_str) could be NULL now, but that can only happen if both the
+     * prelude and array are empty.
+     *
+     * That's fine, since in that case everything will be skipped.
+     */
+    if ((prelude) && (tmp)) {
+      written_size = g_strlcpy (tmp, prelude, tmp_size);
+
+      if (written_size >= tmp_size) {
+        /* Truncation. */
+        ret = FALSE;
+      }
+      else {
+        tmp += written_size;
+        tmp_size -= written_size;
+      }
+    }
+
+#define HANDLE_TRUNC() \
+  do { \
+    if (written_size >= tmp_size) { \
+      /* Truncation. */ \
+      ret = FALSE; \
+      continue; \
+    } \
+    else { \
+      tmp += written_size; \
+      tmp_size -= written_size; \
+    } \
+  } while (0)
+
+    for (gsize i = 0; ((i < arr->len) && (ret)); ++i) {
+      const gchar *cur_entry = g_ptr_array_index (arr, i);
+
+      if ((0 != i) || (prelude)) {
+        written_size = g_strlcpy (tmp, " ", tmp_size);
+        HANDLE_TRUNC ();
+      }
+
+      written_size = g_strlcpy (tmp, "[", tmp_size);
+      HANDLE_TRUNC ();
+
+      if (cur_entry) {
+        written_size = g_strlcpy (tmp, cur_entry, tmp_size);
+      }
+      else {
+        written_size = g_strlcpy (tmp, empty, tmp_size);
+      }
+      HANDLE_TRUNC ();
 
-    tmp = tmp_new;
+      written_size = g_strlcpy (tmp, "]", tmp_size);
+      HANDLE_TRUNC ();
+    }
   }
-  g_log (NULL, G_LOG_LEVEL_DEBUG, "%s", tmp);
 
-  g_free (tmp);
-  tmp = NULL;
+  if (!(ret)) {
+    /* Clean up, we errored. */
+    g_free (*(ret_str));
+    *(ret_str) = tmp = NULL;
+  }
+
+  return (ret);
+#undef HANDLE_TRUNC
+#undef SIZE_LOW_WRAP
 }

--
Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on 
/srv/git/code.x2go.org/libx2goclient.git
_______________________________________________
x2go-commits mailing list
x2go-commits@lists.x2go.org
https://lists.x2go.org/listinfo/x2go-commits

Reply via email to