[ghex/support-block-devices-part-trois: 5/5] Really crappy Gvariant message exchanging backend attempt
- From: Logan Rathbone <larathbone src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ghex/support-block-devices-part-trois: 5/5] Really crappy Gvariant message exchanging backend attempt
- Date: Fri, 17 Jun 2022 02:19:55 +0000 (UTC)
commit 4013d4636e2fc00568a6b2816664e04ba30bf2b8
Author: Logan Rathbone <poprocks gmail com>
Date: Sat Jun 11 01:31:27 2022 -0400
Really crappy Gvariant message exchanging backend attempt
This is to try to have the IO in a separate process.. right now it's way
too slow and doesn't work well. But r/therewasanattempt!
meson.build | 3 +
src/gvar.c | 225 +++++++++++++++
src/hex-buffer-direct-child.h | 29 ++
src/hex-buffer-direct.c | 657 ++++++++++++++++++++++++++++++++++++++----
4 files changed, 861 insertions(+), 53 deletions(-)
---
diff --git a/meson.build b/meson.build
index 63d6c15..ed7d6c3 100644
--- a/meson.build
+++ b/meson.build
@@ -37,6 +37,7 @@ libgtkhex_version = '@0@.@1@.@2@'.format(libgtkhex_api_version, libgtkhex_versio
ghex_prefix = get_option('prefix')
ghex_libdir = join_paths(ghex_prefix, get_option('libdir'))
+ghex_libexecdir = join_paths(ghex_prefix, get_option('libexecdir'))
ghex_includedir = join_paths(ghex_prefix, get_option('includedir'))
ghex_datadir = join_paths(ghex_prefix, get_option('datadir'))
ghex_localedir = join_paths(ghex_prefix, get_option('localedir'))
@@ -80,6 +81,7 @@ config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
config_h.set_quoted('PACKAGE_STRING', '@0@ @1@'.format(meson.project_name(), meson.project_version()))
config_h.set_quoted('PACKAGE_DATADIR', ghex_datadir)
config_h.set_quoted('PACKAGE_LIBDIR', ghex_libdir)
+config_h.set_quoted('PACKAGE_LIBEXECDIR', ghex_libexecdir)
config_h.set_quoted('PACKAGE_PLUGINDIR', ghex_plugindir)
config_h.set_quoted('PACKAGE_LOCALE_DIR', ghex_localedir)
config_h.set_quoted('PACKAGE_DOCDIR', ghex_docdir)
@@ -171,6 +173,7 @@ gnome.post_install(
summary({'prefix': ghex_prefix,
'libdir': ghex_libdir,
+ 'libexecdir': ghex_libexecdir,
'datadir': ghex_datadir,
'docdir': ghex_docdir,
'includedir': ghex_includedir,
diff --git a/src/gvar.c b/src/gvar.c
new file mode 100644
index 0000000..4e715b6
--- /dev/null
+++ b/src/gvar.c
@@ -0,0 +1,225 @@
+#include "hex-buffer-direct-child.h"
+
+static int FD = -1;
+static GVariantType *TYPE_BASE;
+
+/* nb: retval of FALSE here implies a *parsing* error; if the parsing was
+ * handled successfully but the *operation* failed (eg, 'write' command was
+ * properly formed, but the write operation itself failed), we still return
+ * TRUE.
+ */
+static gboolean
+parse_input (const char *input)
+{
+ enum Command cmd;
+ GVariant *cmd_gvar = NULL;
+ GVariant *params = NULL;
+ GVariant *ret_gvar = NULL;
+ gboolean retval = TRUE;
+ gboolean op_ret = TRUE;
+ char *gvar_ret_str = NULL;
+ char *errmsg = NULL;
+
+ cmd_gvar = g_variant_parse (TYPE_BASE, input, NULL, NULL, NULL);
+ if (! cmd_gvar)
+ {
+ g_warning ("Failed to parse command.");
+ retval = FALSE;
+ goto out;
+ }
+
+ g_variant_get (cmd_gvar, FMT_CMD, &cmd, ¶ms);
+
+ if (! params)
+ {
+ g_warning ("No parameters provided or failed to parse parameters.");
+ retval = FALSE;
+ goto out;
+ }
+
+ switch (cmd)
+ {
+ case NEW: case OPEN:
+ {
+ const char *path = g_variant_get_string (params, NULL);
+
+ if (FD != -1)
+ {
+ errmsg = _("Trying to work on multiple file descriptors at once. "
+ "You should not have received this error; please report a
bug.");
+ op_ret = FALSE;
+ goto new_open_out;
+ }
+
+ if (cmd == NEW)
+ {
+ errno = 0;
+ FD = open (path, O_CREAT|O_TRUNC|O_RDWR,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+
+ if (FD < 0)
+ {
+ errmsg = _("Unable to create file");
+ op_ret = FALSE;
+ }
+ }
+ else /* OPEN */
+ {
+ errno = 0;
+ FD = open (path, O_RDWR);
+
+ if (FD < 0)
+ {
+ errno = 0;
+ FD = open (path, O_RDONLY);
+ }
+ if (FD < 0)
+ {
+ errmsg = _("Unable to open file for reading");
+ op_ret = FALSE;
+ }
+ }
+
+ new_open_out:
+ ret_gvar = g_variant_new (FMT_CMD, cmd,
+ g_variant_new (RET_FMT_NEW_OPEN, FD, !op_ret, errno, errmsg));
+ gvar_ret_str = g_variant_print (ret_gvar, TRUE);
+ g_print ("%s\n", gvar_ret_str);
+ }
+ break;
+
+ case CLOSE:
+ {
+ int close_retval;
+
+ if (FD == -1)
+ {
+ errmsg = _("Cannot close a file without opening first. "
+ "You should not have received this error; please report a
bug.");
+ op_ret = FALSE;
+ goto close_out;
+ }
+
+ errno = 0;
+ close_retval = close (FD);
+ if (close_retval != 0)
+ {
+ errmsg = _("Failed to close file");
+ op_ret = FALSE;
+ }
+
+ close_out:
+ ret_gvar = g_variant_new (FMT_CMD, cmd,
+ g_variant_new (RET_FMT_CLOSE, op_ret, !op_ret, errno, errmsg));
+ gvar_ret_str = g_variant_print (ret_gvar, TRUE);
+ g_print ("%s\n", gvar_ret_str);
+ }
+ break;
+
+ case READ:
+ {
+ gint64 off;
+ char b = 0;
+ ssize_t nread;
+
+ if (FD == -1)
+ {
+ errmsg = _("Cannot read from a file without opening first. "
+ "You should not have received this error; please report a
bug.");
+ op_ret = FALSE;
+ goto read_out;
+ }
+
+ g_variant_get (params, FMT_READ, &off);
+
+ /* FIXME/TODO - check retval */
+ lseek (FD, off, SEEK_SET);
+
+ errno = 0;
+ nread = read (FD, &b, 1);
+
+ if (nread != 1)
+ {
+ errmsg = _("Failed to read data from file.");
+ op_ret = FALSE;
+ }
+
+ read_out:
+ ret_gvar = g_variant_new (FMT_CMD, cmd,
+ g_variant_new (RET_FMT_READ,
+ op_ret, op_ret, b, op_ret, off, !op_ret, errno, errmsg));
+ gvar_ret_str = g_variant_print (ret_gvar, TRUE);
+ g_print ("%s\n", gvar_ret_str);
+ }
+ break;
+
+ case WRITE:
+ {
+ gint64 off;
+ char b;
+ ssize_t nwritten;
+ off_t new_off;
+
+ if (FD == -1)
+ {
+ errmsg = _("Cannot write to a file without opening first. "
+ "You should not have received this error; please report a
bug.");
+ op_ret = FALSE;
+ goto write_out;
+ }
+
+ g_variant_get (params, FMT_WRITE, &off, &b);
+
+ errno = 0;
+ new_off = lseek (FD, off, SEEK_SET);
+ if (off != new_off)
+ {
+ errmsg = _("Critical error: read and write offsets do not agree");
+ op_ret = FALSE;
+ }
+
+ errno = 0;
+ nwritten = write (FD, &b, 1);
+ if (nwritten != 1)
+ {
+ errmsg = _("Error writing changes to file");
+ op_ret = FALSE;
+ }
+
+ write_out:
+ ret_gvar = g_variant_new (FMT_CMD, cmd,
+ g_variant_new (RET_FMT_WRITE, op_ret, !op_ret, errno, errmsg));
+ gvar_ret_str = g_variant_print (ret_gvar, TRUE);
+ g_print ("%s\n", gvar_ret_str);
+ }
+ break;
+
+ default:
+ g_warning ("Invalid command. Ignoring.");
+ break;
+ }
+out:
+ g_clear_pointer (&cmd_gvar, g_variant_unref);
+ g_clear_pointer (¶ms, g_variant_unref);
+ g_clear_pointer (&ret_gvar, g_variant_unref);
+ g_free (gvar_ret_str);
+
+ return retval;
+}
+#undef FD_SANITY_CHECK
+
+int main (void)
+{
+ char buf[BUFSIZ];
+
+ TYPE_BASE = g_variant_type_new (FMT_CMD);
+
+ while (fgets (buf, BUFSIZ, stdin) != NULL)
+ {
+ parse_input (g_strchomp (buf));
+ }
+
+ g_variant_type_free (TYPE_BASE);
+
+ return 0;
+}
diff --git a/src/hex-buffer-direct-child.h b/src/hex-buffer-direct-child.h
new file mode 100644
index 0000000..166cbd7
--- /dev/null
+++ b/src/hex-buffer-direct-child.h
@@ -0,0 +1,29 @@
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <stdio.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#define FMT_CMD "(iv)"
+
+#define FMT_NEW_OPEN "s"
+#define FMT_READ "x"
+#define FMT_WRITE "(xy)"
+
+#define RET_FMT_NEW_OPEN "(imims)"
+#define RET_FMT_WRITE "(bmims)"
+#define RET_FMT_READ "(bmymxmims)"
+#define RET_FMT_CLOSE "(bmims)"
+
+enum Command
+{
+ NEW,
+ OPEN,
+ CLOSE,
+ READ,
+ WRITE
+};
diff --git a/src/hex-buffer-direct.c b/src/hex-buffer-direct.c
index 23a4ccc..518eee3 100644
--- a/src/hex-buffer-direct.c
+++ b/src/hex-buffer-direct.c
@@ -22,6 +22,8 @@
*/
#include "hex-buffer-direct.h"
+// FIXME - TEST
+#include "hex-buffer-direct-child.h"
#define HEX_BUFFER_DIRECT_ERROR hex_buffer_direct_error_quark ()
GQuark
@@ -67,6 +69,12 @@ struct _HexBufferDirect
gint64 clean_bytes; /* 'clean' size of the file (no additions or deletions */
GHashTable *changes;
+
+ GSubprocess *sub;
+// GOutputStream *stdin_pipe;
+// GInputStream *stdout_pipe;
+// GDataInputStream *stdout_stream;
+// size_t nread;
};
static void hex_buffer_direct_iface_init (HexBufferInterface *iface);
@@ -78,6 +86,8 @@ G_DEFINE_TYPE_WITH_CODE (HexBufferDirect, hex_buffer_direct, G_TYPE_OBJECT,
static gboolean hex_buffer_direct_set_file (HexBuffer *buf, GFile *file);
static GFile * hex_buffer_direct_get_file (HexBuffer *buf);
+static void set_error (HexBufferDirect *self, const char *blurb);
+static void setup_subprocess (HexBufferDirect *self);
/* PROPERTIES - GETTERS AND SETTERS */
@@ -161,6 +171,534 @@ set_error (HexBufferDirect *self, const char *blurb)
g_free (message);
}
+/* < Commands to send to child process >
+ * We use the templates below, and set `cmd_gvar = ...` to a GVariant
+ * representing the proper command format.
+ */
+
+static void
+child_terminated_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT(user_data);
+ GSubprocess *sub = G_SUBPROCESS(source_object);
+ GError *local_error = NULL;
+ gboolean retval;
+
+ retval = g_subprocess_wait_finish (sub, res, &self->error);
+
+#if 0
+ if (retval)
+ g_print ("%s: child terminated successfully\n", __func__);
+ else
+ g_print ("%s: child terminated with error: %s\n", __func__,
+ self->error->message);
+#endif
+
+}
+
+
+#define SEND_CMD_TEMPLATE_PARAMS \
+ GVariant *cmd_gvar; \
+ GVariant *ret_base_gvar; \
+ GVariant *ret_params_gvar; \
+ char *cmd_str = NULL; \
+ GBytes *cmd_bytes = NULL; \
+ gboolean com_retval; \
+ GBytes *stdout_buf; \
+ char *line; \
+ gsize stdout_len; \
+ int err_num = 0; \
+ char *err_msg = NULL; \
+ gboolean was_err = FALSE;
+
+#define SEND_CMD_TEMPLATE_BOILERPLATE \
+ cmd_bytes = g_bytes_new (cmd_str, strlen(cmd_str)); \
+ \
+ setup_subprocess (self); \
+/* g_subprocess_wait_async (self->sub, NULL, child_terminated_cb, self); */ \
+ \
+ g_clear_error (&self->error); \
+ com_retval = g_subprocess_communicate (self->sub, \
+ cmd_bytes, \
+ NULL, /* cancellable */ \
+ &stdout_buf, \
+ NULL, /* stderr_buf */ \
+ &self->error); \
+ if (! com_retval) \
+ { \
+ g_warning ("g_subprocess_communicate failed: %s", self->error->message); \
+ goto out; \
+ } \
+ \
+ line = g_bytes_unref_to_data (stdout_buf, &stdout_len); \
+ line[stdout_len - 1] = 0; \
+ \
+ ret_base_gvar = g_variant_parse (NULL, line, NULL, NULL, NULL); \
+ if (! ret_base_gvar) \
+ { \
+ g_warning ("Failed to parse retval."); \
+ goto out; \
+ } \
+ \
+ g_variant_get (ret_base_gvar, FMT_CMD, NULL, &ret_params_gvar); \
+ if (! ret_params_gvar) \
+ { \
+ g_warning ("No parameters provided or failed to parse parameters."); \
+ goto out; \
+ }
+
+#define SEND_CMD_TEMPLATE_HANDLE_ERROR \
+ if (was_err) \
+ set_error (self, err_msg);
+
+#define SEND_CMD_TEMPLATE_BOILERPLATE_CLEANUP \
+ g_variant_unref (cmd_gvar); \
+ g_free (cmd_str); \
+ g_bytes_unref (cmd_bytes);
+
+
+static gboolean
+send_close_cmd (HexBufferDirect *self)
+{
+ SEND_CMD_TEMPLATE_PARAMS
+
+ gboolean retval;
+
+ cmd_gvar = g_variant_new (FMT_CMD, CLOSE, g_variant_new_boolean (TRUE));
+ cmd_str = g_strdup_printf ("%s\n", g_variant_print (cmd_gvar, TRUE));
+
+ SEND_CMD_TEMPLATE_BOILERPLATE
+
+ g_variant_get (ret_params_gvar, RET_FMT_CLOSE,
+ &retval, &was_err, &err_num, &err_msg);
+
+ SEND_CMD_TEMPLATE_HANDLE_ERROR
+
+out:
+ SEND_CMD_TEMPLATE_BOILERPLATE_CLEANUP
+
+ return retval;
+}
+
+static char *
+send_read_cmd (HexBufferDirect *self, gint64 off_start, gint64 off_end)
+{
+ GVariant *cmd_gvar;
+ GVariant *ret_base_gvar;
+ GVariant *ret_params_gvar;
+ char *cmd_str = NULL;
+ GBytes *cmd_bytes = NULL;
+ gboolean com_retval;
+ GBytes *stdout_buf;
+ char *line;
+ gsize stdout_len;
+ int err_num = 0;
+ char *err_msg = NULL;
+ gboolean was_err = FALSE;
+
+ char *ret_data = NULL;
+// char b = 0;
+ gboolean op_ret;
+ goffset ret_off;
+ GString *gstr = g_string_new (NULL);
+ char *stdout_str;
+ char **stdout_lines;
+// char *tmp;
+ gint64 i;
+
+ g_assert (off_end >= off_start);
+
+ cmd_gvar = g_variant_new (FMT_CMD, OPEN, g_variant_new_string (g_file_peek_path (self->file)));
+ g_string_append_printf (gstr, "%s\n", g_variant_print (cmd_gvar, TRUE));
+ g_variant_unref (cmd_gvar);
+
+ for (i = 0; i <= off_end - off_start; ++i)
+ {
+ cmd_gvar = g_variant_new (FMT_CMD, READ, g_variant_new_int64 (off_start + i));
+ g_string_append_printf (gstr, "%s\n", g_variant_print (cmd_gvar, TRUE));
+ g_variant_unref (cmd_gvar);
+ }
+
+ cmd_gvar = g_variant_new (FMT_CMD, CLOSE, g_variant_new_boolean (TRUE));
+ g_string_append_printf (gstr, "%s\n", g_variant_print (cmd_gvar, TRUE));
+ g_variant_unref (cmd_gvar);
+
+// cmd_str = g_strdup_printf ("%s\n", g_variant_print (cmd_gvar, TRUE));
+
+ cmd_bytes = g_bytes_new (gstr->str, gstr->len);
+
+ setup_subprocess (self);
+
+ g_clear_error (&self->error);
+ com_retval = g_subprocess_communicate (self->sub,
+ cmd_bytes,
+ NULL, /* cancellable */
+ &stdout_buf,
+ NULL, /* stderr_buf */
+ &self->error);
+ if (! com_retval)
+ {
+ g_warning ("g_subprocess_communicate failed: %s", self->error->message);
+ goto out;
+ }
+
+// cmd_str = g_strdup (gstr->str);
+
+ stdout_str = g_bytes_unref_to_data (stdout_buf, &stdout_len);
+
+ if (!stdout_str)
+ goto out;
+
+ stdout_lines = g_strsplit (stdout_str, "\n", -1);
+
+ for (gint j = 0; j < i; ++j)
+ {
+ char b;
+
+ /* skip first retval for OPEN */
+ ret_base_gvar = g_variant_parse (NULL, stdout_lines[j+1], NULL, NULL, NULL);
+ if (! ret_base_gvar)
+ {
+ g_warning ("Failed to parse retval.");
+ goto out;
+ }
+
+ g_variant_get (ret_base_gvar, FMT_CMD, NULL, &ret_params_gvar);
+ if (! ret_params_gvar)
+ {
+ g_warning ("No parameters provided or failed to parse parameters.");
+ goto out;
+ }
+
+ g_variant_get (ret_params_gvar, RET_FMT_READ,
+ &op_ret, &op_ret, &b, &op_ret, &ret_off, &was_err, &err_num, &err_msg);
+
+ /* Build array to return */
+ if (op_ret)
+ {
+ if (! ret_data)
+ ret_data = g_malloc (i);
+
+ ret_data[j] = b;
+ }
+ else if (was_err)
+ {
+ set_error (self, err_msg);
+ }
+
+ g_clear_pointer (&ret_base_gvar, g_variant_unref);
+ g_clear_pointer (&ret_params_gvar, g_variant_unref);
+ }
+
+ // TEST
+// g_variant_get (ret_params_gvar, RET_FMT_READ,
+// &op_ret, &op_ret, &retval, &op_ret, &ret_off, &was_err, &err_num, &err_msg);
+
+// g_variant_get (ret_params_gvar, RET_FMT_READ,
+// &op_ret, &op_ret, &b, &op_ret, &ret_off, &was_err, &err_num, &err_msg);
+
+// g_debug ("operation: READ - retval: %d - byte: %c - offset: %ld - "
+// "was_err: %d - err_num: %d - err_msg: %s\n",
+// op_ret, b, ret_off, was_err, err_num, err_msg);
+
+
+out:
+ /* free stuff */
+
+ return ret_data;
+}
+
+
+static int
+send_open_cmd (HexBufferDirect *self, const char *path)
+{
+ SEND_CMD_TEMPLATE_PARAMS
+
+ int fd_retval = -1;
+
+ cmd_gvar = g_variant_new (FMT_CMD, OPEN, g_variant_new_string (path));
+ cmd_str = g_strdup_printf ("%s\n", g_variant_print (cmd_gvar, TRUE));
+
+ cmd_bytes = g_bytes_new (cmd_str, strlen(cmd_str));
+
+ setup_subprocess (self);
+/* g_subprocess_wait_async (self->sub, NULL, child_terminated_cb, self); */
+
+ g_clear_error (&self->error);
+ com_retval = g_subprocess_communicate (self->sub,
+ cmd_bytes,
+ NULL, /* cancellable */
+ &stdout_buf,
+ NULL, /* stderr_buf */
+ &self->error);
+ if (! com_retval)
+ {
+ g_warning ("g_subprocess_communicate failed: %s", self->error->message);
+ goto out;
+ }
+
+ line = g_bytes_unref_to_data (stdout_buf, &stdout_len);
+ if (! line)
+ goto out;
+
+ line[stdout_len - 1] = 0;
+
+ ret_base_gvar = g_variant_parse (NULL, line, NULL, NULL, NULL);
+ if (! ret_base_gvar)
+ {
+ g_warning ("Failed to parse retval.");
+ goto out;
+ }
+
+ g_variant_get (ret_base_gvar, FMT_CMD, NULL, &ret_params_gvar);
+ if (! ret_params_gvar)
+ {
+ g_warning ("No parameters provided or failed to parse parameters.");
+ goto out;
+ }
+
+
+
+ g_variant_get (ret_params_gvar, RET_FMT_NEW_OPEN,
+ &fd_retval, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: OPEN - fd: %d - was_err: %d - err_num: %d - err_msg: %s\n",
+ fd_retval, was_err, err_num, err_msg);
+
+ SEND_CMD_TEMPLATE_HANDLE_ERROR
+
+out:
+ SEND_CMD_TEMPLATE_BOILERPLATE_CLEANUP
+
+ return fd_retval;
+}
+
+static gboolean
+send_write_cmd (HexBufferDirect *self, gint64 offset, char byte)
+{
+ SEND_CMD_TEMPLATE_PARAMS
+
+ gboolean retval;
+
+ cmd_gvar = g_variant_new (FMT_CMD, WRITE,
+ g_variant_new (FMT_WRITE, offset, byte));
+ cmd_str = g_strdup_printf ("%s\n", g_variant_print (cmd_gvar, TRUE));
+
+ SEND_CMD_TEMPLATE_BOILERPLATE
+
+ g_variant_get (ret_params_gvar, RET_FMT_WRITE,
+ &retval, &was_err, &err_num, &err_msg);
+
+ SEND_CMD_TEMPLATE_HANDLE_ERROR
+
+out:
+ SEND_CMD_TEMPLATE_BOILERPLATE_CLEANUP
+
+ return retval;
+}
+
+static int
+send_new_cmd (HexBufferDirect *self, const char *path)
+{
+ SEND_CMD_TEMPLATE_PARAMS
+
+ int fd_retval = -1;
+
+ cmd_gvar = g_variant_new (FMT_CMD, NEW, g_variant_new_string (path));
+ cmd_str = g_strdup_printf ("%s\n", g_variant_print (cmd_gvar, TRUE));
+
+ SEND_CMD_TEMPLATE_BOILERPLATE
+
+ g_variant_get (ret_params_gvar, RET_FMT_NEW_OPEN,
+ &fd_retval, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: NEW - fd: %d - was_err: %d - err_num: %d - err_msg: %s\n",
+ fd_retval, was_err, err_num, err_msg);
+
+ SEND_CMD_TEMPLATE_HANDLE_ERROR
+
+out:
+ SEND_CMD_TEMPLATE_BOILERPLATE_CLEANUP
+
+ return fd_retval;
+}
+
+/* </ Commands to send to child process > */
+
+#if 0
+static void
+stdout_read_line_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT(user_data);
+ GDataInputStream *stdout_stream = G_DATA_INPUT_STREAM(source_object);
+ char *line;
+ GVariant *ret_gvar = NULL;
+ GVariant *params = NULL;
+ enum Command cmd;
+
+ line = g_data_input_stream_read_line_finish (stdout_stream, res, NULL, NULL);
+
+ ret_gvar = g_variant_parse (NULL, line, NULL, NULL, NULL);
+
+ if (! ret_gvar)
+ {
+ g_warning ("Failed to parse retval.");
+ goto out;
+ }
+
+ g_variant_get (ret_gvar, FMT_CMD, &cmd, ¶ms);
+ if (! params)
+ {
+ g_warning ("No parameters provided or failed to parse parameters.");
+ goto out;
+ }
+
+ switch (cmd)
+ {
+ case NEW:
+ {
+ int fd = -1;
+ int err_num = 0;
+ char *err_msg = NULL;
+ gboolean was_err = FALSE;
+
+ g_variant_get (params, RET_FMT_NEW_OPEN,
+ &fd, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: NEW - fd: %d - was_err: %d - err_num: %d - err_msg: %s\n",
+ fd, was_err, err_num, err_msg);
+
+ if (was_err)
+ {
+ /* report error */
+ }
+ else
+ {
+ /* do stuff */
+ }
+
+ }
+ break;
+
+ case OPEN:
+ {
+ int fd = -1;
+ int err_num = 0;
+ char *err_msg = NULL;
+ gboolean was_err = FALSE;
+
+ g_variant_get (params, RET_FMT_NEW_OPEN,
+ &fd, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: OPEN - fd: %d - was_err: %d - err_num: %d - err_msg: %s\n",
+ fd, was_err, err_num, err_msg);
+
+ if (was_err)
+ {
+ /* report error */
+ }
+ else
+ {
+ /* do stuff */
+ }
+ }
+ break;
+
+ case CLOSE:
+ {
+ gboolean op_ret = FALSE;
+ int err_num = 0;
+ char *err_msg = NULL;
+ gboolean was_err = FALSE;
+
+ g_variant_get (params, RET_FMT_CLOSE,
+ &op_ret, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: CLOSE - retval: %d - was_err: %d - err_num: %d - err_msg: %s\n",
+ op_ret, was_err, err_num, err_msg);
+
+ if (! op_ret || was_err)
+ {
+ /* report error */
+ }
+ else
+ {
+ /* do stuff */
+ }
+
+ }
+ break;
+
+ case READ:
+ {
+ gboolean op_ret = FALSE;
+ char b;
+ gint64 off;
+ gboolean was_err = FALSE;
+ int err_num = 0;
+ char *err_msg = NULL;
+
+ g_variant_get (params, RET_FMT_READ,
+ &op_ret, &op_ret, &b, &op_ret, &off, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: READ - retval: %d - byte: %c - offset: %ld - was_err: %d -
err_num: %d - err_msg: %s\n",
+ op_ret, b, off, was_err, err_num, err_msg);
+
+ if (was_err)
+ {
+ /* report error */
+ }
+ else
+ {
+ /* do stuff */
+ }
+ }
+ break;
+
+ case WRITE:
+ {
+ gboolean op_ret = FALSE;
+ gboolean was_err = FALSE;
+ int err_num = 0;
+ char *err_msg = NULL;
+
+ g_variant_get (params, RET_FMT_WRITE, &op_ret, &was_err, &err_num, &err_msg);
+
+ g_debug ("operation: WRITE - retval: %d - was_err: %d - err_num: %d - err_msg: %s\n",
+ op_ret, was_err, err_num, err_msg);
+
+ if (was_err)
+ {
+ /* report error */
+ }
+ else
+ {
+ /* do stuff */
+ }
+ }
+ break;
+
+ default:
+ g_warning ("Invalid retval. Ignoring.");
+ break;
+ }
+
+out:
+ g_variant_unref (ret_gvar);
+
+ g_data_input_stream_read_line_async (stdout_stream,
+ G_PRIORITY_DEFAULT,
+ NULL, /* cancellable */
+ stdout_read_line_cb,
+ self); /* data */
+}
+#endif
+
+#if 0
/* mostly a helper for _get_data and _set_data */
static char *
get_file_data (HexBufferDirect *self,
@@ -189,6 +727,7 @@ get_file_data (HexBufferDirect *self,
return data;
}
+#endif
static int
create_fd_from_path (HexBufferDirect *self, const char *path)
@@ -198,7 +737,7 @@ create_fd_from_path (HexBufferDirect *self, const char *path)
errno = 0;
- if (stat (path, &statbuf) != 0)
+ if (stat (path, &statbuf) != 0) /* new file */
{
if (errno != ENOENT) {
set_error (self,
@@ -206,16 +745,9 @@ create_fd_from_path (HexBufferDirect *self, const char *path)
return -1;
}
- errno = 0;
- fd = open(path, O_CREAT|O_TRUNC|O_RDWR,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-
- if (fd < 0) {
- set_error (self, _("Unable to create file"));
- return -1;
- }
+ fd = send_new_cmd (self, path);
}
- else
+ else /* open */
{
/* We only support regular files and block devices. */
if (! S_ISREG(statbuf.st_mode) && ! S_ISBLK(statbuf.st_mode))
@@ -224,28 +756,45 @@ create_fd_from_path (HexBufferDirect *self, const char *path)
return -1;
}
- fd = open (path, O_RDWR);
-
- if (fd < 0) {
- errno = 0;
- fd = open (path, O_RDONLY);
- if (fd < 0) {
- set_error (self, _("Unable to open file for reading"));
- return -1;
- }
- }
+ fd = send_open_cmd (self, path);
}
+
return fd;
}
+static void
+setup_subprocess (HexBufferDirect *self)
+{
+ g_clear_object (&self->sub);
+ g_clear_error (&self->error);
+
+ // TEST
+#define PACKAGE_LIBEXECDIR "/home/logan/git/ghex/src"
+ self->sub = g_subprocess_new (
+ G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+ G_SUBPROCESS_FLAGS_STDERR_PIPE | G_SUBPROCESS_FLAGS_INHERIT_FDS,
+ &self->error,
+ "pkexec",
+ PACKAGE_LIBEXECDIR "/gvar", // FIXME - name, path, etc.
+ NULL);
+
+ // FIXME - shouldn't gerror-out here.
+ if (! self->sub)
+ g_error ("%s: Initializing subprocess object failed!", __func__);
+}
+
/* CONSTRUCTORS AND DESTRUCTORS */
static void
hex_buffer_direct_init (HexBufferDirect *self)
{
+ GInputStream *stdout_pipe;
+
self->fd = -1;
self->changes = g_hash_table_new_full (g_int64_hash, g_int64_equal,
g_free, g_free);
+
+ setup_subprocess (self);
}
static void
@@ -253,6 +802,8 @@ hex_buffer_direct_dispose (GObject *gobject)
{
HexBufferDirect *self = HEX_BUFFER_DIRECT(gobject);
+ g_clear_object (&self->sub);
+
/* chain up */
G_OBJECT_CLASS(hex_buffer_direct_parent_class)->dispose (gobject);
}
@@ -264,7 +815,7 @@ hex_buffer_direct_finalize (GObject *gobject)
if (self->fd >= 0)
{
- close (self->fd);
+ send_close_cmd (self);
}
/* chain up */
@@ -305,8 +856,7 @@ hex_buffer_direct_get_data (HexBuffer *buf,
g_return_val_if_fail (self->fd != -1, NULL);
- data = get_file_data (self, offset, len);
-
+ data = send_read_cmd (self, offset, offset + len-1);
if (! data)
{
return NULL;
@@ -333,14 +883,18 @@ hex_buffer_direct_get_byte (HexBuffer *buf,
gint64 offset)
{
HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
- char *cp = NULL;
+ char *data;
+ char b = 0;
- cp = hex_buffer_direct_get_data (buf, offset, 1);
+ data = send_read_cmd (self, offset, offset);
- if (cp)
- return cp[0];
- else
- return 0;
+ if (data)
+ {
+ b = data[0];
+ g_free (data);
+ }
+
+ return b;
}
/* transfer: none */
@@ -390,12 +944,12 @@ hex_buffer_direct_read (HexBuffer *buf)
return FALSE;
}
- tmp_fd = create_fd_from_path (self, file_path);
- if (tmp_fd < 0)
- {
- set_error (self, _("Unable to read file"));
- return FALSE;
- }
+// tmp_fd = create_fd_from_path (self, file_path);
+// if (tmp_fd < 0)
+// {
+// set_error (self, _("Unable to read file"));
+// return FALSE;
+// }
/* will only return > 0 for a regular file. */
bytes = hex_buffer_util_get_file_size (self->file);
@@ -404,11 +958,12 @@ hex_buffer_direct_read (HexBuffer *buf)
{
gint64 block_file_size;
- if (ioctl (tmp_fd, BLKGETSIZE64, &block_file_size) != 0)
- {
- set_error (self, _("Error attempting to read block device"));
- return FALSE;
- }
+// if (ioctl (tmp_fd, BLKGETSIZE64, &block_file_size) != 0)
+// {
+// set_error (self, _("Error attempting to read block device"));
+// return FALSE;
+// }
+ g_debug ("DOING DUMB TEST NOW"); block_file_size = 100;
bytes = block_file_size;
}
@@ -498,13 +1053,15 @@ hex_buffer_direct_set_data (HexBuffer *buf,
g_debug ("key already existed; replaced");
- tmp = get_file_data (self, offset, 1);
+ // TEST
+ tmp = send_read_cmd (self, offset, offset);
if (*tmp == *cp)
{
g_debug ("key value back to what O.G. file was. Removing hash entry.");
g_hash_table_remove (self->changes, ip);
}
+
g_free (tmp);
}
}
@@ -531,24 +1088,18 @@ hex_buffer_direct_write_to_file (HexBuffer *buf,
*/
for (guint i = 0; i < len; ++i)
{
- ssize_t nwritten;
+ gboolean retval;
char *cp = g_hash_table_lookup (self->changes, keys[i]);
- off_t offset, new_offset;
+ off_t offset = *keys[i];
- offset = *keys[i];
- new_offset = lseek (self->fd, offset, SEEK_SET);
- g_assert (offset == new_offset);
- g_debug ("%u: offset %ld: switch with: %c", i, offset, *cp);
+ retval = send_write_cmd (self, offset, *cp);
- errno = 0;
- nwritten = write (self->fd, cp, 1);
- if (nwritten != 1)
- {
- set_error (self, _("Error writing changes to file"));
+ if (! retval)
return FALSE;
- }
}
+
g_hash_table_remove_all (self->changes);
+
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]