The keybox gets now compressed after 3 hours and ephemeral
authorWerner Koch <wk@gnupg.org>
Mon, 26 Apr 2004 08:09:25 +0000 (08:09 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 26 Apr 2004 08:09:25 +0000 (08:09 +0000)
stored certificates are deleted after about a day.

14 files changed:
NEWS
TODO
doc/gpgsm.texi
kbx/ChangeLog
kbx/Manifest [new file with mode: 0644]
kbx/keybox-blob.c
kbx/keybox-defs.h
kbx/keybox-dump.c
kbx/keybox-file.c
kbx/keybox-search.c
kbx/keybox-update.c
kbx/keybox.h
sm/ChangeLog
sm/keydb.c

diff --git a/NEWS b/NEWS
index 31f76b6..4e246f6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,12 @@ Noteworthy changes in version 1.9.8
  * [scdaemon] Status files named ~/.gnupg/reader_<n>.status are now
    written when using the internal CCID driver.
 
+ * [gpgsm] New commands --dump-{,secret,external}-keys to show a very
+   detailed view of the certificates.
+
+ * The keybox gets now compressed after 3 hours and ephemeral
+   stored certificates are deleted after about a day.
+
 
 Noteworthy changes in version 1.9.7 (2004-04-06)
 ------------------------------------------------
diff --git a/TODO b/TODO
index 1d12b74..21c44a9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -41,7 +41,6 @@ might want to have an agent context for each service request
 
 * sm/keydb.c
 ** Check file permissions
-** Write a keybox header and check for that magic value.
 ** Check that all error code mapping is done.
 ** Remove the inter-module dependencies between gpgsm and keybox
 ** Add an source_of_key field
index 977fe3c..a0da96d 100644 (file)
@@ -130,17 +130,36 @@ use @samp{--help} to get a list of supported operations.
 Generate a new key and a certificate request.
 
 @item --list-keys
+@itemx -k 
 @opindex list-keys
 List all available certificates stored in the local key database.
 
 @item --list-secret-keys
+@itemx -K
 @opindex list-secret-keys
-List all available keys whenre a secret key is available.
+List all available certificates for which a corresponding a secret key
+is available.
 
 @item --list-external-keys @var{pattern}
 @opindex list-keys
 List certificates matching @var{pattern} using an external server.  This
-utilies the @code{dirmngr} service.  
+utilizes the @code{dirmngr} service.  
+
+@item --dump-keys
+@opindex dump-keys
+List all available certificates stored in the local key database using a
+format useful mainly for debugging.
+
+@item --dump-secret-keys
+@opindex dump-secret-keys
+List all available certificates for which a corresponding a secret key
+is available using a format useful mainly for debugging.
+
+@item --dump-external-keys @var{pattern}
+@opindex dump-keys
+List certificates matching @var{pattern} using an external server.
+This utilizes the @code{dirmngr} service.  It uses a format useful
+mainly for debugging.
 
 @item --delete-keys @var{pattern}
 @opindex delete-keys
index d6c7502..aa39df8 100644 (file)
@@ -1,3 +1,27 @@
+2004-04-23  Werner Koch  <wk@gnupg.org>
+
+       * keybox-blob.c (_keybox_update_header_blob): New.
+       * keybox-update.c (blob_filecopy): Handle header blob.
+       * keybox-file.c (_keybox_read_blob2): New. Moved code from
+       _keybox_read_blob to there. 
+       * keybox-dump.c (dump_header_blob): Print header info.
+
+2004-04-21  Werner Koch  <wk@gnupg.org>
+
+       * keybox-search.c (_keybox_get_flag_location): Add flag
+       KEYBOX_FLAG_CREATED_AT.
+       * keybox-update.c (keybox_compress): New.
+
+       * keybox-search.c (get32, get16, blob_get_type) 
+       (blob_get_blob_flags, has_short_kid, has_long_kid) 
+       (has_fingerprint, has_issuer, has_issuer_sn, has_sn, has_subject) 
+       (has_subject_or_alt, has_mail): inline them.
+       
+       * keybox-update.c (blob_filecopy): Fixed an error/eof check
+       (s/if(fread)/if(nread)/).
+
+       * keybox-dump.c (_keybox_dump_blob): Really print the timestamps.
+
 2004-04-20  Werner Koch  <wk@gnupg.org>
 
        * keybox-defs.h: Include jnlib/types.h and remove our own
diff --git a/kbx/Manifest b/kbx/Manifest
new file mode 100644 (file)
index 0000000..95f48d7
--- /dev/null
@@ -0,0 +1,8 @@
+
+keybox-update.c 
+keybox-file.c
+
+
+
+
+$names$
index 9659543..48bce28 100644 (file)
@@ -35,9 +35,11 @@ The first record of a plain KBX file has a special format:
  byte reserved
  byte reserved
  u32  magic 'KBXf'
- byte pgp_marginals  used for validity calculation of this file
- byte pgp_completes  ditto.
- byte pgp_cert_depth ditto.
+ u32  reserved
+ u32  file_created_at
+ u32  last_maintenance_run
+ u32  reserved
+ u32  reserved
 
 The OpenPGP and X.509 blob are very similiar, things which are
 X.509 specific are noted like [X.509: xxx]
@@ -85,7 +87,7 @@ X.509 specific are noted like [X.509: xxx]
  u8    assigned ownertrust [X509: not used]
  u8    all_validity 
            OpenPGP:  see ../g10/trustdb/TRUST_* [not yet used]
-           X509: Bit 4 set := key has been revoked.  nOte that this value
+           X509: Bit 4 set := key has been revoked.  Note that this value
                               matches TRUST_FLAG_REVOKED
  u16   reserved
  u32   recheck_after
@@ -978,6 +980,7 @@ _keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen, off_t off)
   return 0;
 }
 
