7
/*@unused@*/ static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
9
#define _mymemset(_a, _b, _c)
11
#include <rpmio_internal.h>
13
#include <rpmmacro.h> /* XXX rpmGenPath */
14
#include <rpmurl.h> /* XXX urlGetPath */
21
/* XXX must follow rpmdb.h */
22
#define DB_VERSION_MAJOR 1
23
#define DB_VERSION_MINOR 85
24
#define DB_VERSION_PATCH 0
27
void * data; /* data */
28
size_t size; /* data length */
32
#define DBT struct _DBT1
36
/*@access Header@*/ /* XXX compared with NULL */
39
/*@access dbiIndexSet@*/
43
/* XXX remap DB3 types back into DB1 types */
44
static inline DBTYPE db3_to_dbtype(int dbitype)
47
case 1: return DB_BTREE;
48
case 2: return DB_HASH;
49
case 3: return DB_RECNO;
50
case 4: return DB_HASH; /* XXX W2DO? */
51
case 5: return DB_HASH; /* XXX W2DO? */
53
/*@notreached@*/ return DB_HASH;
57
static /*@observer@*/ char * db_strerror(int error)
61
return ("Successful return: 0");
63
return (strerror(error));
70
* Room for a 64-bit number + slop. This buffer is only used
71
* if we're given an unknown error, which should never happen.
72
* Note, however, we're no longer thread-safe if it does.
78
t = stpcpy(t, "Unknown error: ");
79
sprintf(t, "%d", error);
86
static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
87
/*@modifies dbi, fileSystem @*/
100
rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
101
dbi->dbi_api, rc, msg, db_strerror(error));
103
rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
104
dbi->dbi_api, rc, db_strerror(error));
111
static int db1sync(dbiIndex dbi, /*@unused@*/ unsigned int flags)
112
/*@modifies fileSystem @*/
117
if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
118
FD_t pkgs = dbi->dbi_db;
119
int fdno = Fileno(pkgs);
120
if (fdno >= 0 && (rc = fsync(fdno)) != 0)
125
DB * db = dbi->dbi_db;
126
rc = db->sync(db, flags);
127
rc = cvtdberr(dbi, "db->sync", rc, _debug);
135
/*@null@*/ static void * doGetRecord(dbiIndex dbi, unsigned int offset)
136
/*@modifies dbi, fileSystem @*/
138
FD_t pkgs = dbi->dbi_db;
141
const char ** fileNames;
147
if (offset >= fadGetFileSize(pkgs))
150
(void)Fseek(pkgs, offset, SEEK_SET);
152
h = headerRead(pkgs, HEADER_MAGIC_NO);
154
/* let's sanity check this record a bit, otherwise just skip it */
156
!( headerIsEntry(h, RPMTAG_NAME) &&
157
headerIsEntry(h, RPMTAG_VERSION) &&
158
headerIsEntry(h, RPMTAG_RELEASE) &&
159
headerIsEntry(h, RPMTAG_BUILDTIME)))
165
/* XXX HACK: try to reconnect broken chain. */
167
rpmMessage(RPMMESS_WARNING,
168
_("Broken package chain at offset %d(0x%08x), attempting to reconnect ...\n"),
169
(int) offset, offset);
170
lasto = (offset ? offset : -1);
171
offset = fadNextOffset(pkgs, offset);
179
rpmMessage(RPMMESS_WARNING,
180
_("Reconnecting broken chain at offset %d(0x%08x).\n"),
181
(int) offset, offset);
182
dbi->dbi_lastoffset = offset;
185
/* Retrofit "Provide: name = EVR" for binary packages. */
186
providePackageNVR(h);
189
* The RPM used to build much of RH 5.1 could produce packages whose
190
* file lists did not have leading /'s. Now is a good time to fix that.
194
* If this tag isn't present, either no files are in the package or
195
* we're dealing with a package that has just the compressed file name
198
if (!headerGetEntryMinMemory(h, RPMTAG_OLDFILENAMES, NULL,
199
(const void **) &fileNames, &fileCount))
202
for (i = 0; i < fileCount; i++)
203
if (*fileNames[i] != '/') break;
205
if (i == fileCount) {
207
} else { /* bad header -- let's clean it up */
208
const char ** newFileNames = alloca(sizeof(*newFileNames) * fileCount);
209
for (i = 0; i < fileCount; i++) {
210
char * newFileName = alloca(strlen(fileNames[i]) + 2);
211
if (*fileNames[i] != '/') {
212
newFileName[0] = '/';
213
newFileName[1] = '\0';
215
newFileName[0] = '\0';
216
strcat(newFileName, fileNames[i]);
217
newFileNames[i] = newFileName;
222
(void) headerModifyEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
223
newFileNames, fileCount);
227
* The file list was moved to a more compressed format which not
228
* only saves memory (nice), but gives fingerprinting a nice, fat
229
* speed boost (very nice). Go ahead and convert old headers to
230
* the new style (this is a noop for new headers).
236
uh = headerUnload(h);
242
static int db1copen(/*@unused@*/ dbiIndex dbi,
243
/*@unused@*/ DBC ** dbcp, unsigned int flags)
244
/*@modifies *dbcp @*/
246
/* XXX per-iterator cursors need to be set to non-NULL. */
252
static int db1cclose(dbiIndex dbi,
253
/*@unused@*/ DBC * dbcursor, /*@unused@*/ unsigned int flags)
256
dbi->dbi_lastoffset = 0;
261
static int db1cget(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
262
/*@null@*/ void ** keyp,
263
/*@null@*/ size_t * keylen,
264
/*@null@*/ void ** datap,
265
/*@null@*/ size_t * datalen,
266
/*@unused@*/ unsigned int flags)
267
/*@modifies dbi, *keyp, *keylen, *datap, *datalen, fileSystem @*/
275
memset(&key, 0, sizeof(key));
276
memset(&data, 0, sizeof(data));
277
/*@-unqualifiedtrans@*/
278
if (keyp) key.data = *keyp;
279
if (keylen) key.size = *keylen;
280
if (datap) data.data = *datap;
281
if (datalen) data.size = *datalen;
282
/*@=unqualifiedtrans@*/
284
if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
285
FD_t pkgs = dbi->dbi_db;
287
unsigned int newSize;
289
if (key.data == NULL) { /* XXX simulated DB_NEXT */
290
if (dbi->dbi_lastoffset == 0) {
291
dbi->dbi_lastoffset = fadFirstOffset(pkgs);
293
dbi->dbi_lastoffset = fadNextOffset(pkgs, dbi->dbi_lastoffset);
295
/*@-immediatetrans@*/
296
key.data = &dbi->dbi_lastoffset;
297
/*@=immediatetrans@*/
298
key.size = sizeof(dbi->dbi_lastoffset);
300
/* Catch end-of-chain conditions. */
301
if (dbi->dbi_lastoffset == 0)
305
memcpy(&offset, key.data, sizeof(offset));
306
/* XXX hack to pass sizeof header to fadAlloc */
309
if (offset == 0) { /* XXX simulated offset 0 record */
310
offset = fadAlloc(pkgs, newSize);
313
offset--; /* XXX hack: caller will increment */
314
/* XXX hack: return offset as data, free in db1cput */
315
data.data = xmalloc(sizeof(offset));
316
memcpy(data.data, &offset, sizeof(offset));
317
data.size = sizeof(offset);
318
} else { /* XXX simulated retrieval */
319
data.data = doGetRecord(dbi, offset);
320
data.size = 0; /* XXX WRONG */
328
if ((db = dbi->dbi_db) == NULL)
331
if (key.data == NULL) {
332
rc = db->seq(db, &key, &data, (dbi->dbi_lastoffset++ ? R_NEXT : R_FIRST));
333
_printit = (rc == 1 ? 0 : _debug);
334
rc = cvtdberr(dbi, "db->seq", rc, _printit);
336
rc = db->get(db, &key, &data, 0);
337
_printit = (rc == 1 ? 0 : _debug);
338
rc = cvtdberr(dbi, "db1cget", rc, _printit);
348
if (keyp) *keyp = key.data;
349
if (keylen) *keylen = key.size;
350
if (datap) *datap = data.data;
351
if (datalen) *datalen = data.size;
360
static int db1cdel(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, const void * keyp,
361
size_t keylen, /*@unused@*/ unsigned int flags)
362
/*@modifies dbi, fileSystem @*/
367
memset(&key, 0, sizeof(key));
368
key.data = (void *)keyp;
371
if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
372
FD_t pkgs = dbi->dbi_db;
374
memcpy(&offset, keyp, sizeof(offset));
375
fadFree(pkgs, offset);
379
DB * db = dbi->dbi_db;
382
rc = db->del(db, &key, 0);
383
rc = cvtdberr(dbi, "db->del", rc, _debug);
393
static int db1cput(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
394
const void * keyp, size_t keylen,
395
const void * datap, size_t datalen,
396
/*@unused@*/ unsigned int flags)
397
/*@modifies dbi, datap, fileSystem @*/
402
memset(&key, 0, sizeof(key));
403
memset(&data, 0, sizeof(data));
404
key.data = (void *)keyp;
406
data.data = (void *)datap;
409
if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
410
FD_t pkgs = dbi->dbi_db;
413
memcpy(&offset, key.data, sizeof(offset));
415
if (offset == 0) { /* XXX simulated offset 0 record */
416
/* XXX hack: return offset as data, free in db1cput */
417
if (data.size == sizeof(offset))
418
/*@-unqualifiedtrans@*/ free(data.data); /*@=unqualifiedtrans@*/
419
} else { /* XXX simulated DB_KEYLAST */
420
Header h = headerLoad(data.data);
421
int newSize = headerSizeof(h, HEADER_MAGIC_NO);
423
(void)Fseek(pkgs, offset, SEEK_SET);
424
fdSetContentLength(pkgs, newSize);
425
rc = headerWrite(pkgs, h, HEADER_MAGIC_NO);
426
fdSetContentLength(pkgs, -1);
434
DB * db = dbi->dbi_db;
437
rc = db->put(db, &key, &data, 0);
438
rc = cvtdberr(dbi, "db->put", rc, _debug);
448
static int db1ccount(/*@unused@*/ dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
449
/*@unused@*/ /*@out@*/ unsigned int * countp,
450
/*@unused@*/ unsigned int flags)
456
static int db1byteswapped(/*@unused@*/dbiIndex dbi)
462
static int db1stat(/*@unused@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
468
static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
469
/*@modifies dbi, fileSystem @*/
471
rpmdb rpmdb = dbi->dbi_rpmdb;
472
const char * base = db1basename(dbi->dbi_rpmtag);
473
const char * urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
477
(void) urlPath(urlfn, &fn);
480
if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
481
FD_t pkgs = dbi->dbi_db;
486
DB * db = dbi->dbi_db;
488
rc = cvtdberr(dbi, "db->close", rc, _debug);
497
rpmMessage(RPMMESS_DEBUG, _("closed db file %s\n"), urlfn);
498
/* Remove temporary databases */
499
if (dbi->dbi_temporary) {
500
rpmMessage(RPMMESS_DEBUG, _("removed db file %s\n"), urlfn);
506
urlfn = _free(urlfn);
510
static int db1open(/*@keep@*/ rpmdb rpmdb, int rpmtag,
511
/*@out@*/ dbiIndex * dbip)
512
/*@modifies *dbip, fileSystem @*/
515
extern struct _dbiVec db1vec;
517
const char * base = NULL;
518
const char * urlfn = NULL;
519
const char * fn = NULL;
525
if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
527
dbi->dbi_api = DB_VERSION_MAJOR;
529
base = db1basename(rpmtag);
530
urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
531
(void) urlPath(urlfn, &fn);
532
if (!(fn && *fn != '\0')) {
533
rpmError(RPMERR_DBOPEN, _("bad db file %s\n"), urlfn);
538
rpmMessage(RPMMESS_DEBUG, _("opening db file %s mode 0x%x\n"),
539
urlfn, dbi->dbi_mode);
541
if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
544
pkgs = fadOpen(fn, dbi->dbi_mode, dbi->dbi_perms);
546
rc = errno; /* XXX check errno validity */
550
/* XXX HACK: fcntl lock if db3 (DB_INIT_CDB | DB_INIT_LOCK) specified */
551
if (dbi->dbi_lockdbfd || (dbi->dbi_eflags & 0x30)) {
557
l.l_type = (dbi->dbi_mode & O_RDWR) ? F_WRLCK : F_RDLCK;
559
if (Fcntl(pkgs, F_SETLK, (void *) &l)) {
560
rc = errno; /* XXX check errno validity */
561
rpmError(RPMERR_FLOCK, _("cannot get %s lock on database\n"),
562
((dbi->dbi_mode & O_RDWR) ? _("exclusive") : _("shared")));
571
void * dbopeninfo = NULL;
572
int dbimode = dbi->dbi_mode;
574
if (dbi->dbi_temporary)
575
dbimode |= (O_CREAT | O_RDWR);
577
dbi->dbi_db = dbopen(fn, dbimode, dbi->dbi_perms,
578
db3_to_dbtype(dbi->dbi_type), dbopeninfo);
579
if (dbi->dbi_db == NULL) rc = errno;
587
if (rc == 0 && dbi->dbi_db != NULL && dbip) {
588
dbi->dbi_vec = &db1vec;
589
if (dbip) *dbip = dbi;
591
(void) db1close(dbi, 0);
594
urlfn = _free(urlfn);
602
/*@-exportheadervar@*/
603
struct _dbiVec db1vec = {
604
DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
605
db1open, db1close, db1sync, db1copen, db1cclose, db1cdel, db1cget, db1cput,
606
db1ccount, db1byteswapped, db1stat
608
/*@=exportheadervar@*/