|
|
2ff057 |
#define _GNU_SOURCE
|
|
|
2ff057 |
|
|
|
2ff057 |
#include "system.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
#include <rpm/rpmlog.h>
|
|
|
2ff057 |
|
|
|
2ff057 |
#include <sys/types.h>
|
|
|
2ff057 |
#include <sys/stat.h>
|
|
|
2ff057 |
#include <sys/file.h>
|
|
|
2ff057 |
#include <fcntl.h>
|
|
|
2ff057 |
#include <stdio.h>
|
|
|
2ff057 |
#include <time.h>
|
|
|
2ff057 |
#include <unistd.h>
|
|
|
2ff057 |
#include <string.h>
|
|
|
2ff057 |
#include <stdlib.h>
|
|
|
2ff057 |
#include <sys/mman.h>
|
|
|
2ff057 |
#include <endian.h>
|
|
|
2ff057 |
#include <libgen.h>
|
|
|
2ff057 |
|
|
|
2ff057 |
#include "rpmxdb.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
#define RPMRC_OK 0
|
|
|
2ff057 |
#define RPMRC_NOTFOUND 1
|
|
|
2ff057 |
#define RPMRC_FAIL 2
|
|
|
2ff057 |
|
|
|
2ff057 |
typedef struct rpmxdb_s {
|
|
|
2ff057 |
rpmpkgdb pkgdb; /* master database */
|
|
|
2ff057 |
char *filename;
|
|
|
2ff057 |
int fd;
|
|
|
2ff057 |
int flags;
|
|
|
2ff057 |
int mode;
|
|
|
2ff057 |
int rdonly;
|
|
|
2ff057 |
unsigned int pagesize;
|
|
|
2ff057 |
unsigned int generation;
|
|
|
2ff057 |
unsigned int slotnpages;
|
|
|
2ff057 |
unsigned int usergeneration;
|
|
|
2ff057 |
|
|
|
2ff057 |
unsigned char *mapped;
|
|
|
2ff057 |
unsigned int mappedlen;
|
|
|
2ff057 |
|
|
|
2ff057 |
struct xdb_slot {
|
|
|
2ff057 |
unsigned int slotno;
|
|
|
2ff057 |
unsigned int blobtag;
|
|
|
2ff057 |
unsigned int subtag;
|
|
|
2ff057 |
unsigned char *mapped;
|
|
|
2ff057 |
int mapflags;
|
|
|
2ff057 |
unsigned int startpage;
|
|
|
2ff057 |
unsigned int pagecnt;
|
|
|
2ff057 |
void (*mapcallback)(rpmxdb xdb, void *data, void *newaddr, size_t newsize);
|
|
|
2ff057 |
void *mapcallbackdata;
|
|
|
2ff057 |
unsigned int next;
|
|
|
2ff057 |
unsigned int prev;
|
|
|
2ff057 |
} *slots;
|
|
|
2ff057 |
unsigned int nslots;
|
|
|
2ff057 |
unsigned int firstfree;
|
|
|
2ff057 |
unsigned int usedblobpages;
|
|
|
2ff057 |
unsigned int systempagesize;
|
|
|
2ff057 |
int dofsync;
|
|
|
2ff057 |
} *rpmxdb;
|
|
|
2ff057 |
|
|
|
2ff057 |
|
|
|
2ff057 |
static inline void h2le(unsigned int x, unsigned char *p)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
p[0] = x;
|
|
|
2ff057 |
p[1] = x >> 8;
|
|
|
2ff057 |
p[2] = x >> 16;
|
|
|
2ff057 |
p[3] = x >> 24;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* aligned versions */
|
|
|
2ff057 |
static inline unsigned int le2ha(unsigned char *p)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
unsigned int x = *(unsigned int *)p;
|
|
|
2ff057 |
return le32toh(x);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static inline void h2lea(unsigned int x, unsigned char *p)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
*(unsigned int *)p = htole32(x);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
|
|
|
2ff057 |
#define XDB_MAGIC ('R' | 'p' << 8 | 'm' << 16 | 'X' << 24)
|
|
|
2ff057 |
#define XDB_VERSION 0
|
|
|
2ff057 |
|
|
|
2ff057 |
#define XDB_OFFSET_MAGIC 0
|
|
|
2ff057 |
#define XDB_OFFSET_VERSION 4
|
|
|
2ff057 |
#define XDB_OFFSET_GENERATION 8
|
|
|
2ff057 |
#define XDB_OFFSET_SLOTNPAGES 12
|
|
|
2ff057 |
#define XDB_OFFSET_PAGESIZE 16
|
|
|
2ff057 |
#define XDB_OFFSET_USERGENERATION 20
|
|
|
2ff057 |
|
|
|
2ff057 |
/* must be multiple of SLOT_SIZE */
|
|
|
2ff057 |
#define XDB_HEADER_SIZE 32
|
|
|
2ff057 |
|
|
|
2ff057 |
#define SLOT_MAGIC ('S' | 'l' << 8 | 'o' << 16)
|
|
|
2ff057 |
|
|
|
2ff057 |
#define SLOT_SIZE 16
|
|
|
2ff057 |
#define SLOT_START (XDB_HEADER_SIZE / SLOT_SIZE)
|
|
|
2ff057 |
|
|
|
2ff057 |
static void rpmxdbUnmap(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
munmap(xdb->mapped, xdb->mappedlen);
|
|
|
2ff057 |
xdb->mapped = 0;
|
|
|
2ff057 |
xdb->mappedlen = 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* slot mapping functions */
|
|
|
2ff057 |
static int mapslot(rpmxdb xdb, struct xdb_slot *slot)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
void *mapped;
|
|
|
2ff057 |
size_t off, size, shift;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (slot->mapped)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
size = slot->pagecnt * xdb->pagesize;
|
|
|
2ff057 |
off = slot->startpage * xdb->pagesize;
|
|
|
2ff057 |
shift = 0;
|
|
|
2ff057 |
if (xdb->pagesize != xdb->systempagesize) {
|
|
|
2ff057 |
shift = off & (xdb->systempagesize - 1);
|
|
|
2ff057 |
off -= shift;
|
|
|
2ff057 |
size += shift;
|
|
|
2ff057 |
size = (size + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
mapped = mmap(0, size, slot->mapflags, MAP_SHARED, xdb->fd, off);
|
|
|
2ff057 |
if (mapped == MAP_FAILED)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
slot->mapped = (unsigned char *)mapped + shift;
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static void unmapslot(rpmxdb xdb, struct xdb_slot *slot)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
size_t size;
|
|
|
2ff057 |
unsigned char *mapped = slot->mapped;
|
|
|
2ff057 |
if (!mapped)
|
|
|
2ff057 |
return;
|
|
|
2ff057 |
size = slot->pagecnt * xdb->pagesize;
|
|
|
2ff057 |
if (xdb->pagesize != xdb->systempagesize) {
|
|
|
2ff057 |
size_t off = slot->startpage * xdb->pagesize;
|
|
|
2ff057 |
size_t shift = off & (xdb->systempagesize - 1);
|
|
|
2ff057 |
mapped -= shift;
|
|
|
2ff057 |
size += shift;
|
|
|
2ff057 |
size = (size + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
munmap(mapped, size);
|
|
|
2ff057 |
slot->mapped = 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int remapslot(rpmxdb xdb, struct xdb_slot *slot, unsigned int newpagecnt)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
void *mapped;
|
|
|
2ff057 |
size_t off, oldsize, newsize, shift;
|
|
|
2ff057 |
oldsize = slot->pagecnt * xdb->pagesize;
|
|
|
2ff057 |
newsize = newpagecnt * xdb->pagesize;
|
|
|
2ff057 |
off = slot->startpage * xdb->pagesize;
|
|
|
2ff057 |
shift = 0;
|
|
|
2ff057 |
if (xdb->pagesize != xdb->systempagesize) {
|
|
|
2ff057 |
off = slot->startpage * xdb->pagesize;
|
|
|
2ff057 |
shift = off & (xdb->systempagesize - 1);
|
|
|
2ff057 |
off -= shift;
|
|
|
2ff057 |
oldsize += shift;
|
|
|
2ff057 |
oldsize = (oldsize + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
|
|
|
2ff057 |
newsize += shift;
|
|
|
2ff057 |
newsize = (newsize + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot->mapped)
|
|
|
2ff057 |
mapped = mremap(slot->mapped - shift, oldsize, newsize, MREMAP_MAYMOVE);
|
|
|
2ff057 |
else
|
|
|
2ff057 |
mapped = mmap(0, newsize, slot->mapflags, MAP_SHARED, xdb->fd, off);
|
|
|
2ff057 |
if (mapped == MAP_FAILED)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
slot->mapped = (unsigned char *)mapped + shift;
|
|
|
2ff057 |
slot->pagecnt = newpagecnt;
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
|
|
|
2ff057 |
static int usedslots_cmp(const void *a, const void *b)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *sa = *(struct xdb_slot **)a;
|
|
|
2ff057 |
struct xdb_slot *sb = *(struct xdb_slot **)b;
|
|
|
2ff057 |
if (sa->startpage == sb->startpage) {
|
|
|
2ff057 |
return sa->pagecnt > sb->pagecnt ? 1 : sa->pagecnt < sb->pagecnt ? -1 : 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return sa->startpage > sb->startpage ? 1 : -1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbReadHeader(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
unsigned int header[XDB_HEADER_SIZE / sizeof(unsigned int)];
|
|
|
2ff057 |
unsigned int slotnpages, pagesize, generation, usergeneration, version;
|
|
|
2ff057 |
unsigned int page, *lastfreep;
|
|
|
2ff057 |
unsigned char *pageptr;
|
|
|
2ff057 |
struct xdb_slot *slots, **usedslots, *lastslot;
|
|
|
2ff057 |
unsigned int nslots;
|
|
|
2ff057 |
unsigned int usedblobpages;
|
|
|
2ff057 |
int i, nused, slotno;
|
|
|
2ff057 |
struct stat stb;
|
|
|
2ff057 |
size_t mapsize;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (xdb->mapped) {
|
|
|
2ff057 |
if (le2ha(xdb->mapped + XDB_OFFSET_GENERATION) == xdb->generation) {
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmxdbUnmap(xdb);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (fstat(xdb->fd, &stb)) {
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (pread(xdb->fd, header, sizeof(header), 0) != sizeof(header)) {
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (le2ha((unsigned char *)header + XDB_OFFSET_MAGIC) != XDB_MAGIC)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
version = le2ha((unsigned char *)header + XDB_OFFSET_VERSION);
|
|
|
2ff057 |
if (version != XDB_VERSION) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("rpmxdb: Version mismatch. Expected version: %u. "
|
|
|
2ff057 |
"Found version: %u\n"), XDB_VERSION, version);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
generation = le2ha((unsigned char *)header + XDB_OFFSET_GENERATION);
|
|
|
2ff057 |
slotnpages = le2ha((unsigned char *)header + XDB_OFFSET_SLOTNPAGES);
|
|
|
2ff057 |
pagesize = le2ha((unsigned char *)header + XDB_OFFSET_PAGESIZE);
|
|
|
2ff057 |
usergeneration = le2ha((unsigned char *)header + XDB_OFFSET_USERGENERATION);
|
|
|
2ff057 |
if (!slotnpages || !pagesize || stb.st_size % pagesize != 0)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
xdb->pagesize = pagesize;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* round up */
|
|
|
2ff057 |
mapsize = slotnpages * pagesize;
|
|
|
2ff057 |
mapsize = (mapsize + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
|
|
|
2ff057 |
xdb->mapped = mmap(0, mapsize, xdb->rdonly ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, xdb->fd, 0);
|
|
|
2ff057 |
if ((void *)xdb->mapped == MAP_FAILED) {
|
|
|
2ff057 |
xdb->mapped = 0;
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
xdb->mappedlen = mapsize;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* read in all slots */
|
|
|
2ff057 |
xdb->firstfree = 0;
|
|
|
2ff057 |
nslots = slotnpages * (pagesize / SLOT_SIZE) - SLOT_START + 1;
|
|
|
2ff057 |
slots = xcalloc(nslots + 1, sizeof(struct xdb_slot));
|
|
|
2ff057 |
usedslots = xcalloc(nslots + 1, sizeof(int));
|
|
|
2ff057 |
nused = 0;
|
|
|
2ff057 |
slotno = 1;
|
|
|
2ff057 |
slot = slots + 1;
|
|
|
2ff057 |
usedblobpages = 0;
|
|
|
2ff057 |
lastfreep = &xdb->firstfree;
|
|
|
2ff057 |
for (page = 0, pageptr = xdb->mapped; page < slotnpages; page++, pageptr += pagesize) {
|
|
|
2ff057 |
unsigned int o;
|
|
|
2ff057 |
for (o = page ? 0 : SLOT_START * SLOT_SIZE; o < pagesize; o += SLOT_SIZE, slotno++, slot++) {
|
|
|
2ff057 |
unsigned char *pp = pageptr + o;
|
|
|
2ff057 |
slot->slotno = slotno;
|
|
|
2ff057 |
slot->subtag = le2ha(pp);
|
|
|
2ff057 |
if ((slot->subtag & 0x00ffffff) != SLOT_MAGIC) {
|
|
|
2ff057 |
free(slots);
|
|
|
2ff057 |
free(usedslots);
|
|
|
2ff057 |
rpmxdbUnmap(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot->subtag = (slot->subtag >> 24) & 255;
|
|
|
2ff057 |
slot->blobtag = le2ha(pp + 4);
|
|
|
2ff057 |
slot->startpage = le2ha(pp + 8);
|
|
|
2ff057 |
slot->pagecnt = le2ha(pp + 12);
|
|
|
2ff057 |
if (slot->pagecnt == 0 && slot->startpage) /* empty but used slot? */
|
|
|
2ff057 |
slot->startpage = slotnpages;
|
|
|
2ff057 |
if (!slot->startpage) {
|
|
|
2ff057 |
*lastfreep = slotno;
|
|
|
2ff057 |
lastfreep = &slot->next;
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
usedslots[nused++] = slot;
|
|
|
2ff057 |
usedblobpages += slot->pagecnt;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (nused > 1) {
|
|
|
2ff057 |
qsort(usedslots, nused, sizeof(*usedslots), usedslots_cmp);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
/* now chain em */
|
|
|
2ff057 |
slots[0].pagecnt = slotnpages;
|
|
|
2ff057 |
lastslot = slots;
|
|
|
2ff057 |
for (i = 0; i < nused; i++, lastslot = slot) {
|
|
|
2ff057 |
slot = usedslots[i];
|
|
|
2ff057 |
if (lastslot->startpage + lastslot->pagecnt > slot->startpage) {
|
|
|
2ff057 |
free(slots);
|
|
|
2ff057 |
free(usedslots);
|
|
|
2ff057 |
rpmxdbUnmap(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
lastslot->next = slot->slotno;
|
|
|
2ff057 |
slot->prev = lastslot->slotno;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
lastslot->next = nslots;
|
|
|
2ff057 |
slots[nslots].slotno = nslots;
|
|
|
2ff057 |
slots[nslots].prev = lastslot->slotno;
|
|
|
2ff057 |
slots[nslots].startpage = stb.st_size / pagesize;
|
|
|
2ff057 |
free(usedslots);
|
|
|
2ff057 |
/* now sync with the old slot data */
|
|
|
2ff057 |
if (xdb->slots) {
|
|
|
2ff057 |
for (i = 1, slot = xdb->slots + i; i < xdb->nslots; i++, slot++) {
|
|
|
2ff057 |
if (slot->startpage && (slot->mapped || slot->mapcallback)) {
|
|
|
2ff057 |
struct xdb_slot *nslot;
|
|
|
2ff057 |
if (i >= nslots || !slots[i].startpage || slots[i].blobtag != slot->blobtag || slots[i].subtag != slot->subtag) {
|
|
|
2ff057 |
/* slot is gone */
|
|
|
2ff057 |
if (slot->mapped) {
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
continue;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
nslot = slots + i;
|
|
|
2ff057 |
if (slot->mapcallback) {
|
|
|
2ff057 |
nslot->mapflags = slot->mapflags;
|
|
|
2ff057 |
nslot->mapcallback = slot->mapcallback;
|
|
|
2ff057 |
nslot->mapcallbackdata = slot->mapcallbackdata;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot->startpage != nslot->startpage || slot->pagecnt != nslot->pagecnt) {
|
|
|
2ff057 |
/* slot moved or was resized */
|
|
|
2ff057 |
if (slot->mapped)
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
if (nslot->mapcallback) {
|
|
|
2ff057 |
if (nslot->pagecnt) {
|
|
|
2ff057 |
mapslot(xdb, nslot);
|
|
|
2ff057 |
nslot->mapcallback(xdb, nslot->mapcallbackdata, nslot->mapped, nslot->mapped ? nslot->pagecnt * xdb->pagesize : 0);
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
nslot->mapcallback(xdb, nslot->mapcallbackdata, 0, 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(xdb->slots);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
xdb->slots = slots;
|
|
|
2ff057 |
xdb->nslots = nslots;
|
|
|
2ff057 |
xdb->generation = generation;
|
|
|
2ff057 |
xdb->slotnpages = slotnpages;
|
|
|
2ff057 |
xdb->usergeneration = usergeneration;
|
|
|
2ff057 |
xdb->usedblobpages = usedblobpages;
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbWriteHeader(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (!xdb->mapped)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
h2lea(XDB_MAGIC, xdb->mapped + XDB_OFFSET_MAGIC);
|
|
|
2ff057 |
h2lea(XDB_VERSION, xdb->mapped + XDB_OFFSET_VERSION);
|
|
|
2ff057 |
h2lea(xdb->generation, xdb->mapped + XDB_OFFSET_GENERATION);
|
|
|
2ff057 |
h2lea(xdb->slotnpages, xdb->mapped + XDB_OFFSET_SLOTNPAGES);
|
|
|
2ff057 |
h2lea(xdb->pagesize, xdb->mapped + XDB_OFFSET_PAGESIZE);
|
|
|
2ff057 |
h2lea(xdb->usergeneration, xdb->mapped + XDB_OFFSET_USERGENERATION);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static void rpmxdbUpdateSlot(rpmxdb xdb, struct xdb_slot *slot)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
unsigned char *pp = xdb->mapped + (SLOT_START - 1 + slot->slotno) * SLOT_SIZE;
|
|
|
2ff057 |
h2lea(SLOT_MAGIC | (slot->subtag << 24), pp);
|
|
|
2ff057 |
h2lea(slot->blobtag, pp + 4);
|
|
|
2ff057 |
if (slot->pagecnt || !slot->startpage)
|
|
|
2ff057 |
h2lea(slot->startpage, pp + 8);
|
|
|
2ff057 |
else
|
|
|
2ff057 |
h2lea(1, pp + 8); /* "empty but used" blobs always start at 1 */
|
|
|
2ff057 |
h2lea(slot->pagecnt, pp + 12);
|
|
|
2ff057 |
xdb->generation++;
|
|
|
2ff057 |
h2lea(xdb->generation, xdb->mapped + XDB_OFFSET_GENERATION);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbWriteEmptyPages(rpmxdb xdb, unsigned int pageno, unsigned int count)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
unsigned char *page;
|
|
|
2ff057 |
if (!count)
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
page = xmalloc(xdb->pagesize);
|
|
|
2ff057 |
memset(page, 0, xdb->pagesize);
|
|
|
2ff057 |
for (; count; count--, pageno++) {
|
|
|
2ff057 |
if (pwrite(xdb->fd, page, xdb->pagesize, pageno * xdb->pagesize) != xdb->pagesize) {
|
|
|
2ff057 |
free(page);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(page);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbWriteEmptySlotpage(rpmxdb xdb, int pageno)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
unsigned char *page;
|
|
|
2ff057 |
int i, spp;
|
|
|
2ff057 |
page = xmalloc(xdb->pagesize);
|
|
|
2ff057 |
memset(page, 0, xdb->pagesize);
|
|
|
2ff057 |
spp = xdb->pagesize / SLOT_SIZE; /* slots per page */
|
|
|
2ff057 |
for (i = pageno ? 0 : SLOT_START; i < spp; i++)
|
|
|
2ff057 |
h2le(SLOT_MAGIC, page + i * SLOT_SIZE);
|
|
|
2ff057 |
if (!pageno) {
|
|
|
2ff057 |
/* only used when called from InitInternal */
|
|
|
2ff057 |
if (xdb->mapped) {
|
|
|
2ff057 |
free(page);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
xdb->mapped = page;
|
|
|
2ff057 |
rpmxdbWriteHeader(xdb);
|
|
|
2ff057 |
xdb->mapped = 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (pwrite(xdb->fd, page, xdb->pagesize, pageno * xdb->pagesize) != xdb->pagesize) {
|
|
|
2ff057 |
free(page);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(page);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbInitInternal(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct stat stb;
|
|
|
2ff057 |
if (fstat(xdb->fd, &stb)) {
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (stb.st_size == 0) {
|
|
|
2ff057 |
xdb->slotnpages = 1;
|
|
|
2ff057 |
xdb->generation++;
|
|
|
2ff057 |
xdb->pagesize = sysconf(_SC_PAGE_SIZE);
|
|
|
2ff057 |
if (rpmxdbWriteEmptySlotpage(xdb, 0)) {
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* we use the master pdb for locking */
|
|
|
2ff057 |
static int rpmxdbLockOnly(rpmxdb xdb, int excl)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (excl && xdb->rdonly)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
return rpmpkgLock(xdb->pkgdb, excl);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* this is the same as rpmxdbLockReadHeader. It does the
|
|
|
2ff057 |
* ReadHeader to sync the mappings if xdb moved some blobs.
|
|
|
2ff057 |
*/
|
|
|
2ff057 |
int rpmxdbLock(rpmxdb xdb, int excl)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (rpmxdbLockOnly(xdb, excl))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (rpmxdbReadHeader(xdb)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, excl);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbUnlock(rpmxdb xdb, int excl)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
return rpmpkgUnlock(xdb->pkgdb, excl);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbLockReadHeader(rpmxdb xdb, int excl)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (rpmxdbLockOnly(xdb, excl))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (rpmxdbReadHeader(xdb)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, excl);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int rpmxdbInit(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
int rc;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rpmxdbLockOnly(xdb, 1))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
rc = rpmxdbInitInternal(xdb);
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return rc;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbOpen(rpmxdb *xdbp, rpmpkgdb pkgdb, const char *filename, int flags, int mode)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct stat stb;
|
|
|
2ff057 |
rpmxdb xdb;
|
|
|
2ff057 |
|
|
|
2ff057 |
*xdbp = 0;
|
|
|
2ff057 |
xdb = xcalloc(1, sizeof(*xdb));
|
|
|
2ff057 |
xdb->pkgdb = pkgdb;
|
|
|
2ff057 |
xdb->filename = xstrdup(filename);
|
|
|
2ff057 |
xdb->systempagesize = sysconf(_SC_PAGE_SIZE);
|
|
|
2ff057 |
if ((flags & (O_RDONLY|O_RDWR)) == O_RDONLY)
|
|
|
2ff057 |
xdb->rdonly = 1;
|
|
|
2ff057 |
if ((xdb->fd = open(filename, flags, mode)) == -1) {
|
|
|
2ff057 |
free(xdb->filename);
|
|
|
2ff057 |
free(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (flags & O_CREAT) {
|
|
|
2ff057 |
char *filenameCopy;
|
|
|
2ff057 |
DIR *pdir;
|
|
|
2ff057 |
|
|
|
2ff057 |
filenameCopy = xstrdup(xdb->filename);
|
|
|
2ff057 |
|
|
|
2ff057 |
if ((pdir = opendir(dirname(filenameCopy))) == NULL) {
|
|
|
2ff057 |
free(filenameCopy);
|
|
|
2ff057 |
close(xdb->fd);
|
|
|
2ff057 |
free(xdb->filename);
|
|
|
2ff057 |
free(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (fsync(dirfd(pdir)) == -1) {
|
|
|
2ff057 |
closedir(pdir);
|
|
|
2ff057 |
free(filenameCopy);
|
|
|
2ff057 |
close(xdb->fd);
|
|
|
2ff057 |
free(xdb->filename);
|
|
|
2ff057 |
free(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
closedir(pdir);
|
|
|
2ff057 |
free(filenameCopy);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (fstat(xdb->fd, &stb)) {
|
|
|
2ff057 |
close(xdb->fd);
|
|
|
2ff057 |
free(xdb->filename);
|
|
|
2ff057 |
free(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (stb.st_size == 0) {
|
|
|
2ff057 |
if (rpmxdbInit(xdb)) {
|
|
|
2ff057 |
close(xdb->fd);
|
|
|
2ff057 |
free(xdb->filename);
|
|
|
2ff057 |
free(xdb);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
xdb->flags = flags;
|
|
|
2ff057 |
xdb->mode = mode;
|
|
|
2ff057 |
xdb->dofsync = 1;
|
|
|
2ff057 |
*xdbp = xdb;
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
void rpmxdbClose(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
int i;
|
|
|
2ff057 |
|
|
|
2ff057 |
for (i = 1, slot = xdb->slots + 1; i < xdb->nslots; i++, slot++) {
|
|
|
2ff057 |
if (slot->mapped) {
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (xdb->slots)
|
|
|
2ff057 |
free(xdb->slots);
|
|
|
2ff057 |
if (xdb->fd >= 0)
|
|
|
2ff057 |
close(xdb->fd);
|
|
|
2ff057 |
if (xdb->filename)
|
|
|
2ff057 |
free(xdb->filename);
|
|
|
2ff057 |
free(xdb);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* moves the blob to a given new location (possibly resizeing) */
|
|
|
2ff057 |
static int moveblobto(rpmxdb xdb, struct xdb_slot *oldslot, struct xdb_slot *afterslot, unsigned int newpagecnt)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *nextslot;
|
|
|
2ff057 |
unsigned int newstartpage, oldpagecnt;
|
|
|
2ff057 |
unsigned int tocopy;
|
|
|
2ff057 |
int didmap;
|
|
|
2ff057 |
|
|
|
2ff057 |
newstartpage = afterslot->startpage + afterslot->pagecnt;
|
|
|
2ff057 |
nextslot = xdb->slots + afterslot->next;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* make sure there's enough room */
|
|
|
2ff057 |
if (newpagecnt > nextslot->startpage - newstartpage)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
|
|
|
2ff057 |
#if 0
|
|
|
2ff057 |
printf("moveblobto %d %d %d %d, afterslot %d\n", oldslot->startpage, oldslot->pagecnt, newstartpage, newpagecnt, afterslot->slotno);
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
/* map old content */
|
|
|
2ff057 |
didmap = 0;
|
|
|
2ff057 |
oldpagecnt = oldslot->pagecnt;
|
|
|
2ff057 |
if (!oldslot->mapped && oldpagecnt) {
|
|
|
2ff057 |
if (mapslot(xdb, oldslot))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
didmap = 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* copy content */
|
|
|
2ff057 |
tocopy = newpagecnt > oldpagecnt ? oldpagecnt : newpagecnt;
|
|
|
2ff057 |
if (tocopy && pwrite(xdb->fd, oldslot->mapped, tocopy * xdb->pagesize, newstartpage * xdb->pagesize) != tocopy * xdb->pagesize) {
|
|
|
2ff057 |
if (didmap)
|
|
|
2ff057 |
unmapslot(xdb, oldslot);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
/* zero out new pages */
|
|
|
2ff057 |
if (newpagecnt > oldpagecnt) {
|
|
|
2ff057 |
if (rpmxdbWriteEmptyPages(xdb, newstartpage + oldpagecnt, newpagecnt - oldpagecnt)) {
|
|
|
2ff057 |
if (didmap)
|
|
|
2ff057 |
unmapslot(xdb, oldslot);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (oldslot->mapped)
|
|
|
2ff057 |
unmapslot(xdb, oldslot);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* set new offset and position */
|
|
|
2ff057 |
oldslot->startpage = newstartpage;
|
|
|
2ff057 |
oldslot->pagecnt = newpagecnt;
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, oldslot);
|
|
|
2ff057 |
xdb->usedblobpages -= oldpagecnt;
|
|
|
2ff057 |
xdb->usedblobpages += newpagecnt;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (afterslot != oldslot && nextslot != oldslot) {
|
|
|
2ff057 |
/* remove from old chain */
|
|
|
2ff057 |
xdb->slots[oldslot->prev].next = oldslot->next;
|
|
|
2ff057 |
xdb->slots[oldslot->next].prev = oldslot->prev;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* chain into new position, between lastslot and nextslot */
|
|
|
2ff057 |
oldslot->prev = afterslot->slotno;
|
|
|
2ff057 |
afterslot->next = oldslot->slotno;
|
|
|
2ff057 |
|
|
|
2ff057 |
oldslot->next = nextslot->slotno;
|
|
|
2ff057 |
nextslot->prev = oldslot->slotno;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* map again (if needed) */
|
|
|
2ff057 |
if (oldslot->mapcallback) {
|
|
|
2ff057 |
if (newpagecnt) {
|
|
|
2ff057 |
if (mapslot(xdb, oldslot))
|
|
|
2ff057 |
oldslot->mapped = 0; /* XXX: HELP, what can we do here? */
|
|
|
2ff057 |
}
|
|
|
2ff057 |
oldslot->mapcallback(xdb, oldslot->mapcallbackdata, oldslot->mapped, oldslot->mapped ? oldslot->pagecnt * xdb->pagesize : 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* moves the blob to a new location (possibly resizeing) */
|
|
|
2ff057 |
static int moveblob(rpmxdb xdb, struct xdb_slot *oldslot, unsigned int newpagecnt)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot, *lastslot;
|
|
|
2ff057 |
unsigned int nslots;
|
|
|
2ff057 |
unsigned int freecnt;
|
|
|
2ff057 |
int i;
|
|
|
2ff057 |
|
|
|
2ff057 |
nslots = xdb->nslots;
|
|
|
2ff057 |
freecnt = 0;
|
|
|
2ff057 |
lastslot = xdb->slots;
|
|
|
2ff057 |
for (i = xdb->slots[0].next; ; lastslot = slot, i = slot->next) {
|
|
|
2ff057 |
slot = xdb->slots + i;
|
|
|
2ff057 |
freecnt = slot->startpage - (lastslot->startpage + lastslot->pagecnt);
|
|
|
2ff057 |
if (freecnt >= newpagecnt)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
if (i == nslots)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (i == nslots && newpagecnt > freecnt) {
|
|
|
2ff057 |
/* need to grow the file */
|
|
|
2ff057 |
if (rpmxdbWriteEmptyPages(xdb, slot->startpage, newpagecnt - freecnt)) {
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot->startpage += newpagecnt - freecnt;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return moveblobto(xdb, oldslot, lastslot, newpagecnt);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* move the two blobs at the end of our file to the free area after the provided slot */
|
|
|
2ff057 |
static int moveblobstofront(rpmxdb xdb, struct xdb_slot *afterslot)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot1, *slot2;
|
|
|
2ff057 |
unsigned int freestart = afterslot->startpage + afterslot->pagecnt;
|
|
|
2ff057 |
unsigned int freecount = xdb->slots[afterslot->next].startpage - freestart;
|
|
|
2ff057 |
|
|
|
2ff057 |
slot1 = xdb->slots + xdb->slots[xdb->nslots].prev;
|
|
|
2ff057 |
if (slot1 == xdb->slots)
|
|
|
2ff057 |
slot1 = slot2 = 0;
|
|
|
2ff057 |
else {
|
|
|
2ff057 |
slot2 = xdb->slots + slot1->prev;
|
|
|
2ff057 |
if (slot2 == xdb->slots)
|
|
|
2ff057 |
slot2 = 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot1->pagecnt < slot2->pagecnt) {
|
|
|
2ff057 |
struct xdb_slot *tmp = slot1;
|
|
|
2ff057 |
slot1 = slot2;
|
|
|
2ff057 |
slot2 = tmp;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot1 && slot1->pagecnt && slot1->pagecnt <= freecount && slot1->startpage > freestart) {
|
|
|
2ff057 |
if (moveblobto(xdb, slot1, afterslot, slot1->pagecnt))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
freestart += slot1->pagecnt;
|
|
|
2ff057 |
freecount -= slot1->pagecnt;
|
|
|
2ff057 |
afterslot = slot1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot2 && slot2->pagecnt && slot2->pagecnt <= freecount && slot2->startpage > freestart) {
|
|
|
2ff057 |
if (moveblobto(xdb, slot2, afterslot, slot2->pagecnt))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* add a single page containing empty slots */
|
|
|
2ff057 |
static int addslotpage(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
unsigned char *newaddr;
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
int i, spp, nslots;
|
|
|
2ff057 |
size_t newmappedlen;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (xdb->firstfree)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* move first blob if needed */
|
|
|
2ff057 |
nslots = xdb->nslots;
|
|
|
2ff057 |
for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
|
|
|
2ff057 |
slot = xdb->slots + i;
|
|
|
2ff057 |
if (slot->pagecnt)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (i != nslots && slot->pagecnt && slot->startpage == xdb->slotnpages) {
|
|
|
2ff057 |
/* the blob at this slot is in the way. move it. */
|
|
|
2ff057 |
if (moveblob(xdb, slot, slot->pagecnt))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
spp = xdb->pagesize / SLOT_SIZE; /* slots per page */
|
|
|
2ff057 |
slot = xrealloc(xdb->slots, (nslots + 1 + spp) * sizeof(*slot));
|
|
|
2ff057 |
xdb->slots = slot;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rpmxdbWriteEmptySlotpage(xdb, xdb->slotnpages)) {
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
/* remap slots */
|
|
|
2ff057 |
newmappedlen = xdb->slotnpages * xdb->pagesize + xdb->pagesize;
|
|
|
2ff057 |
newmappedlen = (newmappedlen + xdb->systempagesize - 1) & ~(xdb->systempagesize - 1);
|
|
|
2ff057 |
newaddr = mremap(xdb->mapped, xdb->mappedlen, newmappedlen, MREMAP_MAYMOVE);
|
|
|
2ff057 |
if (newaddr == MAP_FAILED)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
xdb->mapped = newaddr;
|
|
|
2ff057 |
xdb->mappedlen = newmappedlen;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* update the header */
|
|
|
2ff057 |
xdb->slotnpages++;
|
|
|
2ff057 |
xdb->generation++;
|
|
|
2ff057 |
rpmxdbWriteHeader(xdb);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* fixup empty but used slots */
|
|
|
2ff057 |
for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
|
|
|
2ff057 |
slot = xdb->slots + i;
|
|
|
2ff057 |
if (slot->startpage >= xdb->slotnpages)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
slot->startpage = xdb->slotnpages;
|
|
|
2ff057 |
if (slot->pagecnt)
|
|
|
2ff057 |
abort();
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* move tail element to the new end */
|
|
|
2ff057 |
slot = xdb->slots + nslots + spp;
|
|
|
2ff057 |
*slot = xdb->slots[nslots];
|
|
|
2ff057 |
slot->slotno = nslots + spp;
|
|
|
2ff057 |
xdb->slots[slot->prev].next = slot->slotno;
|
|
|
2ff057 |
xdb->nslots += spp;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* add new free slots to the firstfree chain */
|
|
|
2ff057 |
memset(xdb->slots + nslots, 0, sizeof(*slot) * spp);
|
|
|
2ff057 |
for (i = 0; i < spp - 1; i++) {
|
|
|
2ff057 |
xdb->slots[nslots + i].slotno = nslots + i;
|
|
|
2ff057 |
xdb->slots[nslots + i].next = i + 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
xdb->slots[nslots + i].slotno = nslots + i;
|
|
|
2ff057 |
xdb->firstfree = nslots;
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int createblob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
unsigned int id;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (subtag > 255)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (!xdb->firstfree) {
|
|
|
2ff057 |
if (addslotpage(xdb))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
id = xdb->firstfree;
|
|
|
2ff057 |
slot = xdb->slots + xdb->firstfree;
|
|
|
2ff057 |
xdb->firstfree = slot->next;
|
|
|
2ff057 |
|
|
|
2ff057 |
slot->mapped = 0;
|
|
|
2ff057 |
slot->blobtag = blobtag;
|
|
|
2ff057 |
slot->subtag = subtag;
|
|
|
2ff057 |
slot->startpage = xdb->slotnpages;
|
|
|
2ff057 |
slot->pagecnt = 0;
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, slot);
|
|
|
2ff057 |
/* enqueue */
|
|
|
2ff057 |
slot->prev = 0;
|
|
|
2ff057 |
slot->next = xdb->slots[0].next;
|
|
|
2ff057 |
xdb->slots[slot->next].prev = id;
|
|
|
2ff057 |
xdb->slots[0].next = id;
|
|
|
2ff057 |
#if 0
|
|
|
2ff057 |
printf("createblob #%d %d/%d\n", id, blobtag, subtag);
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
if (slot->slotno != id)
|
|
|
2ff057 |
abort();
|
|
|
2ff057 |
if (slot->mapped)
|
|
|
2ff057 |
abort();
|
|
|
2ff057 |
*idp = id;
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbLookupBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag, int flags)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
unsigned int i, nslots;
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, flags ? 1 : 0))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
nslots = xdb->nslots;
|
|
|
2ff057 |
slot = 0;
|
|
|
2ff057 |
for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
|
|
|
2ff057 |
slot = xdb->slots + i;
|
|
|
2ff057 |
if (slot->blobtag == blobtag && slot->subtag == subtag)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (i == nslots)
|
|
|
2ff057 |
i = 0;
|
|
|
2ff057 |
if (i && (flags & O_TRUNC) != 0) {
|
|
|
2ff057 |
if (rpmxdbResizeBlob(xdb, i, 0)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, flags ? 1 : 0);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (!i && (flags & O_CREAT) != 0) {
|
|
|
2ff057 |
if (createblob(xdb, &i, blobtag, subtag)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, flags ? 1 : 0);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
*idp = i;
|
|
|
2ff057 |
rpmxdbUnlock(xdb, flags ? 1 : 0);
|
|
|
2ff057 |
return i ? RPMRC_OK : RPMRC_NOTFOUND;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbDelBlob(rpmxdb xdb, unsigned int id)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
if (!id)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 1))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (id >= xdb->nslots) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot = xdb->slots + id;
|
|
|
2ff057 |
if (!slot->startpage) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot->mapped) {
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
/* remove from old chain */
|
|
|
2ff057 |
xdb->slots[slot->prev].next = slot->next;
|
|
|
2ff057 |
xdb->slots[slot->next].prev = slot->prev;
|
|
|
2ff057 |
xdb->usedblobpages -= slot->pagecnt;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (xdb->usedblobpages * 2 < xdb->slots[xdb->nslots].startpage && (slot->startpage + slot->pagecnt) * 2 < xdb->slots[xdb->nslots].startpage) {
|
|
|
2ff057 |
/* freed in first half of pages, move last two blobs if we can */
|
|
|
2ff057 |
moveblobstofront(xdb, xdb->slots + slot->prev);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* zero slot */
|
|
|
2ff057 |
memset(slot, 0, sizeof(*slot));
|
|
|
2ff057 |
slot->slotno = id;
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, slot);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* enqueue into free chain */
|
|
|
2ff057 |
slot->next = xdb->firstfree;
|
|
|
2ff057 |
xdb->firstfree = slot->slotno;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* check if we should truncate the file */
|
|
|
2ff057 |
slot = xdb->slots + xdb->slots[xdb->nslots].prev;
|
|
|
2ff057 |
if (slot->startpage + slot->pagecnt < xdb->slots[xdb->nslots].startpage / 4 * 3) {
|
|
|
2ff057 |
unsigned int newend = slot->startpage + slot->pagecnt;
|
|
|
2ff057 |
if (!ftruncate(xdb->fd, newend * xdb->pagesize))
|
|
|
2ff057 |
xdb->slots[xdb->nslots].startpage = newend;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbResizeBlob(rpmxdb xdb, unsigned int id, size_t newsize)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
unsigned int oldpagecnt, newpagecnt;
|
|
|
2ff057 |
if (!id)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 1))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (id >= xdb->nslots) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot = xdb->slots + id;
|
|
|
2ff057 |
if (!slot->startpage) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
oldpagecnt = slot->pagecnt;
|
|
|
2ff057 |
newpagecnt = (newsize + xdb->pagesize - 1) / xdb->pagesize;
|
|
|
2ff057 |
if (oldpagecnt && newpagecnt && newpagecnt <= oldpagecnt) {
|
|
|
2ff057 |
/* reducing size. zero to end of page */
|
|
|
2ff057 |
unsigned int pg = newsize & (xdb->pagesize - 1);
|
|
|
2ff057 |
if (pg) {
|
|
|
2ff057 |
if (slot->mapped) {
|
|
|
2ff057 |
memset(slot->mapped + pg, 0, xdb->pagesize - pg);
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
char *empty = xcalloc(1, xdb->pagesize - pg);
|
|
|
2ff057 |
if (pwrite(xdb->fd, empty, xdb->pagesize - pg, (slot->startpage + newpagecnt - 1) * xdb->pagesize + pg ) != xdb->pagesize - pg) {
|
|
|
2ff057 |
free(empty);
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(empty);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (newpagecnt == oldpagecnt) {
|
|
|
2ff057 |
/* no size change */
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (!newpagecnt) {
|
|
|
2ff057 |
/* special case: zero size blob, no longer mapped */
|
|
|
2ff057 |
if (slot->mapped)
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
slot->pagecnt = 0;
|
|
|
2ff057 |
slot->startpage = xdb->slotnpages;
|
|
|
2ff057 |
/* remove from old chain */
|
|
|
2ff057 |
xdb->slots[slot->prev].next = slot->next;
|
|
|
2ff057 |
xdb->slots[slot->next].prev = slot->prev;
|
|
|
2ff057 |
/* enqueue into head */
|
|
|
2ff057 |
slot->prev = 0;
|
|
|
2ff057 |
slot->next = xdb->slots[0].next;
|
|
|
2ff057 |
xdb->slots[slot->next].prev = slot->slotno;
|
|
|
2ff057 |
xdb->slots[0].next = slot->slotno;
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, slot);
|
|
|
2ff057 |
xdb->usedblobpages -= oldpagecnt;
|
|
|
2ff057 |
if (slot->mapcallback)
|
|
|
2ff057 |
slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
|
|
|
2ff057 |
} else if (newpagecnt <= xdb->slots[slot->next].startpage - slot->startpage) {
|
|
|
2ff057 |
/* can do it inplace */
|
|
|
2ff057 |
if (newpagecnt > oldpagecnt) {
|
|
|
2ff057 |
/* zero new pages */
|
|
|
2ff057 |
if (rpmxdbWriteEmptyPages(xdb, slot->startpage + oldpagecnt, newpagecnt - oldpagecnt)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot->mapcallback) {
|
|
|
2ff057 |
if (remapslot(xdb, slot, newpagecnt)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
if (slot->mapped)
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
slot->pagecnt = newpagecnt;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, slot);
|
|
|
2ff057 |
xdb->usedblobpages -= oldpagecnt;
|
|
|
2ff057 |
xdb->usedblobpages += newpagecnt;
|
|
|
2ff057 |
if (slot->mapcallback)
|
|
|
2ff057 |
slot->mapcallback(xdb, slot->mapcallbackdata, slot->mapped, slot->pagecnt * xdb->pagesize);
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
/* need to relocate to a new page area */
|
|
|
2ff057 |
if (moveblob(xdb, slot, newpagecnt)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbMapBlob(rpmxdb xdb, unsigned int id, int flags, void (*mapcallback)(rpmxdb xdb, void *data, void *newaddr, size_t newsize), void *mapcallbackdata)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
if (!id || !mapcallback)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if ((flags & (O_RDONLY|O_RDWR)) == O_RDWR && xdb->rdonly)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 0))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (id >= xdb->nslots) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot = xdb->slots + id;
|
|
|
2ff057 |
if (!slot->startpage || slot->mapped) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot->mapflags = (flags & (O_RDONLY|O_RDWR)) == O_RDWR ? PROT_READ | PROT_WRITE : PROT_READ;
|
|
|
2ff057 |
if (slot->pagecnt) {
|
|
|
2ff057 |
if (mapslot(xdb, slot)) {
|
|
|
2ff057 |
slot->mapflags = 0;
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot->mapcallback = mapcallback;
|
|
|
2ff057 |
slot->mapcallbackdata = mapcallbackdata;
|
|
|
2ff057 |
mapcallback(xdb, mapcallbackdata, slot->mapped, slot->mapped ? slot->pagecnt * xdb->pagesize : 0);
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbUnmapBlob(rpmxdb xdb, unsigned int id)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
if (!id)
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 0))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (id >= xdb->nslots) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot = xdb->slots + id;
|
|
|
2ff057 |
if (slot->mapped) {
|
|
|
2ff057 |
unmapslot(xdb, slot);
|
|
|
2ff057 |
slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot->mapcallback = 0;
|
|
|
2ff057 |
slot->mapcallbackdata = 0;
|
|
|
2ff057 |
slot->mapflags = 0;
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbRenameBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
unsigned int otherid;
|
|
|
2ff057 |
unsigned int id = *idp;
|
|
|
2ff057 |
int rc;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (!id || subtag > 255)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 1))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
if (id >= xdb->nslots) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
slot = xdb->slots + id;
|
|
|
2ff057 |
#if 0
|
|
|
2ff057 |
printf("rpmxdbRenameBlob #%d %d/%d -> %d/%d\n", id, slot->blobtag, slot->subtag, blobtag, subtag);
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
if (!slot->startpage) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (slot->blobtag == blobtag && slot->subtag == subtag) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rc = rpmxdbLookupBlob(xdb, &otherid, blobtag, subtag, 0);
|
|
|
2ff057 |
if (rc == RPMRC_NOTFOUND)
|
|
|
2ff057 |
otherid = 0;
|
|
|
2ff057 |
else if (rc) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (otherid) {
|
|
|
2ff057 |
#if 0
|
|
|
2ff057 |
printf("(replacing #%d)\n", otherid);
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
if (rpmxdbDelBlob(xdb, otherid)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
/* get otherid back from free chain */
|
|
|
2ff057 |
if (xdb->firstfree != otherid)
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
xdb->firstfree = xdb->slots[otherid].next;
|
|
|
2ff057 |
|
|
|
2ff057 |
slot->blobtag = blobtag;
|
|
|
2ff057 |
slot->subtag = subtag;
|
|
|
2ff057 |
xdb->slots[otherid] = *slot;
|
|
|
2ff057 |
/* fixup ids */
|
|
|
2ff057 |
xdb->slots[otherid].slotno = otherid;
|
|
|
2ff057 |
xdb->slots[slot->prev].next = otherid;
|
|
|
2ff057 |
xdb->slots[slot->next].prev = otherid;
|
|
|
2ff057 |
/* write */
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, xdb->slots + otherid);
|
|
|
2ff057 |
memset(slot, 0, sizeof(*slot));
|
|
|
2ff057 |
slot->slotno = id;
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, slot);
|
|
|
2ff057 |
slot->next = xdb->firstfree;
|
|
|
2ff057 |
xdb->firstfree = slot->slotno;
|
|
|
2ff057 |
*idp = otherid;
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
slot = xdb->slots + id;
|
|
|
2ff057 |
slot->blobtag = blobtag;
|
|
|
2ff057 |
slot->subtag = subtag;
|
|
|
2ff057 |
rpmxdbUpdateSlot(xdb, slot);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
void rpmxdbSetFsync(rpmxdb xdb, int dofsync)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
xdb->dofsync = dofsync;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbIsRdonly(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
return xdb->rdonly;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbSetUserGeneration(rpmxdb xdb, unsigned int usergeneration)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 1))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
/* sync before the update */
|
|
|
2ff057 |
if (xdb->dofsync && fsync(xdb->fd)) {
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
xdb->usergeneration = usergeneration;
|
|
|
2ff057 |
xdb->generation++;
|
|
|
2ff057 |
rpmxdbWriteHeader(xdb);
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 1);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbGetUserGeneration(rpmxdb xdb, unsigned int *usergenerationp)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 0))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
*usergenerationp = xdb->usergeneration;
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int rpmxdbStats(rpmxdb xdb)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
struct xdb_slot *slot;
|
|
|
2ff057 |
unsigned int i, nslots;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rpmxdbLockReadHeader(xdb, 0))
|
|
|
2ff057 |
return RPMRC_FAIL;
|
|
|
2ff057 |
nslots = xdb->nslots;
|
|
|
2ff057 |
printf("--- XDB Stats\n");
|
|
|
2ff057 |
printf("Filename: %s\n", xdb->filename);
|
|
|
2ff057 |
printf("Generation: %d\n", xdb->generation);
|
|
|
2ff057 |
printf("Slot pages: %d\n", xdb->slotnpages);
|
|
|
2ff057 |
printf("Blob pages: %d\n", xdb->usedblobpages);
|
|
|
2ff057 |
printf("Free pages: %d\n", xdb->slots[nslots].startpage - xdb->usedblobpages - xdb->slotnpages);
|
|
|
2ff057 |
printf("Pagesize: %d / %d\n", xdb->pagesize, xdb->systempagesize);
|
|
|
2ff057 |
for (i = 1, slot = xdb->slots + i; i < nslots; i++, slot++) {
|
|
|
2ff057 |
if (!slot->startpage)
|
|
|
2ff057 |
continue;
|
|
|
2ff057 |
printf("%2d: tag %d/%d, startpage %d, pagecnt %d%s\n", i, slot->blobtag, slot->subtag, slot->startpage, slot->pagecnt, slot->mapcallbackdata ? ", mapped" : "");
|
|
|
2ff057 |
}
|
|
|
2ff057 |
#if 0
|
|
|
2ff057 |
printf("Again in offset order:\n");
|
|
|
2ff057 |
for (i = xdb->slots[0].next; i != nslots; i = slot->next) {
|
|
|
2ff057 |
slot = xdb->slots + i;
|
|
|
2ff057 |
printf("%2d: tag %d/%d, startpage %d, pagecnt %d%s\n", i, slot->blobtag, slot->subtag, slot->startpage, slot->pagecnt, slot->mapcallbackdata ? ", mapped" : "");
|
|
|
2ff057 |
}
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
#if 0
|
|
|
2ff057 |
printf("Free chain:\n");
|
|
|
2ff057 |
for (i = xdb->firstfree; i; i = slot->next) {
|
|
|
2ff057 |
slot = xdb->slots + i;
|
|
|
2ff057 |
printf("%2d [%2d]: tag %d/%d, startpage %d, pagecnt %d%s\n", i, slot->slotno, slot->blobtag, slot->subtag, slot->startpage, slot->pagecnt, slot->mapcallbackdata ? ", mapped" : "");
|
|
|
2ff057 |
}
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
rpmxdbUnlock(xdb, 0);
|
|
|
2ff057 |
return RPMRC_OK;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|