+
 void
 _keybox_release_blob (KEYBOXBLOB blob)
 {
@@ -1010,3 +1013,19 @@ _keybox_get_blob_fileoffset (KEYBOXBLOB blob)
   return blob->fileoffset;
 }
 
+
+
+void
+_keybox_update_header_blob (KEYBOXBLOB blob)
+{
+  if (blob->bloblen >= 32 && blob->blob[4] == BLOBTYPE_HEADER)
+    {
+      u32 val = make_timestamp ();
+
+      /* Update the last maintenance run times tamp. */
+      blob->blob[20]   = (val >> 24);
+      blob->blob[20+1] = (val >> 16);
+      blob->blob[20+2] = (val >>  8);
+      blob->blob[20+3] = (val      );
+    }
+}
index d7e132d..705762c 100644 (file)
@@ -106,10 +106,13 @@ int  _keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen,
 void _keybox_release_blob (KEYBOXBLOB blob);
 const char *_keybox_get_blob_image (KEYBOXBLOB blob, size_t *n);
 off_t _keybox_get_blob_fileoffset (KEYBOXBLOB blob);
+void _keybox_update_header_blob (KEYBOXBLOB blob);
 
 /*-- keybox-file.c --*/
 int _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp);
+int _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted);
 int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp);
+int _keybox_write_header_blob (FILE *fp);
 
 /*-- keybox-search.c --*/
 gpg_err_code_t _keybox_get_flag_location (const unsigned char *buffer,
index 2177bed..2fb0984 100644 (file)
@@ -78,9 +78,22 @@ print_string (FILE *fp, const byte *p, size_t n, int delim)
 static int
 dump_header_blob (const byte *buffer, size_t length, FILE *fp)
 {
+  unsigned long n;
+
+  if (length < 32)
+    {
+      fprintf (fp, "[blob too short]\n");
+      return -1;
+    }
   fprintf (fp, "Version: %d\n", buffer[5]);
   if ( memcmp (buffer+8, "KBXf", 4))
     fprintf (fp, "[Error: invalid magic number]\n");
+
+  n = get32 (buffer+16); 
+  fprintf( fp, "created-at: %lu\n", n );
+  n = get32 (buffer+20); 
+  fprintf( fp, "last-maint: %lu\n", n );
+
   return 0;
 }
 
@@ -101,7 +114,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
 
   buffer = _keybox_get_blob_image (blob, &length);
   
-  if (length < 40)
+  if (length < 32)
     {
       fprintf (fp, "[blob too short]\n");
       return -1;
@@ -136,6 +149,12 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
       return 0;
     }
   fprintf (fp, "Version: %d\n", buffer[5]);
+
+  if (length < 40)
+    {
+      fprintf (fp, "[blob too short]\n");
+      return -1;
+    }
   
   n = get16 (buffer + 6);
   fprintf( fp, "Blob-Flags: %04lX", n);
@@ -290,11 +309,11 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   fprintf (fp, "All-Validity: %d\n", p[1] );
   p += 4;
   n = get32 (p); p += 4;
-  fprintf (fp, "Recheck-After: %s\n", /*n? strtimestamp(n) :*/ "0" );
+  fprintf (fp, "Recheck-After: %lu\n", n );
   n = get32 (p ); p += 4;
-  fprintf( fp, "Latest-Timestamp: %s\n", "0"/*strtimestamp(n)*/ );
+  fprintf( fp, "Latest-Timestamp: %lu\n", n );
   n = get32 (p ); p += 4;
-  fprintf (fp, "Created-At: %s\n", "0"/*strtimestamp(n)*/ );
+  fprintf (fp, "Created-At: %lu\n", n );
   n = get32 (p ); p += 4;
   fprintf (fp, "Reserved-Space: %lu\n", n );
 
index fc93214..db3164f 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <time.h>
 
 #include "keybox-defs.h"
 
 /* Read a block at the current postion and return it in r_blob.
    r_blob may be NULL to simply skip the current block */
 int
-_keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
+_keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
 {
   char *image;
   size_t imagelen = 0;
@@ -37,6 +38,7 @@ _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
   int rc;
   off_t off;
 
+  *skipped_deleted = 0;
  again:
   *r_blob = NULL;
   off = ftello (fp);
@@ -55,7 +57,7 @@ _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
     }
 
   imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
-  if (imagelen > 500000) /* sanity check */
+  if (imagelen > 500000) /* Sanity check. */
     return gpg_error (GPG_ERR_TOO_LARGE);
   
   if (imagelen < 5) 
@@ -63,9 +65,10 @@ _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
 
   if (!type)
     {
-      /* special treatment for empty blobs. */
+      /* Special treatment for empty blobs. */
       if (fseek (fp, imagelen-5, SEEK_CUR))
         return gpg_error (gpg_err_code_from_errno (errno));
+      *skipped_deleted = 1;
       goto again;
     }
 
@@ -87,6 +90,13 @@ _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
   return rc;
 }
 
