/****************
 * Flush the cache.  This cannot be used while in a transaction.
 */
int
tdbio_sync()
{
    CACHE_CTRL r;
    int did_lock = 0;

    if( db_fd == -1 )
	open_db();
    if( in_transaction )
	log_bug("tdbio: syncing while in transaction\n");

    if( !cache_is_dirty )
	return 0;

    if (!take_write_lock ())
        did_lock = 1;

    for( r = cache_list; r; r = r->next ) {
	if( r->flags.used && r->flags.dirty ) {
	    int rc = write_cache_item( r );
	    if( rc )
		return rc;
	}
    }
    cache_is_dirty = 0;
    if (did_lock)
        release_write_lock ();

    return 0;
}
int
tdbio_end_transaction()
{
    int rc;

    if( !in_transaction )
	log_bug("tdbio: no active transaction\n");
    take_write_lock ();
    block_all_signals();
    in_transaction = 0;
    rc = tdbio_sync();
    unblock_all_signals();
    release_write_lock ();
    return rc;
}
Exemple #3
0
int demultiplex_write(void *session, int fd, int id, const void *buf, size_t size)
{
   int result;
   msg_header_t msg_header;
   int write_lock_held = 0;
   int error_return = -1;

   msg_header.msg_size = size;
   msg_header.msg_target = id;

   result = take_write_lock(session);
   if (result == -1)
      goto error;
   write_lock_held = 1;

   result = reliable_write(fd, &msg_header, sizeof(msg_header));
   if (result == -1) {
      set_last_error("Error writing header from client to server");
      goto error;
   }
   if (result == 0) 
      goto eof_error;

   result = reliable_write(fd, buf, size);
   if (result == -1) {
      set_last_error("Error writing message from client to server");
      goto error;
   }
   if (result == 0) 
      goto eof_error;

   result = release_write_lock(session);
   if (result == -1)
      goto error;
   write_lock_held = 0;

   return size;

  eof_error:
   error_return = 0;
  error:
   if (write_lock_held)
      release_write_lock(session);

   return error_return;
}
int
tdbio_set_dbname( const char *new_dbname, int create, int *r_nofile)
{
    char *fname;
    struct stat statbuf;
    static int initialized = 0;

    if( !initialized ) {
	atexit( cleanup );
	initialized = 1;
    }

    *r_nofile = 0;

    if(new_dbname==NULL)
      fname=make_filename(opt.homedir,"trustdb" EXTSEP_S "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;

    /*
     * 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)
      /* OK, we have the valid trustdb.gpg already.  */
      return 0;

    take_write_lock ();

    if( access( fname, R_OK ) ) {
        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 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;
            }
#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);
	    }
	    *p = save_slash;

	    oldmask=umask(077);
            if (is_secured_filename (fname)) {
                fp = NULL;
                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) );

            rc = create_version_record ();
	    if( rc )
		log_fatal( _("%s: failed to create version record: %s"),
						   fname, g10_errstr(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 );

	    if( !opt.quiet )
		log_info(_("%s: trustdb created\n"), db_name);
	}
    }

    release_write_lock ();
    return 0;
}
/****************
 * Put data into the cache.  This function may flush the
 * some cache entries if there is not enough space available.
 */
int
put_record_into_cache( ulong recno, const char *data )
{
    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;
	}
	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;
		}
	    }
	    memcpy( r->data, data, TRUST_RECORD_LEN );
	    return 0;
	}
	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;
    }
    /* 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;
    }
    /* 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;
	    }
	}
	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;
	}
	log_info(_("trustdb transaction too large\n"));
	return G10ERR_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;
	    }
	}
        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;
    }
    BUG();
}
Exemple #6
0
/*
 * 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)
{
  char *fname, *p;
  struct stat statbuf;
  static int initialized = 0;
  int save_slash;

  if (!initialized)
    {
      atexit (cleanup);
      initialized = 1;
    }

  *r_nofile = 0;

  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;

  /* 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;
    }
  else if (!create)
    {
      *r_nofile = 1;
      return 0;
    }

  /* Here comes: No valid trustdb.gpg AND CREATE==1 */

  /*
   * Make sure the directory exists.  This should be done before
   * acquiring the lock, which assumes the existence of the directory.
   */
  p = strrchr (fname, DIRSEP_C);
#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;
  }
#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);
    }
  *p = save_slash;

  take_write_lock ();

  if (access (fname, R_OK))
    {
      FILE *fp;
      TRUSTREC rec;
      int rc;
      mode_t oldmask;

#ifdef HAVE_W32CE_SYSTEM
      /* We know how the cegcc implementation of access works ;-). */
      if (GetLastError () == ERROR_FILE_NOT_FOUND)
        gpg_err_set_errno (ENOENT);
      else
        gpg_err_set_errno (EIO);
#endif /*HAVE_W32CE_SYSTEM*/
      if (errno != ENOENT)
        log_fatal ( _("can't access '%s': %s\n"), fname, strerror (errno));

      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));

      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;
}