00001
00006 #include "system.h"
00007
00008 static int _debug = 1;
00009
00010 #define _mymemset(_a, _b, _c)
00011
00012 #include <rpmio_internal.h>
00013 #include <rpmlib.h>
00014 #include <rpmmacro.h>
00015 #include <rpmurl.h>
00016
00017 #include "falloc.h"
00018 #include "misc.h"
00019
00020 #include "rpmdb.h"
00021
00022
00023 #define DB_VERSION_MAJOR 1
00024 #define DB_VERSION_MINOR 85
00025 #define DB_VERSION_PATCH 0
00026
00027 struct _DBT1 {
00028 void * data;
00029 size_t size;
00030 };
00031
00032 #undef DBT
00033 #define DBT struct _DBT1
00034
00035 #include "debug.h"
00036
00037
00038
00039
00040
00041
00042
00043 #ifdef DYING
00044
00045 static inline DBTYPE db3_to_dbtype(int dbitype)
00046 {
00047 switch(dbitype) {
00048 case 1: return DB_BTREE;
00049 case 2: return DB_HASH;
00050 case 3: return DB_RECNO;
00051 case 4: return DB_HASH;
00052 case 5: return DB_HASH;
00053 }
00054 return DB_HASH;
00055 }
00056
00057
00058 static char * db_strerror(int error)
00059
00060 {
00061 if (error == 0)
00062 return ("Successful return: 0");
00063 if (error > 0)
00064 return (strerror(error));
00065
00066 switch (error) {
00067 default:
00068 {
00069
00070
00071
00072
00073
00074
00075 static char ebuf[40];
00076 char * t = ebuf;
00077
00078 *t = '\0';
00079 t = stpcpy(t, "Unknown error: ");
00080 sprintf(t, "%d", error);
00081 return(ebuf);
00082 }
00083 }
00084
00085 }
00086
00087 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
00088
00089 {
00090 int rc = 0;
00091
00092 if (error == 0)
00093 rc = 0;
00094 else if (error < 0)
00095 rc = errno;
00096 else if (error > 0)
00097 rc = -1;
00098
00099 if (printit && rc) {
00100 if (msg)
00101 rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
00102 dbi->dbi_api, rc, msg, db_strerror(error));
00103 else
00104 rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
00105 dbi->dbi_api, rc, db_strerror(error));
00106 }
00107
00108 return rc;
00109 }
00110 #endif
00111
00112 static int db1sync(dbiIndex dbi, unsigned int flags)
00113
00114
00115 {
00116 int rc = 0;
00117
00118 if (dbi->dbi_db) {
00119 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00120 FD_t pkgs = dbi->dbi_db;
00121 int fdno = Fileno(pkgs);
00122 if (fdno >= 0 && (rc = fsync(fdno)) != 0)
00123 rc = errno;
00124 }
00125 #ifdef DYING
00126 else {
00127 DB * db = dbi->dbi_db;
00128 rc = db->sync(db, flags);
00129 rc = cvtdberr(dbi, "db->sync", rc, _debug);
00130 }
00131 #endif
00132 }
00133
00134 return rc;
00135 }
00136
00137 static void * doGetRecord(dbiIndex dbi, unsigned int offset)
00138
00139
00140 {
00141 FD_t pkgs = dbi->dbi_db;
00142 void * uh = NULL;
00143 Header h = NULL;
00144 const char ** fileNames;
00145 int fileCount = 0;
00146 int lasto = 0;
00147 int i;
00148
00149 retry:
00150 if (offset >= fadGetFileSize(pkgs))
00151 goto exit;
00152
00153 (void)Fseek(pkgs, offset, SEEK_SET);
00154
00155 h = headerRead(pkgs, HEADER_MAGIC_NO);
00156
00157
00158 if (h != NULL &&
00159 !( headerIsEntry(h, RPMTAG_NAME) &&
00160 headerIsEntry(h, RPMTAG_VERSION) &&
00161 headerIsEntry(h, RPMTAG_RELEASE) &&
00162 headerIsEntry(h, RPMTAG_BUILDTIME)))
00163 {
00164 h = headerFree(h);
00165 }
00166
00167 if (h == NULL) {
00168
00169 if (lasto == 0) {
00170 rpmMessage(RPMMESS_WARNING,
00171 _("Broken package chain at offset %d(0x%08x), attempting to reconnect ...\n"),
00172 (int) offset, offset);
00173 lasto = (offset ? offset : -1);
00174 offset = fadNextOffset(pkgs, offset);
00175 if (offset > 0)
00176 goto retry;
00177 }
00178 goto exit;
00179 }
00180
00181 if (lasto) {
00182 rpmMessage(RPMMESS_WARNING,
00183 _("Reconnecting broken chain at offset %d(0x%08x).\n"),
00184 (int) offset, offset);
00185 dbi->dbi_lastoffset = offset;
00186 }
00187
00188
00189 providePackageNVR(h);
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 if (!headerGetEntryMinMemory(h, RPMTAG_OLDFILENAMES, NULL,
00202 (const void **) &fileNames, &fileCount))
00203 goto exit;
00204
00205 for (i = 0; i < fileCount; i++)
00206 if (*fileNames[i] != '/') break;
00207
00208 if (i == fileCount) {
00209 free(fileNames);
00210 } else {
00211 const char ** newFileNames = alloca(sizeof(*newFileNames) * fileCount);
00212 for (i = 0; i < fileCount; i++) {
00213 char * newFileName = alloca(strlen(fileNames[i]) + 2);
00214 if (*fileNames[i] != '/') {
00215 newFileName[0] = '/';
00216 newFileName[1] = '\0';
00217 } else
00218 newFileName[0] = '\0';
00219 strcat(newFileName, fileNames[i]);
00220 newFileNames[i] = newFileName;
00221 }
00222
00223 free(fileNames);
00224
00225 (void) headerModifyEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00226 newFileNames, fileCount);
00227 }
00228
00229
00230
00231
00232
00233
00234
00235 compressFilelist(h);
00236
00237 exit:
00238
00239 if (h != NULL) {
00240 uh = headerUnload(h);
00241 h = headerFree(h);
00242 }
00243
00244 return uh;
00245 }
00246
00247 static int db1copen( dbiIndex dbi,
00248 DBC ** dbcp, unsigned int flags)
00249
00250 {
00251
00252 if (flags)
00253 *dbcp = (DBC *)-1;
00254 return 0;
00255 }
00256
00257 static int db1cclose(dbiIndex dbi,
00258 DBC * dbcursor, unsigned int flags)
00259
00260 {
00261 dbi->dbi_lastoffset = 0;
00262 return 0;
00263 }
00264
00265
00266 static int db1cget(dbiIndex dbi, DBC * dbcursor,
00267 void ** keyp,
00268 size_t * keylen,
00269 void ** datap,
00270 size_t * datalen,
00271 unsigned int flags)
00272
00273
00274 {
00275 DBT key, data;
00276 int rc = 0;
00277
00278 if (dbi == NULL)
00279 return EFAULT;
00280
00281 memset(&key, 0, sizeof(key));
00282 memset(&data, 0, sizeof(data));
00283
00284 if (keyp) key.data = *keyp;
00285 if (keylen) key.size = *keylen;
00286 if (datap) data.data = *datap;
00287 if (datalen) data.size = *datalen;
00288
00289
00290 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00291 FD_t pkgs = dbi->dbi_db;
00292 unsigned int offset;
00293 unsigned int newSize;
00294
00295 if (key.data == NULL) {
00296 if (dbi->dbi_lastoffset == 0) {
00297 dbi->dbi_lastoffset = fadFirstOffset(pkgs);
00298 } else {
00299 dbi->dbi_lastoffset = fadNextOffset(pkgs, dbi->dbi_lastoffset);
00300 }
00301
00302 key.data = &dbi->dbi_lastoffset;
00303
00304 key.size = sizeof(dbi->dbi_lastoffset);
00305
00306
00307 if (dbi->dbi_lastoffset == 0)
00308 goto bail;
00309 }
00310
00311 memcpy(&offset, key.data, sizeof(offset));
00312
00313 newSize = data.size;
00314
00315 if (offset == 0) {
00316 offset = fadAlloc(pkgs, newSize);
00317 if (offset == 0)
00318 return ENOMEM;
00319 offset--;
00320
00321 data.data = xmalloc(sizeof(offset));
00322 memcpy(data.data, &offset, sizeof(offset));
00323 data.size = sizeof(offset);
00324 } else {
00325 data.data = doGetRecord(dbi, offset);
00326 data.size = 0;
00327 }
00328 }
00329 #ifdef DYING
00330 else {
00331 DB * db;
00332 int _printit;
00333
00334 if ((db = dbi->dbi_db) == NULL)
00335 return EFAULT;
00336
00337 if (key.data == NULL) {
00338 rc = db->seq(db, &key, &data, (dbi->dbi_lastoffset++ ? R_NEXT : R_FIRST));
00339 _printit = (rc == 1 ? 0 : _debug);
00340 rc = cvtdberr(dbi, "db->seq", rc, _printit);
00341 } else {
00342 rc = db->get(db, &key, &data, 0);
00343 _printit = (rc == 1 ? 0 : _debug);
00344 rc = cvtdberr(dbi, "db1cget", rc, _printit);
00345 }
00346 }
00347 #else
00348 else
00349 rc = EINVAL;
00350 #endif
00351
00352 bail:
00353 if (rc == 0) {
00354 if (keyp) *keyp = key.data;
00355 if (keylen) *keylen = key.size;
00356 if (datap) *datap = data.data;
00357 if (datalen) *datalen = data.size;
00358 }
00359
00360
00361 return rc;
00362
00363 }
00364
00365
00366 static int db1cdel(dbiIndex dbi, DBC * dbcursor, const void * keyp,
00367 size_t keylen, unsigned int flags)
00368
00369
00370 {
00371 DBT key;
00372 int rc = 0;
00373
00374 memset(&key, 0, sizeof(key));
00375 key.data = (void *)keyp;
00376 key.size = keylen;
00377
00378 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00379 FD_t pkgs = dbi->dbi_db;
00380 unsigned int offset;
00381 memcpy(&offset, keyp, sizeof(offset));
00382 fadFree(pkgs, offset);
00383 }
00384 #ifdef DYING
00385 else {
00386 DB * db = dbi->dbi_db;
00387
00388 if (db)
00389 rc = db->del(db, &key, 0);
00390 rc = cvtdberr(dbi, "db->del", rc, _debug);
00391 }
00392 #else
00393 else
00394 rc = EINVAL;
00395 #endif
00396
00397 return rc;
00398 }
00399
00400 static int db1cput(dbiIndex dbi, DBC * dbcursor,
00401 const void * keyp, size_t keylen,
00402 const void * datap, size_t datalen,
00403 unsigned int flags)
00404
00405
00406 {
00407 DBT key, data;
00408 int rc = 0;
00409
00410 memset(&key, 0, sizeof(key));
00411 memset(&data, 0, sizeof(data));
00412 key.data = (void *)keyp;
00413 key.size = keylen;
00414 data.data = (void *)datap;
00415 data.size = datalen;
00416
00417 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00418 FD_t pkgs = dbi->dbi_db;
00419 unsigned int offset;
00420
00421 memcpy(&offset, key.data, sizeof(offset));
00422
00423 if (offset == 0) {
00424
00425 if (data.size == sizeof(offset))
00426 free(data.data);
00427 } else {
00428 Header h = headerLoad(data.data);
00429 int newSize = headerSizeof(h, HEADER_MAGIC_NO);
00430
00431 (void)Fseek(pkgs, offset, SEEK_SET);
00432 fdSetContentLength(pkgs, newSize);
00433 rc = headerWrite(pkgs, h, HEADER_MAGIC_NO);
00434 fdSetContentLength(pkgs, -1);
00435 if (rc)
00436 rc = EIO;
00437 h = headerFree(h);
00438 }
00439 }
00440 #ifdef DYING
00441 else {
00442 DB * db = dbi->dbi_db;
00443
00444 if (db)
00445 rc = db->put(db, &key, &data, 0);
00446 rc = cvtdberr(dbi, "db->put", rc, _debug);
00447 }
00448 #else
00449 else
00450 rc = EINVAL;
00451 #endif
00452
00453 return rc;
00454 }
00455
00456 static int db1ccount( dbiIndex dbi, DBC * dbcursor,
00457 unsigned int * countp,
00458 unsigned int flags)
00459
00460 {
00461 return EINVAL;
00462 }
00463
00464 static int db1byteswapped(dbiIndex dbi)
00465
00466 {
00467 return 0;
00468 }
00469
00470 static int db1stat( dbiIndex dbi, unsigned int flags)
00471
00472 {
00473 return EINVAL;
00474 }
00475
00476 static int db1close( dbiIndex dbi, unsigned int flags)
00477
00478
00479
00480 {
00481 rpmdb rpmdb = dbi->dbi_rpmdb;
00482 const char * base = db1basename(dbi->dbi_rpmtag);
00483 const char * urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
00484 const char * fn;
00485 int rc = 0;
00486
00487 (void) urlPath(urlfn, &fn);
00488
00489
00490 if (dbi->dbi_db) {
00491 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00492 FD_t pkgs = dbi->dbi_db;
00493 rc = Fclose(pkgs);
00494 }
00495 #ifdef DYING
00496 else {
00497 DB * db = dbi->dbi_db;
00498 rc = db->close(db);
00499 rc = cvtdberr(dbi, "db->close", rc, _debug);
00500 }
00501 #else
00502 else
00503 rc = EINVAL;
00504 #endif
00505 dbi->dbi_db = NULL;
00506 }
00507
00508
00509 rpmMessage(RPMMESS_DEBUG, _("closed db file %s\n"), urlfn);
00510
00511 if (dbi->dbi_temporary) {
00512 rpmMessage(RPMMESS_DEBUG, _("removed db file %s\n"), urlfn);
00513 (void) unlink(fn);
00514 }
00515
00516 dbi = db3Free(dbi);
00517 base = _free(base);
00518 urlfn = _free(urlfn);
00519 return rc;
00520 }
00521
00522 static int db1open( rpmdb rpmdb, int rpmtag,
00523 dbiIndex * dbip)
00524
00525
00526
00527 {
00528
00529 extern struct _dbiVec db1vec;
00530
00531 const char * base = NULL;
00532 const char * urlfn = NULL;
00533 const char * fn = NULL;
00534 dbiIndex dbi = NULL;
00535 int rc = 0;
00536
00537 if (dbip)
00538 *dbip = NULL;
00539 if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
00540 return EFAULT;
00541 dbi->dbi_api = DB_VERSION_MAJOR;
00542
00543 base = db1basename(rpmtag);
00544 urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
00545 (void) urlPath(urlfn, &fn);
00546 if (!(fn && *fn != '\0')) {
00547 rpmError(RPMERR_DBOPEN, _("bad db file %s\n"), urlfn);
00548 rc = EFAULT;
00549 goto exit;
00550 }
00551
00552 rpmMessage(RPMMESS_DEBUG, _("opening db file %s mode 0x%x\n"),
00553 urlfn, dbi->dbi_mode);
00554
00555 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00556 FD_t pkgs;
00557
00558 pkgs = fadOpen(fn, dbi->dbi_mode, dbi->dbi_perms);
00559 if (Ferror(pkgs)) {
00560 rc = errno;
00561 goto exit;
00562 }
00563
00564
00565 if (dbi->dbi_lockdbfd || (dbi->dbi_eflags & 0x30)) {
00566 struct flock l;
00567
00568 l.l_whence = 0;
00569 l.l_start = 0;
00570 l.l_len = 0;
00571 l.l_type = (dbi->dbi_mode & O_RDWR) ? F_WRLCK : F_RDLCK;
00572
00573 if (Fcntl(pkgs, F_SETLK, (void *) &l)) {
00574 rc = errno;
00575 rpmError(RPMERR_FLOCK, _("cannot get %s lock on database\n"),
00576 ((dbi->dbi_mode & O_RDWR) ? _("exclusive") : _("shared")));
00577 goto exit;
00578 }
00579 }
00580
00581 dbi->dbi_db = pkgs;
00582 }
00583 #ifdef DYING
00584 else {
00585 void * dbopeninfo = NULL;
00586 int dbimode = dbi->dbi_mode;
00587
00588 if (dbi->dbi_temporary)
00589 dbimode |= (O_CREAT | O_RDWR);
00590
00591 dbi->dbi_db = dbopen(fn, dbimode, dbi->dbi_perms,
00592 db3_to_dbtype(dbi->dbi_type), dbopeninfo);
00593 if (dbi->dbi_db == NULL) rc = errno;
00594 }
00595 #else
00596 else
00597 rc = EINVAL;
00598 #endif
00599
00600 exit:
00601 if (rc == 0 && dbi->dbi_db != NULL && dbip) {
00602 dbi->dbi_vec = &db1vec;
00603 if (dbip) *dbip = dbi;
00604 } else
00605 (void) db1close(dbi, 0);
00606
00607 base = _free(base);
00608 urlfn = _free(urlfn);
00609
00610 return rc;
00611 }
00612
00613
00616
00617
00618 struct _dbiVec db1vec = {
00619 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
00620 db1open, db1close, db1sync, db1copen, db1cclose, db1cdel, db1cget, db1cput,
00621 db1ccount, db1byteswapped, db1stat
00622 };
00623
00624