+ 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 lls_parse_result *lpr, afs_callback *f)
+{
+ struct osl_object query, stdin_obj;
+ int ret;
+ size_t len = strlen(lls_input(0, lpr));
+
+ 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 = len + 1 + stdin_obj.size;
+ query.data = para_malloc(query.size);
+ memcpy(query.data, lls_input(0, lpr), len + 1);
+ if (stdin_obj.size > 0)
+ memcpy((char *)query.data + len + 1, 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;
+}
+
+static int com_addblob(afs_callback *f, __a_unused const struct lls_command * const cmd,
+ struct command_context *cc, struct lls_parse_result *lpr)
+{
+ char *errctx;
+ int ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx));
+
+ if (ret < 0) {
+ send_errctx(cc, errctx);
+ return ret;
+ }
+ if (!lls_input(0, lpr)[0]) /* empty name is reserved for the dummy row */