[ghex/support-block-devices-part-deux: 1/4] hex-buffer-direct: Initial commit
- From: Logan Rathbone <larathbone src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ghex/support-block-devices-part-deux: 1/4] hex-buffer-direct: Initial commit
- Date: Sun, 12 Jun 2022 01:51:59 +0000 (UTC)
commit 09fc950e4a1f121ed83a27cf210d458f6a6ce420
Author: Logan Rathbone <poprocks gmail com>
Date: Tue Jun 7 13:54:46 2022 -0400
hex-buffer-direct: Initial commit
Written primarily to support reading/writing block devices.
At this stage, there is no special mechanism for privilege escalation.
That is, a normal user will likely need to be added to appropriate
groups.
meson.build | 25 +-
meson_options.txt | 3 +-
src/hex-buffer-direct.c | 646 ++++++++++++++++++++++++++++++++++++++++++++++++
src/hex-buffer-direct.h | 47 ++++
src/hex-document.c | 2 +
src/meson.build | 10 +
6 files changed, 730 insertions(+), 3 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
new file mode 100644
index 0000000..23a4ccc
--- /dev/null
+++ b/src/hex-buffer-direct.c
@@ -0,0 +1,646 @@
+/* vim: ts=4 sw=4 colorcolumn=80
+ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- *
+ */
+/* hex-document-direct.c - `direct` implementation of the HexBuffer iface.
+ *
+ * Copyright © 2022 Logan Rathbone
+ *
+ * GHex is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GHex is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GHex; see the file COPYING.
+ * If not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "hex-buffer-direct.h"
+
+#define HEX_BUFFER_DIRECT_ERROR hex_buffer_direct_error_quark ()
+GQuark
+hex_buffer_direct_error_quark (void)
+{
+ return g_quark_from_static_string ("hex-buffer-direct-error-quark");
+}
+
+/* PROPERTIES */
+
+enum
+{
+ PROP_FILE = 1,
+ N_PROPERTIES
+};
+static GParamSpec *properties[N_PROPERTIES];
+
+static char *invalid_path_msg = N_("The file appears to have an invalid path.");
+
+/**
+ * HexBufferDirect:
+ *
+ * #HexBufferDirect is an object implementing the [iface@Hex.Buffer] interface,
+ * allowing it to be used as a #HexBuffer backend to be used with
+ * [class@Hex.Document].
+ *
+ * #HexBufferDirect allows for direct reading/writing of files, and is
+ * primarily intended to be used with block devices.
+ *
+ * #HexBufferDirect depends upon UNIX/POSIX system calls; as such, it will
+ * be unlikely to be available under WIN32.
+ */
+struct _HexBufferDirect
+{
+ GObject parent_instance;
+
+ GFile *file;
+ GError *error; /* no custom codes; use codes from errno */
+ int last_errno; /* cache in case we need to re-report errno error. */
+
+ int fd; /* file descriptor for direct read/write */
+ 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);
+
+G_DEFINE_TYPE_WITH_CODE (HexBufferDirect, hex_buffer_direct, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (HEX_TYPE_BUFFER, hex_buffer_direct_iface_init))
+
+/* FORWARD DECLARATIONS */
+
+static gboolean hex_buffer_direct_set_file (HexBuffer *buf, GFile *file);
+static GFile * hex_buffer_direct_get_file (HexBuffer *buf);
+
+/* PROPERTIES - GETTERS AND SETTERS */
+
+static void
+hex_buffer_direct_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT(object);
+ HexBuffer *buf = HEX_BUFFER(object);
+
+ switch (property_id)
+ {
+ case PROP_FILE:
+ hex_buffer_direct_set_file (buf, g_value_get_object (value));
+ break;
+
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+hex_buffer_direct_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT(object);
+ HexBuffer *buf = HEX_BUFFER(object);
+
+ switch (property_id)
+ {
+ case PROP_FILE:
+ g_value_set_object (value, self->file);
+ break;
+
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+/* PRIVATE FUNCTIONS AND HELPERS */
+
+/* Helper wrapper for g_set_error and to cache errno */
+static void
+set_error (HexBufferDirect *self, const char *blurb)
+{
+ char *message = NULL;
+
+ if (errno) {
+ /* Translators: the first '%s' is the blurb indicating some kind of an
+ * error has occurred (eg, 'An error has occurred', and the the 2nd '%s'
+ * is the standard error message that will be reported from the system
+ * (eg, 'No such file or directory').
+ */
+ message = g_strdup_printf (_("%s: %s"), blurb, g_strerror (errno));
+ }
+ else
+ {
+ message = g_strdup (blurb);
+ }
+ g_debug ("%s: %s", __func__, message);
+
+ g_clear_error (&self->error);
+
+ g_set_error (&self->error,
+ HEX_BUFFER_DIRECT_ERROR,
+ errno,
+ "%s",
+ message);
+
+ if (errno)
+ self->last_errno = errno;
+
+ 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)
+{
+ int fd = -1;
+ struct stat statbuf;
+
+ errno = 0;
+
+ if (stat (path, &statbuf) != 0)
+ {
+ if (errno != ENOENT) {
+ set_error (self,
+ _("Unable to retrieve file or directory information"));
+ 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;
+ }
+ }
+ else
+ {
+ /* We only support regular files and block devices. */
+ if (! S_ISREG(statbuf.st_mode) && ! S_ISBLK(statbuf.st_mode))
+ {
+ set_error (self, _("Not a regular file or block device"));
+ 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;
+ }
+ }
+ }
+ return fd;
+}
+
+/* CONSTRUCTORS AND DESTRUCTORS */
+
+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
+hex_buffer_direct_dispose (GObject *gobject)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT(gobject);
+
+ /* chain up */
+ G_OBJECT_CLASS(hex_buffer_direct_parent_class)->dispose (gobject);
+}
+
+static void
+hex_buffer_direct_finalize (GObject *gobject)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT(gobject);
+
+ if (self->fd >= 0)
+ {
+ close (self->fd);
+ }
+
+ /* chain up */
+ G_OBJECT_CLASS(hex_buffer_direct_parent_class)->finalize (gobject);
+}
+
+static void
+hex_buffer_direct_class_init (HexBufferDirectClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->finalize = hex_buffer_direct_finalize;
+ gobject_class->dispose = hex_buffer_direct_dispose;
+
+ gobject_class->set_property = hex_buffer_direct_set_property;
+ gobject_class->get_property = hex_buffer_direct_get_property;
+
+ g_object_class_override_property (gobject_class, PROP_FILE, "file");
+}
+
+/* INTERFACE - VFUNC IMPLEMENTATIONS */
+
+static gint64
+hex_buffer_direct_get_payload_size (HexBuffer *buf)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+
+ return self->payload;
+}
+
+static char *
+hex_buffer_direct_get_data (HexBuffer *buf,
+ gint64 offset,
+ size_t len)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+ char *data;
+
+ g_return_val_if_fail (self->fd != -1, NULL);
+
+ data = get_file_data (self, offset, len);
+
+ if (! data)
+ {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < len; ++i)
+ {
+ 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;
+}
+
+static char
+hex_buffer_direct_get_byte (HexBuffer *buf,
+ gint64 offset)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+ char *cp = NULL;
+
+ cp = hex_buffer_direct_get_data (buf, offset, 1);
+
+ if (cp)
+ return cp[0];
+ else
+ return 0;
+}
+
+/* transfer: none */
+static GFile *
+hex_buffer_direct_get_file (HexBuffer *buf)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+
+ return self->file;
+}
+
+
+static gboolean
+hex_buffer_direct_set_file (HexBuffer *buf, GFile *file)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+ const char *file_path;
+
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+ file_path = g_file_peek_path (file);
+ if (! file_path)
+ {
+ set_error (self, _(invalid_path_msg));
+ return FALSE;
+ }
+
+ self->file = file;
+ g_object_notify (G_OBJECT(self), "file");
+ return TRUE;
+}
+
+static gboolean
+hex_buffer_direct_read (HexBuffer *buf)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+ gint64 bytes = 0;
+ int tmp_fd;
+
+ g_return_val_if_fail (G_IS_FILE (self->file), FALSE);
+
+ const char *file_path = g_file_peek_path (self->file);
+
+ if (! file_path)
+ {
+ set_error (self, _(invalid_path_msg));
+ 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);
+
+ 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;
+}
+
+static gboolean
+hex_buffer_direct_read_finish (HexBuffer *buf,
+ GAsyncResult *result,
+ GError **error)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+
+ g_return_val_if_fail (g_task_is_valid (result, G_OBJECT(self)), FALSE);
+
+ return g_task_propagate_boolean (G_TASK(result), error);
+}
+
+static void
+hex_buffer_direct_read_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (source_object);
+ gboolean success;
+
+ success = hex_buffer_direct_read (HEX_BUFFER(self));
+ if (success)
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, self->error);
+}
+
+static void
+hex_buffer_direct_read_async (HexBuffer *buf,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+ GTask *task;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_run_in_thread (task, hex_buffer_direct_read_thread);
+ g_object_unref (task); /* _run_in_thread takes a ref */
+}
+
+static gboolean
+hex_buffer_direct_set_data (HexBuffer *buf,
+ gint64 offset,
+ size_t len,
+ size_t rep_len,
+ char *data)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+
+ 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);
+
+ // 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;
+}
+
+static gboolean
+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);
+
+ 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);
+
+ 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
+hex_buffer_direct_write_to_file_finish (HexBuffer *buf,
+ GAsyncResult *result,
+ GError **error)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+
+ g_return_val_if_fail (g_task_is_valid (result, G_OBJECT(self)), FALSE);
+
+ return g_task_propagate_boolean (G_TASK(result), error);
+}
+
+static void
+hex_buffer_direct_write_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (source_object);
+ GFile *file = G_FILE (task_data);
+ gboolean success;
+
+ success = hex_buffer_direct_write_to_file (HEX_BUFFER(self), file);
+ if (success)
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, self->error);
+}
+
+static void
+hex_buffer_direct_write_to_file_async (HexBuffer *buf,
+ GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ HexBufferDirect *self = HEX_BUFFER_DIRECT (buf);
+ GTask *task;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_task_data (task, file, NULL);
+ g_task_run_in_thread (task, hex_buffer_direct_write_thread);
+ g_object_unref (task); /* _run_in_thread takes a ref */
+}
+
+/* PUBLIC FUNCTIONS */
+
+/**
+ * hex_buffer_direct_new:
+ * @file: a #GFile pointing to a valid file on the system
+ *
+ * Create a new #HexBufferDirect object.
+ *
+ * Returns: a new #HexBufferDirect object, automatically cast to a #HexBuffer
+ * type, or %NULL if the operation failed.
+ */
+HexBuffer *
+hex_buffer_direct_new (GFile *file)
+{
+ HexBufferDirect *self = g_object_new (HEX_TYPE_BUFFER_DIRECT, NULL);
+
+ if (file)
+ {
+ /* If a path is provided but it can't be set, nullify the object */
+ if (! hex_buffer_direct_set_file (HEX_BUFFER(self), file))
+ g_clear_object (&self);
+ }
+
+ if (self)
+ return HEX_BUFFER(self);
+ else
+ return NULL;
+}
+
+/* INTERFACE IMPLEMENTATION FUNCTIONS */
+
+static void
+hex_buffer_direct_iface_init (HexBufferInterface *iface)
+{
+ iface->get_data = hex_buffer_direct_get_data;
+ iface->get_byte = hex_buffer_direct_get_byte;
+ iface->set_data = hex_buffer_direct_set_data;
+ iface->get_file = hex_buffer_direct_get_file;
+ iface->set_file = hex_buffer_direct_set_file;
+ iface->read = hex_buffer_direct_read;
+ iface->read_async = hex_buffer_direct_read_async;
+ iface->read_finish = hex_buffer_direct_read_finish;
+ iface->write_to_file = hex_buffer_direct_write_to_file;
+ iface->write_to_file_async = hex_buffer_direct_write_to_file_async;
+ iface->write_to_file_finish = hex_buffer_direct_write_to_file_finish;
+ iface->get_payload_size = hex_buffer_direct_get_payload_size;
+}
diff --git a/src/hex-buffer-direct.h b/src/hex-buffer-direct.h
new file mode 100644
index 0000000..e59e876
--- /dev/null
+++ b/src/hex-buffer-direct.h
@@ -0,0 +1,47 @@
+/* vim: ts=4 sw=4 colorcolumn=80
+ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- *
+ */
+/* hex-document-direct.h - `direct` implementation of the HexBuffer iface.
+ *
+ * Copyright © 2022 Logan Rathbone
+ *
+ * GHex is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * GHex is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GHex; see the file COPYING.
+ * If not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef HEX_DOCUMENT_DIRECT_H
+#define HEX_DOCUMENT_DIRECT_H
+
+#include <hex-buffer-iface.h>
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+
+G_BEGIN_DECLS
+
+#define HEX_TYPE_BUFFER_DIRECT hex_buffer_direct_get_type ()
+G_DECLARE_FINAL_TYPE (HexBufferDirect, hex_buffer_direct, HEX, BUFFER_DIRECT, GObject)
+
+/* HexBufferNewFunc declaration */
+HexBuffer *hex_buffer_direct_new (GFile *file);
+
+G_END_DECLS
+#endif
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]