+ para_printf(&aca->pbout, "cannot add %s\n", name);
+ else
+ para_printf(&aca->pbout, "added %s as id %u\n", name, id);
+ return ret;
+}
+
+/* Write input from fd to dynamically allocated buffer, but maximal 10M. */
+static int fd2buf(struct stream_cipher_context *scc, struct osl_object *obj)
+{
+ size_t max_size = 10 * 1024 * 1024;
+ int ret;
+ struct iovec iov;
+
+ obj->data = NULL;
+ obj->size = 0;
+again:
+ do {
+ ret = recv_sb(scc, SBD_BLOB_DATA, max_size, &iov);
+ } while (ret == 0);
+
+ if (ret < 0) {
+ free(obj->data);
+ obj->data = NULL;
+ obj->size = 0;
+ return ret;
+ }
+ if (iov.iov_len == 0) /* end of blob */
+ return 1;
+ if (!obj->data) {
+ obj->data = iov.iov_base;
+ obj->size = iov.iov_len;
+ } else {
+ obj->data = para_realloc(obj->data, obj->size + iov.iov_len);
+ memcpy(obj->data + obj->size, iov.iov_base, iov.iov_len);
+ obj->size += iov.iov_len;
+ free(iov.iov_base);
+ max_size -= iov.iov_len;
+ }
+ goto again;
+ return 1;
+}
+
+/*
+ * Read blob from a file descriptor and send it to afs.
+ *
+ * This function is called from the addblob command handlers to instruct the
+ * afs process to store the input in a blob table. Input is read and decrypted
+ * from the file descriptor given by cc and appended to arg_obj, which contains
+ * the name of the blob to create. The combined buffer is made available to the
+ * afs process via the callback method.
+ */
+static int stdin_command(struct command_context *cc, struct osl_object *arg_obj,
+ afs_callback *f)
+{
+ struct osl_object query, stdin_obj;
+ int ret;
+
+ ret = send_sb(&cc->scc, NULL, 0, SBD_AWAITING_DATA, false);
+ if (ret < 0)
+ return ret;
+ ret = fd2buf(&cc->scc, &stdin_obj);
+ if (ret < 0)
+ return ret;
+ query.size = arg_obj->size + stdin_obj.size;
+ query.data = para_malloc(query.size);
+ memcpy(query.data, arg_obj->data, arg_obj->size);
+ if (stdin_obj.size > 0)
+ memcpy((char *)query.data + arg_obj->size, stdin_obj.data,
+ stdin_obj.size);
+ free(stdin_obj.data);
+ ret = send_callback_request(f, &query, afs_cb_result_handler, cc);
+ free(query.data);
+ return ret;