/*
 * dbcreate.c
 * File revision 0
 * Create database files.
 * (c) 2000 Jacob Lundberg, jacob@chaos2.org
 */


/*
 * 2000.10.20	Initial implementation
 */


#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include "db.h"


int db_create(char *file_name, int key_size, int data_size, int hash_size) {
/*
 * db_create()
 * Create the database named file_name, if it's possible.
 */

   FILE *file = NULL;
   struct stat file_info;
   db_data_header data_header;
   db_header header;

   /* Get a prime hash size. */
   hash_size = hash_above(hash_size);

   /* Check args for ``reasonable'' limits. */
   if(strlen(file_name) > DB_PATH_MAX + 5 ||
         key_size > DB_KEY_MAX || key_size < 2 ||
         hash_size < 1) {
      errno = EINVAL;
      return(-1);
   }

   /* Make sure the file doesn't exist yet. */
   if(!stat(file_name, &file_info)) {
      errno = EEXIST;
      return(-1);
   }

   /* Pass other errors on down the chain. */
   if(errno != ENOENT)
      /* Bad errors. */
      return(-1);
   else
      /* We are actually hoping for this error. */
      errno = 0;

   /* In this case we should be able to attempt file creation. */
   file = fopen(file_name, "w+");
   if(file == NULL) return(-1);

   /* Clear all the header values. */
   header.space_table = DB_HEADER_SIZE + DB_LOCK_SIZE + sizeof(off_t) * hash_size;
   header.trans_table = DB_HEADER_SIZE;
   header.min_data_size = data_size;
   header.max_key_size = key_size;
   header.hash_size = hash_size;
   header.lock.read_count = 0;
   header.lock.lock_bits = 0;
   header.lock.write_pid = 0;
   header.lock.lock_pid = 0;

   /* Write out the new file header. */
   if(fseek(file, 0, SEEK_SET) || !fwrite(&header, DB_HEADER_SIZE, 1, file)) {
      fclose(file);
      unlink(file_name);
      return(-1);
   }

   /* Create a free space descriptor. */
   data_header.lock.read_count = 0;
   data_header.lock.lock_bits = 0;
   data_header.lock.write_pid = 0;
   data_header.lock.lock_pid = 0;
   data_header.size = -1;
   data_header.next = -1;

   /* Write out the new free space descriptor. */
   if(fseek(file, DB_HEADER_SIZE + DB_LOCK_SIZE + sizeof(off_t) * hash_size, SEEK_SET) ||
         !fwrite(&data_header, DB_DATA_HEADER_SIZE, 1, file)) {
      fclose(file);
      unlink(file_name);
      return(-1);
   }

   /* Close the newly created database (open is done elsewhere). */
   fclose(file);

   /* Return zero on success. */
   return(0);

}

