+ struct record_index_entry entry;
+ int r, i, size = 0, got;
+ char *cptr;
+ off_t pos = (rec->sysno-1)*sizeof(entry) + sizeof(p->head);
+
+ for (i = 0; i < REC_NO_INFO; i++)
+ if (!rec->info[i])
+ size += sizeof(*rec->size);
+ else
+ size += sizeof(*rec->size) + rec->size[i];
+
+ entry.u.used.offset = p->head.data_size;
+ entry.u.used.size = size;
+ p->head.data_size += size;
+ p->head.data_used += size;
+
+ if (lseek (p->index_fd, pos, SEEK_SET) == (pos) -1)
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "seek in %s to pos %ld",
+ p->index_fname, (long) pos);
+ exit (1);
+ }
+ r = write (p->index_fd, &entry, sizeof(entry));
+ if (r != sizeof(entry))
+ {
+ if (r == -1)
+ logf (LOG_FATAL|LOG_ERRNO, "write of %s at pos %ld",
+ p->index_fname, (long) pos);
+ else
+ logf (LOG_FATAL, "write of %s at pos %ld",
+ p->index_fname, (long) pos);
+ exit (1);
+ }
+ if (lseek (p->data_fd, entry.u.used.offset, SEEK_SET) == -1)
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "lseek in %s to pos %ld",
+ p->data_fname, entry.u.used.offset);
+ exit (1);
+ }
+ if (p->tmp_size < entry.u.used.size)
+ {
+ free (p->tmp_buf);
+ p->tmp_size = entry.u.used.size + 16384;
+ if (!(p->tmp_buf = malloc (p->tmp_size)))
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "malloc");
+ exit (1);
+ }
+ }
+ cptr = p->tmp_buf;
+ for (i = 0; i < REC_NO_INFO; i++)
+ {
+ memcpy (cptr, &rec->size[i], sizeof(*rec->size));
+ cptr += sizeof(*rec->size);
+ if (rec->info[i])
+ {
+ memcpy (cptr, rec->info[i], rec->size[i]);
+ cptr += rec->size[i];
+ }
+ }
+ for (got = 0; got < entry.u.used.size; got += r)
+ {
+ r = write (p->data_fd, p->tmp_buf + got, entry.u.used.size - got);
+ if (r <= 0)
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "write of %s", p->data_fname);
+ exit (1);
+ }
+ }
+}
+
+static void rec_cache_flush (Records p)
+{
+ int i;
+ for (i = 0; i<p->cache_cur; i++)
+ {
+ struct record_cache_entry *e = p->record_cache + i;
+ if (e->dirty)
+ rec_write_single (p, e->rec);
+ rec_rm (&e->rec);
+ }
+ p->cache_cur = 0;
+}
+
+static Record *rec_cache_lookup (Records p, int sysno, int dirty)
+{
+ int i;
+ for (i = 0; i<p->cache_cur; i++)
+ {
+ struct record_cache_entry *e = p->record_cache + i;
+ if (e->rec->sysno == sysno)
+ {
+ if (dirty)
+ e->dirty = 1;
+ return &e->rec;
+ }
+ }
+ return NULL;
+}
+
+static void rec_cache_insert (Records p, Record rec, int dirty)
+{
+ struct record_cache_entry *e;
+
+ if (p->cache_cur == p->cache_max)
+ rec_cache_flush (p);
+ assert (p->cache_cur < p->cache_max);
+
+ e = p->record_cache + (p->cache_cur)++;
+ e->dirty = dirty;
+ e->rec = rec_cp (rec);
+}
+
+void rec_close (Records *p)
+{
+ assert (*p);
+
+ rec_cache_flush (*p);
+ free ((*p)->record_cache);
+
+ if ((*p)->rw)
+ rec_write_head (*p);
+
+ if ((*p)->index_fd != -1)
+ close ((*p)->index_fd);
+
+ if ((*p)->data_fd != -1)
+ close ((*p)->data_fd);
+
+ free ((*p)->tmp_buf);
+
+ free (*p);
+ *p = NULL;