[ghex/support-block-devices-part-trois: 2/5] blockdev: Get basic read/write working. Lots of FIXMEs




commit 0aea094a974a72216ea8662bd57f0f09854a4c26
Author: Logan Rathbone <poprocks gmail com>
Date:   Tue Jun 7 22:16:49 2022 -0400

    blockdev: Get basic read/write working. Lots of FIXMEs
    
    TODOs -- better error handling; sanity checks; privilege escalation

 meson.build             |  25 +++++++-
 meson_options.txt       |   3 +-
 src/hex-buffer-direct.c | 159 +++++++++++++++++++++++++++++++++++++++++-------
 src/hex-buffer-direct.h |   2 +
 src/hex-document.c      |   2 +
 src/meson.build         |  10 +++
 6 files changed, 175 insertions(+), 26 deletions(-)
---
diff --git a/meson.build b/meson.build
index ed846da..8fc22ea 100644
--- a/meson.build
+++ b/meson.build
@@ -17,6 +17,7 @@ endif
 
 # Backend plugins: (nb: only mmap exists at this time along with malloc, which is baked in)
 mmap_backend = get_option('mmap-buffer-backend')
+direct_backend = get_option('direct-buffer-backend')
 
 gir = find_program('g-ir-scanner', required : get_option('introspection'))
 generate_gir = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled())
@@ -90,8 +91,10 @@ config_h.set('LOCALEDIR', 'PACKAGE_LOCALE_DIR')
 config_h.set('CONFIG_H_SHADED_BOX_MAX', shaded_box_max)
 
 # nb: this config.h flag will likely be removed in a future release
-if mmap_backend
-  config_h.set('BACKEND_MMAP', true)
+#if mmap_backend
+#  config_h.set('BACKEND_MMAP', true)
+if direct_backend
+  config_h.set('BACKEND_DIRECT', true)
 endif
 
 config_h.set_quoted('LIBGTKHEX_RELEASE_STRING', 'gtkhex-@0@.0'.format(libgtkhex_api_version))
@@ -130,6 +133,23 @@ if mmap_backend
   message('...DONE')
 endif
 
+# direct buffer backend: Check for required headers
+if direct_backend
+  message('Checking dependencies for `direct` buffer backend...')
+
+  check_headers_direct = [
+    'unistd.h',
+    'fcntl.h',
+    'sys/ioctl.h',
+    'linux/fs.h',
+    ]
+  foreach h : check_headers_direct
+    cc.has_header(h, required: true)
+  endforeach
+
+  message('...DONE')
+endif
+
 glib_ver = '>= 2.68.0'
 gmodule_dep = dependency('gmodule-2.0')
 glib_dep = dependency('glib-2.0', version: glib_ver)
@@ -165,6 +185,7 @@ summary({'prefix': ghex_prefix,
 
 summary({'Development build': get_option('development'),
          '`mmap` buffer backend': mmap_backend,
+         '`direct` buffer backend': direct_backend,
          'Static HTML help': get_option('static-html-help'),
          'API Documentation': build_gtk_doc,
         }, section: 'Configuration')
diff --git a/meson_options.txt b/meson_options.txt
index a5795fc..e7276c6 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -3,7 +3,8 @@
 option('docdir', type: 'string', value: 'share/doc', description: 'docdir (defaults to: share/doc)')
 
 option('development', type: 'boolean', value: false, description: 'If this is a development build')
-option('mmap-buffer-backend', type : 'boolean', value: true, description: 'Build mmap buffer backend')
+option('mmap-buffer-backend', type : 'boolean', value: true, description: 'Build `mmap` buffer backend')
+option('direct-buffer-backend', type : 'boolean', value: true, description: 'Build `direct` buffer backend')
 option('introspection', type: 'feature', value: 'auto', description: 'Generate gir data (requires 
gobject-introspection)')
 option('gtk_doc', type: 'boolean', value: false, description: 'Build reference manual (requires gtk-doc)')
 option('static-html-help', type: 'boolean', value: false, description: 'Install static HTML help files (for 
systems without Yelp)')
diff --git a/src/hex-buffer-direct.c b/src/hex-buffer-direct.c
index d2fa910..23a4ccc 100644
--- a/src/hex-buffer-direct.c
+++ b/src/hex-buffer-direct.c
@@ -66,6 +66,7 @@ struct _HexBufferDirect
        gint64 payload;         /* size of the payload */
 
        gint64 clean_bytes;     /* 'clean' size of the file (no additions or deletions */
+       GHashTable *changes;
 };
 
 static void hex_buffer_direct_iface_init (HexBufferInterface *iface);
@@ -146,6 +147,8 @@ set_error (HexBufferDirect *self, const char *blurb)
        }
        g_debug ("%s: %s", __func__, message);
 
