New module gip: Gateway IPc module.
[egate.git] / util / gw-db.c
diff --git a/util/gw-db.c b/util/gw-db.c
new file mode 100644 (file)
index 0000000..5bbe23f
--- /dev/null
@@ -0,0 +1,290 @@
+/* Gateway utility
+ * Europagate, 1995
+ *
+ * $Log: gw-db.c,v $
+ * Revision 1.1  1995/03/27 08:25:01  adam
+ * New module gip: Gateway IPc module.
+ * New module gw-db: Gateway hash-db module (user information table).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <gw-db.h>
+
+#define FILE_HEAD_LEN 128
+#define DB_HASH 1997
+
+struct gw_db {
+    struct file_head {
+        char magic[8];
+       int no_of_entries;
+       int sequence_no;
+    } head;
+    int *hash_array;
+    int fd;
+    int dirty;
+};
+
+struct db_bucket {
+    int  name_length;
+    int  info_length;
+    int  next;
+    int  prev;
+};
+
+static int write_head (GW_DB db)
+{
+    char file_head_buf[FILE_HEAD_LEN];
+    int r;
+
+    if (lseek (db->fd, 0L, SEEK_SET) == -1)
+        return -1;
+    memcpy (file_head_buf, &db->head, sizeof(db->head));
+    r = write (db->fd, file_head_buf, FILE_HEAD_LEN);
+    if (r == -1)
+        return -1;
+    r = write (db->fd, db->hash_array, DB_HASH * sizeof(*db->hash_array));
+    if (r == -1)
+        return -1;
+    return 0;
+}
+
+static unsigned hash (const char *name)
+{
+    unsigned l = 0;
+
+    while (*name)
+        l = l*65599 + *name++;
+    return l % DB_HASH;
+}
+
+static void lock_file (int fd, int type)
+{
+    struct flock area;
+    area.l_type = type;
+    area.l_whence = SEEK_SET;
+    area.l_start = 0L;
+    area.l_len = 0L;
+    fcntl (fd, F_SETLKW, &area);
+}
+
+int gw_db_lookup (GW_DB db, const char *name, int name_length,
+                  void **buf, size_t *count)
+{
+    struct db_bucket bucket;
+    unsigned l = hash (name);
+    char     *dbuf = NULL;
+    int      dsize = 0;
+    int      pos;
+    int      r;
+
+    for (pos = db->hash_array[l]; pos; pos = bucket.next)
+    {
+        int blen;
+
+        if (lseek (db->fd, pos, SEEK_SET) == -1)
+       {
+           free (dbuf);
+           return -1;
+       }
+        r = read (db->fd, &bucket, sizeof(bucket));
+       if (r == -1)
+       {
+           free (dbuf);
+           return -1;
+       }
+       if (r != sizeof(bucket))
+       {
+           free (dbuf);
+           return -2;
+       }
+       if (bucket.name_length <= 0 || bucket.info_length <= 0 ||
+           bucket.name_length >= 16384 || bucket.info_length >= 262144)
+       {
+           free (dbuf);
+           return -3;
+       }
+       if (bucket.name_length != name_length)
+           continue;
+       blen = bucket.name_length + bucket.info_length;
+       if (blen >= dsize)
+        {
+           dsize = blen + 1024;
+           free (dbuf);
+           if (!(dbuf = malloc (dsize)))
+               return -1;
+        }
+       r = read (db->fd, dbuf, blen);
+       if (r == -1)
+       {
+           free (dbuf);
+           return -1;
+       }
+       else if (r < blen)
+       {
+           free (dbuf);
+           return -2;
+       }
+       if (memcmp (name, dbuf, name_length))
+           continue;
+
+        *count = bucket.info_length;
+        *buf = malloc (*count);
+       if (!*buf)
+       {
+           free (dbuf);
+           return -1;
+       }
+       memcpy (*buf, dbuf + name_length, *count);
+       free (dbuf);
+        return 1;
+    }
+    free (dbuf);
+    return 0;
+}
+
+int gw_db_insert (GW_DB db, const char *name, int name_length,
+                  const void *buf, size_t count)
+{
+    struct db_bucket n_bucket;
+    struct db_bucket bucket;
+    off_t    n_pos, r_pos;
+    unsigned l = hash (name);
+    int      pos = db->hash_array[l];
+    int      r;
+
+    db->dirty = 1;
+    (db->head.no_of_entries)++;
+    (db->head.sequence_no)++;
+    n_bucket.name_length = name_length;
+    n_bucket.info_length = count;
+    n_pos = lseek (db->fd, 0, SEEK_END);
+    if (n_pos == -1)
+        return -1;
+    n_bucket.next = pos;
+    db->hash_array[l] = n_pos;
+    n_bucket.prev = 0;
+
+    r = write (db->fd, &n_bucket, sizeof(n_bucket));
+    if (r == -1)
+        return -1;
+    else if (r < sizeof(n_bucket))
+        return -2;
+
+    r = write (db->fd, name, name_length);
+    if (r == -1)
+        return -1;
+    else if (r < name_length)
+        return -2;
+
+    r = write (db->fd, buf, count);
+    if (r == -1)
+        return -1;
+    else if (r < count)
+        return -2;
+
+    r_pos = lseek (db->fd, pos, SEEK_SET);
+    if (r_pos == -1)
+        return -1;
+    r = read (db->fd, &bucket, sizeof(bucket));
+    if (r == -1)
+        return -1;
+    else if (r < sizeof(bucket))
+        return -2;
+    bucket.prev = n_pos;
+
+    r_pos = lseek (db->fd, pos, SEEK_SET);
+    if (r_pos == -1)
+        return -1;
+    r = write (db->fd, &bucket, sizeof(bucket));
+    if (r == -1)
+        return -1;
+    else if (r < sizeof(bucket))
+        return -2;
+    return 0;
+}
+
+static GW_DB gw_db_free (GW_DB db)
+{
+    free (db->hash_array);
+    free (db);
+    return NULL;
+}
+
+GW_DB gw_db_open (const char *fname, int write_flag)
+{
+    char file_head_buf[FILE_HEAD_LEN];
+    GW_DB db;
+    int r;
+
+    if (!(db = malloc (sizeof(*db))))
+        return NULL;
+    db->dirty = 0;
+    if (!(db->hash_array = malloc (DB_HASH * sizeof(*db->hash_array))))
+        return gw_db_free (db);
+    if (write_flag)
+        db->fd = open (fname, O_RDWR|O_CREAT, 0666);
+    else
+        db->fd = open (fname, O_RDONLY);
+    if (db->fd == -1)
+        return gw_db_free (db);
+    lock_file (db->fd, write_flag ? F_WRLCK : F_RDLCK);
+    r = read (db->fd, file_head_buf, FILE_HEAD_LEN);
+    if (r == -1)
+        return gw_db_free (db);
+    if (r < FILE_HEAD_LEN)
+    {
+        int i;
+
+        if (!write_flag)
+           return gw_db_free (db);
+        db->head.no_of_entries = 0;
+        db->head.sequence_no = 1;
+        for (i=0; i<DB_HASH; i++)
+           db->hash_array[i] = 0;
+       if (write_head (db))
+           return gw_db_free (db);
+    }
+    else
+    {
+        memcpy (&db->head, file_head_buf, sizeof(db->head));
+        r = read (db->fd, db->hash_array, sizeof(*db->hash_array)*DB_HASH);
+       if (r < sizeof(*db->hash_array)*DB_HASH)
+           return gw_db_free (db);
+    }
+    return db;
+}
+
+
+int gw_db_close (GW_DB db)
+{
+    int r = 0;
+
+    if (db->dirty) 
+        r = write_head (db);
+    lock_file (db->fd, F_UNLCK);
+    if (close (db->fd) == -1)
+    {
+        gw_db_free (db);
+        return -1;
+    }
+    gw_db_free (db);
+    return r;
+}
+
+int gw_db_no_ent (GW_DB db)
+{
+    return db->head.no_of_entries;
+}
+
+int gw_db_seq_no (GW_DB db)
+{
+    return db->head.sequence_no;
+}
+