[X2Go-Commits] [libx2goclient] 06/44: src/x2goclient-network-ssh.c: rename x2goclient_network_ssh_ptrarray_print () to x2goclient_network_ssh_gptrarray_to_string () and fully rework it.
git-admin at x2go.org
git-admin at x2go.org
Fri Sep 18 01:55:37 CEST 2020
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 <ionic at 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
More information about the x2go-commits
mailing list