From 089b8c440f7464d39f984b33fbe761f128338f39 Mon Sep 17 00:00:00 2001 From: Bron Gondwana Date: Thu, 30 Jan 2025 11:48:27 +1100 Subject: [PATCH] cyrusdb: handle CONVERT without noise This adds a new "BADFORMAT" return, and only tries to convert if the existing file has BADFORMAT --- lib/cyrusdb.c | 16 +++++++--------- lib/cyrusdb.h | 3 ++- lib/cyrusdb_skiplist.c | 11 +++++++---- lib/cyrusdb_twom.c | 3 +++ lib/cyrusdb_twoskip.c | 6 +++--- lib/twom.c | 20 ++++++++------------ lib/twom.h | 3 +++ 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/cyrusdb.c b/lib/cyrusdb.c index f572131491..12ab85f69c 100644 --- a/lib/cyrusdb.c +++ b/lib/cyrusdb.c @@ -205,20 +205,18 @@ static int _myopen(const char *backend, const char *fname, /* check if it opens normally. Horray */ r = db->backend->open(fname, flags, &db->engine, tid); - if (r == CYRUSDB_NOTFOUND) goto done; /* no open flags */ - if (!r) goto done; - - r = _detect_or_convert(db, backend, fname, flags); + if (r == CYRUSDB_BADFORMAT) { + r = _detect_or_convert(db, backend, fname, flags); + if (r) goto done; + r = db->backend->open(fname, flags, &db->engine, tid); + } if (r) goto done; - r = db->backend->open(fname, flags, &db->engine, tid); - #ifdef DEBUGDB - syslog(LOG_NOTICE, "DEBUGDB open(%s, %d) => %llx", fname, flags, (long long unsigned)db->engine); + syslog(LOG_NOTICE, "DEBUGDB open(%s, %d) => %d, %llx", fname, flags, r, (long long unsigned)db->engine); #endif -done: - + done: if (r) free(db); else *ret = db; diff --git a/lib/cyrusdb.h b/lib/cyrusdb.h index 48cd9d3708..6489d87c3c 100644 --- a/lib/cyrusdb.h +++ b/lib/cyrusdb.h @@ -59,7 +59,8 @@ enum cyrusdb_ret { CYRUSDB_LOCKED = -6, CYRUSDB_NOTIMPLEMENTED = -7, CYRUSDB_FULL = -8, - CYRUSDB_READONLY = -9 + CYRUSDB_READONLY = -9, + CYRUSDB_BADFORMAT = -10, }; enum cyrusdb_initflags { diff --git a/lib/cyrusdb_skiplist.c b/lib/cyrusdb_skiplist.c index 3f0a888750..50b4761fe3 100644 --- a/lib/cyrusdb_skiplist.c +++ b/lib/cyrusdb_skiplist.c @@ -528,16 +528,19 @@ static int read_header(struct dbengine *db) { const char *dptr; - assert(db && db->map_len && db->fname && db->map_base - && db->is_open && db->lock_status); + assert(db); + if (db->map_len < HEADER_SIZE) { syslog(LOG_ERR, "skiplist: file not large enough for header: %s", db->fname); + return CYRUSDB_BADFORMAT; } + assert(db->fname && db->map_base && db->is_open && db->lock_status); + if (memcmp(db->map_base, HEADER_MAGIC, HEADER_MAGIC_SIZE)) { syslog(LOG_ERR, "skiplist: invalid magic header: %s", db->fname); - return CYRUSDB_IOERROR; + return CYRUSDB_BADFORMAT; } db->version = ntohl(*((uint32_t *)(db->map_base + OFFSET_VERSION))); @@ -546,7 +549,7 @@ static int read_header(struct dbengine *db) if (db->version != SKIPLIST_VERSION) { syslog(LOG_ERR, "skiplist: version mismatch: %s has version %d.%d", db->fname, db->version, db->version_minor); - return CYRUSDB_IOERROR; + return CYRUSDB_BADFORMAT; } db->maxlevel = ntohl(*((uint32_t *)(db->map_base + OFFSET_MAXLEVEL))); diff --git a/lib/cyrusdb_twom.c b/lib/cyrusdb_twom.c index d6bcdd9a4c..bb07c7a6d0 100644 --- a/lib/cyrusdb_twom.c +++ b/lib/cyrusdb_twom.c @@ -93,6 +93,9 @@ static int _errormap(int r) { case TWOM_LOCKED: return CYRUSDB_LOCKED; case TWOM_NOTFOUND: return CYRUSDB_NOTFOUND; case TWOM_READONLY: return CYRUSDB_READONLY; + case TWOM_BADFORMAT: return CYRUSDB_BADFORMAT; + case TWOM_BADUSAGE: return CYRUSDB_INTERNAL; + case TWOM_BADCHECKSUM: return CYRUSDB_IOERROR; // must be a foreach result default: return r; } diff --git a/lib/cyrusdb_twoskip.c b/lib/cyrusdb_twoskip.c index 70fa738e96..a81fd1f3d7 100644 --- a/lib/cyrusdb_twoskip.c +++ b/lib/cyrusdb_twoskip.c @@ -479,12 +479,12 @@ static int read_header(struct dbengine *db) if (SIZE(db) < HEADER_SIZE) { syslog(LOG_ERR, "twoskip: file not large enough for header: %s", FNAME(db)); - return CYRUSDB_IOERROR; + return CYRUSDB_BADFORMAT; } if (memcmp(base, HEADER_MAGIC, HEADER_MAGIC_SIZE)) { syslog(LOG_ERR, "twoskip: invalid magic header: %s", FNAME(db)); - return CYRUSDB_IOERROR; + return CYRUSDB_BADFORMAT; } db->header.version @@ -493,7 +493,7 @@ static int read_header(struct dbengine *db) if (db->header.version > VERSION) { syslog(LOG_ERR, "twoskip: version mismatch: %s has version %d", FNAME(db), db->header.version); - return CYRUSDB_IOERROR; + return CYRUSDB_BADFORMAT; } db->header.generation diff --git a/lib/twom.c b/lib/twom.c index e92865915f..9e07882f31 100644 --- a/lib/twom.c +++ b/lib/twom.c @@ -440,7 +440,7 @@ static inline int check_headcsum(struct twom_txn *txn, struct tm_file *file, con txn->db->error("invalid head checksum", "filename=<%s> offset=<%08llX>", txn->db->fname, (LLU)offset); - return TWOM_IOERROR; + return TWOM_BADCHECKSUM; } return 0; @@ -460,7 +460,7 @@ static inline int check_tailcsum(struct twom_txn *txn, struct tm_file *file, con txn->db->error("invalid tail checksum", "filename=<%s> offset=<%08llX>", txn->db->fname, (LLU)offset); - return TWOM_IOERROR; + return TWOM_BADCHECKSUM; } return 0; @@ -585,15 +585,11 @@ static int read_header(struct twom_db *db, struct tm_file *file, struct tm_heade const char *base = file->base; if (file->size < HEADER_SIZE) { - db->error("file not large enough for header", - "filename=<%s>", db->fname); - return TWOM_IOERROR; + return TWOM_BADFORMAT; } if (memcmp(base, HEADER_MAGIC, HEADER_MAGIC_SIZE)) { - db->error("invalid magic header", - "filename=<%s>", db->fname); - return TWOM_IOERROR; + return TWOM_BADFORMAT; } memcpy(header->uuid, base + OFFSET_UUID, 16); @@ -605,7 +601,7 @@ static int read_header(struct twom_db *db, struct tm_file *file, struct tm_heade db->error("invalid version", "filename=<%s> version=<%d>", db->fname, header->version); - return TWOM_IOERROR; + return TWOM_BADFORMAT; } header->flags @@ -615,7 +611,7 @@ static int read_header(struct twom_db *db, struct tm_file *file, struct tm_heade if (!db->external_csum) { db->error("missing external csum function", "filename=<%s>", db->fname); - return TWOM_IOERROR; + return TWOM_BADUSAGE; } } set_csum_engine(db, file, header->flags); @@ -625,7 +621,7 @@ static int read_header(struct twom_db *db, struct tm_file *file, struct tm_heade if (!db->external_compar) { db->error("missing external compar function", "filename=<%s>", db->fname); - return TWOM_IOERROR; + return TWOM_BADUSAGE; } file->compar = db->external_compar; } @@ -660,7 +656,7 @@ static int read_header(struct twom_db *db, struct tm_file *file, struct tm_heade if (file->csum(base, OFFSET_CSUM) != csum) { db->error("header checksum failure", "filename=<%s>", db->fname); - return TWOM_IOERROR; + return TWOM_BADCHECKSUM; } return 0; diff --git a/lib/twom.h b/lib/twom.h index 6abb0c4597..0e660aad91 100644 --- a/lib/twom.h +++ b/lib/twom.h @@ -33,6 +33,9 @@ enum twom_ret { TWOM_LOCKED = -4, TWOM_NOTFOUND = -5, TWOM_READONLY = -6, + TWOM_BADFORMAT = -7, + TWOM_BADUSAGE = -8, + TWOM_BADCHECKSUM = -9, }; // we don't reuse flags for different operations (e.g. open, fetch, foreach), as