+int
+_keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
+{
+  int dummy;
+  return _keybox_read_blob2 (r_blob, fp, &dummy);
+}
+
 
 /* Write the block to the current file position */
 int
@@ -100,3 +110,37 @@ _keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
     return gpg_error (gpg_err_code_from_errno (errno));
   return 0;
 }
+
+
+/* Write a fresh header type blob. */
+int
+_keybox_write_header_blob (FILE *fp)
+{
+  unsigned char image[32];
+  u32 val;
+
+  memset (image, 0, sizeof image);
+  /* Length of this blob. */
+  image[3] = 32;
+
+  image[4] = BLOBTYPE_HEADER;
+  image[5] = 1; /* Version */
+  
+  memcpy (image+8, "KBXf", 4);
+  val = time (NULL);
+  /* created_at and last maintenance run. */
+  image[16]   = (val >> 24);
+  image[16+1] = (val >> 16);
+  image[16+2] = (val >>  8);
+  image[16+3] = (val      );
+  image[20]   = (val >> 24);
+  image[20+1] = (val >> 16);
+  image[20+2] = (val >>  8);
+  image[20+3] = (val      );
+
+  if (fwrite (image, 32, 1, fp) != 1)
+    return gpg_error (gpg_err_code_from_errno (errno));
+  return 0;
+}
+
+
index f23bfda..2ce3c19 100644 (file)
@@ -42,7 +42,7 @@ struct sn_array_s {
 
 
 
-static ulong
+static inline ulong
 get32 (const byte *buffer)
 {
   ulong a;
@@ -53,7 +53,7 @@ get32 (const byte *buffer)
   return a;
 }
 
-static ulong
+static inline ulong
 get16 (const byte *buffer)
 {
   ulong a;
@@ -64,20 +64,20 @@ get16 (const byte *buffer)
 
 
 
-static int
+static inline int
 blob_get_type (KEYBOXBLOB blob)
 {
   const unsigned char *buffer;
   size_t length;
 
   buffer = _keybox_get_blob_image (blob, &length);
-  if (length < 40)
+  if (length < 32)
     return -1; /* blob too short */
 
   return buffer[4];
 }
 
-static unsigned int
+static inline unsigned int
 blob_get_blob_flags (KEYBOXBLOB blob)
 {
   const unsigned char *buffer;
@@ -113,8 +113,9 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
       *flag_size = 2;
       break;
     
-    case KEYBOX_FLAG_VALIDITY:
     case KEYBOX_FLAG_OWNERTRUST:
+    case KEYBOX_FLAG_VALIDITY:
+    case KEYBOX_FLAG_CREATED_AT:
       if (length < 20)
         return GPG_ERR_INV_OBJ;
       /* Key info. */
@@ -148,8 +149,18 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
         return GPG_ERR_INV_OBJ ; /* Out of bounds. */
       *flag_size = 1;
       *flag_off = pos;
-      if (what == KEYBOX_FLAG_VALIDITY)
-        ++*flag_off;
+      switch (what)
+        {
+        case KEYBOX_FLAG_VALIDITY:
+          *flag_off += 1;
+          break;
+        case KEYBOX_FLAG_CREATED_AT:
+          *flag_size = 4;
+          *flag_off += 1+2+4+4+4;
+          break;
+        default:
+          break;
+        }
       break;
 
     default:
@@ -158,6 +169,8 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
   return 0;
 }
 
+
+
 /* Return one of the flags WHAT in VALUE from teh blob BUFFER of
    LENGTH bytes.  Return 0 on success or an raw error code. */
 static gpg_err_code_t
@@ -447,26 +460,26 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
 /*
   The has_foo functions are used as helpers for search 
 */
-static int
+static inline int
 has_short_kid (KEYBOXBLOB blob, const unsigned char *kid)
 {
   return blob_cmp_fpr_part (blob, kid+4, 16, 4);
 }
 
-static int
+static inline int
 has_long_kid (KEYBOXBLOB blob, const unsigned char *kid)
 {
   return blob_cmp_fpr_part (blob, kid, 12, 8);
 }
 
-static int
+static inline int
 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
 {
   return blob_cmp_fpr (blob, fpr);
 }
 
 
-static int
+static inline int
 has_issuer (KEYBOXBLOB blob, const char *name)
 {
   size_t namelen;
@@ -480,7 +493,7 @@ has_issuer (KEYBOXBLOB blob, const char *name)
   return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
 }
 
-static int
+static inline int
 has_issuer_sn (KEYBOXBLOB blob, const char *name,
                const unsigned char *sn, int snlen)
 {
@@ -498,7 +511,7 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name,
           && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
 }
 
-static int
+static inline int
 has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
 {
   return_val_if_fail (sn, 0);
@@ -508,7 +521,7 @@ has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
   return blob_cmp_sn (blob, sn, snlen);
 }
 
-static int
+static inline int
 has_subject (KEYBOXBLOB blob, const char *name)
 {
   size_t namelen;
@@ -522,7 +535,7 @@ has_subject (KEYBOXBLOB blob, const char *name)
   return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
 }
 
-static int
+static inline int
 has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
 {
   size_t namelen;
@@ -538,7 +551,7 @@ has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
 }
 
 
-static int
+static inline int
 has_mail (KEYBOXBLOB blob, const char *name, int substr)
 {
   size_t namelen;
@@ -728,6 +741,10 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
       if (rc)
         break;
 
+      if (blob_get_type (blob) == BLOBTYPE_HEADER)
+        continue;
+
+
       blobflags = blob_get_blob_flags (blob);
       if (!hd->ephemeral && (blobflags & 2))
         continue; /* not in ephemeral mode but blob is flagged ephemeral */
@@ -906,7 +923,7 @@ keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *r_cert)
 
 #endif /*KEYBOX_WITH_X509*/
 
-/* Return the flags named WHAT iat the address of VALUE. IDX is used
+/* Return the flags named WHAT at the address of VALUE. IDX is used
    only for certain flags and should be 0 if not required. */
 int
 keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value)
index 47e5396..1695550 100644 (file)
@@ -1,5 +1,5 @@
 /* keybox-update.c - keybox update operations
- *     Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "keybox-defs.h"
@@ -193,29 +194,30 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
 
   fp = fopen (fname, "rb");
   if (mode == 1 && !fp && errno == ENOENT)
-    { /* insert mode but file does not exist: create a new keybox file */
+    { 
+      /* Insert mode but file does not exist:
+         Create a new keybox file. */
       newfp = fopen (fname, "wb");
       if (!newfp )
-        {
-          return gpg_error (gpg_err_code_from_errno (errno));
-       }
+        return gpg_error (gpg_err_code_from_errno (errno));
+
+      rc = _keybox_write_header_blob (newfp);
+      if (rc)
+        return rc;
 
       rc = _keybox_write_blob (blob, newfp);
       if (rc)
-        {
-          return rc;
-        }
+        return rc;
+
       if ( fclose (newfp) )
-        {
-          return gpg_error (gpg_err_code_from_errno (errno));
-       }
+        return gpg_error (gpg_err_code_from_errno (errno));
 
 /*        if (chmod( fname, S_IRUSR | S_IWUSR )) */
 /*          { */
 /*            log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
 /*            return KEYBOX_File_Error; */
 /*          } */
-      return 0; /* ready */
+      return 0; /* Ready. */
     }
 
   if (!fp)
@@ -224,7 +226,7 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
       goto leave;
     }
 
