Refactor Rhizome manifest parsing

Now the parsing code uses the set/del functions for all supported
manifest fields, so no duplicate logic any more
This commit is contained in:
Andrew Bettison 2014-11-18 18:42:43 +10:30
parent 2f1843858d
commit ff339011b4
2 changed files with 266 additions and 194 deletions

View File

@ -116,10 +116,21 @@ static const char *_rhizome_manifest_set_ui64(struct __sourceloc __whence, rhizo
void _rhizome_manifest_set_id(struct __sourceloc __whence, rhizome_manifest *m, const rhizome_bid_t *bidp) void _rhizome_manifest_set_id(struct __sourceloc __whence, rhizome_manifest *m, const rhizome_bid_t *bidp)
{ {
if (bidp) {
if (m->has_id && (bidp == &m->cryptoSignPublic || cmp_rhizome_bid_t(&m->cryptoSignPublic, bidp) == 0))
return; // unchanged
const char *v = rhizome_manifest_set(m, "id", alloca_tohex_rhizome_bid_t(*bidp)); const char *v = rhizome_manifest_set(m, "id", alloca_tohex_rhizome_bid_t(*bidp));
assert(v); // TODO: remove known manifest fields from vars[] assert(v); // TODO: remove known manifest fields from vars[]
// If the BID is changed, the secret key and bundle key are no longer valid. m->cryptoSignPublic = *bidp;
if (m->has_id && bidp != &m->cryptoSignPublic && cmp_rhizome_bid_t(&m->cryptoSignPublic, bidp) != 0) { m->has_id = 1;
} else if (m->has_id) {
bzero(&m->cryptoSignPublic, sizeof m->cryptoSignPublic); // not strictly necessary but aids debugging
m->has_id = 0;
} else
return; // unchanged
// The BID has changed.
m->finalised = 0;
// Any existing secret key and bundle key are no longer valid.
if (m->haveSecret) { if (m->haveSecret) {
m->haveSecret = SECRET_UNKNOWN; m->haveSecret = SECRET_UNKNOWN;
bzero(m->cryptoSignSecret, sizeof m->cryptoSignSecret); // not strictly necessary but aids debugging bzero(m->cryptoSignSecret, sizeof m->cryptoSignSecret); // not strictly necessary but aids debugging
@ -132,23 +143,26 @@ void _rhizome_manifest_set_id(struct __sourceloc __whence, rhizome_manifest *m,
if (m->authorship == AUTHOR_AUTHENTIC) if (m->authorship == AUTHOR_AUTHENTIC)
m->authorship = AUTHOR_LOCAL; m->authorship = AUTHOR_LOCAL;
} }
m->cryptoSignPublic = *bidp;
m->has_id = 1;
m->finalised = 0;
}
void _rhizome_manifest_set_version(struct __sourceloc __whence, rhizome_manifest *m, uint64_t version) void _rhizome_manifest_set_version(struct __sourceloc __whence, rhizome_manifest *m, uint64_t version)
{ {
if (version) {
const char *v = rhizome_manifest_set_ui64(m, "version", version); const char *v = rhizome_manifest_set_ui64(m, "version", version);
assert(v); // TODO: remove known manifest fields from vars[] assert(v); // TODO: remove known manifest fields from vars[]
} else
rhizome_manifest_del(m, "version");
m->version = version; m->version = version;
m->finalised = 0; m->finalised = 0;
} }
void _rhizome_manifest_set_filesize(struct __sourceloc __whence, rhizome_manifest *m, uint64_t size) void _rhizome_manifest_set_filesize(struct __sourceloc __whence, rhizome_manifest *m, uint64_t size)
{ {
if (size == RHIZOME_SIZE_UNSET) {
rhizome_manifest_del(m, "filesize");
} else {
const char *v = rhizome_manifest_set_ui64(m, "filesize", size); const char *v = rhizome_manifest_set_ui64(m, "filesize", size);
assert(v); // TODO: remove known manifest fields from vars[] assert(v); // TODO: remove known manifest fields from vars[]
}
m->filesize = size; m->filesize = size;
m->finalised = 0; m->finalised = 0;
} }
@ -157,7 +171,6 @@ void _rhizome_manifest_set_filesize(struct __sourceloc __whence, rhizome_manifes
*/ */
void _rhizome_manifest_set_filehash(struct __sourceloc __whence, rhizome_manifest *m, const rhizome_filehash_t *hash) void _rhizome_manifest_set_filehash(struct __sourceloc __whence, rhizome_manifest *m, const rhizome_filehash_t *hash)
{ {
assert(m->filesize != RHIZOME_SIZE_UNSET);
if (hash) { if (hash) {
const char *v = rhizome_manifest_set(m, "filehash", alloca_tohex_rhizome_filehash_t(*hash)); const char *v = rhizome_manifest_set(m, "filehash", alloca_tohex_rhizome_filehash_t(*hash));
assert(v); // TODO: remove known manifest fields from vars[] assert(v); // TODO: remove known manifest fields from vars[]
@ -173,10 +186,15 @@ void _rhizome_manifest_set_filehash(struct __sourceloc __whence, rhizome_manifes
void _rhizome_manifest_set_tail(struct __sourceloc __whence, rhizome_manifest *m, uint64_t tail) void _rhizome_manifest_set_tail(struct __sourceloc __whence, rhizome_manifest *m, uint64_t tail)
{ {
if (tail == RHIZOME_SIZE_UNSET) {
rhizome_manifest_del(m, "tail");
m->is_journal = 0;
} else {
const char *v = rhizome_manifest_set_ui64(m, "tail", tail); const char *v = rhizome_manifest_set_ui64(m, "tail", tail);
assert(v); // TODO: remove known manifest fields from vars[] assert(v); // TODO: remove known manifest fields from vars[]
m->tail = tail; m->tail = tail;
m->is_journal = (tail != RHIZOME_SIZE_UNSET); m->is_journal = 1;
}
m->finalised = 0; m->finalised = 0;
} }
@ -261,6 +279,16 @@ void _rhizome_manifest_set_date(struct __sourceloc __whence, rhizome_manifest *m
m->finalised = 0; m->finalised = 0;
} }
void _rhizome_manifest_del_date(struct __sourceloc __whence, rhizome_manifest *m)
{
if (m->has_date) {
m->has_date = 0;
m->finalised = 0;
rhizome_manifest_del(m, "date");
} else
assert(rhizome_manifest_get(m, "date") == NULL);
}
void _rhizome_manifest_set_sender(struct __sourceloc __whence, rhizome_manifest *m, const sid_t *sidp) void _rhizome_manifest_set_sender(struct __sourceloc __whence, rhizome_manifest *m, const sid_t *sidp)
{ {
if (sidp) { if (sidp) {
@ -556,7 +584,7 @@ int rhizome_manifest_parse(rhizome_manifest *m)
assert(!m->has_recipient); assert(!m->has_recipient);
assert(m->payloadEncryption == PAYLOAD_CRYPT_UNKNOWN); assert(m->payloadEncryption == PAYLOAD_CRYPT_UNKNOWN);
unsigned invalid = 0; unsigned invalid = 0;
unsigned has_invalid_essential = 0; unsigned has_invalid_core = 0;
unsigned has_duplicate = 0; unsigned has_duplicate = 0;
const char *const end = (const char *)m->manifestdata + m->manifest_all_bytes; const char *const end = (const char *)m->manifestdata + m->manifest_all_bytes;
const char *p; const char *p;
@ -600,7 +628,7 @@ int rhizome_manifest_parse(rhizome_manifest *m)
break; break;
case RHIZOME_MANIFEST_INVALID: case RHIZOME_MANIFEST_INVALID:
status_ok = 1; status_ok = 1;
++has_invalid_essential; ++has_invalid_core;
break; break;
case RHIZOME_MANIFEST_MALFORMED: case RHIZOME_MANIFEST_MALFORMED:
status_ok = 1; status_ok = 1;
@ -616,7 +644,7 @@ int rhizome_manifest_parse(rhizome_manifest *m)
assert(p < end); assert(p < end);
assert(*p == '\n'); assert(*p == '\n');
} }
if ((p < end && *p) || has_invalid_essential || has_duplicate) { if ((p < end && *p) || has_invalid_core || has_duplicate) {
rhizome_manifest_clear(m); rhizome_manifest_clear(m);
RETURN(1); RETURN(1);
} }
@ -630,156 +658,231 @@ int rhizome_manifest_parse(rhizome_manifest *m)
OUT(); OUT();
} }
typedef enum rhizome_manifest_parse_status MANIFEST_FIELD_PARSER(rhizome_manifest *, const char *); typedef int MANIFEST_FIELD_TESTER(rhizome_manifest *);
typedef void MANIFEST_FIELD_UNSETTER(rhizome_manifest *);
typedef int MANIFEST_FIELD_PARSER(rhizome_manifest *, const char *);
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_id(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_id(rhizome_manifest *m)
{ {
if (m->has_id) return m->has_id;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
if (str_to_rhizome_bid_t(&m->cryptoSignPublic, text) == -1) static void _rhizome_manifest_unset_id(rhizome_manifest *m)
return RHIZOME_MANIFEST_INVALID; {
m->has_id = 1; rhizome_manifest_set_id(m, NULL);
if (config.debug.rhizome_manifest) }
DEBUGF("PARSE manifest[%d].id = %s", m->manifest_record_number, alloca_tohex_sid_t(m->cryptoSignPublic)); static int _rhizome_manifest_parse_id(rhizome_manifest *m, const char *text)
return RHIZOME_MANIFEST_OK; {
rhizome_bid_t bid;
if (str_to_rhizome_bid_t(&bid, text) == -1)
return 0;
rhizome_manifest_set_id(m, &bid);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_version(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_version(rhizome_manifest *m)
{
return m->version != 0;
}
static void _rhizome_manifest_unset_version(rhizome_manifest *m)
{
m->version = 0;
}
static int _rhizome_manifest_parse_version(rhizome_manifest *m, const char *text)
{ {
if (m->version)
return RHIZOME_MANIFEST_DUPLICATE_FIELD;
uint64_t version; uint64_t version;
if (!str_to_uint64(text, 10, &version, NULL) || version == 0) if (!str_to_uint64(text, 10, &version, NULL) || version == 0)
return RHIZOME_MANIFEST_INVALID; return 0;
m->version = version; rhizome_manifest_set_version(m, version);
if (config.debug.rhizome_manifest) return 1;
DEBUGF("PARSE manifest[%d].version = %"PRIu64, m->manifest_record_number, m->version);
return RHIZOME_MANIFEST_OK;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_filehash(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_filehash(rhizome_manifest *m)
{ {
if (m->has_filehash) return m->has_filehash;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
if (str_to_rhizome_filehash_t(&m->filehash, text) == -1) static void _rhizome_manifest_unset_filehash(rhizome_manifest *m)
return RHIZOME_MANIFEST_INVALID; {
m->has_filehash = 1; rhizome_manifest_set_filehash(m, NULL);
if (config.debug.rhizome_manifest) }
DEBUGF("PARSE manifest[%d].filehash = %s", m->manifest_record_number, alloca_tohex_rhizome_filehash_t(m->filehash)); static int _rhizome_manifest_parse_filehash(rhizome_manifest *m, const char *text)
return RHIZOME_MANIFEST_OK; {
rhizome_filehash_t hash;
if (str_to_rhizome_filehash_t(&hash, text) == -1)
return 0;
rhizome_manifest_set_filehash(m, &hash);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_filesize(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_filesize(rhizome_manifest *m)
{ {
if (m->filesize != RHIZOME_SIZE_UNSET) return m->filesize != RHIZOME_SIZE_UNSET;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
uint64_t filesize; static void _rhizome_manifest_unset_filesize(rhizome_manifest *m)
if (!str_to_uint64(text, 10, &filesize, NULL) || filesize == RHIZOME_SIZE_UNSET) {
return RHIZOME_MANIFEST_INVALID; rhizome_manifest_set_filesize(m, RHIZOME_SIZE_UNSET);
m->filesize = filesize; }
if (config.debug.rhizome_manifest) static int _rhizome_manifest_parse_filesize(rhizome_manifest *m, const char *text)
DEBUGF("PARSE manifest[%d].filesize = %"PRIu64, m->manifest_record_number, m->filesize); {
return RHIZOME_MANIFEST_OK; uint64_t size;
if (!str_to_uint64(text, 10, &size, NULL) || size == RHIZOME_SIZE_UNSET)
return 0;
rhizome_manifest_set_filesize(m, size);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_tail(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_tail(rhizome_manifest *m)
{
return m->is_journal;
}
static void _rhizome_manifest_unset_tail(rhizome_manifest *m)
{
rhizome_manifest_set_tail(m, RHIZOME_SIZE_UNSET);
}
static int _rhizome_manifest_parse_tail(rhizome_manifest *m, const char *text)
{ {
if (m->tail != RHIZOME_SIZE_UNSET)
return RHIZOME_MANIFEST_DUPLICATE_FIELD;
uint64_t tail; uint64_t tail;
if (!str_to_uint64(text, 10, &tail, NULL) || tail == RHIZOME_SIZE_UNSET) if (!str_to_uint64(text, 10, &tail, NULL) || tail == RHIZOME_SIZE_UNSET)
return RHIZOME_MANIFEST_INVALID; return 0;
m->tail = tail; rhizome_manifest_set_tail(m, tail);
m->is_journal = 1; return 1;
if (config.debug.rhizome_manifest)
DEBUGF("PARSE manifest[%d].tail = %"PRIu64, m->manifest_record_number, m->tail);
return RHIZOME_MANIFEST_OK;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_BK(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_BK(rhizome_manifest *m)
{ {
if (m->has_bundle_key) return m->has_bundle_key;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
if (str_to_rhizome_bk_t(&m->bundle_key, text) == -1) static void _rhizome_manifest_unset_BK(rhizome_manifest *m)
return RHIZOME_MANIFEST_MALFORMED; {
m->has_bundle_key = 1; m->has_bundle_key = 0;
if (config.debug.rhizome_manifest) }
DEBUGF("PARSE manifest[%d].BK = %s", m->manifest_record_number, alloca_tohex_rhizome_bk_t(m->bundle_key)); static int _rhizome_manifest_parse_BK(rhizome_manifest *m, const char *text)
return RHIZOME_MANIFEST_OK; {
rhizome_bk_t bk;
if (str_to_rhizome_bk_t(&bk, text) == -1)
return 0;
rhizome_manifest_set_bundle_key(m, &bk);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_service(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_service(rhizome_manifest *m)
{
return m->service != NULL;
}
static void _rhizome_manifest_unset_service(rhizome_manifest *m)
{
rhizome_manifest_del_service(m);
}
static int _rhizome_manifest_parse_service(rhizome_manifest *m, const char *text)
{ {
if (m->service)
return RHIZOME_MANIFEST_DUPLICATE_FIELD;
if (!rhizome_str_is_manifest_service(text)) if (!rhizome_str_is_manifest_service(text))
return RHIZOME_MANIFEST_MALFORMED; return 0;
m->service = text; // will be free()d when vars[] and values[] are free()d rhizome_manifest_set_service(m, text);
if (config.debug.rhizome_manifest) return 1;
DEBUGF("PARSE manifest[%d].service = %s", m->manifest_record_number, alloca_str_toprint(m->service));
return RHIZOME_MANIFEST_OK;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_date(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_date(rhizome_manifest *m)
{
return m->has_date;
}
static void _rhizome_manifest_unset_date(rhizome_manifest *m)
{
rhizome_manifest_del_date(m);
}
static int _rhizome_manifest_parse_date(rhizome_manifest *m, const char *text)
{ {
if (m->has_date)
return RHIZOME_MANIFEST_DUPLICATE_FIELD;
int64_t date; int64_t date;
if (!str_to_int64(text, 10, &date, NULL)) if (!str_to_int64(text, 10, &date, NULL))
return RHIZOME_MANIFEST_MALFORMED; return 0;
m->date = date; rhizome_manifest_set_date(m, date);
m->has_date = 1; return 1;
if (config.debug.rhizome_manifest)
DEBUGF("PARSE manifest[%d].date = %"PRItime_ms_t, m->manifest_record_number, m->date);
return RHIZOME_MANIFEST_OK;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_sender(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_sender(rhizome_manifest *m)
{ {
if (m->has_sender) return m->has_sender;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
if (str_to_sid_t(&m->sender, text) == -1) static void _rhizome_manifest_unset_sender(rhizome_manifest *m)
return RHIZOME_MANIFEST_MALFORMED; {
m->has_sender = 1; rhizome_manifest_set_sender(m, NULL);
if (config.debug.rhizome_manifest) }
DEBUGF("PARSE manifest[%d].sender = %s", m->manifest_record_number, alloca_tohex_sid_t(m->sender)); static int _rhizome_manifest_parse_sender(rhizome_manifest *m, const char *text)
return RHIZOME_MANIFEST_OK; {
sid_t sid;
if (str_to_sid_t(&sid, text) == -1)
return 0;
rhizome_manifest_set_sender(m, &sid);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_recipient(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_recipient(rhizome_manifest *m)
{ {
if (m->has_recipient) return m->has_recipient;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
if (str_to_sid_t(&m->recipient, text) == -1) static void _rhizome_manifest_unset_recipient(rhizome_manifest *m)
return RHIZOME_MANIFEST_MALFORMED; {
m->has_recipient = 1; rhizome_manifest_set_recipient(m, NULL);
if (config.debug.rhizome_manifest) }
DEBUGF("PARSE manifest[%d].recipient = %s", m->manifest_record_number, alloca_tohex_sid_t(m->recipient)); static int _rhizome_manifest_parse_recipient(rhizome_manifest *m, const char *text)
return RHIZOME_MANIFEST_OK; {
sid_t sid;
if (str_to_sid_t(&sid, text) == -1)
return 0;
rhizome_manifest_set_recipient(m, &sid);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_name(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_name(rhizome_manifest *m)
{ {
if (m->name) return m->name != NULL;
return RHIZOME_MANIFEST_DUPLICATE_FIELD; }
m->name = text; // will be free()d when vars[] and values[] are free()d static void _rhizome_manifest_unset_name(rhizome_manifest *m)
if (config.debug.rhizome_manifest) {
DEBUGF("PARSE manifest[%d].name = %s", m->manifest_record_number, alloca_str_toprint(m->name)); rhizome_manifest_del_name(m);
return RHIZOME_MANIFEST_OK; }
static int _rhizome_manifest_parse_name(rhizome_manifest *m, const char *text)
{
rhizome_manifest_set_name(m, text);
return 1;
} }
static enum rhizome_manifest_parse_status _rhizome_manifest_parse_crypt(rhizome_manifest *m, const char *text) static int _rhizome_manifest_test_crypt(rhizome_manifest *m)
{
return m->payloadEncryption != PAYLOAD_CRYPT_UNKNOWN;
}
static void _rhizome_manifest_unset_crypt(rhizome_manifest *m)
{
rhizome_manifest_set_crypt(m, PAYLOAD_CRYPT_UNKNOWN);
}
static int _rhizome_manifest_parse_crypt(rhizome_manifest *m, const char *text)
{ {
if (m->payloadEncryption != PAYLOAD_CRYPT_UNKNOWN)
return RHIZOME_MANIFEST_DUPLICATE_FIELD;
if (!(strcmp(text, "0") == 0 || strcmp(text, "1") == 0)) if (!(strcmp(text, "0") == 0 || strcmp(text, "1") == 0))
return RHIZOME_MANIFEST_MALFORMED; return 0;
m->payloadEncryption = (text[0] == '1') ? PAYLOAD_ENCRYPTED : PAYLOAD_CLEAR; rhizome_manifest_set_crypt(m, (text[0] == '1') ? PAYLOAD_ENCRYPTED : PAYLOAD_CLEAR);
if (config.debug.rhizome_manifest) return 1;
DEBUGF("PARSE manifest[%d].crypt = %u", m->manifest_record_number, m->payloadEncryption == PAYLOAD_ENCRYPTED ? 1 : 0);
return RHIZOME_MANIFEST_OK;
} }
static struct rhizome_manifest_field_descriptor {
const char *label;
int core;
MANIFEST_FIELD_TESTER *test;
MANIFEST_FIELD_UNSETTER *unset;
MANIFEST_FIELD_PARSER *parse;
}
rhizome_manifest_fields[] = {
{ "id", 1, _rhizome_manifest_test_id, _rhizome_manifest_unset_id, _rhizome_manifest_parse_id },
{ "version", 1, _rhizome_manifest_test_version, _rhizome_manifest_unset_version, _rhizome_manifest_parse_version },
{ "filehash", 1, _rhizome_manifest_test_filehash, _rhizome_manifest_unset_filehash, _rhizome_manifest_parse_filehash },
{ "filesize", 1, _rhizome_manifest_test_filesize, _rhizome_manifest_unset_filesize, _rhizome_manifest_parse_filesize },
{ "tail", 1, _rhizome_manifest_test_tail, _rhizome_manifest_unset_tail, _rhizome_manifest_parse_tail },
{ "BK", 0, _rhizome_manifest_test_BK, _rhizome_manifest_unset_BK, _rhizome_manifest_parse_BK },
{ "service", 0, _rhizome_manifest_test_service, _rhizome_manifest_unset_service, _rhizome_manifest_parse_service },
{ "date", 0, _rhizome_manifest_test_date, _rhizome_manifest_unset_date, _rhizome_manifest_parse_date },
{ "sender", 0, _rhizome_manifest_test_sender, _rhizome_manifest_unset_sender, _rhizome_manifest_parse_sender },
{ "recipient", 0, _rhizome_manifest_test_recipient, _rhizome_manifest_unset_recipient, _rhizome_manifest_parse_recipient },
{ "name", 0, _rhizome_manifest_test_name, _rhizome_manifest_unset_name, _rhizome_manifest_parse_name },
{ "crypt", 0, _rhizome_manifest_test_crypt, _rhizome_manifest_unset_crypt, _rhizome_manifest_parse_crypt },
};
/* Parse a single Rhizome manifest field. Used for incremental construction or modification of /* Parse a single Rhizome manifest field. Used for incremental construction or modification of
* manifests. * manifests.
* *
@ -792,14 +895,13 @@ static enum rhizome_manifest_parse_status _rhizome_manifest_parse_crypt(rhizome_
* field, first remove it by calling rhizome_manifest_remove_field() then call * field, first remove it by calling rhizome_manifest_remove_field() then call
* rhizome_manifest_parse_field().) * rhizome_manifest_parse_field().)
* *
* If the maximum number of fields are already occupied in the manifest, then returns
* RHIZOME_MANIFEST_OVERFLOW and leaves the manifest unchanged.
*
* If the supplied field_value is invalid (does not parse according to the field's syntax, eg, * If the supplied field_value is invalid (does not parse according to the field's syntax, eg,
* unsigned integer) then returns RHIZOME_MANIFEST_INVALID if it is a core field, otherwise returns * unsigned integer) then returns RHIZOME_MANIFEST_INVALID if it is a core field, otherwise returns
* RHIZOME_MANIFEST_MALFORMED and leaves the manifest unchanged. Unrecognised fields are not * RHIZOME_MANIFEST_MALFORMED and leaves the manifest unchanged. Unsupported fields are not parsed;
* parsed; the value string is simply stored, so unrecognised fields cannot evoke a MALFORMED * their value string is simply stored, so they cannot evoke a MALFORMED result.
* result.
*
* If the field parses successfully but the maximum number of fields are already occupied in the
* manifest, then returns RHIZOME_MANIFEST_OVERFLOW and leaves the manifest unchanged.
* *
* Otherwise, sets the relevant element(s) of the manifest structure and appends the field_label and * Otherwise, sets the relevant element(s) of the manifest structure and appends the field_label and
* field_value strings into the m->vars[] and m->values[] arrays, as pointers to malloc(3)ed NUL * field_value strings into the m->vars[] and m->values[] arrays, as pointers to malloc(3)ed NUL
@ -826,9 +928,7 @@ rhizome_manifest_parse_field(rhizome_manifest *m, const char *field_label, size_
DEBUGF("Invalid manifest field name: %s", alloca_toprint(-1, field_label, field_label_len)); DEBUGF("Invalid manifest field name: %s", alloca_toprint(-1, field_label, field_label_len));
return RHIZOME_MANIFEST_SYNTAX_ERROR; return RHIZOME_MANIFEST_SYNTAX_ERROR;
} }
const char *label = strn_edup(field_label, field_label_len); const char *label = alloca_strndup(field_label, field_label_len);
if (label == NULL)
return RHIZOME_MANIFEST_ERROR;
// Sanity and syntax check on field value. // Sanity and syntax check on field value.
if (field_value_len > MAX_MANIFEST_BYTES) { if (field_value_len > MAX_MANIFEST_BYTES) {
if (config.debug.rhizome_manifest) if (config.debug.rhizome_manifest)
@ -846,59 +946,32 @@ rhizome_manifest_parse_field(rhizome_manifest *m, const char *field_label, size_
free((char *)label); free((char *)label);
return RHIZOME_MANIFEST_SYNTAX_ERROR; return RHIZOME_MANIFEST_SYNTAX_ERROR;
} }
const char *value = strn_edup(field_value, field_value_len); const char *value = alloca_strndup(field_value, field_value_len);
if (value == NULL) { struct rhizome_manifest_field_descriptor *desc = NULL;
free((char *)label); for (i = 0; desc == NULL && i < NELS(rhizome_manifest_fields); ++i)
return RHIZOME_MANIFEST_ERROR; if (strcasecmp(label, rhizome_manifest_fields[i].label) == 0)
} desc = &rhizome_manifest_fields[i];
MANIFEST_FIELD_PARSER *parser = NULL;
if (strcasecmp(label, "id") == 0)
parser = _rhizome_manifest_parse_id;
else if (strcasecmp(label, "version") == 0)
parser = _rhizome_manifest_parse_version;
else if (strcasecmp(label, "filehash") == 0)
parser = _rhizome_manifest_parse_filehash;
else if (strcasecmp(label, "filesize") == 0)
parser = _rhizome_manifest_parse_filesize;
else if (strcasecmp(label, "tail") == 0)
parser = _rhizome_manifest_parse_tail;
else if (strcasecmp(label, "BK") == 0)
parser = _rhizome_manifest_parse_BK;
else if (strcasecmp(label, "service") == 0)
parser = _rhizome_manifest_parse_service;
else if (strcasecmp(label, "date") == 0)
parser = _rhizome_manifest_parse_date;
else if (strcasecmp(label, "sender") == 0)
parser = _rhizome_manifest_parse_sender;
else if (strcasecmp(label, "recipient") == 0)
parser = _rhizome_manifest_parse_recipient;
else if (strcasecmp(label, "name") == 0)
parser = _rhizome_manifest_parse_name;
else if (strcasecmp(label, "crypt") == 0)
parser = _rhizome_manifest_parse_crypt;
enum rhizome_manifest_parse_status status = RHIZOME_MANIFEST_OK; enum rhizome_manifest_parse_status status = RHIZOME_MANIFEST_OK;
if (rhizome_manifest_get(m, label)) { assert(m->var_count <= NELS(m->vars));
if (desc ? desc->test(m) : rhizome_manifest_get(m, label) != NULL) {
if (config.debug.rhizome_manifest) if (config.debug.rhizome_manifest)
DEBUGF("Duplicate field at %s=%s", label, alloca_toprint(100, field_value, field_value_len)); DEBUGF("Duplicate field at %s=%s", label, alloca_toprint(100, field_value, field_value_len));
status = RHIZOME_MANIFEST_DUPLICATE_FIELD; status = RHIZOME_MANIFEST_DUPLICATE_FIELD;
} else if (m->var_count >= NELS(m->vars)) { } else if (m->var_count == NELS(m->vars)) {
if (config.debug.rhizome_manifest) if (config.debug.rhizome_manifest)
DEBUGF("Manifest field limit reached at %s=%s", label, alloca_toprint(100, field_value, field_value_len)); DEBUGF("Manifest field limit reached at %s=%s", label, alloca_toprint(100, field_value, field_value_len));
status = RHIZOME_MANIFEST_OVERFLOW; status = RHIZOME_MANIFEST_OVERFLOW;
} else if (parser) { } else if (desc) {
status = parser(m, value); if (!desc->parse(m, value)) {
assert(status != RHIZOME_MANIFEST_DUPLICATE_FIELD); if (config.debug.rhizome_manifest)
DEBUGF("Manifest field parse failed at %s=%s", label, alloca_toprint(100, field_value, field_value_len));
status = desc->core ? RHIZOME_MANIFEST_INVALID : RHIZOME_MANIFEST_MALFORMED;
} }
if (status == RHIZOME_MANIFEST_OK) { } else if ((rhizome_manifest_set(m, label, value)) == NULL)
assert(m->var_count < NELS(m->vars)); status = RHIZOME_MANIFEST_ERROR;
m->vars[m->var_count] = label; if (status != RHIZOME_MANIFEST_OK) {
m->values[m->var_count] = value;
++m->var_count;
} else {
if (config.debug.rhizome_manifest) if (config.debug.rhizome_manifest)
DEBUGF("SKIP manifest[%d].%s = %s (status=%d)", m->manifest_record_number, label, alloca_str_toprint(value), status); DEBUGF("SKIP manifest[%d].%s = %s (status=%d)", m->manifest_record_number, label, alloca_str_toprint(value), status);
free((char *)label);
free((char *)value);
} }
return status; return status;
} }
@ -983,7 +1056,6 @@ int rhizome_hash_file(rhizome_manifest *m, const char *path, rhizome_filehash_t
// TODO encrypted payloads // TODO encrypted payloads
if (m && m->payloadEncryption == PAYLOAD_ENCRYPTED) if (m && m->payloadEncryption == PAYLOAD_ENCRYPTED)
return WHY("Encryption of payloads not implemented"); return WHY("Encryption of payloads not implemented");
uint64_t filesize = 0; uint64_t filesize = 0;
SHA512_CTX context; SHA512_CTX context;
SHA512_Init(&context); SHA512_Init(&context);

View File

@ -140,7 +140,7 @@ setup_AddNoAuthorEncrypted() {
} }
test_AddNoAuthorEncrypted() { test_AddNoAuthorEncrypted() {
executeOk_servald rhizome add file '' file1 file1.manifest executeOk_servald rhizome add file '' file1 file1.manifest
tfw_cat --stdout --stderr tfw_cat --stdout --stderr -v file1.manifest
assert_manifest_fields file1.manifest !BK assert_manifest_fields file1.manifest !BK
assert_stdout_add_file file1 !.author !BK assert_stdout_add_file file1 !.author !BK
extract_stdout_secret file1_secret extract_stdout_secret file1_secret