#include "system.h" #include #include #include "lib/rpmdb_internal.h" #include #include #include "lib/backend/ndb/rpmpkg.h" #include "lib/backend/ndb/rpmxdb.h" #include "lib/backend/ndb/rpmidx.h" #include "debug.h" struct dbiCursor_s { dbiIndex dbi; const void *key; unsigned int keylen; unsigned int hdrNum; int flags; unsigned int *list; unsigned int nlist; unsigned int ilist; unsigned char *listdata; }; struct ndbEnv_s { rpmpkgdb pkgdb; rpmxdb xdb; int refs; unsigned int hdrNum; void *data; unsigned int datalen; }; static void closeEnv(rpmdb rdb) { struct ndbEnv_s *ndbenv = rdb->db_dbenv; if (--ndbenv->refs == 0) { if (ndbenv->xdb) { rpmxdbClose(ndbenv->xdb); rpmlog(RPMLOG_DEBUG, "closed db index %s/Index.db\n", rpmdbHome(rdb)); } if (ndbenv->pkgdb) { rpmpkgClose(ndbenv->pkgdb); rpmlog(RPMLOG_DEBUG, "closed db index %s/Packages.db\n", rpmdbHome(rdb)); } if (ndbenv->data) free(ndbenv->data); free(ndbenv); } rdb->db_dbenv = 0; } static struct ndbEnv_s *openEnv(rpmdb rdb) { struct ndbEnv_s *ndbenv = rdb->db_dbenv; if (!ndbenv) rdb->db_dbenv = ndbenv = xcalloc(1, sizeof(struct ndbEnv_s)); ndbenv->refs++; return ndbenv; } static int ndb_Close(dbiIndex dbi, unsigned int flags) { rpmdb rdb = dbi->dbi_rpmdb; if (dbi->dbi_type != DBI_PRIMARY && dbi->dbi_db) { rpmidxClose(dbi->dbi_db); rpmlog(RPMLOG_DEBUG, "closed db index %s\n", dbi->dbi_file); } if (rdb->db_dbenv) closeEnv(rdb); dbi->dbi_db = 0; return 0; } static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) { const char *dbhome = rpmdbHome(rdb); struct ndbEnv_s *ndbenv; dbiIndex dbi; int rc, oflags, ioflags; if (dbip) *dbip = NULL; if ((dbi = dbiNew(rdb, rpmtag)) == NULL) return 1; ndbenv = openEnv(rdb); oflags = O_RDWR; if ((rdb->db_mode & O_ACCMODE) == O_RDONLY) oflags = O_RDONLY; if (dbi->dbi_type == DBI_PRIMARY) { rpmpkgdb pkgdb = 0; char *path = rstrscat(NULL, dbhome, "/Packages.db", NULL); rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode); rc = rpmpkgOpen(&pkgdb, path, oflags, 0666); if (rc && errno == ENOENT) { oflags = O_RDWR|O_CREAT; dbi->dbi_flags |= DBI_CREATED; rc = rpmpkgOpen(&pkgdb, path, oflags, 0666); } if (rc) { perror("rpmpkgOpen"); free(path); ndb_Close(dbi, 0); return 1; } free(path); dbi->dbi_db = ndbenv->pkgdb = pkgdb; if ((oflags & (O_RDWR | O_RDONLY)) == O_RDONLY) dbi->dbi_flags |= DBI_RDONLY; } else { unsigned int id; rpmidxdb idxdb = 0; if (!ndbenv->pkgdb) { ndb_Close(dbi, 0); return 1; /* please open primary first */ } if (!ndbenv->xdb) { char *path = rstrscat(NULL, dbhome, "/Index.db", NULL); rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode); /* Open indexes readwrite if possible */ ioflags = O_RDWR; rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666); if (rc && errno == EACCES) { /* If it is not asked for rw explicitly, try to open ro */ if (!(oflags & O_RDWR)) { ioflags = O_RDONLY; rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666); } } else if (rc && errno == ENOENT) { ioflags = O_CREAT|O_RDWR; rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666); } if (rc) { perror("rpmxdbOpen"); free(path); ndb_Close(dbi, 0); return 1; } free(path); } if (rpmxdbLookupBlob(ndbenv->xdb, &id, rpmtag, 0, 0) == RPMRC_NOTFOUND) { dbi->dbi_flags |= DBI_CREATED; } rpmlog(RPMLOG_DEBUG, "opening db index %s tag=%d\n", dbiName(dbi), rpmtag); if (rpmidxOpenXdb(&idxdb, rdb->db_pkgs->dbi_db, ndbenv->xdb, rpmtag)) { perror("rpmidxOpenXdb"); ndb_Close(dbi, 0); return 1; } dbi->dbi_db = idxdb; if (rpmxdbIsRdonly(ndbenv->xdb)) dbi->dbi_flags |= DBI_RDONLY; } if (dbip != NULL) *dbip = dbi; else ndb_Close(dbi, 0); return 0; } static int ndb_Verify(dbiIndex dbi, unsigned int flags) { return 1; } static void ndb_SetFSync(rpmdb rdb, int enable) { } static int indexSync(rpmpkgdb pkgdb, rpmxdb xdb) { unsigned int generation; int rc; if (!pkgdb || !xdb) return 1; if (rpmpkgLock(pkgdb, 1)) return 1; if (rpmpkgGeneration(pkgdb, &generation)) { rpmpkgUnlock(pkgdb, 1); return 1; } rc = rpmxdbSetUserGeneration(xdb, generation); rpmpkgUnlock(pkgdb, 1); return rc; } static int ndb_Ctrl(rpmdb rdb, dbCtrlOp ctrl) { struct ndbEnv_s *ndbenv = rdb->db_dbenv; switch (ctrl) { case DB_CTRL_LOCK_RO: if (!rdb->db_pkgs) return 1; return rpmpkgLock(rdb->db_pkgs->dbi_db, 0); case DB_CTRL_LOCK_RW: if (!rdb->db_pkgs) return 1; return rpmpkgLock(rdb->db_pkgs->dbi_db, 1); case DB_CTRL_UNLOCK_RO: if (!rdb->db_pkgs) return 1; return rpmpkgUnlock(rdb->db_pkgs->dbi_db, 0); case DB_CTRL_UNLOCK_RW: if (!rdb->db_pkgs) return 1; return rpmpkgUnlock(rdb->db_pkgs->dbi_db, 1); case DB_CTRL_INDEXSYNC: if (!ndbenv) return 1; return indexSync(ndbenv->pkgdb, ndbenv->xdb); default: break; } return 0; } static dbiCursor ndb_CursorInit(dbiIndex dbi, unsigned int flags) { dbiCursor dbc = xcalloc(1, sizeof(*dbc)); dbc->dbi = dbi; dbc->flags = flags; return dbc; } static dbiCursor ndb_CursorFree(dbiIndex dbi, dbiCursor dbc) { if (dbc) { if (dbc->list) free(dbc->list); if (dbc->listdata) free(dbc->listdata); free(dbc); } return NULL; } static void setdata(dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen) { struct ndbEnv_s *ndbenv = dbc->dbi->dbi_rpmdb->db_dbenv; if (ndbenv->data) free(ndbenv->data); ndbenv->hdrNum = hdrNum; ndbenv->data = hdrBlob; ndbenv->datalen = hdrLen; } static rpmRC ndb_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum) { int rc = rpmpkgNextPkgIdx(dbc->dbi->dbi_db, hdrNum); if (!rc) setdata(dbc, *hdrNum, 0, 0); return rc; } static rpmRC ndb_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char *hdrBlob, unsigned int hdrLen) { int rc = rpmpkgPut(dbc->dbi->dbi_db, hdrNum, hdrBlob, hdrLen); if (!rc) { dbc->hdrNum = hdrNum; setdata(dbc, hdrNum, 0, 0); } return rc; } static rpmRC ndb_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum) { dbc->hdrNum = 0; setdata(dbc, 0, 0, 0); return rpmpkgDel(dbc->dbi->dbi_db, hdrNum); } /* iterate over all packages */ static rpmRC ndb_pkgdbIter(dbiIndex dbi, dbiCursor dbc, unsigned char **hdrBlob, unsigned int *hdrLen) { int rc; unsigned int hdrNum; if (!dbc->list) { rc = rpmpkgList(dbc->dbi->dbi_db, &dbc->list, &dbc->nlist); if (rc) return rc; dbc->ilist = 0; } for (;;) { if (dbc->ilist >= dbc->nlist) { rc = RPMRC_NOTFOUND; break; } *hdrBlob = 0; hdrNum = dbc->list[dbc->ilist]; rc = rpmpkgGet(dbc->dbi->dbi_db, hdrNum, hdrBlob, hdrLen); if (rc && rc != RPMRC_NOTFOUND) break; dbc->ilist++; if (!rc) { dbc->hdrNum = hdrNum; setdata(dbc, hdrNum, *hdrBlob, *hdrLen); break; } } return rc; } static rpmRC ndb_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, unsigned char **hdrBlob, unsigned int *hdrLen) { int rc; struct ndbEnv_s *ndbenv = dbc->dbi->dbi_rpmdb->db_dbenv; if (!hdrNum) return ndb_pkgdbIter(dbi, dbc, hdrBlob, hdrLen); if (hdrNum == ndbenv->hdrNum && ndbenv->data) { *hdrBlob = ndbenv->data; *hdrLen = ndbenv->datalen; return RPMRC_OK; } rc = rpmpkgGet(dbc->dbi->dbi_db, hdrNum, hdrBlob, hdrLen); if (!rc) { dbc->hdrNum = hdrNum; setdata(dbc, hdrNum, *hdrBlob, *hdrLen); } return rc; } static unsigned int ndb_pkgdbKey(dbiIndex dbi, dbiCursor dbc) { return dbc->hdrNum; } static void addtoset(dbiIndexSet *set, unsigned int *pkglist, unsigned int pkglistn) { unsigned int i, j; dbiIndexSet newset = dbiIndexSetNew(pkglistn / 2); for (i = j = 0; i < pkglistn; i += 2) { newset->recs[j].hdrNum = pkglist[i]; newset->recs[j].tagNum = pkglist[i + 1]; j++; } newset->count = j; if (pkglist) free(pkglist); if (*set) { dbiIndexSetAppendSet(*set, newset, 0); dbiIndexSetFree(newset); } else *set = newset; } /* Iterate over all index entries */ static rpmRC ndb_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set) { int rc; if (!dbc->list) { /* setup iteration list on first call */ rc = rpmidxList(dbc->dbi->dbi_db, &dbc->list, &dbc->nlist, &dbc->listdata); if (rc) return rc; dbc->ilist = 0; } for (;;) { unsigned char *k; unsigned int kl; unsigned int *pkglist, pkglistn; if (dbc->ilist >= dbc->nlist) { rc = RPMRC_NOTFOUND; break; } k = dbc->listdata + dbc->list[dbc->ilist]; kl = dbc->list[dbc->ilist + 1]; #if 0 if (searchType == DBC_KEY_SEARCH) { dbc->ilist += 2; dbc->key = k; dbc->keylen = kl; rc = RPMRC_OK; break; } #endif pkglist = 0; pkglistn = 0; rc = rpmidxGet(dbc->dbi->dbi_db, k, kl, &pkglist, &pkglistn); if (rc && rc != RPMRC_NOTFOUND) break; dbc->ilist += 2; if (!rc && pkglistn) { addtoset(set, pkglist, pkglistn); dbc->key = k; dbc->keylen = kl; break; } if (pkglist) free(pkglist); } return rc; } static rpmRC ndb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexSet *set, int searchType) { int rc; unsigned int *pkglist = 0, pkglistn = 0; if (!keyp) return ndb_idxdbIter(dbi, dbc, set); if (searchType == DBC_PREFIX_SEARCH) { unsigned int *list = 0, nlist = 0, i = 0; unsigned char *listdata = 0; int rrc = RPMRC_NOTFOUND; rc = rpmidxList(dbc->dbi->dbi_db, &list, &nlist, &listdata); if (rc) return rc; for (i = 0; i < nlist && !rc; i += 2) { unsigned char *k = listdata + list[i]; unsigned int kl = list[i + 1]; if (kl < keylen || memcmp(k, keyp, keylen) != 0) continue; rc = ndb_idxdbGet(dbi, dbc, (char *)k, kl, set, DBC_NORMAL_SEARCH); if (rc == RPMRC_NOTFOUND) rc = 0; else rrc = rc; } if (list) free(list); if (listdata) free(listdata); return rc ? rc : rrc; } rc = rpmidxGet(dbc->dbi->dbi_db, (const unsigned char *)keyp, keylen, &pkglist, &pkglistn); if (!rc) addtoset(set, pkglist, pkglistn); return rc; } static rpmRC ndb_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec) { return rpmidxPut(dbc->dbi->dbi_db, (const unsigned char *)keyp, keylen, rec->hdrNum, rec->tagNum); } static rpmRC ndb_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec) { return rpmidxDel(dbc->dbi->dbi_db, (const unsigned char *)keyp, keylen, rec->hdrNum, rec->tagNum); } static const void * ndb_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen) { if (dbc->key && keylen) *keylen = dbc->keylen; return dbc->key; } struct rpmdbOps_s ndb_dbops = { .open = ndb_Open, .close = ndb_Close, .verify = ndb_Verify, .setFSync = ndb_SetFSync, .ctrl = ndb_Ctrl, .cursorInit = ndb_CursorInit, .cursorFree = ndb_CursorFree, .pkgdbNew = ndb_pkgdbNew, .pkgdbPut = ndb_pkgdbPut, .pkgdbDel = ndb_pkgdbDel, .pkgdbGet = ndb_pkgdbGet, .pkgdbKey = ndb_pkgdbKey, .idxdbGet = ndb_idxdbGet, .idxdbPut = ndb_idxdbPut, .idxdbDel = ndb_idxdbDel, .idxdbKey = ndb_idxdbKey };