+       g_clear_error (&self->error);
+
        g_set_error (&self->error,
                        HEX_BUFFER_DIRECT_ERROR,
                        errno,
@@ -158,6 +161,35 @@ set_error (HexBufferDirect *self, const char *blurb)
        g_free (message);
 }
 
+/* mostly a helper for _get_data and _set_data */
+static char *
+get_file_data (HexBufferDirect *self,
+               gint64 offset,
+               size_t len)
+{
+       char *data = NULL;
+       off_t new_offset;
+       ssize_t nread;
+
+       data = g_malloc (len);
+       new_offset = lseek (self->fd, offset, SEEK_SET);
+
+       g_assert (offset == new_offset);
+
+       errno = 0;
+       nread = read (self->fd, data, len);
+
+       /* FIXME/TODO - test that if nread is less than amount requested, that it
+        * marries up with amount left in payload */
+       if (nread == -1)
+       {
+               set_error (self, _("Failed to read data from file."));
+               g_clear_pointer (&data, g_free);
+       }
+
+       return data;
+}
+
 static int
 create_fd_from_path (HexBufferDirect *self, const char *path)
 {
@@ -212,6 +244,8 @@ static void
 hex_buffer_direct_init (HexBufferDirect *self)
 {
        self->fd = -1;
+       self->changes = g_hash_table_new_full (g_int64_hash, g_int64_equal,
+                       g_free, g_free);
 }
 
 static void
@@ -267,26 +301,28 @@ hex_buffer_direct_get_data (HexBuffer *buf,
                size_t len)
 {
        HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
-       char *data = NULL;
-       off_t new_offset;
-       ssize_t nread;
+       char *data;
 
        g_return_val_if_fail (self->fd != -1, NULL);
 
-       data = g_malloc (len);
-       new_offset = lseek (self->fd, offset, SEEK_SET);
-
-       g_assert (offset == new_offset);
+       data = get_file_data (self, offset, len);
 
-       errno = 0;
-       nread = read (self->fd, data, len);
+       if (! data)
+       {
+               return NULL;
+       }
 
-       /* FIXME/TODO - test that if nread is less than amount requested, that it
-        * marries up with amount left in payload */
-       if (nread == -1)
+       for (size_t i = 0; i < len; ++i)
        {
-               set_error (self, _("Failed to read data from file."));
-               g_clear_pointer (&data, g_free);
+               char *cp;
+               gint64 loc = offset + i;
+
+               cp = g_hash_table_lookup (self->changes, &loc);
+               if (cp)
+               {
+                       g_debug ("found change - swapping byte at: %ld", loc);
+                       data[i] = *cp;
+               }
        }
 
        return data;
@@ -354,10 +390,6 @@ hex_buffer_direct_read (HexBuffer *buf)
                return FALSE;
        }
 
-       bytes = hex_buffer_util_get_file_size (self->file);
-
-       self->payload = self->clean_bytes = bytes;
-
        tmp_fd = create_fd_from_path (self, file_path);
        if (tmp_fd < 0)
        {
@@ -365,6 +397,25 @@ hex_buffer_direct_read (HexBuffer *buf)
                return FALSE;
        }
 
+       /* will only return > 0 for a regular file. */
+       bytes = hex_buffer_util_get_file_size (self->file);
+
+       if (! bytes)    /* block device */
+       {
+               gint64 block_file_size;
+
+               if (ioctl (tmp_fd, BLKGETSIZE64, &block_file_size) != 0)
+               {
+                       set_error (self, _("Error attempting to read block device"));
+                       return FALSE;
+               }
+               bytes = block_file_size;
+       }
+
+       self->payload = self->clean_bytes = bytes;
+
+       self->fd = tmp_fd;
+
        return TRUE;
 }
 
