"guestfs_close";
"guestfs_get_error_handler";
"guestfs_get_out_of_memory_handler";
+ "guestfs_get_private";
"guestfs_last_error";
"guestfs_set_close_callback";
"guestfs_set_error_handler";
"guestfs_set_launch_done_callback";
"guestfs_set_log_message_callback";
"guestfs_set_out_of_memory_handler";
+ "guestfs_set_private";
"guestfs_set_progress_callback";
"guestfs_set_subprocess_quit_callback";
*/
struct inspect_fs *fses;
size_t nr_fses;
+
+ /* Private data area. */
+ struct hash_table *pda;
};
/* Per-filesystem data stored for inspect_os. */
#include <sys/select.h>
#include <dirent.h>
#include <signal.h>
+#include <assert.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "c-ctype.h"
#include "glthread/lock.h"
+#include "hash.h"
+#include "hash-pjw.h"
#include "ignore-value.h"
#include "guestfs.h"
}
gl_lock_unlock (handles_lock);
+ if (g->pda)
+ hash_free (g->pda);
free (g->last_error);
free (g->path);
free (g->qemu);
g->progress_cb = cb;
g->progress_cb_data = opaque;
}
+
+/* Note the private data area is allocated lazily, since the vast
+ * majority of callers will never use it. This means g->pda is
+ * likely to be NULL.
+ */
+struct pda_entry {
+ char *key; /* key */
+ void *data; /* opaque user data pointer */
+};
+
+static size_t
+hasher (void const *x, size_t table_size)
+{
+ struct pda_entry const *p = x;
+ return hash_pjw (p->key, table_size);
+}
+
+static bool
+comparator (void const *x, void const *y)
+{
+ struct pda_entry const *a = x;
+ struct pda_entry const *b = y;
+ return STREQ (a->key, b->key);
+}
+
+static void
+freer (void *x)
+{
+ if (x) {
+ struct pda_entry *p = x;
+ free (p->key);
+ free (p);
+ }
+}
+
+void
+guestfs_set_private (guestfs_h *g, const char *key, void *data)
+{
+ if (g->pda == NULL) {
+ g->pda = hash_initialize (16, NULL, hasher, comparator, freer);
+ if (g->pda == NULL)
+ g->abort_cb ();
+ }
+
+ struct pda_entry *new_entry = safe_malloc (g, sizeof *new_entry);
+ new_entry->key = safe_strdup (g, key);
+ new_entry->data = data;
+
+ struct pda_entry *old_entry = hash_delete (g->pda, new_entry);
+ freer (old_entry);
+
+ struct pda_entry *entry = hash_insert (g->pda, new_entry);
+ if (entry == NULL)
+ g->abort_cb ();
+ assert (entry == new_entry);
+}
+
+static inline char *
+bad_cast (char const *s)
+{
+ return (char *) s;
+}
+
+void *
+guestfs_get_private (guestfs_h *g, const char *key)
+{
+ if (g->pda == NULL)
+ return NULL; /* no keys have been set */
+
+ const struct pda_entry k = { .key = bad_cast (key) };
+ struct pda_entry *entry = hash_lookup (g->pda, &k);
+ if (entry)
+ return entry->data;
+ else
+ return NULL;
+}
extern void guestfs_set_close_callback (guestfs_h *g, guestfs_close_cb cb, void *opaque);
extern void guestfs_set_progress_callback (guestfs_h *g, guestfs_progress_cb cb, void *opaque);
+/*--- Private data area ---*/
+extern void guestfs_set_private (guestfs_h *g, const char *key, void *data);
+extern void *guestfs_get_private (guestfs_h *g, const char *key);
+
/*--- Structures and actions ---*/
#include <rpc/types.h>
#include <rpc/xdr.h>
the callback can normally ignore them. The callback may want to
print these numbers in error messages or debugging messages.
+=head1 PRIVATE DATA AREA
+
+You can attach named pieces of private data to the libguestfs handle,
+and fetch them by name for the lifetime of the handle. This is called
+the private data area and is only available from the C API.
+
+To attach a named piece of data, use the following call:
+
+ void guestfs_set_private (guestfs_h *g, const char *key, void *data);
+
+C<key> is the name to associate with this data, and C<data> is an
+arbitrary pointer (which can be C<NULL>). Any previous item with the
+same name is overwritten.
+
+You can use any C<key> you want, but names beginning with an
+underscore character are reserved for internal libguestfs purposes
+(for implementing language bindings). It is recommended to prefix the
+name with some unique string to avoid collisions with other users.
+
+To retrieve the pointer, use:
+
+ void *guestfs_get_private (guestfs_h *g, const char *key);
+
+This function returns C<NULL> if either no data is found associated
+with C<key>, or if the user previously set the C<key>'s C<data>
+pointer to C<NULL>.
+
+Libguestfs does not try to look at or interpret the C<data> pointer in
+any way. As far as libguestfs is concerned, it need not be a valid
+pointer at all. In particular, libguestfs does I<not> try to free the
+data when the handle is closed. If the data must be freed, then the
+caller must either free it before calling L</guestfs_close> or must
+set up a close callback to do it (see L</guestfs_set_close_callback>,
+and note that only one callback can be registered for a handle).
+
+The private data area is implemented using a hash table, and should be
+reasonably efficient for moderate numbers of keys.
+
=head1 BLOCK DEVICE NAMING
In the kernel there is now quite a profusion of schemata for naming