-  /* create the new file */
+  /* Create the new file. */
   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
   if (rc)
     {
@@ -235,7 +237,7 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
   /* prepare for insert */
   if (mode == 1)
     { 
-      /* copy everything to the new file */
+      /* Copy everything to the new file. */
       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
         {
           if (fwrite (buffer, nread, 1, newfp) != 1)
@@ -251,19 +253,19 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
         }
     }
   
-  /* prepare for delete or update */
+  /* Prepare for delete or update. */
   if ( mode == 2 || mode == 3 ) 
     { 
       off_t current = 0;
       
-      /* copy first part to the new file */
+      /* Copy first part to the new file. */
       while ( current < start_offset )
         {
           nbytes = DIM(buffer);
           if (current + nbytes > start_offset)
               nbytes = start_offset - current;
           nread = fread (buffer, 1, nbytes, fp);
-          if (!fread)
+          if (!nread)
             break;
           current += nread;
           
@@ -279,13 +281,13 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
           goto leave;
         }
       
-      /* skip this blob */
+      /* Skip this blob. */
       rc = _keybox_read_blob (NULL, fp);
       if (rc)
         return rc;
     }
   
-  /* Do an insert or update */
+  /* Do an insert or update. */
   if ( mode == 1 || mode == 3 )
     { 
       rc = _keybox_write_blob (blob, newfp);
@@ -293,7 +295,7 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
           return rc;
     }
   
-  /* copy the rest of the packet for an delete or update */
+  /* Copy the rest of the packet for an delete or update. */
   if (mode == 2 || mode == 3)
     { 
       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
@@ -311,7 +313,7 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
         }
     }
     
