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