#ifndef _LVD_MAP_H_
#define _LVD_MAP_H_

#include <stdint.h>
#include <sys/types.h>

/*
 * LVD per-domain registry — single C implementation for liblve.so.
 *
 * Two file types live under LVD_MAP_DIR:
 *
 *   <uid>    Per-uid open-addressing hash table (docroot -> domain_id).
 *            The hot lookup path touches only this file — no locking,
 *            no .index access.
 *
 *   .index   Global next_id counter (12 bytes).  Touched only on writes
 *            (assign/remove), under flock().
 *
 * Per-uid on-disk format (version 2):
 *
 *   Header (16 bytes):
 *     magic[4]       = "LVDM"
 *     version(u16)   = 2
 *     count(u16)     — number of occupied slots
 *     str_offset(u32)— byte offset from file start to string pool
 *     capacity(u32)  — hash table slot count (power of 2)
 *
 *   Hash table (capacity * 16 bytes, starts at byte 16):
 *     Per slot (16 bytes):
 *       hash(u32)      — FNV-1a of docroot; 0 = empty slot
 *       key_offset(u32)— offset into string pool (from pool start)
 *       key_len(u32)   — docroot string length (excluding NUL)
 *       domain_id(u32) — assigned domain LVE ID
 *
 *   String pool (at str_offset):
 *     Packed null-terminated docroot strings
 *
 * Version 1 (legacy sorted-array format) is still accepted by
 * lvd_map_lookup() for transparent migration.
 */

#define LVD_MAP_MAGIC   "LVDM"
#define LVD_MAP_VERSION 2
#define LVD_MAP_DIR     "/etc/container/lvd_ids"

/* Legacy format version for backward-compatible reads */
#define LVD_MAP_VERSION_V1 1

struct lvd_map_header {
	char     magic[4];
	uint16_t version;
	uint16_t count;
	uint32_t str_offset;
	uint32_t capacity;	/* v2: hash table slot count; v1: reserved */
} __attribute__((packed));

struct lvd_map_slot {
	uint32_t hash;		/* FNV-1a of docroot; 0 = empty */
	uint32_t key_offset;	/* offset into string pool */
	uint32_t key_len;	/* docroot length (no NUL) */
	uint32_t domain_id;
} __attribute__((packed));

/* Legacy v1 entry (12 bytes, sorted by docroot) */
struct lvd_map_entry_v1 {
	uint32_t key_offset;
	uint32_t key_len;
	uint32_t domain_id;
} __attribute__((packed));

/* ------------------------------------------------------------------ */
/* Hash                                                               */
/* ------------------------------------------------------------------ */

uint32_t lvd_fnv1a(const char *docroot);

/* ------------------------------------------------------------------ */
/* Read-only (no locking, no .index access)                           */
/* ------------------------------------------------------------------ */

uint32_t lvd_map_lookup(uid_t uid, const char *docroot);

int lvd_map_verify_ownership(uid_t uid, uint32_t domain_id);

/* ------------------------------------------------------------------ */
/* Iteration (opendir/readdir style — zero-copy, mmap-backed)         */
/* ------------------------------------------------------------------ */

typedef struct lvd_iter lvd_iter_t;

lvd_iter_t *lvd_map_iter_open(uid_t uid);
int         lvd_map_iter_next(lvd_iter_t *it,
			      const char **docroot,
			      uint32_t *domain_id);
void        lvd_map_iter_close(lvd_iter_t *it);

/* ------------------------------------------------------------------ */
/* Read-write (acquires flock on .index)                              */
/* ------------------------------------------------------------------ */

int lvd_map_assign(uid_t uid, const char *docroot, uint32_t *out_id);
int lvd_map_remove(uid_t uid, const char *docroot, uint32_t *old_id);
int lvd_map_remove_all(uid_t uid);

/* ------------------------------------------------------------------ */
/* Index management                                                   */
/* ------------------------------------------------------------------ */

int lvd_index_rebuild(void);

/* ------------------------------------------------------------------ */
/* Domain ID threshold                                                */
/* ------------------------------------------------------------------ */

/*
 * Minimum domain LVE ID — reads UID_MAX from /etc/login.defs at runtime.
 * Returns max(UID_MAX, LVD_UID_MAX_DEFAULT) so domain IDs never go
 * below the compile-time floor (60000).
 */
uint32_t lvd_get_id_min(void);

#endif /* _LVD_MAP_H_ */