-  /* close both files */
+  /* Close both files. */
   if (fclose(fp))
     {
       rc = gpg_error (gpg_err_code_from_errno (errno));
@@ -334,7 +336,6 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
 
 
 
-
 #ifdef KEYBOX_WITH_X509 
 int
 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
@@ -352,7 +353,7 @@ keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
   if (!fname)
     return gpg_error (GPG_ERR_INV_HANDLE); 
 
-  /* close this one otherwise we will mess up the position for a next
+  /* Close this one otherwise we will mess up the position for a next
      search.  Fixme: it would be better to adjust the position after
      the write opertions.  */
   if (hd->fp)
@@ -517,3 +518,181 @@ keybox_delete (KEYBOX_HANDLE hd)
 }
 
 
+/* Compress the keybox file.  This should be run with the file
+   locked. */
+int
+keybox_compress (KEYBOX_HANDLE hd)
+{
+  int read_rc, rc;
+  const char *fname;
+  FILE *fp, *newfp;
+  char *bakfname = NULL;
+  char *tmpfname = NULL;
+  int first_blob;
+  KEYBOXBLOB blob = NULL;
+  u32 cut_time;
+  int any_changes = 0;
+  int skipped_deleted;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_HANDLE); 
+  if (!hd->kb)
+    return gpg_error (GPG_ERR_INV_HANDLE); 
+  if (hd->secret)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  fname = hd->kb->fname;
+  if (!fname)
+    return gpg_error (GPG_ERR_INV_HANDLE); 
+
+  if (hd->fp)
+    {
+      fclose (hd->fp);
+      hd->fp = NULL;
+    }
+
+  /* Open the source file. Because we do a rename, we have to check the 
+     permissions of the file */
+  if (access (fname, W_OK))
+    return gpg_error (gpg_err_code_from_errno (errno));
+
+  fp = fopen (fname, "rb");
+  if (!fp && errno == ENOENT)
+    return 0; /* Ready. File has been deleted right after the access above. */
+  if (!fp)
+    {
+      rc = gpg_error (gpg_err_code_from_errno (errno));
+      return rc;
+    }
+
+  /* A quick test to see if we need to compress the file at all.  We
+     schedule a compress run after 3 hours. */
+  if ( !_keybox_read_blob (&blob, fp) )
+    {
+      const unsigned char *buffer;
+      size_t length;
+
+      buffer = _keybox_get_blob_image (blob, &length);
+      if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
+        {
+          u32 last_maint = ((buffer[20] << 24) | (buffer[20+1] << 16)
+                            | (buffer[20+2] << 8) | (buffer[20+3]));
+          
+          if ( (last_maint + 3*3600) > time (NULL) )
+            {
+              fclose (fp);
+              _keybox_release_blob (blob);
+              return 0; /* Compress run not yet needed. */
+            }
+        }
+      _keybox_release_blob (blob);
+      rewind (fp);
+    }
+
+  /* Create the new file. */
+  rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
+  if (rc)
+    {
+      fclose(fp);
+      return rc;;
+    }
+
+  
+  /* Processing loop.  By reading using _keybox_read_blob we
+     automagically skip and blobs flagged as deleted.  Thus what we
+     only have to do is to check all ephemeral flagged blocks whether
+     their time has come and write out all other blobs. */
+  cut_time = time(NULL) - 86400;
+  first_blob = 1;
+  skipped_deleted = 0;
+  for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
+       _keybox_release_blob (blob), blob = NULL )
+    {
+      unsigned int blobflags;
+      const unsigned char *buffer;
+      size_t length, pos, size;
+      u32 created_at;
+
+      if (skipped_deleted)
+        any_changes = 1;
+      buffer = _keybox_get_blob_image (blob, &length);
+      if (first_blob)
+        {
+          first_blob = 0;
+          if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
+            {
+              /* Write out the blob with an updated maintenance time stamp. */
+              _keybox_update_header_blob (blob);
+              rc = _keybox_write_blob (blob, newfp);
+              if (rc)
+                break;
+              continue;
+            }
+
+          /* The header blob is missing.  Insert it.  */
+          rc = _keybox_write_header_blob (newfp);
+          if (rc)
+            break;
+          any_changes = 1;
+        }
+      else if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
+        {
+          /* Oops: There is another header record - remove it. */
+          any_changes = 1;
+          continue;
+        }
+
+      if (_keybox_get_flag_location (buffer, length, 
+                                     KEYBOX_FLAG_BLOB, &pos, &size)
+          || size != 2)
+        {
+          rc = gpg_error (GPG_ERR_BUG);
+          break;
+        }
+      blobflags = ((buffer[pos] << 8) | (buffer[pos+1]));
+      if ((blobflags & 2))
+        {
+          /* This is an ephemeral blob. */
+          if (_keybox_get_flag_location (buffer, length, 
+                                         KEYBOX_FLAG_CREATED_AT, &pos, &size)
+              || size != 4)
+            created_at = 0; /* oops. */
+          else
+            created_at = ((buffer[pos] << 24) | (buffer[pos+1] << 16)
+                          | (buffer[pos+2] << 8) | (buffer[pos+3]));
+
+          if (created_at && created_at < cut_time)
+            {
+              any_changes = 1;
+              continue; /* Skip this blob. */
+            }
+        }
+
+      rc = _keybox_write_blob (blob, newfp);
+      if (rc)
+        break;
+    }
+  if (skipped_deleted)
+    any_changes = 1;
+  _keybox_release_blob (blob); blob = NULL;
+  if (!rc && read_rc == -1)
+    rc = 0;
+  else if (!rc)
+    rc = read_rc;
+
+  /* Close both files. */
+  if (fclose(fp) && !rc)
+    rc = gpg_error (gpg_err_code_from_errno (errno));
+  if (fclose(newfp) && !rc)
+    rc = gpg_error (gpg_err_code_from_errno (errno));
+
+  /* Rename or remove the temporary file. */
+  if (rc || !any_changes)
+    remove (tmpfname);
+  else
+    rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
+
+  xfree(bakfname);
+  xfree(tmpfname);
+  return rc;
+}
+
index e4dc9d6..af1fc45 100644 (file)
@@ -52,9 +52,10 @@ typedef enum
     KEYBOX_FLAG_OWNERTRUST, /* The assigned ownertrust. */
     KEYBOX_FLAG_KEY,        /* The key flags; requires a key index. */
     KEYBOX_FLAG_UID,        /* The user ID flags; requires an uid index. */
