diff --git a/g10/tdbdump.c b/g10/tdbdump.c index bf9f3875b..f9a047351 100644 --- a/g10/tdbdump.c +++ b/g10/tdbdump.c @@ -46,8 +46,8 @@ (x) >= 'A' && (x) <= 'F' ? ((x)-'A'+10) : ((x)-'a'+10)) -/**************** - * Wirte a record but die on error +/* + * Write a record; die on error. */ static void write_record( TRUSTREC *rec ) @@ -65,7 +65,7 @@ write_record( TRUSTREC *rec ) * Dump the entire trustdb or only the entries of one key. */ void -list_trustdb( const char *username ) +list_trustdb (const char *username) { TRUSTREC rec; diff --git a/g10/tdbio.c b/g10/tdbio.c index 940165cc2..4d65e61e8 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -1,5 +1,6 @@ /* tdbio.c - trust database I/O operations * Copyright (C) 1998-2002, 2012 Free Software Foundation, Inc. + * Copyright (C) 1998-2015 Werner Koch * * This file is part of GnuPG. * @@ -56,50 +57,81 @@ #define strerror(a) ("[errno not available]") #endif -/**************** +/* * Yes, this is a very simple implementation. We should really * use a page aligned buffer and read complete pages. * To implement a simple trannsaction system, this is sufficient. */ typedef struct cache_ctrl_struct *CACHE_CTRL; -struct cache_ctrl_struct { - CACHE_CTRL next; - struct { - unsigned used:1; - unsigned dirty:1; - } flags; - ulong recno; - char data[TRUST_RECORD_LEN]; +struct cache_ctrl_struct +{ + CACHE_CTRL next; + struct { + unsigned used:1; + unsigned dirty:1; + } flags; + ulong recno; + char data[TRUST_RECORD_LEN]; }; -#define MAX_CACHE_ENTRIES_SOFT 200 /* may be increased while in a */ -#define MAX_CACHE_ENTRIES_HARD 10000 /* transaction to this one */ +/* Size of the cache. The SOFT value is the general one. While in a + transaction this may not be sufficient and thus we may increase it + then up to the HARD limit. */ +#define MAX_CACHE_ENTRIES_SOFT 200 +#define MAX_CACHE_ENTRIES_HARD 10000 + + +/* The cache is controlled by these variables. */ static CACHE_CTRL cache_list; static int cache_entries; static int cache_is_dirty; -/* a type used to pass infomation to cmp_krec_fpr */ -struct cmp_krec_fpr_struct { - int pubkey_algo; - const char *fpr; - int fprlen; + +/* An object to pass infomation to cmp_krec_fpr. */ +struct cmp_krec_fpr_struct +{ + int pubkey_algo; + const char *fpr; + int fprlen; }; -/* a type used to pass infomation to cmp_[s]dir */ -struct cmp_xdir_struct { - int pubkey_algo; - u32 keyid[2]; +/* An object used to pass infomation to cmp_[s]dir. */ +struct cmp_xdir_struct +{ + int pubkey_algo; + u32 keyid[2]; }; +/* 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. */ static dotlock_t lockhandle; static 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 void open_db(void); + +static void open_db (void); + + + +/* + * Take a lock on the trustdb file name. I a lock file can't be + * created the function terminates the process. Excvept for a + * different return code the function does nothing if the lock has + * already been taken. + * + * Returns: True if lock already exists, False if the lock has + * actually been taken. + */ static int take_write_lock (void) { @@ -120,6 +152,11 @@ take_write_lock (void) return 1; } + +/* + * Release a lock from the trustdb file unless the global option + * --lock-once has been used. + */ static void release_write_lock (void) { @@ -132,193 +169,245 @@ release_write_lock (void) ************* record cache ********** *************************************/ -/**************** - * Get the data from therecord cache and return a - * pointer into that cache. Caller should copy - * the return data. NULL is returned on a cache miss. +/* + * Get the data from the record cache and return a pointer into that + * cache. Caller should copy the returned data. NULL is returned on + * a cache miss. */ static const char * -get_record_from_cache( ulong recno ) +get_record_from_cache (ulong recno) { - CACHE_CTRL r; + CACHE_CTRL r; - for( r = cache_list; r; r = r->next ) { - if( r->flags.used && r->recno == recno ) - return r->data; + for (r = cache_list; r; r = r->next) + { + if (r->flags.used && r->recno == recno) + return r->data; } - return NULL; + return NULL; } +/* + * Write a cached item back to the trustdb file. + * + * Returns: 0 on success or an error code. + */ static int -write_cache_item( CACHE_CTRL r ) +write_cache_item (CACHE_CTRL r) { - gpg_error_t err; - int n; + gpg_error_t err; + int n; - if( lseek( db_fd, r->recno * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) { - err = gpg_error_from_syserror (); - log_error(_("trustdb rec %lu: lseek failed: %s\n"), - r->recno, strerror(errno) ); - return err; + if (lseek (db_fd, r->recno * TRUST_RECORD_LEN, SEEK_SET) == -1) + { + err = gpg_error_from_syserror (); + log_error (_("trustdb rec %lu: lseek failed: %s\n"), + r->recno, strerror (errno)); + return err; } - n = write( db_fd, r->data, TRUST_RECORD_LEN); - if( n != TRUST_RECORD_LEN ) { - err = gpg_error_from_syserror (); - log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"), - r->recno, n, strerror(errno) ); - return err; + n = write (db_fd, r->data, TRUST_RECORD_LEN); + if (n != TRUST_RECORD_LEN) + { + err = gpg_error_from_syserror (); + log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"), + r->recno, n, strerror (errno) ); + return err; } - r->flags.dirty = 0; - return 0; + r->flags.dirty = 0; + return 0; } -/**************** - * Put data into the cache. This function may flush the - * some cache entries if there is not enough space available. + +/* + * Put data into the cache. This function may flush + * some cache entries if the cache is filled up. + * + * Returns: 0 on success or an error code. */ int -put_record_into_cache( ulong recno, const char *data ) +put_record_into_cache (ulong recno, const char *data) { - CACHE_CTRL r, unused; - int dirty_count = 0; - int clean_count = 0; + CACHE_CTRL r, unused; + int dirty_count = 0; + int clean_count = 0; - /* see whether we already cached this one */ - for( unused = NULL, r = cache_list; r; r = r->next ) { - if( !r->flags.used ) { - if( !unused ) - unused = r; + /* See whether we already cached this one. */ + for (unused = NULL, r = cache_list; r; r = r->next) + { + if (!r->flags.used) + { + if (!unused) + unused = r; } - else if( r->recno == recno ) { - if( !r->flags.dirty ) { - /* Hmmm: should we use a a copy and compare? */ - if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) { - r->flags.dirty = 1; - cache_is_dirty = 1; + else if (r->recno == recno) + { + if (!r->flags.dirty) + { + /* Hmmm: should we use a copy and compare? */ + if (memcmp (r->data, data, TRUST_RECORD_LEN)) + { + r->flags.dirty = 1; + cache_is_dirty = 1; } } - memcpy( r->data, data, TRUST_RECORD_LEN ); - return 0; + memcpy (r->data, data, TRUST_RECORD_LEN); + return 0; } - if( r->flags.used ) { - if( r->flags.dirty ) - dirty_count++; - else - clean_count++; + if (r->flags.used) + { + if (r->flags.dirty) + dirty_count++; + else + clean_count++; } } - /* not in the cache: add a new entry */ - if( unused ) { /* reuse this entry */ - r = unused; - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - cache_is_dirty = 1; - cache_entries++; - return 0; + + /* Not in the cache: add a new entry. */ + if (unused) + { + /* Reuse this entry. */ + r = unused; + r->flags.used = 1; + r->recno = recno; + memcpy (r->data, data, TRUST_RECORD_LEN); + r->flags.dirty = 1; + cache_is_dirty = 1; + cache_entries++; + return 0; } - /* see whether we reached the limit */ - if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */ - r = xmalloc( sizeof *r ); - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - r->next = cache_list; - cache_list = r; - cache_is_dirty = 1; - cache_entries++; - return 0; + + /* See whether we reached the limit. */ + if (cache_entries < MAX_CACHE_ENTRIES_SOFT) + { + /* No: Put into cache. */ + r = xmalloc (sizeof *r); + r->flags.used = 1; + r->recno = recno; + memcpy (r->data, data, TRUST_RECORD_LEN); + r->flags.dirty = 1; + r->next = cache_list; + cache_list = r; + cache_is_dirty = 1; + cache_entries++; + return 0; } - /* cache is full: discard some clean entries */ - if( clean_count ) { - int n = clean_count / 3; /* discard a third of the clean entries */ - if( !n ) - n = 1; - for( unused = NULL, r = cache_list; r; r = r->next ) { - if( r->flags.used && !r->flags.dirty ) { - if( !unused ) - unused = r; - r->flags.used = 0; - cache_entries--; - if( !--n ) - break; + + /* Cache is full: discard some clean entries. */ + if (clean_count) + { + int n; + + /* We discard a third of the clean entries. */ + n = clean_count / 3; + if (!n) + n = 1; + + for (unused = NULL, r = cache_list; r; r = r->next) + { + if (r->flags.used && !r->flags.dirty) + { + if (!unused) + unused = r; + r->flags.used = 0; + cache_entries--; + if (!--n) + break; } } - assert( unused ); - r = unused; - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - cache_is_dirty = 1; - cache_entries++; - return 0; + + /* Now put into the cache. */ + assert (unused); + r = unused; + r->flags.used = 1; + r->recno = recno; + memcpy (r->data, data, TRUST_RECORD_LEN); + r->flags.dirty = 1; + cache_is_dirty = 1; + cache_entries++; + return 0; } - /* no clean entries: have to flush some dirty entries */ - if( in_transaction ) { - /* but we can't do this while in a transaction - * we increase the cache size instead */ - if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */ - if( opt.debug && !(cache_entries % 100) ) - log_debug("increasing tdbio cache size\n"); - r = xmalloc( sizeof *r ); - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - r->next = cache_list; - cache_list = r; - cache_is_dirty = 1; - cache_entries++; - return 0; + + /* No clean entries: We have to flush some dirty entries. */ + if (in_transaction) + { + /* But we can't do this while in a transaction. Thus we + * increase the cache size instead. */ + if (cache_entries < MAX_CACHE_ENTRIES_HARD) + { + if (opt.debug && !(cache_entries % 100)) + log_debug ("increasing tdbio cache size\n"); + r = xmalloc (sizeof *r); + r->flags.used = 1; + r->recno = recno; + memcpy (r->data, data, TRUST_RECORD_LEN); + r->flags.dirty = 1; + r->next = cache_list; + cache_list = r; + cache_is_dirty = 1; + cache_entries++; + return 0; } - log_info(_("trustdb transaction too large\n")); - return GPG_ERR_RESOURCE_LIMIT; + /* Hard limit for the cache size reached. */ + log_info (_("trustdb transaction too large\n")); + return GPG_ERR_RESOURCE_LIMIT; } - if( dirty_count ) { - int n = dirty_count / 5; /* discard some dirty entries */ - if( !n ) - n = 1; - take_write_lock (); - for( unused = NULL, r = cache_list; r; r = r->next ) { - if( r->flags.used && r->flags.dirty ) { - int rc = write_cache_item( r ); - if( rc ) - return rc; - if( !unused ) - unused = r; - r->flags.used = 0; - cache_entries--; - if( !--n ) - break; + + if (dirty_count) + { + int n; + + /* Discard some dirty entries. */ + n = dirty_count / 5; + if (!n) + n = 1; + + take_write_lock (); + for (unused = NULL, r = cache_list; r; r = r->next) + { + if (r->flags.used && r->flags.dirty) + { + int rc; + + rc = write_cache_item (r); + if (rc) + return rc; + if (!unused) + unused = r; + r->flags.used = 0; + cache_entries--; + if (!--n) + break; } } - release_write_lock (); - assert( unused ); - r = unused; - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - cache_is_dirty = 1; - cache_entries++; - return 0; + release_write_lock (); + + /* Now put into the cache. */ + assert (unused); + r = unused; + r->flags.used = 1; + r->recno = recno; + memcpy (r->data, data, TRUST_RECORD_LEN); + r->flags.dirty = 1; + cache_is_dirty = 1; + cache_entries++; + return 0; } - BUG(); + + /* We should never reach this. */ + BUG(); } +/* Return true if the cache is dirty. */ int tdbio_is_dirty() { - return cache_is_dirty; + return cache_is_dirty; } -/**************** +/* * Flush the cache. This cannot be used while in a transaction. */ int @@ -352,97 +441,109 @@ tdbio_sync() return 0; } -#if 0 -/* The transaction code is disabled in the 1.2.x branch, as it is not - yet used. It will be enabled in 1.3.x. */ -/**************** +#if 0 /* Not yet used. */ +/* * Simple transactions system: * Everything between begin_transaction and end/cancel_transaction * is not immediatly written but at the time of end_transaction. * + * NOTE: The transaction code is disabled in the 1.2 branch, as it is + * not yet used. */ int -tdbio_begin_transaction() +tdbio_begin_transaction () /* Not yet used. */ { - int rc; + int rc; - if( in_transaction ) - log_bug("tdbio: nested transactions\n"); - /* flush everything out */ - rc = tdbio_sync(); - if( rc ) - return rc; - in_transaction = 1; - return 0; -} - -int -tdbio_end_transaction() -{ - int rc; - - if( !in_transaction ) - log_bug("tdbio: no active transaction\n"); - take_write_lock (); - gnupg_block_all_signals(); - in_transaction = 0; - rc = tdbio_sync(); - gnupg_unblock_all_signals(); - release_write_lock (); + if (in_transaction) + log_bug ("tdbio: nested transactions\n"); + /* Flush everything out. */ + rc = tdbio_sync(); + if (rc) return rc; + in_transaction = 1; + return 0; } int -tdbio_cancel_transaction() +tdbio_end_transaction () /* Not yet used. */ { - CACHE_CTRL r; + int rc; - if( !in_transaction ) - log_bug("tdbio: no active transaction\n"); + if (!in_transaction) + log_bug ("tdbio: no active transaction\n"); + take_write_lock (); + gnupg_block_all_signals (); + in_transaction = 0; + rc = tdbio_sync(); + gnupg_unblock_all_signals(); + release_write_lock (); + return rc; +} - /* remove all dirty marked entries, so that the original ones - * are read back the next time */ - if( cache_is_dirty ) { - for( r = cache_list; r; r = r->next ) { - if( r->flags.used && r->flags.dirty ) { - r->flags.used = 0; - cache_entries--; +int +tdbio_cancel_transaction () /* Not yet used. */ +{ + CACHE_CTRL r; + + if (!in_transaction) + log_bug ("tdbio: no active transaction\n"); + + /* Remove all dirty marked entries, so that the original ones are + * read back the next time. */ + if (cache_is_dirty) + { + for (r = cache_list; r; r = r->next) + { + if (r->flags.used && r->flags.dirty) + { + r->flags.used = 0; + cache_entries--; } } - cache_is_dirty = 0; + cache_is_dirty = 0; } - in_transaction = 0; - return 0; + in_transaction = 0; + return 0; } -#endif +#endif /* Not yet used. */ + /******************************************************** **************** cached I/O functions ****************** ********************************************************/ +/* The cleanup handler for this module. */ static void -cleanup(void) +cleanup (void) { - if( is_locked ) { - if( !dotlock_release (lockhandle) ) - is_locked = 0; + if (is_locked) + { + if (!dotlock_release (lockhandle)) + is_locked = 0; } } -/* Caller must sync */ + +/* + * Update an existing trustdb record. The caller must call + * tdbio_sync. + * + * Returns: 0 on success or an error code. + */ int tdbio_update_version_record (void) { TRUSTREC rec; int rc; - memset( &rec, 0, sizeof rec ); + memset (&rec, 0, sizeof rec); - rc=tdbio_read_record( 0, &rec, RECTYPE_VER); - if(rc==0) + rc = tdbio_read_record (0, &rec, RECTYPE_VER); + if (!rc) { rec.r.ver.created = make_timestamp(); rec.r.ver.marginals = opt.marginals_needed; @@ -456,75 +557,97 @@ tdbio_update_version_record (void) return rc; } + +/* + * Create and write the trustdb version record. + * + * Returns: 0 on success or an error code. + */ static int create_version_record (void) { TRUSTREC rec; int rc; - memset( &rec, 0, sizeof rec ); + memset (&rec, 0, sizeof rec); rec.r.ver.version = 3; - rec.r.ver.created = make_timestamp(); + rec.r.ver.created = make_timestamp (); rec.r.ver.marginals = opt.marginals_needed; rec.r.ver.completes = opt.completes_needed; rec.r.ver.cert_depth = opt.max_cert_depth; - if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC) + if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC) rec.r.ver.trust_model = opt.trust_model; else rec.r.ver.trust_model = TM_PGP; rec.r.ver.min_cert_level = opt.min_cert_level; rec.rectype = RECTYPE_VER; rec.recnum = 0; - rc = tdbio_write_record( &rec ); - if( !rc ) - tdbio_sync(); + rc = tdbio_write_record (&rec); + if (!rc) + tdbio_sync (); return rc; } - +/* + * Set the file name for the trustdb to NEW_DBNAME and if CREATE is + * true create that file. If NEW_DBNAME is NULL a default name is + * used, if the it does not contain a path component separator ('/') + * the global GnuPG home directory is used. + * + * Returns: 0 on success or an error code. + * + * On the first call this function registers an atexit handler. + * + */ int -tdbio_set_dbname( const char *new_dbname, int create, int *r_nofile) +tdbio_set_dbname (const char *new_dbname, int create, int *r_nofile) { - char *fname; - struct stat statbuf; - static int initialized = 0; + char *fname; + struct stat statbuf; + static int initialized = 0; - if( !initialized ) { - atexit( cleanup ); - initialized = 1; + if (!initialized) + { + atexit (cleanup); + initialized = 1; } - *r_nofile = 0; + *r_nofile = 0; - if(new_dbname==NULL) - fname=make_filename(opt.homedir,"trustdb" EXTSEP_S GPGEXT_GPG, NULL); - else if (*new_dbname != DIRSEP_C ) - { - if (strchr(new_dbname, DIRSEP_C) ) - fname = make_filename (new_dbname, NULL); - else - fname = make_filename (opt.homedir, new_dbname, NULL); - } - else + if (!new_dbname) + { + fname = make_filename (opt.homedir, "trustdb" EXTSEP_S GPGEXT_GPG, NULL); + } + else if (*new_dbname != DIRSEP_C ) + { + if (strchr (new_dbname, DIRSEP_C)) + fname = make_filename (new_dbname, NULL); + else + fname = make_filename (opt.homedir, new_dbname, NULL); + } + else + { fname = xstrdup (new_dbname); + } - xfree (db_name); - db_name = fname; + xfree (db_name); + db_name = fname; - /* - * Quick check for (likely) case where there is trustdb.gpg - * already. This check is not required in theory, but it helps in - * practice, avoiding costly operations of preparing and taking - * the lock. - */ - if (stat (fname, &statbuf) == 0 && statbuf.st_size > 0) + /* Quick check for (likely) case where there already is a + * trustdb.gpg. This check is not required in theory, but it helps + * in practice avoiding costly operations of preparing and taking + * the lock. */ + if (!stat (fname, &statbuf) && statbuf.st_size > 0) + { /* OK, we have the valid trustdb.gpg already. */ return 0; + } - take_write_lock (); + take_write_lock (); - if( access( fname, R_OK ) ) { + if (access (fname, R_OK)) + { #ifdef HAVE_W32CE_SYSTEM /* We know how the cegcc implementation of access works ;-). */ if (GetLastError () == ERROR_FILE_NOT_FOUND) @@ -532,83 +655,93 @@ tdbio_set_dbname( const char *new_dbname, int create, int *r_nofile) else gpg_err_set_errno (EIO); #endif /*HAVE_W32CE_SYSTEM*/ - if( errno != ENOENT ) - log_fatal( _("can't access '%s': %s\n"), fname, strerror(errno) ); + if (errno != ENOENT) + log_fatal ( _("can't access '%s': %s\n"), fname, strerror (errno)); - if (!create) - *r_nofile = 1; - else { - FILE *fp; - TRUSTREC rec; - int rc; - char *p = strrchr( fname, DIRSEP_C ); - mode_t oldmask; - int save_slash; + if (!create) + *r_nofile = 1; + else + { + FILE *fp; + TRUSTREC rec; + int rc; + char *p = strrchr (fname, DIRSEP_C); + mode_t oldmask; + int save_slash; #if HAVE_W32_SYSTEM - { - /* Windows may either have a slash or a backslash. Take - care of it. */ - char *pp = strrchr (fname, '/'); - if (!p || pp > p) - p = pp; - } + { + /* Windows may either have a slash or a backslash. Take + care of it. */ + char *pp = strrchr (fname, '/'); + if (!p || pp > p) + p = pp; + } #endif /*HAVE_W32_SYSTEM*/ - assert (p); - save_slash = *p; - *p = 0; - if( access( fname, F_OK ) ) { - try_make_homedir( fname ); - if (access (fname, F_OK )) - log_fatal (_("%s: directory does not exist!\n"), fname); + assert (p); + save_slash = *p; + *p = 0; + if (access (fname, F_OK)) + { + try_make_homedir (fname); + if (access (fname, F_OK)) + log_fatal (_("%s: directory does not exist!\n"), fname); } - *p = save_slash; + *p = save_slash; - oldmask=umask(077); - if (is_secured_filename (fname)) { - fp = NULL; - gpg_err_set_errno (EPERM); + oldmask = umask (077); + if (is_secured_filename (fname)) + { + fp = NULL; + gpg_err_set_errno (EPERM); } - else - fp =fopen( fname, "wb" ); - umask(oldmask); - if( !fp ) - log_fatal (_("can't create '%s': %s\n"), - fname, strerror (errno)); - fclose(fp); - db_fd = open( db_name, O_RDWR | MY_O_BINARY ); - if( db_fd == -1 ) - log_fatal (_("can't open '%s': %s\n"), - db_name, strerror (errno)); + else + fp = fopen (fname, "wb"); + umask(oldmask); + if (!fp) + log_fatal (_("can't create '%s': %s\n"), fname, strerror (errno)); + fclose (fp); - rc = create_version_record (); - if( rc ) - log_fatal( _("%s: failed to create version record: %s"), - fname, gpg_strerror (rc)); - /* and read again to check that we are okay */ - if( tdbio_read_record( 0, &rec, RECTYPE_VER ) ) - log_fatal( _("%s: invalid trustdb created\n"), db_name ); + db_fd = open (db_name, O_RDWR | MY_O_BINARY); + if (db_fd == -1) + log_fatal (_("can't open '%s': %s\n"), db_name, strerror (errno)); - if( !opt.quiet ) - log_info(_("%s: trustdb created\n"), db_name); + rc = create_version_record (); + if (rc) + log_fatal (_("%s: failed to create version record: %s"), + fname, gpg_strerror (rc)); + + /* Read again to check that we are okay. */ + if (tdbio_read_record (0, &rec, RECTYPE_VER)) + log_fatal (_("%s: invalid trustdb created\n"), db_name); + + if (!opt.quiet) + log_info (_("%s: trustdb created\n"), db_name); } } - release_write_lock (); - return 0; + release_write_lock (); + return 0; } +/* + * Return the full name of the trustdb. + */ const char * -tdbio_get_dbname() +tdbio_get_dbname () { - return db_name; + return db_name; } - +/* + * Open the trustdb. This may only be called if it has not yet been + * opened and after a successful call to tdbio_set_dbname. On return + * the trustdb handle (DB_FD) is guaranteed to be open. + */ static void -open_db() +open_db () { TRUSTREC rec; @@ -653,58 +786,69 @@ open_db() } -/**************** - * Make a hashtable: type 0 = trust hash +/* + * Append a new empty hashtable to the trustdb. TYPE gives the type + * of the hash table. The only defined type is 0 for a trust hash. + * On return the hashtable has been created, written, the version + * record update, and the data flushed to the disk. On a fatal error + * the function terminates the process. */ static void create_hashtable( TRUSTREC *vr, int type ) { - TRUSTREC rec; - off_t offset; - ulong recnum; - int i, n, rc; + TRUSTREC rec; + off_t offset; + ulong recnum; + int i, n, rc; - offset = lseek( db_fd, 0, SEEK_END ); - if( offset == -1 ) - log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) ); - recnum = offset / TRUST_RECORD_LEN; - assert(recnum); /* this is will never be the first record */ + offset = lseek (db_fd, 0, SEEK_END); + if (offset == -1) + log_fatal ("trustdb: lseek to end failed: %s\n", strerror(errno)); + recnum = offset / TRUST_RECORD_LEN; + assert (recnum); /* This is will never be the first record. */ - if( !type ) - vr->r.ver.trusthashtbl = recnum; + if (!type) + vr->r.ver.trusthashtbl = recnum; - /* Now write the records */ - n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD; - for(i=0; i < n; i++, recnum++ ) { - memset( &rec, 0, sizeof rec ); - rec.rectype = RECTYPE_HTBL; - rec.recnum = recnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_fatal( _("%s: failed to create hashtable: %s\n"), - db_name, gpg_strerror (rc)); + /* Now write the records making up the hash table. */ + n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD; + for (i=0; i < n; i++, recnum++) + { + memset (&rec, 0, sizeof rec); + rec.rectype = RECTYPE_HTBL; + rec.recnum = recnum; + rc = tdbio_write_record (&rec); + if (rc) + log_fatal (_("%s: failed to create hashtable: %s\n"), + db_name, gpg_strerror (rc)); } - /* update the version record */ - rc = tdbio_write_record( vr ); - if( !rc ) - rc = tdbio_sync(); - if( rc ) - log_fatal( _("%s: error updating version record: %s\n"), - db_name, gpg_strerror (rc)); + /* Update the version record and flush. */ + rc = tdbio_write_record (vr); + if (!rc) + rc = tdbio_sync (); + if (rc) + log_fatal (_("%s: error updating version record: %s\n"), + db_name, gpg_strerror (rc)); } +/* + * Check whether open trustdb matches the global trust options given + * for this process. On a read problem the process is terminated. + * + * Return: 1 for yes, 0 for no. + */ int tdbio_db_matches_options() { static int yes_no = -1; - if( yes_no == -1 ) + if (yes_no == -1) { TRUSTREC vr; int rc; - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); + rc = tdbio_read_record (0, &vr, RECTYPE_VER); if( rc ) log_fatal( _("%s: error reading version record: %s\n"), db_name, gpg_strerror (rc) ); @@ -719,793 +863,933 @@ tdbio_db_matches_options() return yes_no; } + +/* + * Read and return the trust model identifier from the trustdb. On a + * read problem the process is terminated. + */ byte -tdbio_read_model(void) +tdbio_read_model (void) { TRUSTREC vr; int rc; - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), + rc = tdbio_read_record (0, &vr, RECTYPE_VER ); + if (rc) + log_fatal (_("%s: error reading version record: %s\n"), db_name, gpg_strerror (rc) ); return vr.r.ver.trust_model; } -/**************** - * Return the nextstamp value. + +/* + * Read and return the nextstamp value from the trustdb. On a read + * problem the process is terminated. */ ulong tdbio_read_nextcheck () { - TRUSTREC vr; - int rc; + TRUSTREC vr; + int rc; - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - db_name, gpg_strerror (rc)); - return vr.r.ver.nextcheck; + rc = tdbio_read_record (0, &vr, RECTYPE_VER); + if (rc) + log_fatal (_("%s: error reading version record: %s\n"), + db_name, gpg_strerror (rc)); + return vr.r.ver.nextcheck; } -/* Return true when the stamp was actually changed. */ + +/* + * Write the STAMP nextstamp timestamp to the trustdb. On a read or + * write problem the process is terminated. + * + * Return: True if the stamp actually changed. + */ int tdbio_write_nextcheck (ulong stamp) { - TRUSTREC vr; - int rc; + TRUSTREC vr; + int rc; - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - db_name, gpg_strerror (rc) ); + rc = tdbio_read_record (0, &vr, RECTYPE_VER); + if (rc) + log_fatal (_("%s: error reading version record: %s\n"), + db_name, gpg_strerror (rc)); - if (vr.r.ver.nextcheck == stamp) - return 0; + if (vr.r.ver.nextcheck == stamp) + return 0; - vr.r.ver.nextcheck = stamp; - rc = tdbio_write_record( &vr ); - if( rc ) - log_fatal( _("%s: error writing version record: %s\n"), - db_name, gpg_strerror (rc) ); - return 1; + vr.r.ver.nextcheck = stamp; + rc = tdbio_write_record( &vr ); + if (rc) + log_fatal (_("%s: error writing version record: %s\n"), + db_name, gpg_strerror (rc)); + return 1; } -/**************** - * Return the record number of the trusthash tbl or create a new one. +/* + * Return the record number of the trusthash table or create one if it + * does not yet exist. On a read or write problem the process is + * terminated. + * + * Return: record number */ static ulong get_trusthashrec(void) { - static ulong trusthashtbl; /* record number of the trust hashtable */ + static ulong trusthashtbl; /* Record number of the trust hashtable. */ - if( !trusthashtbl ) { - TRUSTREC vr; - int rc; + if (!trusthashtbl) + { + TRUSTREC vr; + int rc; - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - db_name, gpg_strerror (rc) ); - if( !vr.r.ver.trusthashtbl ) - create_hashtable( &vr, 0 ); + rc = tdbio_read_record (0, &vr, RECTYPE_VER ); + if (rc) + log_fatal (_("%s: error reading version record: %s\n"), + db_name, gpg_strerror (rc) ); + if (!vr.r.ver.trusthashtbl) + create_hashtable (&vr, 0); - trusthashtbl = vr.r.ver.trusthashtbl; + trusthashtbl = vr.r.ver.trusthashtbl; } - return trusthashtbl; + + return trusthashtbl; } -/**************** - * Update a hashtable. - * table gives the start of the table, key and keylen is the key, - * newrecnum is the record number to insert. +/* + * Update a hashtable in the trustdb. TABLE gives the start of the + * table, KEY and KEYLEN are the key, NEWRECNUM is the record number + * to insert into the table. + * + * Return: 0 on success or an error code. */ static int -upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum ) +upd_hashtable (ulong table, byte *key, int keylen, ulong newrecnum) { - TRUSTREC lastrec, rec; - ulong hashrec, item; - int msb; - int level=0; - int rc, i; + TRUSTREC lastrec, rec; + ulong hashrec, item; + int msb; + int level = 0; + int rc, i; - hashrec = table; - next_level: - msb = key[level]; - hashrec += msb / ITEMS_PER_HTBL_RECORD; - rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL ); - if( rc ) { - log_error("upd_hashtable: read failed: %s\n", gpg_strerror (rc) ); - return rc; + hashrec = table; + next_level: + msb = key[level]; + hashrec += msb / ITEMS_PER_HTBL_RECORD; + rc = tdbio_read_record (hashrec, &rec, RECTYPE_HTBL); + if (rc) + { + log_error ("upd_hashtable: read failed: %s\n", gpg_strerror (rc)); + return rc; } - item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; - if( !item ) { /* insert a new item into the hash table */ - rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum; - rc = tdbio_write_record( &rec ); - if( rc ) { - log_error("upd_hashtable: write htbl failed: %s\n", - gpg_strerror (rc) ); - return rc; + item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; + if (!item) /* Insert a new item into the hash table. */ + { + rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum; + rc = tdbio_write_record (&rec); + if (rc) + { + log_error ("upd_hashtable: write htbl failed: %s\n", + gpg_strerror (rc)); + return rc; } } - else if( item != newrecnum ) { /* must do an update */ - lastrec = rec; - rc = tdbio_read_record( item, &rec, 0 ); - if( rc ) { - log_error( "upd_hashtable: read item failed: %s\n", - gpg_strerror (rc) ); - return rc; + else if (item != newrecnum) /* Must do an update. */ + { + lastrec = rec; + rc = tdbio_read_record (item, &rec, 0); + if (rc) + { + log_error ("upd_hashtable: read item failed: %s\n", + gpg_strerror (rc)); + return rc; } - if( rec.rectype == RECTYPE_HTBL ) { - hashrec = item; - level++; - if( level >= keylen ) { - log_error( "hashtable has invalid indirections.\n"); - return GPG_ERR_TRUSTDB; + if (rec.rectype == RECTYPE_HTBL) + { + hashrec = item; + level++; + if (level >= keylen) + { + log_error ("hashtable has invalid indirections.\n"); + return GPG_ERR_TRUSTDB; } - goto next_level; + goto next_level; } - else if( rec.rectype == RECTYPE_HLST ) { /* extend list */ - /* see whether the key is already in this list */ - for(;;) { - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( rec.r.hlst.rnum[i] == newrecnum ) { - return 0; /* okay, already in the list */ + else if (rec.rectype == RECTYPE_HLST) /* Extend the list. */ + { + /* Check whether the key is already in this list. */ + for (;;) + { + for (i=0; i < ITEMS_PER_HLST_RECORD; i++) + { + if (rec.r.hlst.rnum[i] == newrecnum) + { + return 0; /* Okay, already in the list. */ } } - if( rec.r.hlst.next ) { - rc = tdbio_read_record( rec.r.hlst.next, - &rec, RECTYPE_HLST); - if( rc ) { - log_error ("upd_hashtable: read hlst failed: %s\n", - gpg_strerror (rc) ); - return rc; + if (rec.r.hlst.next) + { + rc = tdbio_read_record (rec.r.hlst.next, &rec, RECTYPE_HLST); + if (rc) + { + log_error ("upd_hashtable: read hlst failed: %s\n", + gpg_strerror (rc) ); + return rc; } } - else - break; /* not there */ + else + break; /* key is not in the list */ } - /* find the next free entry and put it in */ - for(;;) { - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( !rec.r.hlst.rnum[i] ) { - rec.r.hlst.rnum[i] = newrecnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_error ("upd_hashtable: write hlst failed: %s\n", - gpg_strerror (rc)); - return rc; /* done */ - } - } - if( rec.r.hlst.next ) { - rc = tdbio_read_record( rec.r.hlst.next, - &rec, RECTYPE_HLST ); - if( rc ) { - log_error ("upd_hashtable: read hlst failed: %s\n", + + /* Find the next free entry and put it in. */ + for (;;) + { + for (i=0; i < ITEMS_PER_HLST_RECORD; i++) + { + if (!rec.r.hlst.rnum[i]) + { + /* Empty slot found. */ + rec.r.hlst.rnum[i] = newrecnum; + rc = tdbio_write_record (&rec); + if (rc) + log_error ("upd_hashtable: write hlst failed: %s\n", gpg_strerror (rc)); - return rc; + return rc; /* Done. */ } } - else { /* add a new list record */ - rec.r.hlst.next = item = tdbio_new_recnum(); - rc = tdbio_write_record( &rec ); - if( rc ) { - log_error( "upd_hashtable: write hlst failed: %s\n", - gpg_strerror (rc) ); - return rc; + + if (rec.r.hlst.next) + { + /* read the next reord of the list. */ + rc = tdbio_read_record (rec.r.hlst.next, &rec, RECTYPE_HLST); + if (rc) + { + log_error ("upd_hashtable: read hlst failed: %s\n", + gpg_strerror (rc)); + return rc; } - memset( &rec, 0, sizeof rec ); - rec.rectype = RECTYPE_HLST; - rec.recnum = item; - rec.r.hlst.rnum[0] = newrecnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_error( "upd_hashtable: write ext hlst failed: %s\n", - gpg_strerror (rc) ); - return rc; /* done */ } - } /* end loop over hlst slots */ + else + { + /* Append a new record to the list. */ + rec.r.hlst.next = item = tdbio_new_recnum (); + rc = tdbio_write_record (&rec); + if (rc) + { + log_error ("upd_hashtable: write hlst failed: %s\n", + gpg_strerror (rc)); + return rc; + } + memset (&rec, 0, sizeof rec); + rec.rectype = RECTYPE_HLST; + rec.recnum = item; + rec.r.hlst.rnum[0] = newrecnum; + rc = tdbio_write_record (&rec); + if (rc) + log_error ("upd_hashtable: write ext hlst failed: %s\n", + gpg_strerror (rc)); + return rc; /* Done. */ + } + } /* end loop over list slots */ + } - else if( rec.rectype == RECTYPE_TRUST ) { /* insert a list record */ - if( rec.recnum == newrecnum ) { - return 0; - } - item = rec.recnum; /* save number of key record */ - memset( &rec, 0, sizeof rec ); - rec.rectype = RECTYPE_HLST; - rec.recnum = tdbio_new_recnum(); - rec.r.hlst.rnum[0] = item; /* old keyrecord */ - rec.r.hlst.rnum[1] = newrecnum; /* and new one */ - rc = tdbio_write_record( &rec ); - if( rc ) { - log_error( "upd_hashtable: write new hlst failed: %s\n", - gpg_strerror (rc) ); - return rc; - } - /* update the hashtable record */ - lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum; - rc = tdbio_write_record( &lastrec ); - if( rc ) - log_error ("upd_hashtable: update htbl failed: %s\n", - gpg_strerror (rc)); - return rc; /* ready */ - } - else { - log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n", - table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); - list_trustdb(NULL); - return GPG_ERR_TRUSTDB; + else if (rec.rectype == RECTYPE_TRUST) /* Insert a list record. */ + { + if (rec.recnum == newrecnum) + { + return 0; + } + item = rec.recnum; /* Save number of key record. */ + memset (&rec, 0, sizeof rec); + rec.rectype = RECTYPE_HLST; + rec.recnum = tdbio_new_recnum (); + rec.r.hlst.rnum[0] = item; /* Old key record */ + rec.r.hlst.rnum[1] = newrecnum; /* and new key record */ + rc = tdbio_write_record (&rec); + if (rc) + { + log_error( "upd_hashtable: write new hlst failed: %s\n", + gpg_strerror (rc) ); + return rc; + } + /* Update the hashtable record. */ + lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum; + rc = tdbio_write_record (&lastrec); + if (rc) + log_error ("upd_hashtable: update htbl failed: %s\n", + gpg_strerror (rc)); + return rc; /* Ready. */ + } + else + { + log_error ("hashtbl %lu: %lu/%d points to an invalid record %lu\n", + table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); + list_trustdb (NULL); /*FIXME: Bad - prints to stdout!!! */ + return GPG_ERR_TRUSTDB; } } - return 0; + return 0; } -/**************** - * Drop an entry from a hashtable - * table gives the start of the table, key and keylen is the key, +/* + * Drop an entry from a hashtable. TABLE gives the start of the + * table, KEY and KEYLEN are the key. + * + * Return: 0 on success or an error code. */ static int -drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum ) +drop_from_hashtable (ulong table, byte *key, int keylen, ulong recnum) { - TRUSTREC rec; - ulong hashrec, item; - int msb; - int level=0; - int rc, i; + TRUSTREC rec; + ulong hashrec, item; + int msb; + int level = 0; + int rc, i; - hashrec = table; - next_level: - msb = key[level]; - hashrec += msb / ITEMS_PER_HTBL_RECORD; - rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL ); - if( rc ) { - log_error("drop_from_hashtable: read failed: %s\n", - gpg_strerror (rc) ); - return rc; + hashrec = table; + next_level: + msb = key[level]; + hashrec += msb / ITEMS_PER_HTBL_RECORD; + rc = tdbio_read_record (hashrec, &rec, RECTYPE_HTBL ); + if (rc) + { + log_error ("drop_from_hashtable: read failed: %s\n", gpg_strerror (rc)); + return rc; } - item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; - if( !item ) /* not found - forget about it */ - return 0; + item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; + if (!item) + return 0; /* Not found - forget about it. */ - if( item == recnum ) { /* tables points direct to the record */ - rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0; - rc = tdbio_write_record( &rec ); - if( rc ) - log_error("drop_from_hashtable: write htbl failed: %s\n", - gpg_strerror (rc) ); - return rc; + if (item == recnum) /* Table points direct to the record. */ + { + rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0; + rc = tdbio_write_record( &rec ); + if (rc) + log_error ("drop_from_hashtable: write htbl failed: %s\n", + gpg_strerror (rc)); + return rc; } - rc = tdbio_read_record( item, &rec, 0 ); - if( rc ) { - log_error( "drop_from_hashtable: read item failed: %s\n", - gpg_strerror (rc) ); - return rc; + rc = tdbio_read_record (item, &rec, 0); + if (rc) + { + log_error ("drop_from_hashtable: read item failed: %s\n", + gpg_strerror (rc)); + return rc; } - if( rec.rectype == RECTYPE_HTBL ) { - hashrec = item; - level++; - if( level >= keylen ) { - log_error( "hashtable has invalid indirections.\n"); - return GPG_ERR_TRUSTDB; + if (rec.rectype == RECTYPE_HTBL) + { + hashrec = item; + level++; + if (level >= keylen) + { + log_error ("hashtable has invalid indirections.\n"); + return GPG_ERR_TRUSTDB; } - goto next_level; + goto next_level; } - if( rec.rectype == RECTYPE_HLST ) { - for(;;) { - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( rec.r.hlst.rnum[i] == recnum ) { - rec.r.hlst.rnum[i] = 0; /* drop */ - rc = tdbio_write_record( &rec ); - if( rc ) - log_error("drop_from_hashtable: write htbl failed: %s\n", - gpg_strerror (rc)); - return rc; + if (rec.rectype == RECTYPE_HLST) + { + for (;;) + { + for (i=0; i < ITEMS_PER_HLST_RECORD; i++) + { + if (rec.r.hlst.rnum[i] == recnum) + { + rec.r.hlst.rnum[i] = 0; /* Mark as free. */ + rc = tdbio_write_record (&rec); + if (rc) + log_error("drop_from_hashtable: write htbl failed: %s\n", + gpg_strerror (rc)); + return rc; } } - if( rec.r.hlst.next ) { - rc = tdbio_read_record( rec.r.hlst.next, - &rec, RECTYPE_HLST); - if( rc ) { - log_error( "drop_from_hashtable: read hlst failed: %s\n", - gpg_strerror (rc) ); - return rc; + if (rec.r.hlst.next) + { + rc = tdbio_read_record (rec.r.hlst.next, &rec, RECTYPE_HLST); + if (rc) + { + log_error ("drop_from_hashtable: read hlst failed: %s\n", + gpg_strerror (rc)); + return rc; } } - else - return 0; /* key not in table */ + else + return 0; /* Key not in table. */ } } - log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n", - table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); - return GPG_ERR_TRUSTDB; + log_error ("hashtbl %lu: %lu/%d points to wrong record %lu\n", + table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); + return GPG_ERR_TRUSTDB; } -/**************** - * Lookup a record via the hashtable tablewith key/keylen and return the - * result in rec. cmp() should return if the record is the desired one. - * Returns -1 if not found, 0 if found or another errocode +/* + * Lookup a record via the hashtable TABLE by (KEY,KEYLEN) and return + * the result in REC. The return value of CMP() should be True if the + * record is the desired one. + * + * Return: -1 if not found, 0 if found or another error code. + * FIXME: Use GPG_ERR_NOT_FOUND instead of -1. */ static int -lookup_hashtable( ulong table, const byte *key, size_t keylen, +lookup_hashtable (ulong table, const byte *key, size_t keylen, int (*cmpfnc)(const void*, const TRUSTREC *), const void *cmpdata, TRUSTREC *rec ) { - int rc; - ulong hashrec, item; - int msb; - int level=0; + int rc; + ulong hashrec, item; + int msb; + int level = 0; - hashrec = table; - next_level: - msb = key[level]; - hashrec += msb / ITEMS_PER_HTBL_RECORD; - rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL ); - if( rc ) { - log_error("lookup_hashtable failed: %s\n", gpg_strerror (rc) ); - return rc; + hashrec = table; + next_level: + msb = key[level]; + hashrec += msb / ITEMS_PER_HTBL_RECORD; + rc = tdbio_read_record (hashrec, rec, RECTYPE_HTBL); + if (rc) + { + log_error("lookup_hashtable failed: %s\n", gpg_strerror (rc) ); + return rc; } - item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; - if( !item ) - return -1; /* not found */ + item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; + if (!item) + return -1; /* Not found. */ - rc = tdbio_read_record( item, rec, 0 ); - if( rc ) { - log_error( "hashtable read failed: %s\n", gpg_strerror (rc) ); - return rc; + rc = tdbio_read_record (item, rec, 0); + if (rc) + { + log_error( "hashtable read failed: %s\n", gpg_strerror (rc) ); + return rc; } - if( rec->rectype == RECTYPE_HTBL ) { - hashrec = item; - level++; - if( level >= keylen ) { - log_error("hashtable has invalid indirections\n"); - return GPG_ERR_TRUSTDB; + if (rec->rectype == RECTYPE_HTBL) + { + hashrec = item; + level++; + if (level >= keylen) + { + log_error ("hashtable has invalid indirections\n"); + return GPG_ERR_TRUSTDB; } - goto next_level; + goto next_level; } - else if( rec->rectype == RECTYPE_HLST ) { - for(;;) { - int i; + else if (rec->rectype == RECTYPE_HLST) + { + for (;;) + { + int i; - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( rec->r.hlst.rnum[i] ) { - TRUSTREC tmp; + for (i=0; i < ITEMS_PER_HLST_RECORD; i++) + { + if (rec->r.hlst.rnum[i]) + { + TRUSTREC tmp; - rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 ); - if( rc ) { - log_error ("lookup_hashtable: read item failed: %s\n", - gpg_strerror (rc)); - return rc; + rc = tdbio_read_record (rec->r.hlst.rnum[i], &tmp, 0); + if (rc) + { + log_error ("lookup_hashtable: read item failed: %s\n", + gpg_strerror (rc)); + return rc; } - if( (*cmpfnc)( cmpdata, &tmp ) ) { - *rec = tmp; - return 0; + if ((*cmpfnc)(cmpdata, &tmp)) + { + *rec = tmp; + return 0; } } } - if( rec->r.hlst.next ) { - rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST ); - if( rc ) { - log_error ("lookup_hashtable: read hlst failed: %s\n", - gpg_strerror (rc) ); - return rc; + if (rec->r.hlst.next) + { + rc = tdbio_read_record (rec->r.hlst.next, rec, RECTYPE_HLST); + if (rc) + { + log_error ("lookup_hashtable: read hlst failed: %s\n", + gpg_strerror (rc) ); + return rc; } } - else - return -1; /* not found */ + else + return -1; /* not found */ } } + if ((*cmpfnc)(cmpdata, rec)) + return 0; /* really found */ - if( (*cmpfnc)( cmpdata, rec ) ) - return 0; /* really found */ - - return -1; /* no: not found */ + return -1; /* no: not found */ } -/**************** - * Update the trust hashtbl or create the table if it does not exist +/* + * Update the trust hash table TR or create the table if it does not + * exist. + * + * Return: 0 on success or an error code. */ static int update_trusthashtbl( TRUSTREC *tr ) { - return upd_hashtable( get_trusthashrec(), - tr->r.trust.fingerprint, 20, tr->recnum ); + return upd_hashtable (get_trusthashrec(), + tr->r.trust.fingerprint, 20, tr->recnum); } - +/* + * Dump the trustdb record REC to stream FP. + */ void tdbio_dump_record (TRUSTREC *rec, estream_t fp) { - int i; - ulong rnum = rec->recnum; + int i; + ulong rnum = rec->recnum; - es_fprintf ( fp, "rec %5lu, ", rnum ); + es_fprintf (fp, "rec %5lu, ", rnum); - switch( rec->rectype ) { - case 0: - es_fprintf (fp, "blank\n"); - break; - case RECTYPE_VER: - es_fprintf (fp, + switch (rec->rectype) + { + case 0: + es_fprintf (fp, "blank\n"); + break; + + case RECTYPE_VER: + es_fprintf (fp, "version, td=%lu, f=%lu, m/c/d=%d/%d/%d tm=%d mcl=%d nc=%lu (%s)\n", - rec->r.ver.trusthashtbl, - rec->r.ver.firstfree, - rec->r.ver.marginals, - rec->r.ver.completes, - rec->r.ver.cert_depth, - rec->r.ver.trust_model, - rec->r.ver.min_cert_level, - rec->r.ver.nextcheck, - strtimestamp(rec->r.ver.nextcheck) - ); - break; - case RECTYPE_FREE: - es_fprintf (fp, "free, next=%lu\n", rec->r.free.next ); - break; - case RECTYPE_HTBL: - es_fprintf (fp, "htbl,"); - for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) - es_fprintf (fp, " %lu", rec->r.htbl.item[i] ); - es_putc ('\n', fp); - break; - case RECTYPE_HLST: - es_fprintf (fp, "hlst, next=%lu,", rec->r.hlst.next ); - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) - es_fprintf (fp, " %lu", rec->r.hlst.rnum[i] ); - es_putc ('\n', fp); - break; - case RECTYPE_TRUST: - es_fprintf (fp, "trust "); - for(i=0; i < 20; i++ ) - es_fprintf (fp, "%02X", rec->r.trust.fingerprint[i] ); - es_fprintf (fp, ", ot=%d, d=%d, vl=%lu\n", rec->r.trust.ownertrust, - rec->r.trust.depth, rec->r.trust.validlist); - break; - case RECTYPE_VALID: - es_fprintf (fp, "valid "); - for(i=0; i < 20; i++ ) - es_fprintf(fp, "%02X", rec->r.valid.namehash[i] ); - es_fprintf (fp, ", v=%d, next=%lu\n", rec->r.valid.validity, - rec->r.valid.next); - break; - default: - es_fprintf (fp, "unknown type %d\n", rec->rectype ); - break; + rec->r.ver.trusthashtbl, + rec->r.ver.firstfree, + rec->r.ver.marginals, + rec->r.ver.completes, + rec->r.ver.cert_depth, + rec->r.ver.trust_model, + rec->r.ver.min_cert_level, + rec->r.ver.nextcheck, + strtimestamp(rec->r.ver.nextcheck) + ); + break; + + case RECTYPE_FREE: + es_fprintf (fp, "free, next=%lu\n", rec->r.free.next); + break; + + case RECTYPE_HTBL: + es_fprintf (fp, "htbl,"); + for (i=0; i < ITEMS_PER_HTBL_RECORD; i++) + es_fprintf (fp, " %lu", rec->r.htbl.item[i]); + es_putc ('\n', fp); + break; + + case RECTYPE_HLST: + es_fprintf (fp, "hlst, next=%lu,", rec->r.hlst.next); + for (i=0; i < ITEMS_PER_HLST_RECORD; i++) + es_fprintf (fp, " %lu", rec->r.hlst.rnum[i]); + es_putc ('\n', fp); + break; + + case RECTYPE_TRUST: + es_fprintf (fp, "trust "); + for (i=0; i < 20; i++) + es_fprintf (fp, "%02X", rec->r.trust.fingerprint[i]); + es_fprintf (fp, ", ot=%d, d=%d, vl=%lu\n", rec->r.trust.ownertrust, + rec->r.trust.depth, rec->r.trust.validlist); + break; + + case RECTYPE_VALID: + es_fprintf (fp, "valid "); + for (i=0; i < 20; i++) + es_fprintf(fp, "%02X", rec->r.valid.namehash[i]); + es_fprintf (fp, ", v=%d, next=%lu\n", rec->r.valid.validity, + rec->r.valid.next); + break; + + default: + es_fprintf (fp, "unknown type %d\n", rec->rectype ); + break; } } -/**************** - * read the record with number recnum - * returns: -1 on error, 0 on success + +/* + * Read the record with number RECNUM into the structure REC. If + * EXPECTED is not 0 reading any other record type will return an + * error. + * + * Return: 0 on success, -1 on EOF, or an error code. */ int -tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) +tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected) { - byte readbuf[TRUST_RECORD_LEN]; - const byte *buf, *p; - gpg_error_t err = 0; - int n, i; + byte readbuf[TRUST_RECORD_LEN]; + const byte *buf, *p; + gpg_error_t err = 0; + int n, i; - if( db_fd == -1 ) - open_db(); - buf = get_record_from_cache( recnum ); - if( !buf ) { - if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) { - err = gpg_error_from_syserror (); - log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) ); - return err; + if (db_fd == -1) + open_db (); + + buf = get_record_from_cache( recnum ); + if (!buf) + { + if (lseek (db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET) == -1) + { + err = gpg_error_from_syserror (); + log_error (_("trustdb: lseek failed: %s\n"), strerror (errno)); + return err; } - n = read( db_fd, readbuf, TRUST_RECORD_LEN); - if( !n ) { - return -1; /* eof */ + n = read (db_fd, readbuf, TRUST_RECORD_LEN); + if (!n) + { + return -1; /* eof */ } - else if( n != TRUST_RECORD_LEN ) { - err = gpg_error_from_syserror (); - log_error(_("trustdb: read failed (n=%d): %s\n"), n, - strerror(errno) ); - return err; + else if (n != TRUST_RECORD_LEN) + { + err = gpg_error_from_syserror (); + log_error (_("trustdb: read failed (n=%d): %s\n"), + n, strerror(errno)); + return err; } - buf = readbuf; + buf = readbuf; } - rec->recnum = recnum; - rec->dirty = 0; - p = buf; - rec->rectype = *p++; - if( expected && rec->rectype != expected ) { - log_error("%lu: read expected rec type %d, got %d\n", - recnum, expected, rec->rectype ); - return gpg_error (GPG_ERR_TRUSTDB); + rec->recnum = recnum; + rec->dirty = 0; + p = buf; + rec->rectype = *p++; + if (expected && rec->rectype != expected) + { + log_error ("%lu: read expected rec type %d, got %d\n", + recnum, expected, rec->rectype); + return gpg_error (GPG_ERR_TRUSTDB); } - p++; /* skip reserved byte */ - switch( rec->rectype ) { - case 0: /* unused (free) record */ - break; - case RECTYPE_VER: /* version record */ - if( memcmp(buf+1, GPGEXT_GPG, 3 ) ) { - log_error( _("%s: not a trustdb file\n"), db_name ); - err = gpg_error (GPG_ERR_TRUSTDB); + p++; /* Skip reserved byte. */ + switch (rec->rectype) + { + case 0: /* unused (free) record */ + break; + + case RECTYPE_VER: /* version record */ + if (memcmp(buf+1, GPGEXT_GPG, 3)) + { + log_error (_("%s: not a trustdb file\n"), db_name ); + err = gpg_error (GPG_ERR_TRUSTDB); + /* FIXME ^ */ + } + p += 2; /* skip "gpg" */ + rec->r.ver.version = *p++; + rec->r.ver.marginals = *p++; + rec->r.ver.completes = *p++; + rec->r.ver.cert_depth = *p++; + rec->r.ver.trust_model = *p++; + rec->r.ver.min_cert_level = *p++; + p += 2; + rec->r.ver.created = buf32_to_ulong(p); p += 4; + rec->r.ver.nextcheck = buf32_to_ulong(p); p += 4; + p += 4; + p += 4; + rec->r.ver.firstfree =buf32_to_ulong(p); p += 4; + p += 4; + rec->r.ver.trusthashtbl =buf32_to_ulong(p); p += 4; + if (recnum) + { + log_error( _("%s: version record with recnum %lu\n"), db_name, + (ulong)recnum ); + err = gpg_error (GPG_ERR_TRUSTDB); } - p += 2; /* skip "gpg" */ - rec->r.ver.version = *p++; - rec->r.ver.marginals = *p++; - rec->r.ver.completes = *p++; - rec->r.ver.cert_depth = *p++; - rec->r.ver.trust_model = *p++; - rec->r.ver.min_cert_level = *p++; - p += 2; - rec->r.ver.created = buf32_to_ulong(p); p += 4; - rec->r.ver.nextcheck = buf32_to_ulong(p); p += 4; - p += 4; - p += 4; - rec->r.ver.firstfree =buf32_to_ulong(p); p += 4; - p += 4; - rec->r.ver.trusthashtbl =buf32_to_ulong(p); p += 4; - if( recnum ) { - log_error( _("%s: version record with recnum %lu\n"), db_name, - (ulong)recnum ); - err = gpg_error (GPG_ERR_TRUSTDB); + else if (rec->r.ver.version != 3) + { + log_error( _("%s: invalid file version %d\n"), db_name, + rec->r.ver.version ); + err = gpg_error (GPG_ERR_TRUSTDB); + } + break; + + case RECTYPE_FREE: + rec->r.free.next = buf32_to_ulong(p); p += 4; + break; + + case RECTYPE_HTBL: + for (i=0; i < ITEMS_PER_HTBL_RECORD; i++) + { + rec->r.htbl.item[i] = buf32_to_ulong(p); p += 4; } - else if( rec->r.ver.version != 3 ) { - log_error( _("%s: invalid file version %d\n"), db_name, - rec->r.ver.version ); - err = gpg_error (GPG_ERR_TRUSTDB); + break; + + case RECTYPE_HLST: + rec->r.hlst.next = buf32_to_ulong(p); p += 4; + for (i=0; i < ITEMS_PER_HLST_RECORD; i++) + { + rec->r.hlst.rnum[i] = buf32_to_ulong(p); p += 4; } - break; - case RECTYPE_FREE: - rec->r.free.next = buf32_to_ulong(p); p += 4; - break; - case RECTYPE_HTBL: - for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) { - rec->r.htbl.item[i] = buf32_to_ulong(p); p += 4; - } - break; - case RECTYPE_HLST: - rec->r.hlst.next = buf32_to_ulong(p); p += 4; - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - rec->r.hlst.rnum[i] = buf32_to_ulong(p); p += 4; - } - break; - case RECTYPE_TRUST: - memcpy( rec->r.trust.fingerprint, p, 20); p+=20; - rec->r.trust.ownertrust = *p++; - rec->r.trust.depth = *p++; - rec->r.trust.min_ownertrust = *p++; - p++; - rec->r.trust.validlist = buf32_to_ulong(p); p += 4; - break; - case RECTYPE_VALID: - memcpy( rec->r.valid.namehash, p, 20); p+=20; - rec->r.valid.validity = *p++; - rec->r.valid.next = buf32_to_ulong(p); p += 4; - rec->r.valid.full_count = *p++; - rec->r.valid.marginal_count = *p++; - break; - default: - log_error( "%s: invalid record type %d at recnum %lu\n", - db_name, rec->rectype, (ulong)recnum ); - err = gpg_error (GPG_ERR_TRUSTDB); - break; + break; + + case RECTYPE_TRUST: + memcpy (rec->r.trust.fingerprint, p, 20); p+=20; + rec->r.trust.ownertrust = *p++; + rec->r.trust.depth = *p++; + rec->r.trust.min_ownertrust = *p++; + p++; + rec->r.trust.validlist = buf32_to_ulong(p); p += 4; + break; + + case RECTYPE_VALID: + memcpy (rec->r.valid.namehash, p, 20); p+=20; + rec->r.valid.validity = *p++; + rec->r.valid.next = buf32_to_ulong(p); p += 4; + rec->r.valid.full_count = *p++; + rec->r.valid.marginal_count = *p++; + break; + + default: + log_error ("%s: invalid record type %d at recnum %lu\n", + db_name, rec->rectype, (ulong)recnum); + err = gpg_error (GPG_ERR_TRUSTDB); + break; } - return err; + return err; } -/**************** - * Write the record at RECNUM + +/* + * Write the record from the struct REC. + * + * Return: 0 on success or an error code. */ int tdbio_write_record( TRUSTREC *rec ) { - byte buf[TRUST_RECORD_LEN], *p; - int rc = 0; - int i; - ulong recnum = rec->recnum; + byte buf[TRUST_RECORD_LEN]; + byte *p; + int rc = 0; + int i; + ulong recnum = rec->recnum; - if( db_fd == -1 ) - open_db(); + if (db_fd == -1) + open_db (); - memset(buf, 0, TRUST_RECORD_LEN); - p = buf; - *p++ = rec->rectype; p++; - switch( rec->rectype ) { - case 0: /* unused record */ - break; - case RECTYPE_VER: /* version record */ - if( recnum ) - BUG(); - memcpy(p-1, GPGEXT_GPG, 3 ); p += 2; - *p++ = rec->r.ver.version; - *p++ = rec->r.ver.marginals; - *p++ = rec->r.ver.completes; - *p++ = rec->r.ver.cert_depth; - *p++ = rec->r.ver.trust_model; - *p++ = rec->r.ver.min_cert_level; - p += 2; - ulongtobuf(p, rec->r.ver.created); p += 4; - ulongtobuf(p, rec->r.ver.nextcheck); p += 4; - p += 4; - p += 4; - ulongtobuf(p, rec->r.ver.firstfree ); p += 4; - p += 4; - ulongtobuf(p, rec->r.ver.trusthashtbl ); p += 4; - break; + memset (buf, 0, TRUST_RECORD_LEN); + p = buf; + *p++ = rec->rectype; p++; - case RECTYPE_FREE: - ulongtobuf(p, rec->r.free.next); p += 4; - break; + switch (rec->rectype) + { + case 0: /* unused record */ + break; + case RECTYPE_VER: /* version record */ + if (recnum) + BUG (); + memcpy(p-1, GPGEXT_GPG, 3 ); p += 2; + *p++ = rec->r.ver.version; + *p++ = rec->r.ver.marginals; + *p++ = rec->r.ver.completes; + *p++ = rec->r.ver.cert_depth; + *p++ = rec->r.ver.trust_model; + *p++ = rec->r.ver.min_cert_level; + p += 2; + ulongtobuf(p, rec->r.ver.created); p += 4; + ulongtobuf(p, rec->r.ver.nextcheck); p += 4; + p += 4; + p += 4; + ulongtobuf(p, rec->r.ver.firstfree ); p += 4; + p += 4; + ulongtobuf(p, rec->r.ver.trusthashtbl ); p += 4; + break; - case RECTYPE_HTBL: - for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) { - ulongtobuf( p, rec->r.htbl.item[i]); p += 4; + case RECTYPE_FREE: + ulongtobuf(p, rec->r.free.next); p += 4; + break; + + case RECTYPE_HTBL: + for (i=0; i < ITEMS_PER_HTBL_RECORD; i++) + { + ulongtobuf( p, rec->r.htbl.item[i]); p += 4; + } + break; + + case RECTYPE_HLST: + ulongtobuf( p, rec->r.hlst.next); p += 4; + for (i=0; i < ITEMS_PER_HLST_RECORD; i++ ) + { + ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4; } - break; + break; - case RECTYPE_HLST: - ulongtobuf( p, rec->r.hlst.next); p += 4; - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4; - } - break; + case RECTYPE_TRUST: + memcpy (p, rec->r.trust.fingerprint, 20); p += 20; + *p++ = rec->r.trust.ownertrust; + *p++ = rec->r.trust.depth; + *p++ = rec->r.trust.min_ownertrust; + p++; + ulongtobuf( p, rec->r.trust.validlist); p += 4; + break; - case RECTYPE_TRUST: - memcpy( p, rec->r.trust.fingerprint, 20); p += 20; - *p++ = rec->r.trust.ownertrust; - *p++ = rec->r.trust.depth; - *p++ = rec->r.trust.min_ownertrust; - p++; - ulongtobuf( p, rec->r.trust.validlist); p += 4; - break; + case RECTYPE_VALID: + memcpy (p, rec->r.valid.namehash, 20); p += 20; + *p++ = rec->r.valid.validity; + ulongtobuf( p, rec->r.valid.next); p += 4; + *p++ = rec->r.valid.full_count; + *p++ = rec->r.valid.marginal_count; + break; - case RECTYPE_VALID: - memcpy( p, rec->r.valid.namehash, 20); p += 20; - *p++ = rec->r.valid.validity; - ulongtobuf( p, rec->r.valid.next); p += 4; - *p++ = rec->r.valid.full_count; - *p++ = rec->r.valid.marginal_count; - break; - - default: - BUG(); + default: + BUG(); } - rc = put_record_into_cache( recnum, buf ); - if( rc ) - ; - else if( rec->rectype == RECTYPE_TRUST ) - rc = update_trusthashtbl( rec ); + rc = put_record_into_cache (recnum, buf); + if (rc) + ; + else if (rec->rectype == RECTYPE_TRUST) + rc = update_trusthashtbl (rec); - return rc; + return rc; } + +/* + * Delete the record at record number RECNUm from the trustdb. + * + * Return: 0 on success or an error code. + */ int -tdbio_delete_record( ulong recnum ) +tdbio_delete_record (ulong recnum) { - TRUSTREC vr, rec; - int rc; + TRUSTREC vr, rec; + int rc; - /* Must read the record fist, so we can drop it from the hash tables */ - rc = tdbio_read_record( recnum, &rec, 0 ); - if( rc ) - ; - else if( rec.rectype == RECTYPE_TRUST ) { - rc = drop_from_hashtable( get_trusthashrec(), - rec.r.trust.fingerprint, 20, rec.recnum ); + /* Must read the record fist, so we can drop it from the hash tables */ + rc = tdbio_read_record (recnum, &rec, 0); + if (rc) + ; + else if (rec.rectype == RECTYPE_TRUST) + { + rc = drop_from_hashtable (get_trusthashrec(), + rec.r.trust.fingerprint, 20, rec.recnum); } - if( rc ) - return rc; - - /* now we can chnage it to a free record */ - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - db_name, gpg_strerror (rc) ); - - rec.recnum = recnum; - rec.rectype = RECTYPE_FREE; - rec.r.free.next = vr.r.ver.firstfree; - vr.r.ver.firstfree = recnum; - rc = tdbio_write_record( &rec ); - if( !rc ) - rc = tdbio_write_record( &vr ); + if (rc) return rc; + + /* Now we can chnage it to a free record. */ + rc = tdbio_read_record (0, &vr, RECTYPE_VER); + if (rc) + log_fatal (_("%s: error reading version record: %s\n"), + db_name, gpg_strerror (rc)); + + rec.recnum = recnum; + rec.rectype = RECTYPE_FREE; + rec.r.free.next = vr.r.ver.firstfree; + vr.r.ver.firstfree = recnum; + rc = tdbio_write_record (&rec); + if (!rc) + rc = tdbio_write_record (&vr); + + return rc; } -/**************** - * create a new record and return its record number + +/* + * Create a new record and return its record number. */ ulong -tdbio_new_recnum() +tdbio_new_recnum () { - off_t offset; - ulong recnum; - TRUSTREC vr, rec; - int rc; + off_t offset; + ulong recnum; + TRUSTREC vr, rec; + int rc; - /* look for unused records */ - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - db_name, gpg_strerror (rc) ); - if( vr.r.ver.firstfree ) { - 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; + /* Look for unused records. */ + rc = tdbio_read_record (0, &vr, RECTYPE_VER); + if (rc) + log_fatal( _("%s: error reading version record: %s\n"), + db_name, gpg_strerror (rc)); + if (vr.r.ver.firstfree) + { + 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; } - /* update dir record */ - vr.r.ver.firstfree = rec.r.free.next; - rc = tdbio_write_record( &vr ); - if( rc ) { - log_error (_("%s: error writing dir record: %s\n"), - db_name, gpg_strerror (rc)); - return rc; + /* Update dir record. */ + vr.r.ver.firstfree = rec.r.free.next; + rc = tdbio_write_record (&vr); + if (rc) + { + log_error (_("%s: error writing dir record: %s\n"), + db_name, gpg_strerror (rc)); + return rc; } - /*zero out the new record */ - memset( &rec, 0, sizeof rec ); - rec.rectype = 0; /* unused record */ - rec.recnum = recnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_fatal(_("%s: failed to zero a 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 + my the memset). */ + rec.recnum = recnum; + rc = tdbio_write_record (&rec); + if (rc) + log_fatal (_("%s: failed to zero a record: %s\n"), + db_name, gpg_strerror (rc)); } - else { /* not found, append a new record */ - offset = lseek( db_fd, 0, SEEK_END ); - if( offset == -1 ) - log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) ); - recnum = offset / TRUST_RECORD_LEN; - assert(recnum); /* this is 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 ); - rec.rectype = 0; /* unused record */ - rec.recnum = recnum; - rc = 0; - if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) { - rc = gpg_error_from_syserror (); - log_error(_("trustdb rec %lu: lseek failed: %s\n"), - recnum, strerror(errno) ); + else /* Not found - append a new record. */ + { + offset = lseek (db_fd, 0, SEEK_END); + if (offset == (off_t)(-1)) + log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno)); + recnum = offset / TRUST_RECORD_LEN; + assert (recnum); /* this is 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); + rec.rectype = 0; /* unused record */ + rec.recnum = recnum; + rc = 0; + if (lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET) == -1) + { + rc = gpg_error_from_syserror (); + log_error (_("trustdb rec %lu: lseek failed: %s\n"), + recnum, strerror (errno)); } - else { - int n = write( db_fd, &rec, TRUST_RECORD_LEN); - if( n != TRUST_RECORD_LEN ) { - rc = gpg_error_from_syserror (); - log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"), - recnum, n, strerror(errno) ); + else + { + int n; + + n = write (db_fd, &rec, TRUST_RECORD_LEN); + if (n != TRUST_RECORD_LEN) + { + rc = gpg_error_from_syserror (); + log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"), + recnum, n, strerror (errno)); } } - if( rc ) - log_fatal(_("%s: failed to append a record: %s\n"), - db_name, gpg_strerror (rc)); + if (rc) + log_fatal (_("%s: failed to append a record: %s\n"), + db_name, gpg_strerror (rc)); } - return recnum ; + + return recnum ; } +/* Helper function for tdbio_search_trust_byfpr. */ static int cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec ) { @@ -1514,32 +1798,50 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec ) } +/* + * Given a 20 byte FINGERPRINT search its trust record and return + * that at REC. + * + * Return: -1 if not found, 0 if found or another error code. + * FIXME: Use GPG_ERR_NOT_FOUND instead of -1. + */ int -tdbio_search_trust_byfpr( const byte *fingerprint, TRUSTREC *rec ) +tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec) { - int rc; + int rc; - /* locate the trust record using the hash table */ - rc = lookup_hashtable( get_trusthashrec(), fingerprint, 20, - cmp_trec_fpr, fingerprint, rec ); - return rc; + /* Locate the trust record using the hash table */ + rc = lookup_hashtable (get_trusthashrec(), fingerprint, 20, + cmp_trec_fpr, fingerprint, rec ); + return rc; } + +/* + * Given a primary public key object PK search its trust record and + * return that at REC. + * + * Return: -1 if not found, 0 if found or another error code. + * FIXME: Use GPG_ERR_NOT_FOUND instead of -1. + */ int tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) { - byte fingerprint[MAX_FINGERPRINT_LEN]; - size_t fingerlen; + byte fingerprint[MAX_FINGERPRINT_LEN]; + size_t fingerlen; - fingerprint_from_pk( pk, fingerprint, &fingerlen ); - for (; fingerlen < 20; fingerlen++ ) - fingerprint[fingerlen] = 0; - return tdbio_search_trust_byfpr (fingerprint, rec); + fingerprint_from_pk( pk, fingerprint, &fingerlen ); + for (; fingerlen < 20; fingerlen++) + fingerprint[fingerlen] = 0; + return tdbio_search_trust_byfpr (fingerprint, rec); } +/* + * Terminate the process with a message about a corrupted trustdb. + */ void -tdbio_invalid(void) +tdbio_invalid (void) { log_error (_("Error: The trustdb is corrupted.\n")); how_to_fix_the_trustdb ();