2 * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
27 #include <sys/types.h>
44 * Yes, this is a very simple implementation. We should really
45 * use a page aligned buffer and read complete pages.
46 * To implement a simple trannsaction system, this is sufficient.
48 typedef struct cache_ctrl_struct
*CACHE_CTRL
;
49 struct cache_ctrl_struct
{
56 char data
[TRUST_RECORD_LEN
];
59 #define MAX_CACHE_ENTRIES_SOFT 200 /* may be increased while in a */
60 #define MAX_CACHE_ENTRIES_HARD 10000 /* transaction to this one */
61 static CACHE_CTRL cache_list
;
62 static int cache_entries
;
63 static int cache_is_dirty
;
65 /* a type used to pass infomation to cmp_krec_fpr */
66 struct cmp_krec_fpr_struct
{
72 /* a type used to pass infomation to cmp_[s]dir */
73 struct cmp_xdir_struct
{
80 static DOTLOCK lockhandle
;
82 static int db_fd
= -1;
83 static int in_transaction
;
85 static void open_db(void);
88 /*************************************
89 ************* record cache **********
90 *************************************/
93 * Get the data from therecord cache and return a
94 * pointer into that cache. Caller should copy
95 * the return data. NULL is returned on a cache miss.
98 get_record_from_cache( ulong recno
)
102 for( r
= cache_list
; r
; r
= r
->next
) {
103 if( r
->flags
.used
&& r
->recno
== recno
)
111 write_cache_item( CACHE_CTRL r
)
115 if( lseek( db_fd
, r
->recno
* TRUST_RECORD_LEN
, SEEK_SET
) == -1 ) {
116 log_error(_("trustdb rec %lu: lseek failed: %s\n"),
117 r
->recno
, strerror(errno
) );
118 return GPGERR_WRITE_FILE
;
120 n
= write( db_fd
, r
->data
, TRUST_RECORD_LEN
);
121 if( n
!= TRUST_RECORD_LEN
) {
122 log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
123 r
->recno
, n
, strerror(errno
) );
124 return GPGERR_WRITE_FILE
;
131 * Put data into the cache. This function may flush the
132 * some cache entries if there is not enough space available.
135 put_record_into_cache( ulong recno
, const char *data
)
137 CACHE_CTRL r
, unused
;
141 /* see whether we already cached this one */
142 for( unused
= NULL
, r
= cache_list
; r
; r
= r
->next
) {
143 if( !r
->flags
.used
) {
147 else if( r
->recno
== recno
) {
148 if( !r
->flags
.dirty
) {
149 /* Hmmm: should we use a a copy and compare? */
150 if( memcmp(r
->data
, data
, TRUST_RECORD_LEN
) ) {
155 memcpy( r
->data
, data
, TRUST_RECORD_LEN
);
158 if( r
->flags
.used
) {
165 /* not in the cache: add a new entry */
166 if( unused
) { /* reuse this entry */
170 memcpy( r
->data
, data
, TRUST_RECORD_LEN
);
176 /* see whether we reached the limit */
177 if( cache_entries
< MAX_CACHE_ENTRIES_SOFT
) { /* no */
178 r
= gcry_xmalloc( sizeof *r
);
181 memcpy( r
->data
, data
, TRUST_RECORD_LEN
);
183 r
->next
= cache_list
;
189 /* cache is full: discard some clean entries */
191 int n
= clean_count
/ 3; /* discard a third of the clean entries */
194 for( unused
= NULL
, r
= cache_list
; r
; r
= r
->next
) {
195 if( r
->flags
.used
&& !r
->flags
.dirty
) {
208 memcpy( r
->data
, data
, TRUST_RECORD_LEN
);
214 /* no clean entries: have to flush some dirty entries */
215 if( in_transaction
) {
216 /* but we can't do this while in a transaction
217 * we increase the cache size instead */
218 if( cache_entries
< MAX_CACHE_ENTRIES_HARD
) { /* no */
219 if( opt
.debug
&& !(cache_entries
% 100) )
220 log_debug("increasing tdbio cache size\n");
221 r
= gcry_xmalloc( sizeof *r
);
224 memcpy( r
->data
, data
, TRUST_RECORD_LEN
);
226 r
->next
= cache_list
;
232 log_info(_("trustdb transaction too large\n"));
233 return GPGERR_RESOURCE_LIMIT
;
236 int n
= dirty_count
/ 5; /* discard some dirty entries */
240 if( make_dotlock( lockhandle
, -1 ) )
241 log_fatal("can't acquire lock - giving up\n");
245 for( unused
= NULL
, r
= cache_list
; r
; r
= r
->next
) {
246 if( r
->flags
.used
&& r
->flags
.dirty
) {
247 int rc
= write_cache_item( r
);
258 if( !opt
.lock_once
) {
259 if( !release_dotlock( lockhandle
) )
266 memcpy( r
->data
, data
, TRUST_RECORD_LEN
);
279 return cache_is_dirty
;
284 * Flush the cache. This cannot be used while in a transaction.
295 log_bug("tdbio: syncing while in transaction\n");
297 if( !cache_is_dirty
)
301 if( make_dotlock( lockhandle
, -1 ) )
302 log_fatal("can't acquire lock - giving up\n");
307 for( r
= cache_list
; r
; r
= r
->next
) {
308 if( r
->flags
.used
&& r
->flags
.dirty
) {
309 int rc
= write_cache_item( r
);
315 if( did_lock
&& !opt
.lock_once
) {
316 if( !release_dotlock( lockhandle
) )
326 * Simple transactions system:
327 * Everything between begin_transaction and end/cancel_transaction
328 * is not immediatly written but at the time of end_transaction.
332 tdbio_begin_transaction()
337 log_bug("tdbio: nested transactions\n");
338 /* flush everything out */
347 tdbio_end_transaction()
351 if( !in_transaction
)
352 log_bug("tdbio: no active transaction\n");
354 if( make_dotlock( lockhandle
, -1 ) )
355 log_fatal("can't acquire lock - giving up\n");
362 unblock_all_signals();
363 if( !opt
.lock_once
) {
364 if( !release_dotlock( lockhandle
) )
371 tdbio_cancel_transaction()
375 if( !in_transaction
)
376 log_bug("tdbio: no active transaction\n");
378 /* remove all dirty marked entries, so that the original ones
379 * are read back the next time */
380 if( cache_is_dirty
) {
381 for( r
= cache_list
; r
; r
= r
->next
) {
382 if( r
->flags
.used
&& r
->flags
.dirty
) {
396 /********************************************************
397 **************** cached I/O functions ******************
398 ********************************************************/
404 if( !release_dotlock(lockhandle
) )
410 tdbio_set_dbname( const char *new_dbname
, int create
)
413 static int initialized
= 0;
419 fname
= new_dbname
? gcry_xstrdup( new_dbname
)
420 : make_filename(opt
.homedir
, "trustdb.gpg", NULL
);
422 if( access( fname
, R_OK
) ) {
423 if( errno
!= ENOENT
) {
424 log_error( _("%s: can't access: %s\n"), fname
, strerror(errno
) );
426 return GPGERR_TRUSTDB
;
432 char *p
= strrchr( fname
, '/' );
436 if( access( fname
, F_OK
) ) {
437 try_make_homedir( fname
);
438 log_fatal( _("%s: directory does not exist!\n"), fname
);
442 fp
=fopen( fname
, "wb" );
444 log_fatal( _("%s: can't create: %s\n"), fname
, strerror(errno
) );
448 #ifdef HAVE_DOSISH_SYSTEM
449 db_fd
= open( db_name
, O_RDWR
| O_BINARY
);
451 db_fd
= open( db_name
, O_RDWR
);
454 log_fatal( _("%s: can't open: %s\n"), db_name
, strerror(errno
) );
457 lockhandle
= create_dotlock( db_name
);
459 log_fatal( _("%s: can't create lock\n"), db_name
);
461 memset( &rec
, 0, sizeof rec
);
462 rec
.r
.ver
.version
= 2;
463 rec
.r
.ver
.created
= make_timestamp();
464 rec
.r
.ver
.marginals
= opt
.marginals_needed
;
465 rec
.r
.ver
.completes
= opt
.completes_needed
;
466 rec
.r
.ver
.cert_depth
= opt
.max_cert_depth
;
467 rec
.rectype
= RECTYPE_VER
;
469 rc
= tdbio_write_record( &rec
);
473 log_fatal( _("%s: failed to create version record: %s"),
474 fname
, gpg_errstr(rc
));
475 /* and read again to check that we are okay */
476 if( tdbio_read_record( 0, &rec
, RECTYPE_VER
) )
477 log_fatal( _("%s: invalid trustdb created\n"), db_name
);
480 log_info(_("%s: trustdb created\n"), db_name
);
503 assert( db_fd
== -1 );
506 lockhandle
= create_dotlock( db_name
);
508 log_fatal( _("%s: can't create lock\n"), db_name
);
509 #ifdef HAVE_DOSISH_SYSTEM
510 db_fd
= open( db_name
, O_RDWR
| O_BINARY
);
512 db_fd
= open( db_name
, O_RDWR
);
515 log_fatal( _("%s: can't open: %s\n"), db_name
, strerror(errno
) );
516 if( tdbio_read_record( 0, &rec
, RECTYPE_VER
) )
517 log_fatal( _("%s: invalid trustdb\n"), db_name
);
522 * Make a hashtable: type 0 = key hash, 1 = sdir hash
525 create_hashtable( TRUSTREC
*vr
, int type
)
532 offset
= lseek( db_fd
, 0, SEEK_END
);
534 log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno
) );
535 recnum
= offset
/ TRUST_RECORD_LEN
;
536 assert(recnum
); /* this is will never be the first record */
539 vr
->r
.ver
.keyhashtbl
= recnum
;
541 vr
->r
.ver
.sdirhashtbl
= recnum
;
542 /* Now write the records */
543 n
= (256+ITEMS_PER_HTBL_RECORD
-1) / ITEMS_PER_HTBL_RECORD
;
544 for(i
=0; i
< n
; i
++, recnum
++ ) {
545 memset( &rec
, 0, sizeof rec
);
546 rec
.rectype
= RECTYPE_HTBL
;
548 rc
= tdbio_write_record( &rec
);
550 log_fatal( _("%s: failed to create hashtable: %s\n"),
551 db_name
, gpg_errstr(rc
));
553 /* update the version record */
554 rc
= tdbio_write_record( vr
);
558 log_fatal( _("%s: error updating version record: %s\n"),
559 db_name
, gpg_errstr(rc
));
564 tdbio_db_matches_options()
566 static int yes_no
= -1;
572 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
574 log_fatal( _("%s: error reading version record: %s\n"),
575 db_name
, gpg_errstr(rc
) );
577 if( !vr
.r
.ver
.marginals
&& !vr
.r
.ver
.completes
578 && !vr
.r
.ver
.cert_depth
)
579 { /* special hack for trustdbs created by old versions of GnuPG */
580 vr
.r
.ver
.marginals
= opt
.marginals_needed
;
581 vr
.r
.ver
.completes
= opt
.completes_needed
;
582 vr
.r
.ver
.cert_depth
= opt
.max_cert_depth
;
583 rc
= tdbio_write_record( &vr
);
584 if( !rc
&& !in_transaction
)
587 log_error( _("%s: error writing version record: %s\n"),
588 db_name
, gpg_errstr(rc
) );
591 yes_no
= vr
.r
.ver
.marginals
== opt
.marginals_needed
592 && vr
.r
.ver
.completes
== opt
.completes_needed
593 && vr
.r
.ver
.cert_depth
== opt
.max_cert_depth
;
600 * Return the modifiy stamp.
601 * if modify_down is true, the modify_down stamp will be
602 * returned, otherwise the modify_up stamp.
605 tdbio_read_modify_stamp( int modify_down
)
611 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
613 log_fatal( _("%s: error reading version record: %s\n"),
614 db_name
, gpg_errstr(rc
) );
616 mod
= modify_down
? vr
.r
.ver
.mod_down
: vr
.r
.ver
.mod_up
;
618 /* Always return at least 1 to make comparison easier;
619 * this is still far back in history (before Led Zeppelin III :-) */
620 return mod
? mod
: 1;
624 tdbio_write_modify_stamp( int up
, int down
)
633 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
635 log_fatal( _("%s: error reading version record: %s\n"),
636 db_name
, gpg_errstr(rc
) );
638 stamp
= make_timestamp();
640 vr
.r
.ver
.mod_down
= stamp
;
642 vr
.r
.ver
.mod_up
= stamp
;
644 rc
= tdbio_write_record( &vr
);
646 log_fatal( _("%s: error writing version record: %s\n"),
647 db_name
, gpg_errstr(rc
) );
652 * Return the record number of the keyhash tbl or create a new one.
657 static ulong keyhashtbl
; /* record number of the key hashtable */
663 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
665 log_fatal( _("%s: error reading version record: %s\n"),
666 db_name
, gpg_errstr(rc
) );
667 if( !vr
.r
.ver
.keyhashtbl
)
668 create_hashtable( &vr
, 0 );
670 keyhashtbl
= vr
.r
.ver
.keyhashtbl
;
676 * Return the record number of the shadow direcory hash table
677 * or create a new one.
680 get_sdirhashrec(void)
682 static ulong sdirhashtbl
; /* record number of the hashtable */
688 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
690 log_fatal( _("%s: error reading version record: %s\n"),
691 db_name
, gpg_errstr(rc
) );
692 if( !vr
.r
.ver
.sdirhashtbl
)
693 create_hashtable( &vr
, 1 );
695 sdirhashtbl
= vr
.r
.ver
.sdirhashtbl
;
702 * Update a hashtable.
703 * table gives the start of the table, key and keylen is the key,
704 * newrecnum is the record number to insert.
707 upd_hashtable( ulong table
, byte
*key
, int keylen
, ulong newrecnum
)
709 TRUSTREC lastrec
, rec
;
718 hashrec
+= msb
/ ITEMS_PER_HTBL_RECORD
;
719 rc
= tdbio_read_record( hashrec
, &rec
, RECTYPE_HTBL
);
721 log_error( db_name
, "upd_hashtable: read failed: %s\n",
726 item
= rec
.r
.htbl
.item
[msb
% ITEMS_PER_HTBL_RECORD
];
727 if( !item
) { /* insert a new item into the hash table */
728 rec
.r
.htbl
.item
[msb
% ITEMS_PER_HTBL_RECORD
] = newrecnum
;
729 rc
= tdbio_write_record( &rec
);
731 log_error( db_name
, "upd_hashtable: write htbl failed: %s\n",
736 else if( item
!= newrecnum
) { /* must do an update */
738 rc
= tdbio_read_record( item
, &rec
, 0 );
740 log_error( "upd_hashtable: read item failed: %s\n",
745 if( rec
.rectype
== RECTYPE_HTBL
) {
748 if( level
>= keylen
) {
749 log_error( "hashtable has invalid indirections.\n");
750 return GPGERR_TRUSTDB
;
754 else if( rec
.rectype
== RECTYPE_HLST
) { /* extend list */
755 /* see whether the key is already in this list */
757 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ ) {
758 if( rec
.r
.hlst
.rnum
[i
] == newrecnum
) {
759 return 0; /* okay, already in the list */
762 if( rec
.r
.hlst
.next
) {
763 rc
= tdbio_read_record( rec
.r
.hlst
.next
,
766 log_error( "scan keyhashtbl read hlst failed: %s\n",
772 break; /* not there */
774 /* find the next free entry and put it in */
776 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ ) {
777 if( !rec
.r
.hlst
.rnum
[i
] ) {
778 rec
.r
.hlst
.rnum
[i
] = newrecnum
;
779 rc
= tdbio_write_record( &rec
);
781 log_error( "upd_hashtable: write hlst failed: %s\n",
783 return rc
; /* done */
786 if( rec
.r
.hlst
.next
) {
787 rc
= tdbio_read_record( rec
.r
.hlst
.next
,
788 &rec
, RECTYPE_HLST
);
790 log_error( "upd_hashtable: read hlst failed: %s\n",
795 else { /* add a new list record */
796 rec
.r
.hlst
.next
= item
= tdbio_new_recnum();
797 rc
= tdbio_write_record( &rec
);
799 log_error( "upd_hashtable: write hlst failed: %s\n",
803 memset( &rec
, 0, sizeof rec
);
804 rec
.rectype
= RECTYPE_HLST
;
806 rec
.r
.hlst
.rnum
[0] = newrecnum
;
807 rc
= tdbio_write_record( &rec
);
809 log_error( "upd_hashtable: write ext hlst failed: %s\n",
811 return rc
; /* done */
813 } /* end loop over hlst slots */
815 else if( rec
.rectype
== RECTYPE_KEY
816 || rec
.rectype
== RECTYPE_DIR
817 || rec
.rectype
== RECTYPE_SDIR
) { /* insert a list record */
818 if( rec
.recnum
== newrecnum
) {
821 item
= rec
.recnum
; /* save number of key record */
822 memset( &rec
, 0, sizeof rec
);
823 rec
.rectype
= RECTYPE_HLST
;
824 rec
.recnum
= tdbio_new_recnum();
825 rec
.r
.hlst
.rnum
[0] = item
; /* old keyrecord */
826 rec
.r
.hlst
.rnum
[1] = newrecnum
; /* and new one */
827 rc
= tdbio_write_record( &rec
);
829 log_error( "upd_hashtable: write new hlst failed: %s\n",
833 /* update the hashtable record */
834 lastrec
.r
.htbl
.item
[msb
% ITEMS_PER_HTBL_RECORD
] = rec
.recnum
;
835 rc
= tdbio_write_record( &lastrec
);
837 log_error( "upd_hashtable: update htbl failed: %s\n",
839 return rc
; /* ready */
842 log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n",
843 table
, hashrec
, (msb
% ITEMS_PER_HTBL_RECORD
), item
);
845 return GPGERR_TRUSTDB
;
854 * Drop an entry from a hashtable
855 * table gives the start of the table, key and keylen is the key,
858 drop_from_hashtable( ulong table
, byte
*key
, int keylen
, ulong recnum
)
869 hashrec
+= msb
/ ITEMS_PER_HTBL_RECORD
;
870 rc
= tdbio_read_record( hashrec
, &rec
, RECTYPE_HTBL
);
872 log_error( db_name
, "drop_from_hashtable: read failed: %s\n",
877 item
= rec
.r
.htbl
.item
[msb
% ITEMS_PER_HTBL_RECORD
];
878 if( !item
) /* not found - forget about it */
881 if( item
== recnum
) { /* tables points direct to the record */
882 rec
.r
.htbl
.item
[msb
% ITEMS_PER_HTBL_RECORD
] = 0;
883 rc
= tdbio_write_record( &rec
);
885 log_error( db_name
, "drop_from_hashtable: write htbl failed: %s\n",
890 rc
= tdbio_read_record( item
, &rec
, 0 );
892 log_error( "drop_from_hashtable: read item failed: %s\n",
897 if( rec
.rectype
== RECTYPE_HTBL
) {
900 if( level
>= keylen
) {
901 log_error( "hashtable has invalid indirections.\n");
902 return GPGERR_TRUSTDB
;
907 if( rec
.rectype
== RECTYPE_HLST
) {
909 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ ) {
910 if( rec
.r
.hlst
.rnum
[i
] == recnum
) {
911 rec
.r
.hlst
.rnum
[i
] = 0; /* drop */
912 rc
= tdbio_write_record( &rec
);
914 log_error( db_name
, "drop_from_hashtable: write htbl failed: %s\n",
919 if( rec
.r
.hlst
.next
) {
920 rc
= tdbio_read_record( rec
.r
.hlst
.next
,
923 log_error( "scan keyhashtbl read hlst failed: %s\n",
929 return 0; /* key not in table */
933 log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n",
934 table
, hashrec
, (msb
% ITEMS_PER_HTBL_RECORD
), item
);
935 return GPGERR_TRUSTDB
;
941 * Lookup a record via the hashtable tablewith key/keylen and return the
942 * result in rec. cmp() should return if the record is the desired one.
943 * Returns -1 if not found, 0 if found or another errocode
946 lookup_hashtable( ulong table
, const byte
*key
, size_t keylen
,
947 int (*cmpfnc
)(void*, const TRUSTREC
*), void *cmpdata
,
958 hashrec
+= msb
/ ITEMS_PER_HTBL_RECORD
;
959 rc
= tdbio_read_record( hashrec
, rec
, RECTYPE_HTBL
);
961 log_error( db_name
, "lookup_hashtable failed: %s\n", gpg_errstr(rc
) );
965 item
= rec
->r
.htbl
.item
[msb
% ITEMS_PER_HTBL_RECORD
];
967 return -1; /* not found */
969 rc
= tdbio_read_record( item
, rec
, 0 );
971 log_error( db_name
, "hashtable read failed: %s\n", gpg_errstr(rc
) );
974 if( rec
->rectype
== RECTYPE_HTBL
) {
977 if( level
>= keylen
) {
978 log_error( db_name
, "hashtable has invalid indirections\n");
979 return GPGERR_TRUSTDB
;
983 else if( rec
->rectype
== RECTYPE_HLST
) {
987 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ ) {
988 if( rec
->r
.hlst
.rnum
[i
] ) {
991 rc
= tdbio_read_record( rec
->r
.hlst
.rnum
[i
], &tmp
, 0 );
993 log_error( "lookup_hashtable: read item failed: %s\n",
997 if( (*cmpfnc
)( cmpdata
, &tmp
) ) {
1003 if( rec
->r
.hlst
.next
) {
1004 rc
= tdbio_read_record( rec
->r
.hlst
.next
, rec
, RECTYPE_HLST
);
1006 log_error( "lookup_hashtable: read hlst failed: %s\n",
1012 return -1; /* not found */
1017 if( (*cmpfnc
)( cmpdata
, rec
) )
1018 return 0; /* really found */
1020 return -1; /* no: not found */
1027 * Update the key hashtbl or create the table if it does not exist
1030 update_keyhashtbl( TRUSTREC
*kr
)
1032 return upd_hashtable( get_keyhashrec(),
1033 kr
->r
.key
.fingerprint
,
1034 kr
->r
.key
.fingerprint_len
, kr
->recnum
);
1038 * Update the shadow dir hashtbl or create the table if it does not exist
1041 update_sdirhashtbl( TRUSTREC
*sr
)
1045 u32tobuf( key
, sr
->r
.sdir
.keyid
[0] );
1046 u32tobuf( key
+4 , sr
->r
.sdir
.keyid
[1] );
1047 return upd_hashtable( get_sdirhashrec(), key
, 8, sr
->recnum
);
1051 * Drop the records from the key-hashtbl
1054 drop_from_keyhashtbl( TRUSTREC
*kr
)
1056 return drop_from_hashtable( get_keyhashrec(),
1057 kr
->r
.key
.fingerprint
,
1058 kr
->r
.key
.fingerprint_len
, kr
->recnum
);
1062 * Drop record drom the shadow dir hashtbl
1065 drop_from_sdirhashtbl( TRUSTREC
*sr
)
1069 u32tobuf( key
, sr
->r
.sdir
.keyid
[0] );
1070 u32tobuf( key
+4 , sr
->r
.sdir
.keyid
[1] );
1071 return drop_from_hashtable( get_sdirhashrec(), key
, 8, sr
->recnum
);
1078 tdbio_dump_record( TRUSTREC
*rec
, FILE *fp
)
1081 ulong rnum
= rec
->recnum
;
1084 fprintf(fp
, "rec %5lu, ", rnum
);
1086 switch( rec
->rectype
) {
1087 case 0: fprintf(fp
, "blank\n");
1089 case RECTYPE_VER
: fprintf(fp
,
1090 "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d down=%s",
1091 rec
->r
.ver
.keyhashtbl
, rec
->r
.ver
.sdirhashtbl
,
1092 rec
->r
.ver
.firstfree
,
1093 rec
->r
.ver
.marginals
,
1094 rec
->r
.ver
.completes
,
1095 rec
->r
.ver
.cert_depth
,
1096 strtimestamp(rec
->r
.ver
.mod_down
) );
1097 fprintf(fp
, ", up=%s\n", strtimestamp(rec
->r
.ver
.mod_up
) );
1099 case RECTYPE_FREE
: fprintf(fp
, "free, next=%lu\n", rec
->r
.free
.next
);
1102 fprintf(fp
, "dir %lu, keys=%lu, uids=%lu, t=%02x",
1106 rec
->r
.dir
.ownertrust
);
1107 if( rec
->r
.dir
.valcheck
)
1108 fprintf( fp
, ", v=%02x/%s", rec
->r
.dir
.validity
,
1109 strtimestamp(rec
->r
.dir
.valcheck
) );
1110 if( rec
->r
.dir
.checkat
)
1111 fprintf( fp
, ", a=%s", strtimestamp(rec
->r
.dir
.checkat
) );
1112 if( rec
->r
.dir
.dirflags
& DIRF_CHECKED
) {
1113 if( rec
->r
.dir
.dirflags
& DIRF_VALID
)
1114 fputs(", valid", fp
);
1115 if( rec
->r
.dir
.dirflags
& DIRF_EXPIRED
)
1116 fputs(", expired", fp
);
1117 if( rec
->r
.dir
.dirflags
& DIRF_REVOKED
)
1118 fputs(", revoked", fp
);
1119 if( rec
->r
.dir
.dirflags
& DIRF_NEWKEYS
)
1120 fputs(", newkeys", fp
);
1125 fprintf(fp
, "key %lu, n=%lu a=%d ",
1128 rec
->r
.key
.pubkey_algo
);
1129 for(i
=0; i
< rec
->r
.key
.fingerprint_len
; i
++ )
1130 fprintf(fp
, "%02X", rec
->r
.key
.fingerprint
[i
] );
1131 if( rec
->r
.key
.keyflags
& KEYF_CHECKED
) {
1132 if( rec
->r
.key
.keyflags
& KEYF_VALID
)
1133 fputs(", valid", fp
);
1134 if( rec
->r
.key
.keyflags
& KEYF_EXPIRED
)
1135 fputs(", expired", fp
);
1136 if( rec
->r
.key
.keyflags
& KEYF_REVOKED
)
1137 fputs(", revoked", fp
);
1142 fprintf(fp
, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X",
1147 rec
->r
.uid
.namehash
[18], rec
->r
.uid
.namehash
[19]);
1148 fprintf( fp
, ", v=%02x", rec
->r
.uid
.validity
);
1149 if( rec
->r
.uid
.uidflags
& UIDF_CHECKED
) {
1150 if( rec
->r
.uid
.uidflags
& UIDF_VALID
)
1151 fputs(", valid", fp
);
1152 if( rec
->r
.uid
.uidflags
& UIDF_REVOKED
)
1153 fputs(", revoked", fp
);
1158 fprintf(fp
, "pref %lu, next=%lu,",
1159 rec
->r
.pref
.lid
, rec
->r
.pref
.next
);
1160 for(i
=0,p
=rec
->r
.pref
.data
; i
< ITEMS_PER_PREF_RECORD
; i
+=2,p
+=2 ) {
1162 fprintf(fp
, " %c%d", *p
== PREFTYPE_SYM
? 'S' :
1163 *p
== PREFTYPE_HASH
? 'H' :
1164 *p
== PREFTYPE_COMPR
? 'Z' : '?', p
[1]);
1169 fprintf(fp
, "sig %lu, next=%lu,",
1170 rec
->r
.sig
.lid
, rec
->r
.sig
.next
);
1171 for(i
=0; i
< SIGS_PER_RECORD
; i
++ ) {
1172 if( rec
->r
.sig
.sig
[i
].lid
) {
1173 fprintf(fp
, " %lu:", rec
->r
.sig
.sig
[i
].lid
);
1174 if( rec
->r
.sig
.sig
[i
].flag
& SIGF_CHECKED
) {
1175 fprintf(fp
,"%c%c%c",
1176 (rec
->r
.sig
.sig
[i
].flag
& SIGF_VALID
) ? 'V':
1177 (rec
->r
.sig
.sig
[i
].flag
& SIGF_IGNORED
) ? 'I':'-',
1178 (rec
->r
.sig
.sig
[i
].flag
& SIGF_EXPIRED
) ? 'E':'-',
1179 (rec
->r
.sig
.sig
[i
].flag
& SIGF_REVOKED
) ? 'R':'-');
1181 else if( rec
->r
.sig
.sig
[i
].flag
& SIGF_NOPUBKEY
)
1190 fprintf(fp
, "sdir %lu, keyid=%08lX%08lX, algo=%d, hint=%lu\n",
1192 (ulong
)rec
->r
.sdir
.keyid
[0],
1193 (ulong
)rec
->r
.sdir
.keyid
[1],
1194 rec
->r
.sdir
.pubkey_algo
,
1195 (ulong
)rec
->r
.sdir
.hintlist
);
1198 fprintf(fp
, "cach\n");
1201 fprintf(fp
, "htbl,");
1202 for(i
=0; i
< ITEMS_PER_HTBL_RECORD
; i
++ )
1203 fprintf(fp
, " %lu", rec
->r
.htbl
.item
[i
] );
1207 fprintf(fp
, "hlst, next=%lu,", rec
->r
.hlst
.next
);
1208 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ )
1209 fprintf(fp
, " %lu", rec
->r
.hlst
.rnum
[i
] );
1213 fprintf(fp
, "unknown type %d\n", rec
->rectype
);
1219 * read the record with number recnum
1220 * returns: -1 on error, 0 on success
1223 tdbio_read_record( ulong recnum
, TRUSTREC
*rec
, int expected
)
1225 byte readbuf
[TRUST_RECORD_LEN
];
1226 const byte
*buf
, *p
;
1232 buf
= get_record_from_cache( recnum
);
1234 if( lseek( db_fd
, recnum
* TRUST_RECORD_LEN
, SEEK_SET
) == -1 ) {
1235 log_error(_("trustdb: lseek failed: %s\n"), strerror(errno
) );
1236 return GPGERR_READ_FILE
;
1238 n
= read( db_fd
, readbuf
, TRUST_RECORD_LEN
);
1240 return -1; /* eof */
1242 else if( n
!= TRUST_RECORD_LEN
) {
1243 log_error(_("trustdb: read failed (n=%d): %s\n"), n
,
1245 return GPGERR_READ_FILE
;
1249 rec
->recnum
= recnum
;
1252 rec
->rectype
= *p
++;
1253 if( expected
&& rec
->rectype
!= expected
) {
1254 log_error("%lu: read expected rec type %d, got %d\n",
1255 recnum
, expected
, rec
->rectype
);
1256 return GPGERR_TRUSTDB
;
1258 p
++; /* skip reserved byte */
1259 switch( rec
->rectype
) {
1260 case 0: /* unused (free) record */
1262 case RECTYPE_VER
: /* version record */
1263 if( memcmp(buf
+1, "gpg", 3 ) ) {
1264 log_error( _("%s: not a trustdb file\n"), db_name
);
1265 rc
= GPGERR_TRUSTDB
;
1267 p
+= 2; /* skip "pgp" */
1268 rec
->r
.ver
.version
= *p
++;
1269 rec
->r
.ver
.marginals
= *p
++;
1270 rec
->r
.ver
.completes
= *p
++;
1271 rec
->r
.ver
.cert_depth
= *p
++;
1272 p
+= 4; /* lock flags */
1273 rec
->r
.ver
.created
= buftoulong(p
); p
+= 4;
1274 rec
->r
.ver
.mod_down
= buftoulong(p
); p
+= 4;
1275 rec
->r
.ver
.mod_up
= buftoulong(p
); p
+= 4;
1276 rec
->r
.ver
.keyhashtbl
=buftoulong(p
); p
+= 4;
1277 rec
->r
.ver
.firstfree
=buftoulong(p
); p
+= 4;
1278 rec
->r
.ver
.sdirhashtbl
=buftoulong(p
); p
+= 4;
1280 log_error( _("%s: version record with recnum %lu\n"), db_name
,
1282 rc
= GPGERR_TRUSTDB
;
1284 else if( rec
->r
.ver
.version
!= 2 ) {
1285 log_error( _("%s: invalid file version %d\n"), db_name
,
1286 rec
->r
.ver
.version
);
1287 rc
= GPGERR_TRUSTDB
;
1291 rec
->r
.free
.next
= buftoulong(p
); p
+= 4;
1293 case RECTYPE_DIR
: /*directory record */
1294 rec
->r
.dir
.lid
= buftoulong(p
); p
+= 4;
1295 rec
->r
.dir
.keylist
= buftoulong(p
); p
+= 4;
1296 rec
->r
.dir
.uidlist
= buftoulong(p
); p
+= 4;
1297 rec
->r
.dir
.cacherec
= buftoulong(p
); p
+= 4;
1298 rec
->r
.dir
.ownertrust
= *p
++;
1299 rec
->r
.dir
.dirflags
= *p
++;
1300 rec
->r
.dir
.validity
= *p
++;
1301 rec
->r
.dir
.valcheck
= buftoulong(p
); p
+= 4;
1302 rec
->r
.dir
.checkat
= buftoulong(p
); p
+= 4;
1303 switch( rec
->r
.dir
.validity
) {
1305 case TRUST_UNDEFINED
:
1307 case TRUST_MARGINAL
:
1309 case TRUST_ULTIMATE
:
1312 log_info("lid %lu: invalid validity value - cleared\n", recnum
);
1314 if( rec
->r
.dir
.lid
!= recnum
) {
1315 log_error( "%s: dir LID != recnum (%lu,%lu)\n",
1316 db_name
, rec
->r
.dir
.lid
, (ulong
)recnum
);
1317 rc
= GPGERR_TRUSTDB
;
1320 case RECTYPE_KEY
: /* public key record */
1321 rec
->r
.key
.lid
= buftoulong(p
); p
+= 4;
1322 rec
->r
.key
.next
= buftoulong(p
); p
+= 4;
1324 rec
->r
.key
.keyflags
= *p
++;
1325 rec
->r
.key
.pubkey_algo
= *p
++;
1326 rec
->r
.key
.fingerprint_len
= *p
++;
1327 if( rec
->r
.key
.fingerprint_len
< 1 || rec
->r
.key
.fingerprint_len
> 20 )
1328 rec
->r
.key
.fingerprint_len
= 20;
1329 memcpy( rec
->r
.key
.fingerprint
, p
, 20);
1331 case RECTYPE_UID
: /* user id record */
1332 rec
->r
.uid
.lid
= buftoulong(p
); p
+= 4;
1333 rec
->r
.uid
.next
= buftoulong(p
); p
+= 4;
1334 rec
->r
.uid
.prefrec
= buftoulong(p
); p
+= 4;
1335 rec
->r
.uid
.siglist
= buftoulong(p
); p
+= 4;
1336 rec
->r
.uid
.uidflags
= *p
++;
1337 rec
->r
.uid
.validity
= *p
++;
1338 switch( rec
->r
.uid
.validity
) {
1340 case TRUST_UNDEFINED
:
1342 case TRUST_MARGINAL
:
1344 case TRUST_ULTIMATE
:
1347 log_info("lid %lu: invalid validity value - cleared\n", recnum
);
1349 memcpy( rec
->r
.uid
.namehash
, p
, 20);
1351 case RECTYPE_PREF
: /* preference record */
1352 rec
->r
.pref
.lid
= buftoulong(p
); p
+= 4;
1353 rec
->r
.pref
.next
= buftoulong(p
); p
+= 4;
1354 memcpy( rec
->r
.pref
.data
, p
, 30 );
1357 rec
->r
.sig
.lid
= buftoulong(p
); p
+= 4;
1358 rec
->r
.sig
.next
= buftoulong(p
); p
+= 4;
1359 for(i
=0; i
< SIGS_PER_RECORD
; i
++ ) {
1360 rec
->r
.sig
.sig
[i
].lid
= buftoulong(p
); p
+= 4;
1361 rec
->r
.sig
.sig
[i
].flag
= *p
++;
1364 case RECTYPE_SDIR
: /* shadow directory record */
1365 rec
->r
.sdir
.lid
= buftoulong(p
); p
+= 4;
1366 rec
->r
.sdir
.keyid
[0]= buftou32(p
); p
+= 4;
1367 rec
->r
.sdir
.keyid
[1]= buftou32(p
); p
+= 4;
1368 rec
->r
.sdir
.pubkey_algo
= *p
++;
1370 rec
->r
.sdir
.hintlist
= buftoulong(p
);
1371 if( rec
->r
.sdir
.lid
!= recnum
) {
1372 log_error( "%s: sdir LID != recnum (%lu,%lu)\n",
1373 db_name
, rec
->r
.sdir
.lid
, (ulong
)recnum
);
1374 rc
= GPGERR_TRUSTDB
;
1377 case RECTYPE_CACH
: /* cache record */
1378 rec
->r
.cache
.lid
= buftoulong(p
); p
+= 4;
1379 memcpy(rec
->r
.cache
.blockhash
, p
, 20); p
+= 20;
1380 rec
->r
.cache
.trustlevel
= *p
++;
1383 for(i
=0; i
< ITEMS_PER_HTBL_RECORD
; i
++ ) {
1384 rec
->r
.htbl
.item
[i
] = buftoulong(p
); p
+= 4;
1388 rec
->r
.hlst
.next
= buftoulong(p
); p
+= 4;
1389 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ ) {
1390 rec
->r
.hlst
.rnum
[i
] = buftoulong(p
); p
+= 4;
1394 log_error( "%s: invalid record type %d at recnum %lu\n",
1395 db_name
, rec
->rectype
, (ulong
)recnum
);
1396 rc
= GPGERR_TRUSTDB
;
1404 * Write the record at RECNUM
1407 tdbio_write_record( TRUSTREC
*rec
)
1409 byte buf
[TRUST_RECORD_LEN
], *p
;
1412 ulong recnum
= rec
->recnum
;
1417 memset(buf
, 0, TRUST_RECORD_LEN
);
1419 *p
++ = rec
->rectype
; p
++;
1420 switch( rec
->rectype
) {
1421 case 0: /* unused record */
1423 case RECTYPE_VER
: /* version record */
1426 memcpy(p
-1, "gpg", 3 ); p
+= 2;
1427 *p
++ = rec
->r
.ver
.version
;
1428 *p
++ = rec
->r
.ver
.marginals
;
1429 *p
++ = rec
->r
.ver
.completes
;
1430 *p
++ = rec
->r
.ver
.cert_depth
;
1431 p
+= 4; /* skip lock flags */
1432 ulongtobuf(p
, rec
->r
.ver
.created
); p
+= 4;
1433 ulongtobuf(p
, rec
->r
.ver
.mod_down
); p
+= 4;
1434 ulongtobuf(p
, rec
->r
.ver
.mod_up
); p
+= 4;
1435 ulongtobuf(p
, rec
->r
.ver
.keyhashtbl
); p
+= 4;
1436 ulongtobuf(p
, rec
->r
.ver
.firstfree
); p
+= 4;
1437 ulongtobuf(p
, rec
->r
.ver
.sdirhashtbl
); p
+= 4;
1441 ulongtobuf(p
, rec
->r
.free
.next
); p
+= 4;
1444 case RECTYPE_DIR
: /*directory record */
1445 ulongtobuf(p
, rec
->r
.dir
.lid
); p
+= 4;
1446 ulongtobuf(p
, rec
->r
.dir
.keylist
); p
+= 4;
1447 ulongtobuf(p
, rec
->r
.dir
.uidlist
); p
+= 4;
1448 ulongtobuf(p
, rec
->r
.dir
.cacherec
); p
+= 4;
1449 *p
++ = rec
->r
.dir
.ownertrust
;
1450 *p
++ = rec
->r
.dir
.dirflags
;
1451 *p
++ = rec
->r
.dir
.validity
;
1452 ulongtobuf(p
, rec
->r
.dir
.valcheck
); p
+= 4;
1453 ulongtobuf(p
, rec
->r
.dir
.checkat
); p
+= 4;
1454 assert( rec
->r
.dir
.lid
== recnum
);
1458 ulongtobuf(p
, rec
->r
.key
.lid
); p
+= 4;
1459 ulongtobuf(p
, rec
->r
.key
.next
); p
+= 4;
1461 *p
++ = rec
->r
.key
.keyflags
;
1462 *p
++ = rec
->r
.key
.pubkey_algo
;
1463 *p
++ = rec
->r
.key
.fingerprint_len
;
1464 memcpy( p
, rec
->r
.key
.fingerprint
, 20); p
+= 20;
1467 case RECTYPE_UID
: /* user id record */
1468 ulongtobuf(p
, rec
->r
.uid
.lid
); p
+= 4;
1469 ulongtobuf(p
, rec
->r
.uid
.next
); p
+= 4;
1470 ulongtobuf(p
, rec
->r
.uid
.prefrec
); p
+= 4;
1471 ulongtobuf(p
, rec
->r
.uid
.siglist
); p
+= 4;
1472 *p
++ = rec
->r
.uid
.uidflags
;
1473 *p
++ = rec
->r
.uid
.validity
;
1474 memcpy( p
, rec
->r
.uid
.namehash
, 20 ); p
+= 20;
1478 ulongtobuf(p
, rec
->r
.pref
.lid
); p
+= 4;
1479 ulongtobuf(p
, rec
->r
.pref
.next
); p
+= 4;
1480 memcpy( p
, rec
->r
.pref
.data
, 30 );
1484 ulongtobuf(p
, rec
->r
.sig
.lid
); p
+= 4;
1485 ulongtobuf(p
, rec
->r
.sig
.next
); p
+= 4;
1486 for(i
=0; i
< SIGS_PER_RECORD
; i
++ ) {
1487 ulongtobuf(p
, rec
->r
.sig
.sig
[i
].lid
); p
+= 4;
1488 *p
++ = rec
->r
.sig
.sig
[i
].flag
;
1493 ulongtobuf( p
, rec
->r
.sdir
.lid
); p
+= 4;
1494 u32tobuf( p
, rec
->r
.sdir
.keyid
[0] ); p
+= 4;
1495 u32tobuf( p
, rec
->r
.sdir
.keyid
[1] ); p
+= 4;
1496 *p
++ = rec
->r
.sdir
.pubkey_algo
;
1498 ulongtobuf( p
, rec
->r
.sdir
.hintlist
);
1502 ulongtobuf(p
, rec
->r
.cache
.lid
); p
+= 4;
1503 memcpy(p
, rec
->r
.cache
.blockhash
, 20); p
+= 20;
1504 *p
++ = rec
->r
.cache
.trustlevel
;
1508 for(i
=0; i
< ITEMS_PER_HTBL_RECORD
; i
++ ) {
1509 ulongtobuf( p
, rec
->r
.htbl
.item
[i
]); p
+= 4;
1514 ulongtobuf( p
, rec
->r
.hlst
.next
); p
+= 4;
1515 for(i
=0; i
< ITEMS_PER_HLST_RECORD
; i
++ ) {
1516 ulongtobuf( p
, rec
->r
.hlst
.rnum
[i
]); p
+= 4;
1524 rc
= put_record_into_cache( recnum
, buf
);
1527 else if( rec
->rectype
== RECTYPE_KEY
)
1528 rc
= update_keyhashtbl( rec
);
1529 else if( rec
->rectype
== RECTYPE_SDIR
)
1530 rc
= update_sdirhashtbl( rec
);
1536 tdbio_delete_record( ulong recnum
)
1541 /* Must read the record fist, so we can drop it from the hash tables */
1542 rc
= tdbio_read_record( recnum
, &rec
, 0 );
1545 else if( rec
.rectype
== RECTYPE_KEY
)
1546 rc
= drop_from_keyhashtbl( &rec
);
1547 else if( rec
.rectype
== RECTYPE_SDIR
)
1548 rc
= drop_from_sdirhashtbl( &rec
);
1553 /* now we can chnage it to a free record */
1554 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
1556 log_fatal( _("%s: error reading version record: %s\n"),
1557 db_name
, gpg_errstr(rc
) );
1559 rec
.recnum
= recnum
;
1560 rec
.rectype
= RECTYPE_FREE
;
1561 rec
.r
.free
.next
= vr
.r
.ver
.firstfree
;
1562 vr
.r
.ver
.firstfree
= recnum
;
1563 rc
= tdbio_write_record( &rec
);
1565 rc
= tdbio_write_record( &vr
);
1570 * create a new record and return its record number
1580 /* look for unused records */
1581 rc
= tdbio_read_record( 0, &vr
, RECTYPE_VER
);
1583 log_fatal( _("%s: error reading version record: %s\n"),
1584 db_name
, gpg_errstr(rc
) );
1585 if( vr
.r
.ver
.firstfree
) {
1586 recnum
= vr
.r
.ver
.firstfree
;
1587 rc
= tdbio_read_record( recnum
, &rec
, RECTYPE_FREE
);
1589 log_error( _("%s: error reading free record: %s\n"),
1590 db_name
, gpg_errstr(rc
) );
1593 /* update dir record */
1594 vr
.r
.ver
.firstfree
= rec
.r
.free
.next
;
1595 rc
= tdbio_write_record( &vr
);
1597 log_error( _("%s: error writing dir record: %s\n"),
1598 db_name
, gpg_errstr(rc
) );
1601 /*zero out the new record */
1602 memset( &rec
, 0, sizeof rec
);
1603 rec
.rectype
= 0; /* unused record */
1604 rec
.recnum
= recnum
;
1605 rc
= tdbio_write_record( &rec
);
1607 log_fatal(_("%s: failed to zero a record: %s\n"),
1608 db_name
, gpg_errstr(rc
));
1610 else { /* not found, append a new record */
1611 offset
= lseek( db_fd
, 0, SEEK_END
);
1613 log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno
) );
1614 recnum
= offset
/ TRUST_RECORD_LEN
;
1615 assert(recnum
); /* this is will never be the first record */
1616 /* we must write a record, so that the next call to this function
1617 * returns another recnum */
1618 memset( &rec
, 0, sizeof rec
);
1619 rec
.rectype
= 0; /* unused record */
1620 rec
.recnum
= recnum
;
1622 if( lseek( db_fd
, recnum
* TRUST_RECORD_LEN
, SEEK_SET
) == -1 ) {
1623 log_error(_("trustdb rec %lu: lseek failed: %s\n"),
1624 recnum
, strerror(errno
) );
1625 rc
= GPGERR_WRITE_FILE
;
1628 int n
= write( db_fd
, &rec
, TRUST_RECORD_LEN
);
1629 if( n
!= TRUST_RECORD_LEN
) {
1630 log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
1631 recnum
, n
, strerror(errno
) );
1632 rc
= GPGERR_WRITE_FILE
;
1637 log_fatal(_("%s: failed to append a record: %s\n"),
1638 db_name
, gpg_errstr(rc
));
1646 * Search the trustdb for a key which matches PK and return the dir record
1647 * The local_id of PK is set to the correct value
1650 tdbio_search_dir_bypk( PKT_public_key
*pk
, TRUSTREC
*rec
)
1652 byte fingerprint
[MAX_FINGERPRINT_LEN
];
1657 keyid_from_pk( pk
, keyid
);
1658 fingerprint_from_pk( pk
, fingerprint
, &fingerlen
);
1659 rc
= tdbio_search_dir_byfpr( fingerprint
, fingerlen
,
1660 pk
->pubkey_algo
, rec
);
1663 if( pk
->local_id
&& pk
->local_id
!= rec
->recnum
)
1664 log_error("%s: found record, but LID from memory does "
1665 "not match recnum (%lu,%lu)\n",
1666 db_name
, pk
->local_id
, rec
->recnum
);
1667 pk
->local_id
= rec
->recnum
;
1674 cmp_krec_fpr( void *dataptr
, const TRUSTREC
*rec
)
1676 const struct cmp_krec_fpr_struct
*d
= dataptr
;
1678 return rec
->rectype
== RECTYPE_KEY
1679 && ( !d
->pubkey_algo
|| rec
->r
.key
.pubkey_algo
== d
->pubkey_algo
)
1680 && rec
->r
.key
.fingerprint_len
== d
->fprlen
1681 && !memcmp( rec
->r
.key
.fingerprint
, d
->fpr
, d
->fprlen
);
1685 tdbio_search_dir_byfpr( const byte
*fingerprint
, size_t fingerlen
,
1686 int pubkey_algo
, TRUSTREC
*rec
)
1688 struct cmp_krec_fpr_struct cmpdata
;
1692 assert( fingerlen
== 20 || fingerlen
== 16 );
1694 /* locate the key using the hash table */
1695 cmpdata
.pubkey_algo
= pubkey_algo
;
1696 cmpdata
.fpr
= fingerprint
;
1697 cmpdata
.fprlen
= fingerlen
;
1698 rc
= lookup_hashtable( get_keyhashrec(), fingerprint
, fingerlen
,
1699 cmp_krec_fpr
, &cmpdata
, rec
);
1701 recnum
= rec
->r
.key
.lid
;
1702 /* Now read the dir record */
1703 rc
= tdbio_read_record( recnum
, rec
, RECTYPE_DIR
);
1705 log_error("%s: can't read dirrec %lu: %s\n",
1706 db_name
, recnum
, gpg_errstr(rc
) );
1714 cmp_sdir( void *dataptr
, const TRUSTREC
*rec
)
1716 const struct cmp_xdir_struct
*d
= dataptr
;
1718 return rec
->rectype
== RECTYPE_SDIR
1719 && ( !d
->pubkey_algo
|| rec
->r
.sdir
.pubkey_algo
== d
->pubkey_algo
)
1720 && rec
->r
.sdir
.keyid
[0] == d
->keyid
[0]
1721 && rec
->r
.sdir
.keyid
[1] == d
->keyid
[1];
1726 tdbio_search_sdir( u32
*keyid
, int pubkey_algo
, TRUSTREC
*rec
)
1728 struct cmp_xdir_struct cmpdata
;
1732 /* locate the shadow dir record using the hash table */
1733 u32tobuf( key
, keyid
[0] );
1734 u32tobuf( key
+4 , keyid
[1] );
1735 cmpdata
.pubkey_algo
= pubkey_algo
;
1736 cmpdata
.keyid
[0] = keyid
[0];
1737 cmpdata
.keyid
[1] = keyid
[1];
1738 rc
= lookup_hashtable( get_sdirhashrec(), key
, 8,
1739 cmp_sdir
, &cmpdata
, rec
);
1748 "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n") );