-    KEYBOX_FLAG_UID_VALIDITY/* The validity of a specific uid, requires
+    KEYBOX_FLAG_UID_VALIDITY,/* The validity of a specific uid, requires
                                an uid index. */
-  } keyxox_flag_t;
+    KEYBOX_FLAG_CREATED_AT  /* The date the block was created. */
+  } keybox_flag_t;
 
 
 /*-- keybox-init.c --*/
@@ -87,6 +88,7 @@ int keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
 int keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value);
 
 int keybox_delete (KEYBOX_HANDLE hd);
+int keybox_compress (KEYBOX_HANDLE hd);
 
 
 /*--  --*/
index 28171b9..8c0297d 100644 (file)
@@ -1,5 +1,7 @@
 2004-04-23  Werner Koch  <wk@gnupg.org>
 
+       * keydb.c (keydb_add_resource): Try to compress the file on init.
+
        * keylist.c (oidtranstbl): New.  OIDs collected from several sources.
        (print_name_raw, print_names_raw, list_cert_raw): New.
        (gpgsm_list_keys): Check the dump mode and pass it down as
index 858baf2..3223075 100644 (file)
@@ -218,10 +218,25 @@ keydb_add_resource (const char *url, int force, int secret)
                 = create_dotlock (filename);
               if (!all_resources[used_resources].lockhandle)
                 log_fatal ( _("can't create lock for `%s'\n"), filename);
+
+              /* Do a compress run if needed and the file is not locked. */
+              if (!make_dotlock (all_resources[used_resources].lockhandle, 0))
+                {
+                  KEYBOX_HANDLE kbxhd = keybox_new (token, secret);
+                  
+                  if (kbxhd)
+                    {
+                      keybox_compress (kbxhd);
+                      keybox_release (kbxhd);
+                    }
+                  release_dotlock (all_resources[used_resources].lockhandle);
+                }
                   
               used_resources++;
             }
         }
+
+
        break;
     default:
       log_error ("resource type of `%s' not supported\n", url);