@@ -419,11 +470,46 @@ hex_buffer_direct_set_data (HexBuffer *buf,
 {
        HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
 
-       g_warning ("%s: NOT IMPLEMENTED", __func__);
+       if (rep_len != len)
+       {
+               g_debug ("%s: rep_len != len; returning false", __func__);
+               return FALSE;
+       }
+
+       for (size_t i = 0; i < len; ++i)
+       {
+               gboolean retval;
+               gint64 *ip = g_new (gint64, 1);
+               char *cp = g_new (char, 1);
+
+               *ip = offset + i;
+               *cp = data[i];
+
+               retval = g_hash_table_replace (self->changes, ip, cp);
 
-       return FALSE;
+               // TEST
+               if (retval) /* key did not exist yet */
+               {
+                       g_debug ("key did not exist yet");
+               }
+               else
+               {
+                       char *tmp = NULL;
+
+                       g_debug ("key already existed; replaced");
+
+                       tmp = get_file_data (self, offset, 1);
+
+                       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);
+               }
+       }
 
-//     return TRUE;
+       return TRUE;
 }
 
 static gboolean
@@ -431,12 +517,39 @@ hex_buffer_direct_write_to_file (HexBuffer *buf,
                GFile *file)
 {
        HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+       guint len;
+       gint64 **keys;
 
+       g_return_val_if_fail (self->fd != -1, FALSE);
        g_return_val_if_fail (G_IS_FILE (file), FALSE);
 
-       g_warning ("%s: NOT IMPLEMENTED", __func__);
+       keys = (gint64 **)g_hash_table_get_keys_as_array (self->changes, &len);
+
+       /* FIXME - very inefficient - we should at least implement a sorter
+        * function that puts the changes in order, and merges changes that
+        * are adjacent to one another.
+        */
+       for (guint i = 0; i < len; ++i)
+       {
+               ssize_t nwritten;
+               char *cp = g_hash_table_lookup (self->changes, keys[i]);
+               off_t offset, new_offset;
+
+               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);
 
-       return FALSE;
+               errno = 0;
+               nwritten = write (self->fd, cp, 1);
+               if (nwritten != 1)
+               {
+                       set_error (self, _("Error writing changes to file"));
+                       return FALSE;
+               }
+       }
+       g_hash_table_remove_all (self->changes);
+       return TRUE;
 }
 
 static gboolean
diff --git a/src/hex-buffer-direct.h b/src/hex-buffer-direct.h
index e794f10..e59e876 100644
--- a/src/hex-buffer-direct.h
+++ b/src/hex-buffer-direct.h
@@ -32,6 +32,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
 
 G_BEGIN_DECLS
 
diff --git a/src/hex-document.c b/src/hex-document.c
index 83e1235..2d3afa1 100644
--- a/src/hex-document.c
+++ b/src/hex-document.c
@@ -358,6 +358,8 @@ hex_document_init (HexDocument *doc)
 {
 #ifdef BACKEND_MMAP
        doc->buffer = hex_buffer_util_new ("mmap", NULL);
+#elif defined BACKEND_DIRECT
+       doc->buffer = hex_buffer_util_new ("direct", NULL);
 #else
        doc->buffer = hex_buffer_util_new (NULL, NULL);
 #endif
diff --git a/src/meson.build b/src/meson.build
index 4091859..80a37b4 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -102,6 +102,16 @@ if mmap_backend
   )
 endif
 
+if direct_backend
+    shared_module('hex-buffer-direct',
+    sources: 'hex-buffer-direct.c',
+    c_args: libgtkhex_c_args,
+    dependencies: libgtkhex_dep,
+    install_dir: ghex_plugindir,
+    install: true,
+  )
+endif
+
 ghex_sources = [
   'chartable.c',
   'common-ui.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]