Logo Search packages:      
Sourcecode: ladcca version File versions  Download package

store.c

/*
 *   LADCCA
 *    
 *   Copyright (C) 2002 Robert Ham <rah@bash.sh>
 *    
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>


#include <ladcca/ladcca.h>
#include <ladcca/internal_headers.h>

#include "store.h"
#include "globals.h"

#define STORE_INFO_FILE ".store_info"

void
store_free (store_t * store)
{
  cca_list_t * list;
  cca_config_t * config;
  
  store_set_dir (store, NULL);
  
  list = store->keys;
  while (list)
    {
      free (list->data);
      list = list->next;
    }
  cca_list_free (store->keys);
  
  list = store->unstored_configs;
  while (list)
    {
      config = (cca_config_t *) list->data;
      cca_config_destroy (config);
      list = list->next;
    }
  cca_list_free (store->unstored_configs);
}

store_t *
store_new ()
{
  store_t * store;
  store = cca_malloc0 (sizeof (store_t));
  return store;
}

void
store_destroy (store_t * store)
{
  store_free (store);
  free (store);
}

void
store_set_dir (store_t * store, const char * dir)
{
  set_string_property (store->dir, dir);
}

const char *
store_get_info_filename (store_t * store)
{
  get_store_and_return_fqn (store->dir, STORE_INFO_FILE);
}

const char *
store_get_config_filename (store_t * store, const char * key)
{
  get_store_and_return_fqn (store->dir, key);
}

int
store_open (store_t * store)
{
  unsigned long i;
  FILE * info_file;
  char * line = NULL;
  size_t line_size = 0;
  ssize_t err;
  char * ptr;
  
  CCA_DEBUGARGS ("reading store in dir '%s'", store->dir);
  
  if (!cca_dir_exists (store->dir))
    return 0;
  
  if (!cca_file_exists (store_get_info_filename (store)))
    return 0;
  
  /* open the info file */
  info_file = fopen (store_get_info_filename (store), "r");
  if (!info_file)
    {
      fprintf (stderr, "%s: could not open info file for store '%s': %s\n",
               __FUNCTION__, store->dir, strerror (errno));
      return 1;
    }
  
  /* read the number of keys */
  err = getline (&line, &line_size, info_file);
  if (err == -1)
    {
      fprintf (stderr, "%s: error reading from info file for store '%s': %s\n",
               __FUNCTION__, store->dir, strerror (errno));
      if (line) free (line);
      return 1;
    }
  
  store->key_count = strtol (line, NULL, 10);
  
  for (i = 0; i < store->key_count; i++)
    {
      err = getline (&line, &line_size, info_file);
      if (err == -1)
        {
          cca_list_t * list;
          
          fprintf (stderr, "%s: error reading from info file for store '%s': %s\n",
                   __FUNCTION__, store->dir, strerror (errno));
          free (line);
          
          list = store->keys;
          while (list)
            {
              free (list->data);
              list = list->next;
            }
          cca_list_free (store->keys);
          store->keys = 0;
          store->key_count = 0;
          
          return 1;
        }
      
      ptr = strchr (line, '\n');
      if (ptr)
        *ptr = '\0';
      
      store->keys = cca_list_append (store->keys, cca_strdup (line));
    }
  
  err = fclose (info_file);
  if (err)
    {
      fprintf (stderr, "%s: error closing info file for store '%s': %s\n",
             __FUNCTION__, store->dir, strerror (errno));
    }
  
#ifdef LADCCA_DEBUG
  {
    cca_list_t * list;
    list = store->keys;
    
    if (list)
      {
        CCA_DEBUGARGS ("opened store in '%s' with keys: ", store->dir);
        for (; list; list = cca_list_next (list))
          {
            CCA_DEBUGARGS ("  '%s'", (char *) list->data);
          }
      }
    else
      {
        CCA_DEBUGARGS ("opened store in '%s' with no keys", store->dir);
      }
      
    
  }
#endif

  return 0;
}

void
store_remove_config (store_t * store, const char * key)
{
  cca_list_t * list;
  char * old_key;
  cca_config_t * config;
  
  /* remove the key */
  for (list = store->keys; list; list = cca_list_next (list))
    {
      old_key = (char *) list->data;
      
      if (strcmp (key, old_key) == 0)
        {
          store->keys = cca_list_remove (store->keys, old_key);
          store->key_count--;
          free (old_key);

          break;
        }
    }
    
  /* check if there's one in the unstored configs */
  for (list = store->unstored_configs; list; list = cca_list_next (list))
    {
      config = (cca_config_t *) list->data;
      
      if (strcmp (cca_config_get_key (config), key) == 0)
        {
          store->unstored_configs = cca_list_remove (store->unstored_configs, config);
          cca_config_destroy (config);
          break;
        }
    }
  
  
  /* add it to the list of removed configs */
  store->removed_configs = cca_list_append (store->removed_configs, cca_strdup (key));
}

