# rpmdb/db1.c

Go to the documentation of this file.

    00001 /*@-type@*/ /* FIX: shrug */
    00006 #include "system.h"
    00007
    00008 /*@unused@*/ static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
    00009
    00010 #define _mymemset(_a, _b, _c)
    00011
    00012 #include <rpmio_internal.h>
    00013 #include <rpmlib.h>
    00014 #include <rpmmacro.h>   /* XXX rpmGenPath */
    00015 #include <rpmurl.h>     /* XXX urlGetPath */
    00016
    00017 #include "falloc.h"
    00018 #include "misc.h"
    00019
    00020 #include "rpmdb.h"
    00021
    00022 /* XXX must follow rpmdb.h */
    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;        /* data */
    00029     size_t size;        /* data length */
    00030 };
    00031
    00032 #undef  DBT
    00033 #define DBT struct _DBT1
    00034
    00035 #include "debug.h"
    00036
    00037 /*@access Header@*/             /* XXX compared with NULL */
    00038 /*@access rpmdb@*/
    00039 /*@access dbiIndex@*/
    00040 /*@access dbiIndexSet@*/
    00041 /*@-onlytrans@*/
    00042
    00043 #ifdef  DYING
    00044 /* XXX remap DB3 types back into DB1 types */
    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;         /* XXX W2DO? */
    00052     case 5:     return DB_HASH;         /* XXX W2DO? */
    00053     }
    00054     /*@notreached@*/ return DB_HASH;
    00055 }
    00056
    00057 /*@-shadow@*/
    00058 static /*@observer@*/ char * db_strerror(int error)
    00059 /*@=shadow@*/
    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          * Room for a 64-bit number + slop.  This buffer is only used
    00072          * if we're given an unknown error, which should never happen.
    00073          * Note, however, we're no longer thread-safe if it does.
    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     /*@notreached@*/
    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  /* DYING */
    00111
    00112 static int db1sync(dbiIndex dbi, /*@unused@*/ unsigned int flags)
    00113         /*@globals fileSystem @*/
    00114         /*@modifies fileSystem @*/
    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 /*@null@*/ static void * doGetRecord(dbiIndex dbi, unsigned int offset)
    00138         /*@globals fileSystem @*/
    00139         /*@modifies dbi, fileSystem @*/
    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     /* let's sanity check this record a bit, otherwise just skip it */
    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         /* XXX HACK: try to reconnect broken chain. */
    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     /* Retrofit "Provide: name = EVR" for binary packages. */
    00189     providePackageNVR(h);
    00190
    00191     /*
    00192      * The RPM used to build much of RH 5.1 could produce packages whose
    00193      * file lists did not have leading /'s. Now is a good time to fix that.
    00194      */
    00195
    00196     /*
    00197      * If this tag isn't present, either no files are in the package or
    00198      * we're dealing with a package that has just the compressed file name
    00199      * list.
    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 {    /* bad header -- let's clean it up */
    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      * The file list was moved to a more compressed format which not
    00231      * only saves memory (nice), but gives fingerprinting a nice, fat
    00232      * speed boost (very nice). Go ahead and convert old headers to
    00233      * the new style (this is a noop for new headers).
    00234      */
    00235     compressFilelist(h);
    00236
    00237 exit:
    00238     /*@-branchstate@*/
    00239     if (h != NULL) {
    00240         uh = headerUnload(h);
    00241         h = headerFree(h);
    00242     }
    00243     /*@=branchstate@*/
    00244     return uh;
    00245 }
    00246
    00247 static int db1copen(/*@unused@*/ dbiIndex dbi,
    00248                 /*@unused@*/ DBC ** dbcp, unsigned int flags)
    00249         /*@modifies *dbcp @*/
    00250 {
    00251     /* XXX per-iterator cursors need to be set to non-NULL. */
    00252     if (flags)
    00253         *dbcp = (DBC *)-1;
    00254     return 0;
    00255 }
    00256
    00257 static int db1cclose(dbiIndex dbi,
    00258                 /*@unused@*/ DBC * dbcursor, /*@unused@*/ unsigned int flags)
    00259         /*@modifies dbi @*/
    00260 {
    00261     dbi->dbi_lastoffset = 0;
    00262     return 0;
    00263 }
    00264
    00265 /*@-compmempass@*/
    00266 static int db1cget(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
    00267                 /*@null@*/ void ** keyp,
    00268                 /*@null@*/ size_t * keylen,
    00269                 /*@null@*/ void ** datap,
    00270                 /*@null@*/ size_t * datalen,
    00271                 /*@unused@*/ unsigned int flags)
    00272         /*@globals fileSystem @*/
    00273         /*@modifies dbi, *keyp, *keylen, *datap, *datalen, fileSystem @*/
    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     /*@-unqualifiedtrans@*/
    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     /*@=unqualifiedtrans@*/
    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) { /* XXX simulated DB_NEXT */
    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             /*@-immediatetrans@*/
    00302             key.data = &dbi->dbi_lastoffset;
    00303             /*@=immediatetrans@*/
    00304             key.size = sizeof(dbi->dbi_lastoffset);
    00305
    00306             /* Catch end-of-chain conditions. */
    00307             if (dbi->dbi_lastoffset == 0)
    00308                 goto bail;
    00309         }
    00310
    00311         memcpy(&offset, key.data, sizeof(offset));
    00312         /* XXX hack to pass sizeof header to fadAlloc */
    00313         newSize = data.size;
    00314
    00315         if (offset == 0) {      /* XXX simulated offset 0 record */
    00316             offset = fadAlloc(pkgs, newSize);
    00317             if (offset == 0)
    00318                 return ENOMEM;
    00319             offset--;   /* XXX hack: caller will increment */
    00320             /* XXX hack: return offset as data, free in db1cput */
    00321             data.data = xmalloc(sizeof(offset));
    00322             memcpy(data.data, &offset, sizeof(offset));
    00323             data.size = sizeof(offset);
    00324         } else {                /* XXX simulated retrieval */
    00325             data.data = doGetRecord(dbi, offset);
    00326             data.size = 0;      /* XXX WRONG */
    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     /*@-nullstate@*/
    00361     return rc;
    00362     /*@=nullstate@*/
    00363 }
    00364 /*@=compmempass@*/
    00365
    00366 static int db1cdel(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, const void * keyp,
    00367                 size_t keylen, /*@unused@*/ unsigned int flags)
    00368         /*@globals fileSystem @*/
    00369         /*@modifies dbi, fileSystem @*/
    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, /*@unused@*/ DBC * dbcursor,
    00401                 const void * keyp, size_t keylen,
    00402                 const void * datap, size_t datalen,
    00403                 /*@unused@*/ unsigned int flags)
    00404         /*@globals fileSystem @*/
    00405         /*@modifies dbi, datap, fileSystem @*/
    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) {      /* XXX simulated offset 0 record */
    00424             /* XXX hack: return offset as data, free in db1cput */
    00425             if (data.size == sizeof(offset))
    00426                 /*@-unqualifiedtrans@*/ free(data.data); /*@=unqualifiedtrans@*/
    00427         } else {                /* XXX simulated DB_KEYLAST */
    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(/*@unused@*/ dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
    00457                 /*@unused@*/ /*@out@*/ unsigned int * countp,
    00458                 /*@unused@*/ unsigned int flags)
    00459         /*@*/
    00460 {
    00461     return EINVAL;
    00462 }
    00463
    00464 static int db1byteswapped(/*@unused@*/dbiIndex dbi)
    00465         /*@*/
    00466 {
    00467     return 0;
    00468 }
    00469
    00470 static int db1stat(/*@unused@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
    00471         /*@*/
    00472 {
    00473     return EINVAL;
    00474 }
    00475
    00476 static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
    00477         /*@globals rpmGlobalMacroContext,
    00478                 fileSystem @*/
    00479         /*@modifies dbi, rpmGlobalMacroContext, fileSystem @*/
    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     /*@-branchstate@*/
    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     /*@=branchstate@*/
    00508
    00509     rpmMessage(RPMMESS_DEBUG, _("closed  db file        %s\n"), urlfn);
    00510     /* Remove temporary databases */
    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(/*@keep@*/ rpmdb rpmdb, int rpmtag,
    00523         /*@out@*/ dbiIndex * dbip)
    00524         /*@globals rpmGlobalMacroContext,
    00525                 fileSystem @*/
    00526         /*@modifies *dbip, rpmGlobalMacroContext, fileSystem @*/
    00527 {
    00528     /*@-nestedextern@*/
    00529     extern struct _dbiVec db1vec;
    00530     /*@=nestedextern@*/
    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;         /* XXX check errno validity */
    00561             goto exit;
    00562         }
    00563
    00564         /* XXX HACK: fcntl lock if db3 (DB_INIT_CDB | DB_INIT_LOCK) specified */
    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;     /* XXX check errno validity */
    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 /*@=onlytrans@*/
    00613
    00616 /*@-exportheadervar@*/
    00617 /*@observer@*/ /*@unchecked@*/
    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 /*@=exportheadervar@*/
    00624 /*@=type@*/