As a starting point in the task of trying to understand the pristine database format, create a subcommand - pristine - that can be used to dump various bits of information from a repository .pijul/pristine/db file.
For now, the subcommand parses out the globalheader in each root page, and prints the information there. We have learned that Pijul uses a fixed number of root pages (2), but Sanakirja supports a user-provided number of roots.
ZYBYX2TBKWAKNMPCWT3B7CJRDEO3LOENGOXZF27JGD4UH6YCN25AC
SMB3M6ESOIR2LMFII2VFQJSPFIUYXHD7CXYARIGOKPB2QF2ORFLAC
YM2LC6QP2D7TK3JUKOXWUWTQEGMCEGQDGPTOZPWC3BRDFNRKSZWQC
XJ2PEH74CLJUELZBR47QHGUSKXB4Z5T7EKEF6Y4CYY2VBHZXUTDAC
67HZZ5HS7AA5KA6W4TV24YMO33V5FR6GJ34P3FPTRN547RFNL4DQC
PEUS54XQ5KJQYAVUYBG5MWLEHIOVPMZ3ANVC7HPQP6JUWWPRDW5AC
ZTDGWUGPKDVIUA6V5BZ5ATDTGKZEE6ZZIXLGNTUJU2KIV7H7YSVQC
DRK7G22JO77N3RP5SS4ICZODMLYHJONKNPXREODMFC6YZVDHUXBQC
FB67XX5EGNF45JNAQISW7CBLSLS36F6JEUOBTTPUMVBMOVLGA3VQC
B3XLVPNC4COLLC3FUE34Y7HIKTMF6CJZUASZOU3YM2YGPZKJZP7QC
XTKRT6OQYN4LARQRDLI2KBSAJTOFZNT4AMBZ46CPUDZXD7IDYYWQC
ZPNA2D42RFGGC45PLDYDGQUDPC7D4NBEH2HD4Y2L5P2CK3R52FAQC
#ifndef ANI_DB_H
#define ANI_DB_H
struct globalheader {
u16 version; // sanakirja version
u8 root; // which page is currently the root page?
u8 nroots; // how many root pages are there?
u32 crc; // CRC of this page
u64 length; // first free page at the end of the file
u64 freedb; // offset of the free list
u64 rcdb; // offset of the RC db
};
void dbrun(char *);
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/mman.h>
#include "common.h"
#include "types.h"
#include "scaffold.h"
#include "db.h"
#define err(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
static void
dumpbytes(u8 *mem, usize len)
{
usize i;
for (i = 0; i < len; i++) {
printf("%02x ", mem[i]);
}
printf("\n");
}
static void
readglobalheader(u8 *mem, struct globalheader *gh)
{
dumpbytes(mem, sizeof(struct globalheader));
// FIXME: Does not work for big-endian systems
*gh = *((struct globalheader *)mem);
}
static void
printglobalheader(struct globalheader *gh, bool currentroot)
{
printf("version = %u root = %u %s nroots = %u\n", gh->version, gh->root,
currentroot ? "(current)" : "", gh->nroots);
printf("CRC = 0x%04x (%u)\n", gh->crc, gh->crc);
printf("length = %lu (0x%08lx)\n", gh->length, gh->length);
printf("freedb = %lu\n", gh->freedb);
printf("rcdb = %lu\n", gh->rcdb);
}
void
dbrun(char *db)
{
int fd;
u8 *addr;
u8 nroots, curroot;
size i;
struct globalheader gh;
printf("opening %s\n", db);
fd = open(db, O_RDONLY);
if (fd == -1)
err("open");
usize length = 4096;
int prot = PROT_READ; // memory protection; PROT_{EXEC,READ,WRITE,NONE}
int flags = MAP_PRIVATE; // determines visibility
off_t offset = 0;
addr = mmap(NULL, length, prot, flags, fd, offset);
if (addr == MAP_FAILED)
err("mmap");
readglobalheader(addr, &gh);
munmap(addr, length);
nroots = gh.nroots;
curroot = gh.root;
printglobalheader(&gh, curroot == 0);
// for nroots-1 times, read the i << 12'th page
for (i = 1; i < nroots; i++) {
addr = mmap(NULL, length, prot, flags, fd, i << 12);
if (addr == MAP_FAILED)
err("mmap2");
readglobalheader(addr, &gh);
munmap(addr, length);
printglobalheader(&gh, curroot == i);
}
close(fd);
}
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include "common.h"
#include "types.h"
#include "repository.h"
#include "db.h"
static void
formatdbpath(char *dst, const char *repodir)
{
char *p;
p = stpncpy(dst, repodir, PATH_MAX);
*p++ = '/';
p = stpncpy(p, DOTPIJUL, 6);
*p++ = '/';
p = stpncpy(p, "pristine/db", 11);
}
int
cmd_pristine(int argc, char *argv, struct repository *repo)
{
char dbpath[4096] = { 0 };
(void)argc;
(void)argv;
formatdbpath(dbpath, repo->path);
dbrun(dbpath);
return 0;
}
" init Initialize empty repository\n"
" change Show information about a particular change\n";
" init Initialize empty repository\n"
" change Show information about a particular change\n"
" pristine Show information about the repository database\n";