void
store_set_config (store_t * store, const cca_config_t * config)
{
  cca_list_t * list;
  char * key;
  cca_config_t * exconfig;
  
  /* possibly add the new key to the list */
  for (list = store->keys; list; list = cca_list_next (list))
    {
      key = (char *) list->data;
      if (strcmp (key, cca_config_get_key (config)) == 0)
        break;
    }
  
  if (!list) {
    store->keys = cca_list_append (store->keys, cca_strdup (cca_config_get_key (config)));
    store->key_count++;
  }
  
  
  /* check whether we're overwriting a previous config, and remove it if we are */
  for (list = store->unstored_configs; list; list = cca_list_next (list))
    {
      exconfig = (cca_config_t *) list->data;
      
      if (strcmp (cca_config_get_key (config), cca_config_get_key (exconfig)) == 0)
        {
          store->unstored_configs = cca_list_remove (store->unstored_configs, exconfig);
          cca_config_destroy (exconfig);
          break;
        }
    }
  
  /* add it to the unstored list */
  store->unstored_configs = cca_list_append (store->unstored_configs, cca_config_dup (config));
}

int
store_write_config (store_t * store, const cca_config_t * config)
{
  int config_file;
  ssize_t written;
  uint32_t size;
  int err;
  
  config_file = creat (store_get_config_filename (store, cca_config_get_key (config)),
                       S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
  
  if (config_file == -1)
    {
      fprintf (stderr, "%s: error opening config file '%s' for writing in store '%s'!: %s\n", 
               __FUNCTION__, cca_config_get_key (config), store->dir,
               strerror (errno));
      return 1;
    }
  
  size = htonl (cca_config_get_value_size (config));
  
  written = write (config_file, &size, sizeof (size));
  if (written == -1 || written < sizeof (size))
    {
      fprintf (stderr, "%s: error writing to config file '%s' in store '%s'!: %s\n",
               __FUNCTION__, cca_config_get_key (config), store->dir, strerror (errno));
      close (config_file);
      return 1;
    }
  
  if (size > 0)
    {
      written = write (config_file, cca_config_get_value (config), cca_config_get_value_size (config));
      if (written == -1 || written < sizeof (size))
        {
          fprintf (stderr, "%s: error writing to config file '%s' in store '%s'!: %s\n",
                   __FUNCTION__, cca_config_get_key (config), store->dir, strerror (errno));
          close (config_file);
          return 1;
        }
   }
  
  err = close (config_file);
  if (err == -1)
    {
      fprintf (stderr, "%s: error close config file '%s' in store '%s'!: %s\n",
               __FUNCTION__, cca_config_get_key (config), store->dir, strerror (errno));
      return 1;
    }
  
  return 0;
}

int
store_remove_written_config (store_t * store, const char * key)
{
  int err;
  const char * filename;
  
  filename = store_get_config_filename (store, key);
  
  err = unlink (filename);
  if (err == -1)
    {
      fprintf (stderr, "%s: could not unlink config data file '%s': %s\n",
               __FUNCTION__, filename, strerror (errno));
      return 1;
    }
  
  return 0;
}

int
store_write_configs (store_t * store)
{
  cca_list_t * list, * old_list;
  cca_config_t * config;
  char * key;
  int err;
  int ret_err = 0;

  for (list = store->unstored_configs; list;)
    {
      config = (cca_config_t *) list->data;

      old_list = list;
      list = cca_list_next (list);
      
      err = store_write_config (store, config);
      if (err)
        ret_err = 1;
      else
        store->unstored_configs = cca_list_remove (store->unstored_configs, old_list);
    }
  
  /* remove the removed configs */
  list = store->removed_configs;
  for (list = store->removed_configs; list;)
    {
      key = (list->data);
      
      old_list = list;
      list = cca_list_next (list);
      
      err = store_remove_written_config (store, key);
      
      free (key);
      
      if (err)
        ret_err = 1;
      else
        store->removed_configs = cca_list_remove (store->removed_configs, old_list);
    }
  
  return ret_err;
}

int
store_write_info_file (store_t * store)
{
  cca_list_t * list;
  char * key;
  FILE * info_file;
  int err;

  info_file = fopen (store_get_info_filename (store), "w");
  if (!info_file)
    {
      fprintf (stderr, "%s: error opening info file for store '%s'!: %s\n",
               __FUNCTION__, store->dir, strerror (errno));
      return 1;
    }
  
  err = fprintf (info_file, "%ld\n", store->key_count);
  if (err < 0)
    {
      fprintf (stderr, "%s: error writing to info file for store '%s'!: %s\n",
               __FUNCTION__, store->dir, strerror (errno));
      fclose (info_file);
      return 1;
    }

  list = store->keys;
  while (list)
    {
      key = (char *) list->data;
      
      err = fprintf (info_file, "%s\n", key);
      if (err < 0)
        {
          fprintf (stderr, "%s: error writing to info file for store '%s'!: %s\n",
                   __FUNCTION__, store->dir, strerror (errno));
          fclose (info_file);
          return 1;
        }
      
      list = list->next;
    }

  err = fclose (info_file);
  if (err == EOF)
    {
      fprintf (stderr, "%s: error closing info file for store '%s'!: %s\n",
               __FUNCTION__, store->dir, strerror (errno));
      return 1;
    }
  
  return 0;
}

void
store_remove_configs (store_t * store)
{
  cca_list_t * list;
  char * key;
  const char * filename;
  int err;
  
  list = store->removed_configs;
  while (list)
    {
      key = (char *) list->data;
      
      
      filename = store_get_config_filename (store, key);

      CCA_DEBUGARGS ("removing config with key '%s', filename '%s'", key, filename);
      
      if (cca_file_exists (filename))
        {
          err = unlink (filename);
          if (err == -1)
            fprintf (stderr, "%s: could not remove file '%s': %s\n",
                     __FUNCTION__, filename, strerror (errno));
        }
      
      free (key);
      
      list = list->next;
    }
  
  cca_list_free (store->removed_configs);
  store->removed_configs = NULL;
}

int
store_write (store_t * store)
{
  cca_list_t * list;
  int err;
  
  if (!store->unstored_configs)
    return 0;
  
  if (!cca_dir_exists (store->dir))
    cca_create_dir (store->dir);
  
  /* write the config files */
  err = store_write_configs (store);
  if (err)
    {
      fprintf (stderr, "%s: error writing configs; returning\n", __FUNCTION__);
      return 1;
    }
  
  /* write the info file */
  err = store_write_info_file (store);
  if (err)
    {
      fprintf (stderr, "%s: error writing info file; returning\n", __FUNCTION__);
      return 1;
    }
  
  /* only delete the unstored data now we're sure it's all been written
   * (or at least given to the OS) */
  for (list = store->unstored_configs; list; list = cca_list_next (list))
    {
      cca_config_destroy ((cca_config_t *) list->data);
    }
  cca_list_free (store->unstored_configs);
  store->unstored_configs = NULL;

  store_remove_configs (store);
  
  return 0;
}

unsigned long
store_get_key_count (const store_t * store)
{
  return store->key_count;
}

cca_list_t *
store_get_keys (store_t * store)
{
  return store->keys;
}

cca_config_t *
store_get_unstored_config (store_t * store, const char * key)
{
  cca_list_t * list;
  cca_config_t * config;
  
  for (list = store->unstored_configs; list; list = cca_list_next (list))
    {
      config = (cca_config_t *) list->data;
      
      if (strcmp (cca_config_get_key (config), key) == 0)
        return cca_config_dup (config);
      
    }
  
  return NULL;
}

cca_config_t *
store_get_config (store_t * store, const char * key)
{
  uint32_t size;
  void * value;
  size_t value_size;
  int config_file;
  cca_config_t * config;
  ssize_t err;

  config = store_get_unstored_config (store, key);
  if (config)
    return config;
  
  config_file = open (store_get_config_filename (store, key), O_RDONLY);
  if (config_file == -1)
    {
      fprintf (stderr, "%s: could not open config file '%s' for reading!: %s\n",
               __FUNCTION__, store_get_config_filename (store, key), strerror (errno));
      return NULL;
    }
  
  err = read (config_file, &size, sizeof (size));
  if (err == -1 || err < sizeof (size))
    {
      fprintf (stderr, "%s: error reading value size in config file '%s': %s\n",
               __FUNCTION__, store_get_config_filename (store, key),
               err == -1 ? strerror (errno) : "not enough data read");
      close (config_file);
      return NULL;
    }
  
  value_size = ntohl (size);
  if (value_size > 0)
    {
      value = cca_malloc (value_size);
  
      err = read (config_file, value, value_size);
      if (err == -1 || err < sizeof (size))
        {
          fprintf (stderr, "%s: error reading value size in config file '%s': %s\n",
                   __FUNCTION__, store_get_config_filename (store, key),
                   err == -1 ? strerror (errno) : "not enough data read");
          close (config_file);
          free (value);
          return NULL;
        }
    }
    
  err = close (config_file);
  if (err == -1)
    {
      fprintf (stderr, "%s: error closing config file '%s': %s\n",
               __FUNCTION__, store_get_config_filename (store, key), strerror (errno));
    }
  
  config = cca_config_new ();
  cca_config_set_key (config, key);
  if (value_size > 0)
    {
      cca_config_set_value (config, value, value_size);
      free (value);
    }
  
  return config;
}



/* EOF */


Generated by  Doxygen 1.6.0   Back to index