diff options
Diffstat (limited to 'g10/tdbio.c')
-rw-r--r-- | g10/tdbio.c | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/g10/tdbio.c b/g10/tdbio.c index 7572b9aeb..fed0cf5ab 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -105,16 +105,17 @@ struct cmp_xdir_struct /* The name of the trustdb file. */ static char *db_name; -/* The handle for locking the trustdb file and a flag to record - whether a lock has been taken. */ +/* The handle for locking the trustdb file and a counter to record how + * often this lock has been taken. That counter is required becuase + * dotlock does not implemen recursive locks. */ static dotlock_t lockhandle; -static int is_locked; +static unsigned int is_locked; /* The file descriptor of the trustdb. */ static int db_fd = -1; /* A flag indicating that a transaction is active. */ -static int in_transaction; +/* static int in_transaction; Not yet used. */ @@ -125,7 +126,7 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type); /* * Take a lock on the trustdb file name. I a lock file can't be - * created the function terminates the process. Excvept for a + * created the function terminates the process. Except for a * different return code the function does nothing if the lock has * already been taken. * @@ -135,6 +136,8 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type); static int take_write_lock (void) { + int rc; + if (!lockhandle) lockhandle = dotlock_create (db_name, 0); if (!lockhandle) @@ -144,12 +147,16 @@ take_write_lock (void) { if (dotlock_take (lockhandle, -1) ) log_fatal ( _("can't lock '%s'\n"), db_name ); - else - is_locked = 1; - return 0; + rc = 0; } else - return 1; + rc = 1; + + if (opt.lock_once) + is_locked = 1; + else + is_locked++; + return rc; } @@ -160,10 +167,22 @@ take_write_lock (void) static void release_write_lock (void) { - if (!opt.lock_once) - if (!dotlock_release (lockhandle)) - is_locked = 0; + if (opt.lock_once) + return; /* Don't care; here IS_LOCKED is fixed to 1. */ + + if (!is_locked) + { + log_error ("Ooops, tdbio:release_write_lock with no lock held\n"); + return; + } + if (--is_locked) + return; + + if (dotlock_release (lockhandle)) + log_error ("Oops, tdbio:release_write_locked failed\n"); } + + /************************************* ************* record cache ********** @@ -329,6 +348,7 @@ put_record_into_cache (ulong recno, const char *data) } /* No clean entries: We have to flush some dirty entries. */ +#if 0 /* Transactions are not yet used. */ if (in_transaction) { /* But we can't do this while in a transaction. Thus we @@ -352,6 +372,7 @@ put_record_into_cache (ulong recno, const char *data) log_info (_("trustdb transaction too large\n")); return GPG_ERR_RESOURCE_LIMIT; } +#endif if (dirty_count) { @@ -418,8 +439,10 @@ tdbio_sync() if( db_fd == -1 ) open_db(); +#if 0 /* Transactions are not yet used. */ if( in_transaction ) log_bug("tdbio: syncing while in transaction\n"); +#endif if( !cache_is_dirty ) return 0; @@ -560,7 +583,7 @@ tdbio_update_version_record (ctrl_t ctrl) /* * Create and write the trustdb version record. - * + * This is called with the writelock activ. * Returns: 0 on success or an error code. */ static int @@ -951,10 +974,12 @@ tdbio_write_nextcheck (ctrl_t ctrl, ulong stamp) * Return: record number */ static ulong -get_trusthashrec(void) +get_trusthashrec (ctrl_t ctrl) { static ulong trusthashtbl; /* Record number of the trust hashtable. */ + (void)ctrl; + if (!trusthashtbl) { TRUSTREC vr; @@ -965,6 +990,20 @@ get_trusthashrec(void) log_fatal (_("%s: error reading version record: %s\n"), db_name, gpg_strerror (rc) ); + if (!vr.r.ver.trusthashtbl) + { + /* Oops: the trustdb is corrupt because the hashtable is + * always created along with the version record. However, + * if something went initially wrong it may happen that + * there is just the version record. We try to fix it here. + * If we can't do that we return 0 - this is the version + * record and thus the actual read will detect the mismatch + * and bail out. Note that create_hashtable updates VR. */ + take_write_lock (); + if (lseek (db_fd, 0, SEEK_END) == TRUST_RECORD_LEN) + create_hashtable (ctrl, &vr, 0); + release_write_lock (); + } trusthashtbl = vr.r.ver.trusthashtbl; } @@ -1269,6 +1308,13 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen, int msb; int level = 0; + if (!table) + { + rc = gpg_error (GPG_ERR_INV_RECORD); + log_error("lookup_hashtable failed: %s\n", "request for record 0"); + return rc; + } + hashrec = table; next_level: msb = key[level]; @@ -1358,7 +1404,7 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen, static int update_trusthashtbl (ctrl_t ctrl, TRUSTREC *tr) { - return upd_hashtable (ctrl, get_trusthashrec (), + return upd_hashtable (ctrl, get_trusthashrec (ctrl), tr->r.trust.fingerprint, 20, tr->recnum); } @@ -1441,7 +1487,7 @@ tdbio_dump_record (TRUSTREC *rec, estream_t fp) * EXPECTED is not 0 reading any other record type will return an * error. * - * Return: 0 on success, -1 on EOF, or an error code. + * Return: 0 on success or an error code. */ int tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected) @@ -1466,7 +1512,7 @@ tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected) n = read (db_fd, readbuf, TRUST_RECORD_LEN); if (!n) { - return -1; /* eof */ + return gpg_error (GPG_ERR_EOF); } else if (n != TRUST_RECORD_LEN) { @@ -1700,7 +1746,7 @@ tdbio_delete_record (ctrl_t ctrl, ulong recnum) ; else if (rec.rectype == RECTYPE_TRUST) { - rc = drop_from_hashtable (ctrl, get_trusthashrec(), + rc = drop_from_hashtable (ctrl, get_trusthashrec (ctrl), rec.r.trust.fingerprint, 20, rec.recnum); } @@ -1746,20 +1792,14 @@ tdbio_new_recnum (ctrl_t ctrl) recnum = vr.r.ver.firstfree; rc = tdbio_read_record (recnum, &rec, RECTYPE_FREE); if (rc) - { - log_error (_("%s: error reading free record: %s\n"), - db_name, gpg_strerror (rc)); - return rc; - } + log_fatal (_("%s: error reading free record: %s\n"), + db_name, gpg_strerror (rc)); /* Update dir record. */ vr.r.ver.firstfree = rec.r.free.next; rc = tdbio_write_record (ctrl, &vr); if (rc) - { - log_error (_("%s: error writing dir record: %s\n"), - db_name, gpg_strerror (rc)); - return rc; - } + log_fatal (_("%s: error writing dir record: %s\n"), + db_name, gpg_strerror (rc)); /* Zero out the new record. */ memset (&rec, 0, sizeof rec); rec.rectype = 0; /* Mark as unused record (actually already done @@ -1776,7 +1816,7 @@ tdbio_new_recnum (ctrl_t ctrl) if (offset == (off_t)(-1)) log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno)); recnum = offset / TRUST_RECORD_LEN; - log_assert (recnum); /* this is will never be the first record */ + log_assert (recnum); /* This will never be the first record */ /* We must write a record, so that the next call to this * function returns another recnum. */ memset (&rec, 0, sizeof rec); @@ -1798,13 +1838,13 @@ tdbio_new_recnum (ctrl_t ctrl) { rc = gpg_error_from_syserror (); log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"), - recnum, n, strerror (errno)); + recnum, n, gpg_strerror (rc)); } } if (rc) log_fatal (_("%s: failed to append a record: %s\n"), - db_name, gpg_strerror (rc)); + db_name, gpg_strerror (rc)); } return recnum ; @@ -1828,12 +1868,12 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec ) * Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code. */ gpg_error_t -tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec) +tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, TRUSTREC *rec) { int rc; /* Locate the trust record using the hash table */ - rc = lookup_hashtable (get_trusthashrec(), fingerprint, 20, + rc = lookup_hashtable (get_trusthashrec (ctrl), fingerprint, 20, cmp_trec_fpr, fingerprint, rec ); return rc; } @@ -1846,7 +1886,7 @@ tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec) * Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code. */ gpg_error_t -tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) +tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec) { byte fingerprint[MAX_FINGERPRINT_LEN]; size_t fingerlen; @@ -1854,7 +1894,7 @@ tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) fingerprint_from_pk( pk, fingerprint, &fingerlen ); for (; fingerlen < 20; fingerlen++) fingerprint[fingerlen] = 0; - return tdbio_search_trust_byfpr (fingerprint, rec); + return tdbio_search_trust_byfpr (ctrl, fingerprint, rec); } |