Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

rpmdb/db1.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 /*@unused@*/ static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
00008 
00009 #define _mymemset(_a, _b, _c)
00010 
00011 #include <rpmio_internal.h>
00012 #include <rpmlib.h>
00013 #include <rpmmacro.h>   /* XXX rpmGenPath */
00014 #include <rpmurl.h>     /* XXX urlGetPath */
00015 
00016 #include "falloc.h"
00017 #include "misc.h"
00018 
00019 #include "rpmdb.h"
00020 
00021 /* XXX must follow rpmdb.h */
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;        /* data */
00028     size_t size;        /* data length */
00029 };
00030 
00031 #undef  DBT
00032 #define DBT struct _DBT1
00033 
00034 #include "debug.h"
00035 
00036 /*@access Header@*/             /* XXX compared with NULL */
00037 /*@access rpmdb@*/
00038 /*@access dbiIndex@*/
00039 /*@access dbiIndexSet@*/
00040 /*@-onlytrans@*/
00041 
00042 #ifdef  DYING
00043 /* XXX remap DB3 types back into DB1 types */
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;         /* XXX W2DO? */
00051     case 5:     return DB_HASH;         /* XXX W2DO? */
00052     }
00053     /*@notreached@*/ return DB_HASH;
00054 }
00055 
00056 /*@-shadow@*/
00057 static /*@observer@*/ char * db_strerror(int error)
00058 /*@=shadow@*/
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          * Room for a 64-bit number + slop.  This buffer is only used
00071          * if we're given an unknown error, which should never happen.
00072          * Note, however, we're no longer thread-safe if it does.
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     /*@notreached@*/
00084 }
00085 
00086 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
00087         /*@modifies dbi, fileSystem @*/
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  /* DYING */
00110 
00111 static int db1sync(dbiIndex dbi, /*@unused@*/ unsigned int flags)
00112         /*@modifies fileSystem @*/
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 /*@null@*/ static void * doGetRecord(dbiIndex dbi, unsigned int offset)
00136         /*@modifies dbi, fileSystem @*/
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     /* let's sanity check this record a bit, otherwise just skip it */
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         /* XXX HACK: try to reconnect broken chain. */
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     /* Retrofit "Provide: name = EVR" for binary packages. */
00186     providePackageNVR(h);
00187 
00188     /*
00189      * The RPM used to build much of RH 5.1 could produce packages whose
00190      * file lists did not have leading /'s. Now is a good time to fix that.
00191      */
00192 
00193     /*
00194      * If this tag isn't present, either no files are in the package or
00195      * we're dealing with a package that has just the compressed file name
00196      * list.
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 {    /* bad header -- let's clean it up */
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      * The file list was moved to a more compressed format which not
00228      * only saves memory (nice), but gives fingerprinting a nice, fat
00229      * speed boost (very nice). Go ahead and convert old headers to
00230      * the new style (this is a noop for new headers).
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(/*@unused@*/ dbiIndex dbi,
00243                 /*@unused@*/ DBC ** dbcp, unsigned int flags)
00244         /*@modifies *dbcp @*/
00245 {
00246     /* XXX per-iterator cursors need to be set to non-NULL. */
00247     if (flags)
00248         *dbcp = (DBC *)-1;
00249     return 0;
00250 }
00251 
00252 static int db1cclose(dbiIndex dbi,
00253                 /*@unused@*/ DBC * dbcursor, /*@unused@*/ unsigned int flags)
00254         /*@modifies dbi @*/
00255 {
00256     dbi->dbi_lastoffset = 0;
00257     return 0;
00258 }
00259 
00260 /*@-compmempass@*/
00261 static int db1cget(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
00262                 /*@null@*/ void ** keyp,
00263                 /*@null@*/ size_t * keylen, 
00264                 /*@null@*/ void ** datap, 
00265                 /*@null@*/ size_t * datalen,
00266                 /*@unused@*/ unsigned int flags)
00267         /*@modifies dbi, *keyp, *keylen, *datap, *datalen, fileSystem @*/
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     /*@-unqualifiedtrans@*/
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     /*@=unqualifiedtrans@*/
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) { /* XXX simulated DB_NEXT */
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             /*@-immediatetrans@*/
00296             key.data = &dbi->dbi_lastoffset;
00297             /*@=immediatetrans@*/
00298             key.size = sizeof(dbi->dbi_lastoffset);
00299 
00300             /* Catch end-of-chain conditions. */
00301             if (dbi->dbi_lastoffset == 0)
00302                 goto bail;
00303         }
00304 
00305         memcpy(&offset, key.data, sizeof(offset));
00306         /* XXX hack to pass sizeof header to fadAlloc */
00307         newSize = data.size;
00308 
00309         if (offset == 0) {      /* XXX simulated offset 0 record */
00310             offset = fadAlloc(pkgs, newSize);
00311             if (offset == 0)
00312                 return ENOMEM;
00313             offset--;   /* XXX hack: caller will increment */
00314             /* XXX hack: return offset as data, free in db1cput */
00315             data.data = xmalloc(sizeof(offset));
00316             memcpy(data.data, &offset, sizeof(offset));
00317             data.size = sizeof(offset);
00318         } else {                /* XXX simulated retrieval */
00319             data.data = doGetRecord(dbi, offset);
00320             data.size = 0;      /* XXX WRONG */
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     /*@-nullstate@*/
00355     return rc;
00356     /*@=nullstate@*/
00357 }
00358 /*@=compmempass@*/
00359 
00360 static int db1cdel(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, const void * keyp,
00361                 size_t keylen, /*@unused@*/ unsigned int flags)
00362         /*@modifies dbi, fileSystem @*/
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, /*@unused@*/ DBC * dbcursor,
00394                 const void * keyp, size_t keylen,
00395                 const void * datap, size_t datalen,
00396                 /*@unused@*/ unsigned int flags)
00397         /*@modifies dbi, datap, fileSystem @*/
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) {      /* XXX simulated offset 0 record */
00416             /* XXX hack: return offset as data, free in db1cput */
00417             if (data.size == sizeof(offset))
00418                 /*@-unqualifiedtrans@*/ free(data.data); /*@=unqualifiedtrans@*/
00419         } else {                /* XXX simulated DB_KEYLAST */
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(/*@unused@*/ dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
00449                 /*@unused@*/ /*@out@*/ unsigned int * countp,
00450                 /*@unused@*/ unsigned int flags)
00451         /*@*/
00452 {
00453     return EINVAL;
00454 }
00455 
00456 static int db1byteswapped(/*@unused@*/dbiIndex dbi)
00457         /*@*/
00458 {
00459     return 0;
00460 }
00461 
00462 static int db1stat(/*@unused@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
00463         /*@*/
00464 {
00465     return EINVAL;
00466 }
00467 
00468 static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
00469         /*@modifies dbi, fileSystem @*/
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     /* Remove temporary databases */
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(/*@keep@*/ rpmdb rpmdb, int rpmtag,
00511         /*@out@*/ dbiIndex * dbip)
00512         /*@modifies *dbip, fileSystem @*/
00513 {
00514     /*@-nestedextern@*/
00515     extern struct _dbiVec db1vec;
00516     /*@=nestedextern@*/
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;         /* XXX check errno validity */
00547             goto exit;
00548         }
00549 
00550         /* XXX HACK: fcntl lock if db3 (DB_INIT_CDB | DB_INIT_LOCK) specified */
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;     /* XXX check errno validity */
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 /*@=onlytrans@*/
00599 
00602 /*@-exportheadervar@*/
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 /*@=exportheadervar@*/

Generated at Wed Mar 27 03:56:52 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001