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@*/

Generated on Wed Mar 15 21:44:41 2006 for rpm by  doxygen 1.4.6