+/* An alternate constructor for RAIT devices */
+%typemap(in) GSList *child_devices {
+ AV *av;
+ int i, len;
+
+ if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
+ SWIG_exception(SWIG_TypeError, "Expected an arrayref");
+ }
+ av = (AV *)SvRV($input);
+
+ $1 = NULL;
+ len = av_len(av);
+ for (i = 0; i <= len; i++) {
+ SV **elt = av_fetch(av, i, 0);
+ Device *d;
+
+ if (elt && !SvOK(*elt)) {
+ $1 = g_slist_append($1, NULL); /* 'undef' => NULL */
+ } else if (!elt || SWIG_ConvertPtr(*elt, (void **)&d, $descriptor(Device *), 0) == -1) {
+ SWIG_exception(SWIG_TypeError, "array member is not a Device");
+ } else {
+ $1 = g_slist_append($1, d);
+ }
+ }
+}
+%typemap(freearg) GSList *child_devices {
+ g_slist_free($1);
+}
+%newobject rait_device_open_from_children;
+Device *rait_device_open_from_children(GSList *child_devices);
+%perlcode %{
+sub new_rait_from_children {
+ my $class = shift; # strip the $class from the arguments
+ return rait_device_open_from_children([@_]);
+}
+%}
+
+/*
+ * Utilities for installchecks (not described in POD)
+ */
+
+%inline %{
+
+/* write LENGTH bytes of random data to FILENAME, seeded with SEED */
+gboolean
+write_random_to_device(guint32 seed, size_t length, Device *device) {
+ simpleprng_state_t prng;
+ char *buf;
+ gsize block_size = device->block_size;
+ g_assert(block_size < G_MAXUINT);
+
+ buf = g_malloc(block_size);
+ simpleprng_seed(&prng, seed);
+
+ while (length) {
+ size_t to_write = min(block_size, length);
+
+ simpleprng_fill_buffer(&prng, buf, to_write);
+ if (!device_write_block(device, (guint)block_size, buf)) {
+ g_free(buf);
+ return FALSE;
+ }
+ length -= to_write;
+ }
+
+ g_free(buf);
+ return TRUE;
+}
+
+/* read LENGTH bytes of random data from FILENAME verifying it against
+ * a PRNG seeded with SEED. Sends any error messages to stderr.
+ */
+gboolean
+verify_random_from_device(guint32 seed, size_t length, Device *device) {
+ simpleprng_state_t prng;
+ char *buf = NULL; /* first device_read_block will get the size */
+ int block_size = 0;
+
+ simpleprng_seed(&prng, seed);
+
+ while (length) {
+ int bytes_read;
+ int size = block_size;
+
+ bytes_read = device_read_block(device, buf, &size);
+ if (bytes_read == 0 && size > block_size) {
+ g_free(buf);
+ block_size = size;
+ buf = g_malloc(block_size);
+ continue;
+ }
+ if (bytes_read == -1) {
+ if (device->status == DEVICE_STATUS_SUCCESS) {
+ g_assert(device->is_eof);
+ g_debug("verify_random_from_device got unexpected EOF");
+ }
+ goto error;
+ }
+
+ /* strip padding */
+ bytes_read = min(bytes_read, length);
+
+ if (!simpleprng_verify_buffer(&prng, buf, bytes_read))
+ goto error;
+
+ length -= bytes_read;
+ }
+
+ g_free(buf);
+ return TRUE;
+
+error:
+ g_free(buf);
+ return FALSE;
+}
+%}
+