+ part->mapped = psz;
+ part->data = n;
+ }
+
+ part->munmap_this = true;
+ } else {
+ n = realloc(part->data, sz);
+ if (!n) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+
+ part->data = n;
+ part->free_this = true;
+ }
+
+ if (q)
+ *q = part->data ? (uint8_t*) part->data + part->size : NULL;
+
+ part->size = sz;
+ return 0;
+}
+
+static void message_extend_containers(sd_bus_message *m, size_t expand) {
+ struct bus_container *c;
+
+ assert(m);
+
+ if (expand <= 0)
+ return;
+
+ /* Update counters */
+ for (c = m->containers; c < m->containers + m->n_containers; c++)
+ if (c->array_size)
+ *c->array_size += expand;
+}
+
+static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz) {
+ struct bus_body_part *part = NULL;
+ size_t start_body, end_body, padding, start_part, end_part, added;
+ bool add_new_part;
+ void *p;
+ int r;
+
+ assert(m);
+ assert(align > 0);
+ assert(!m->sealed);
+
+ if (m->poisoned)
+ return NULL;
+
+ start_body = ALIGN_TO((size_t) m->header->body_size, align);
+ end_body = start_body + sz;
+
+ padding = start_body - m->header->body_size;
+ added = padding + sz;
+
+ /* Check for 32bit overflows */
+ if (end_body > (size_t) ((uint32_t) -1)) {
+ m->poisoned = true;
+ return NULL;
+ }
+
+ add_new_part =
+ m->n_body_parts <= 0 ||
+ m->body_end->sealed ||
+ padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
+
+ if (add_new_part) {
+ if (padding > 0) {
+ part = message_append_part(m);
+ if (!part)
+ return NULL;
+
+ part_zero(part, padding);
+ }
+
+ part = message_append_part(m);
+ if (!part)
+ return NULL;
+
+ r = part_make_space(m, part, sz, &p);
+ if (r < 0)
+ return NULL;
+ } else {
+ struct bus_container *c;
+ void *op;
+ size_t os;
+
+ part = m->body_end;
+ op = part->data;
+ os = part->size;
+
+ start_part = ALIGN_TO(part->size, align);
+ end_part = start_part + sz;
+
+ r = part_make_space(m, part, end_part, &p);
+ if (r < 0)
+ return NULL;
+
+ if (padding > 0) {
+ memset(p, 0, padding);
+ p = (uint8_t*) p + padding;
+ }
+
+ /* Readjust pointers */
+ for (c = m->containers; c < m->containers + m->n_containers; c++)
+ c->array_size = adjust_pointer(c->array_size, op, os, part->data);
+
+ m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
+ }
+
+ m->header->body_size = end_body;
+ message_extend_containers(m, added);
+
+ return p;
+}
+
+int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
+ struct bus_container *c;
+ ssize_t align, sz;
+ uint32_t k;
+ void *a;
+ int fd = -1;
+ uint32_t fdi = 0;
+ int r;
+
+ if (!m)
+ return -EINVAL;
+ if (!p)
+ return -EINVAL;
+ if (m->sealed)
+ return -EPERM;
+ if (!bus_type_is_basic(type))
+ return -EINVAL;
+ if (m->poisoned)
+ return -ESTALE;
+
+ c = message_get_container(m);
+
+ if (c->signature && c->signature[c->index]) {
+ /* Container signature is already set */
+
+ if (c->signature[c->index] != type)
+ return -ENXIO;
+ } else {
+ char *e;
+
+ /* Maybe we can append to the signature? But only if this is the top-level container*/
+ if (c->enclosing != 0)
+ return -ENXIO;
+
+ e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
+ if (!e) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+ }
+
+ switch (type) {
+
+ case SD_BUS_TYPE_STRING:
+ case SD_BUS_TYPE_OBJECT_PATH:
+
+ align = 4;
+ sz = 4 + strlen(p) + 1;
+ break;
+
+ case SD_BUS_TYPE_SIGNATURE:
+
+ align = 1;
+ sz = 1 + strlen(p) + 1;
+ break;
+
+ case SD_BUS_TYPE_BOOLEAN:
+ align = sz = 4;
+
+ assert_cc(sizeof(int) == sizeof(uint32_t));
+ memcpy(&k, p, 4);
+ k = !!k;
+ p = &k;
+ break;
+
+ case SD_BUS_TYPE_UNIX_FD: {
+ int z, *f;
+
+ if (!m->allow_fds) {
+ r = -ENOTSUP;
+ goto fail;
+ }
+
+ align = sz = 4;
+
+ z = *(int*) p;
+ if (z < 0) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ fd = fcntl(z, F_DUPFD_CLOEXEC, 3);
+ if (fd < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
+ if (!f) {
+ m->poisoned = true;
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ fdi = m->n_fds;
+ f[fdi] = fd;
+ m->fds = f;
+ m->free_fds = true;
+ break;
+ }
+
+ default:
+ align = bus_type_get_alignment(type);
+ sz = bus_type_get_size(type);
+ break;
+ }
+
+ assert(align > 0);
+ assert(sz > 0);
+
+ a = message_extend_body(m, align, sz);
+ if (!a) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
+ *(uint32_t*) a = sz - 5;
+ memcpy((uint8_t*) a + 4, p, sz - 4);
+
+ if (stored)
+ *stored = (const uint8_t*) a + 4;
+
+ } else if (type == SD_BUS_TYPE_SIGNATURE) {
+ *(uint8_t*) a = sz - 1;
+ memcpy((uint8_t*) a + 1, p, sz - 1);
+
+ if (stored)
+ *stored = (const uint8_t*) a + 1;
+ } else if (type == SD_BUS_TYPE_UNIX_FD) {
+ *(uint32_t*) a = fdi;
+
+ if (stored)
+ *stored = a;
+
+ m->n_fds ++;
+
+ } else {
+ memcpy(a, p, sz);
+
+ if (stored)
+ *stored = a;
+ }
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ c->index++;
+
+ return 0;
+
+fail:
+ if (fd >= 0)
+ close_nointr_nofail(fd);
+
+ return r;
+}
+
+int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
+ return message_append_basic(m, type, p, NULL);
+}
+
+int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s) {
+ struct bus_container *c;
+ void *a;
+
+ if (!m)
+ return -EINVAL;
+ if (!s)
+ return -EINVAL;
+ if (m->sealed)
+ return -EPERM;
+ if (m->poisoned)
+ return -ESTALE;
+
+ c = message_get_container(m);
+
+ if (c->signature && c->signature[c->index]) {
+ /* Container signature is already set */
+
+ if (c->signature[c->index] != SD_BUS_TYPE_STRING)
+ return -ENXIO;
+ } else {
+ char *e;
+
+ /* Maybe we can append to the signature? But only if this is the top-level container*/
+ if (c->enclosing != 0)
+ return -ENXIO;
+
+ e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
+ if (!e) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+ }
+
+ a = message_extend_body(m, 4, 4 + size + 1);
+ if (!a)
+ return -ENOMEM;
+
+ *(uint32_t*) a = size;
+ *s = (char*) a + 4;
+
+ (*s)[size] = 0;
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ c->index++;
+
+ return 0;
+}
+
+static int bus_message_open_array(
+ sd_bus_message *m,
+ struct bus_container *c,
+ const char *contents,
+ uint32_t **array_size) {
+
+ unsigned nindex;
+ void *a, *op;
+ int alignment;
+ size_t os;
+ struct bus_body_part *o;
+
+ assert(m);
+ assert(c);
+ assert(contents);
+ assert(array_size);
+
+ if (!signature_is_single(contents, true))
+ return -EINVAL;
+
+ alignment = bus_type_get_alignment(contents[0]);
+ if (alignment < 0)
+ return alignment;
+
+ if (c->signature && c->signature[c->index]) {
+
+ /* Verify the existing signature */
+
+ if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
+ return -ENXIO;
+
+ if (!startswith(c->signature + c->index + 1, contents))
+ return -ENXIO;
+
+ nindex = c->index + 1 + strlen(contents);
+ } else {
+ char *e;
+
+ if (c->enclosing != 0)
+ return -ENXIO;
+
+ /* Extend the existing signature */
+
+ e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
+ if (!e) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+
+ nindex = e - c->signature;
+ }
+
+ a = message_extend_body(m, 4, 4);
+ if (!a)
+ return -ENOMEM;
+
+ o = m->body_end;
+ op = m->body_end->data;
+ os = m->body_end->size;
+
+ /* Add alignment between size and first element */
+ if (!message_extend_body(m, alignment, 0))
+ return -ENOMEM;
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ c->index = nindex;
+
+ /* location of array size might have changed so let's readjust a */
+ if (o == m->body_end)
+ a = adjust_pointer(a, op, os, m->body_end->data);
+
+ *(uint32_t*) a = 0;
+ *array_size = a;
+ return 0;
+}
+
+static int bus_message_open_variant(
+ sd_bus_message *m,
+ struct bus_container *c,
+ const char *contents) {
+
+ size_t l;
+ void *a;
+
+ assert(m);
+ assert(c);
+ assert(contents);
+
+ if (!signature_is_single(contents, false))
+ return -EINVAL;
+
+ if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
+ return -EINVAL;
+
+ if (c->signature && c->signature[c->index]) {
+
+ if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
+ return -ENXIO;
+
+ } else {
+ char *e;
+
+ if (c->enclosing != 0)
+ return -ENXIO;
+
+ e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
+ if (!e) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+ }
+
+ l = strlen(contents);
+ a = message_extend_body(m, 1, 1 + l + 1);
+ if (!a)
+ return -ENOMEM;
+
+ *(uint8_t*) a = l;
+ memcpy((uint8_t*) a + 1, contents, l + 1);
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ c->index++;
+
+ return 0;
+}
+
+static int bus_message_open_struct(
+ sd_bus_message *m,
+ struct bus_container *c,
+ const char *contents) {
+
+ size_t nindex;
+
+ assert(m);
+ assert(c);
+ assert(contents);
+
+ if (!signature_is_valid(contents, false))
+ return -EINVAL;
+
+ if (c->signature && c->signature[c->index]) {
+ size_t l;
+
+ l = strlen(contents);
+
+ if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
+ !startswith(c->signature + c->index + 1, contents) ||
+ c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
+ return -ENXIO;
+
+ nindex = c->index + 1 + l + 1;
+ } else {
+ char *e;
+
+ if (c->enclosing != 0)
+ return -ENXIO;
+
+ e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
+ if (!e) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+
+ nindex = e - c->signature;
+ }
+
+ /* Align contents to 8 byte boundary */
+ if (!message_extend_body(m, 8, 0))
+ return -ENOMEM;
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ c->index = nindex;
+
+ return 0;
+}
+
+static int bus_message_open_dict_entry(
+ sd_bus_message *m,
+ struct bus_container *c,
+ const char *contents) {
+
+ size_t nindex;
+
+ assert(m);
+ assert(c);
+ assert(contents);
+
+ if (!signature_is_pair(contents))
+ return -EINVAL;
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ return -ENXIO;
+
+ if (c->signature && c->signature[c->index]) {
+ size_t l;
+
+ l = strlen(contents);
+
+ if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
+ !startswith(c->signature + c->index + 1, contents) ||
+ c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
+ return -ENXIO;
+
+ nindex = c->index + 1 + l + 1;
+ } else
+ return -ENXIO;
+
+ /* Align contents to 8 byte boundary */
+ if (!message_extend_body(m, 8, 0))
+ return -ENOMEM;
+
+ if (c->enclosing != SD_BUS_TYPE_ARRAY)
+ c->index = nindex;
+
+ return 0;
+}
+
+int sd_bus_message_open_container(
+ sd_bus_message *m,
+ char type,
+ const char *contents) {
+
+ struct bus_container *c, *w;
+ uint32_t *array_size = NULL;
+ char *signature;
+ size_t before;
+ int r;
+
+ if (!m)
+ return -EINVAL;
+ if (m->sealed)
+ return -EPERM;
+ if (!contents)
+ return -EINVAL;
+ if (m->poisoned)
+ return -ESTALE;
+
+ /* Make sure we have space for one more container */
+ w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
+ if (!w) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+
+ m->containers = w;
+
+ c = message_get_container(m);
+
+ signature = strdup(contents);
+ if (!signature) {
+ m->poisoned = true;
+ return -ENOMEM;
+ }
+
+ /* Save old index in the parent container, in case we have to
+ * abort this container */
+ c->saved_index = c->index;
+ before = m->header->body_size;
+
+ if (type == SD_BUS_TYPE_ARRAY)
+ r = bus_message_open_array(m, c, contents, &array_size);
+ else if (type == SD_BUS_TYPE_VARIANT)
+ r = bus_message_open_variant(m, c, contents);
+ else if (type == SD_BUS_TYPE_STRUCT)
+ r = bus_message_open_struct(m, c, contents);
+ else if (type == SD_BUS_TYPE_DICT_ENTRY)
+ r = bus_message_open_dict_entry(m, c, contents);
+ else
+ r = -EINVAL;
+
+ if (r < 0) {
+ free(signature);
+ return r;