aboutsummaryrefslogtreecommitdiffstats
path: root/g10/tdbio.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/tdbio.c')
-rw-r--r--g10/tdbio.c110
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);
}