Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

lib/db1.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 static int _debug = 1;  /* XXX if < 0 debugging, > 0 unusual error returns */
00008 
00009 #ifdef HAVE_DB1_DB_H
00010 #include <db1/db.h>
00011 #else
00012 #ifdef HAVE_DB_185_H
00013 #include <db_185.h> /* XXX there are too mant compat API's for this to work */
00014 #else
00015 #include <db.h>
00016 #endif
00017 #endif
00018 
00019 #define DB_VERSION_MAJOR        1
00020 #define DB_VERSION_MINOR        85
00021 #define DB_VERSION_PATCH        0
00022 
00023 #define _mymemset(_a, _b, _c)
00024 
00025 #include <rpmio_internal.h>
00026 #include <rpmlib.h>
00027 #include <rpmmacro.h>   /* XXX rpmGenPath */
00028 #include <rpmurl.h>     /* XXX urlGetPath */
00029 
00030 #include "falloc.h"
00031 #include "misc.h"
00032 
00033 #define DBC     void
00034 #include "rpmdb.h"
00035 
00036 #include "debug.h"
00037 
00038 /*@access rpmdb@*/
00039 /*@access dbiIndex@*/
00040 /*@access dbiIndexSet@*/
00041 
00042 /* XXX remap DB3 types back into DB1 types */
00043 static inline DBTYPE db3_to_dbtype(int dbitype)
00044 {
00045     switch(dbitype) {
00046     case 1:     return DB_BTREE;
00047     case 2:     return DB_HASH;
00048     case 3:     return DB_RECNO;
00049     case 4:     return DB_HASH;         /* XXX W2DO? */
00050     case 5:     return DB_HASH;         /* XXX W2DO? */
00051     }
00052     /*@notreached@*/ return DB_HASH;
00053 }
00054 
00055 static /*@observer@*/ const char * db_strerror(int error)
00056 {
00057     if (error == 0)
00058         return ("Successful return: 0");
00059     if (error > 0)
00060         return (strerror(error));
00061 
00062     switch (error) {
00063     default:
00064       {
00065         /*
00066          * !!!
00067          * Room for a 64-bit number + slop.  This buffer is only used
00068          * if we're given an unknown error, which should never happen.
00069          * Note, however, we're no longer thread-safe if it does.
00070          */
00071         static char ebuf[40];
00072 
00073         (void)snprintf(ebuf, sizeof(ebuf), "Unknown error: %d", error);
00074         return(ebuf);
00075       }
00076     }
00077     /*@notreached@*/
00078 }
00079 
00080 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit) {
00081     int rc = 0;
00082 
00083     if (error == 0)
00084         rc = 0;
00085     else if (error < 0)
00086         rc = errno;
00087     else if (error > 0)
00088         rc = -1;
00089 
00090     if (printit && rc) {
00091         if (msg)
00092             rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
00093                 dbi->dbi_api, rc, msg, db_strerror(error));
00094         else
00095             rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
00096                 dbi->dbi_api, rc, db_strerror(error));
00097     }
00098 
00099     return rc;
00100 }
00101 
00102 static int db1sync(dbiIndex dbi, unsigned int flags) {
00103     int rc = 0;
00104 
00105     if (dbi->dbi_db) {
00106         if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00107             FD_t pkgs = dbi->dbi_db;
00108             int fdno = Fileno(pkgs);
00109             if (fdno >= 0 && (rc = fsync(fdno)) != 0)
00110                 rc = errno;
00111         } else {
00112             DB * db = dbi->dbi_db;
00113             rc = db->sync(db, flags);
00114             rc = cvtdberr(dbi, "db->sync", rc, _debug);
00115         }
00116     }
00117 
00118     return rc;
00119 }
00120 
00121 static int db1byteswapped(/*@unused@*/dbiIndex dbi)
00122 {
00123     return 0;
00124 }
00125 
00126 static void * doGetRecord(FD_t pkgs, unsigned int offset)
00127 {
00128     void * uh = NULL;
00129     Header h = NULL;
00130     const char ** fileNames;
00131     int fileCount = 0;
00132     int i;
00133 
00134     if (offset >= fadGetFileSize(pkgs))
00135         goto exit;
00136 
00137     (void)Fseek(pkgs, offset, SEEK_SET);
00138 
00139     h = headerRead(pkgs, HEADER_MAGIC_NO);
00140 
00141     if (h == NULL)
00142         goto exit;
00143 
00144     /* Retrofit "Provide: name = EVR" for binary packages. */
00145     providePackageNVR(h);
00146 
00147     /*
00148      * The RPM used to build much of RH 5.1 could produce packages whose
00149      * file lists did not have leading /'s. Now is a good time to fix that.
00150      */
00151 
00152     /*
00153      * If this tag isn't present, either no files are in the package or
00154      * we're dealing with a package that has just the compressed file name
00155      * list.
00156      */
00157     if (!headerGetEntryMinMemory(h, RPMTAG_OLDFILENAMES, NULL, 
00158                            (const void **) &fileNames, &fileCount)) goto exit;
00159 
00160     for (i = 0; i < fileCount; i++) 
00161         if (*fileNames[i] != '/') break;
00162 
00163     if (i == fileCount) {
00164         free(fileNames);
00165     } else {    /* bad header -- let's clean it up */
00166         const char ** newFileNames = alloca(sizeof(*newFileNames) * fileCount);
00167         for (i = 0; i < fileCount; i++) {
00168             char * newFileName = alloca(strlen(fileNames[i]) + 2);
00169             if (*fileNames[i] != '/') {
00170                 newFileName[0] = '/';
00171                 newFileName[1] = '\0';
00172             } else
00173                 newFileName[0] = '\0';
00174             strcat(newFileName, fileNames[i]);
00175             newFileNames[i] = newFileName;
00176         }
00177 
00178         free(fileNames);
00179 
00180         headerModifyEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE, 
00181                           newFileNames, fileCount);
00182     }
00183 
00184     /*
00185      * The file list was moved to a more compressed format which not
00186      * only saves memory (nice), but gives fingerprinting a nice, fat
00187      * speed boost (very nice). Go ahead and convert old headers to
00188      * the new style (this is a noop for new headers).
00189      */
00190     compressFilelist(h);
00191 
00192 exit:
00193     if (h) {
00194         uh = headerUnload(h);
00195         headerFree(h);
00196     }
00197     return uh;
00198 }
00199 
00200 static int db1copen(/*@unused@*/ dbiIndex dbi, /*@unused@*/ DBC ** dbcp, unsigned int flags) {
00201     /* XXX per-iterator cursors need to be set to non-NULL. */
00202     if (flags)
00203         *dbcp = (DBC *)-1;
00204     return 0;
00205 }
00206 
00207 static int db1cclose(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, /*@unused@*/ unsigned int flags) {
00208     dbi->dbi_lastoffset = 0;
00209     return 0;
00210 }
00211 
00212 static int db1cget(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, void ** keyp,
00213                 size_t * keylen, void ** datap, size_t * datalen,
00214                 /*@unused@*/ unsigned int flags)
00215 {
00216     DBT key, data;
00217     int rc = 0;
00218 
00219     if (dbi == NULL)
00220         return EFAULT;
00221 
00222     memset(&key, 0, sizeof(key));
00223     memset(&data, 0, sizeof(data));
00224     if (keyp)           key.data = *keyp;
00225     if (keylen)         key.size = *keylen;
00226     if (datap)          data.data = *datap;
00227     if (datalen)        data.size = *datalen;
00228 
00229     if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00230         FD_t pkgs = dbi->dbi_db;
00231         unsigned int offset;
00232         unsigned int newSize;
00233 
00234         if (key.data == NULL) { /* XXX simulated DB_NEXT */
00235             if (dbi->dbi_lastoffset == 0) {
00236                 dbi->dbi_lastoffset = fadFirstOffset(pkgs);
00237             } else {
00238                 dbi->dbi_lastoffset = fadNextOffset(pkgs, dbi->dbi_lastoffset);
00239             }
00240             key.data = &dbi->dbi_lastoffset;
00241             key.size = sizeof(dbi->dbi_lastoffset);
00242         }
00243 
00244         memcpy(&offset, key.data, sizeof(offset));
00245         /* XXX hack to pass sizeof header to fadAlloc */
00246         newSize = data.size;
00247 
00248         if (offset == 0) {      /* XXX simulated offset 0 record */
00249             offset = fadAlloc(pkgs, newSize);
00250             if (offset == 0)
00251                 return ENOMEM;
00252             offset--;   /* XXX hack: caller will increment */
00253             /* XXX hack: return offset as data, free in db1cput */
00254             data.data = xmalloc(sizeof(offset));
00255             memcpy(data.data, &offset, sizeof(offset));
00256             data.size = sizeof(offset);
00257         } else {                /* XXX simulated retrieval */
00258             data.data = doGetRecord(pkgs, offset);
00259             data.size = 0;      /* XXX WRONG */
00260             if (data.data == NULL)
00261                 rc = EFAULT;
00262         }
00263     } else {
00264         DB * db;
00265         int _printit;
00266 
00267         if ((db = dbi->dbi_db) == NULL)
00268             return EFAULT;
00269 
00270         if (key.data == NULL) {
00271             rc = db->seq(db, &key, &data, (dbi->dbi_lastoffset++ ? R_NEXT : R_FIRST));
00272             _printit = (rc == 1 ? 0 : _debug);
00273             rc = cvtdberr(dbi, "db->seq", rc, _printit);
00274         } else {
00275             rc = db->get(db, &key, &data, 0);
00276             _printit = (rc == 1 ? 0 : _debug);
00277             rc = cvtdberr(dbi, "db1cget", rc, _printit);
00278         }
00279     }
00280 
00281     if (rc == 0) {
00282         if (keyp)       *keyp = key.data;
00283         if (keylen)     *keylen = key.size;
00284         if (datap)      *datap = data.data;
00285         if (datalen)    *datalen = data.size;
00286     }
00287 
00288     return rc;
00289 }
00290 
00291 static int db1cdel(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, const void * keyp,
00292                 size_t keylen, /*@unused@*/ unsigned int flags)
00293 {
00294     int rc = 0;
00295 
00296     if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00297         FD_t pkgs = dbi->dbi_db;
00298         unsigned int offset;
00299         memcpy(&offset, keyp, sizeof(offset));
00300         fadFree(pkgs, offset);
00301     } else {
00302         DBT key;
00303         DB * db = dbi->dbi_db;
00304 
00305         _mymemset(&key, 0, sizeof(key));
00306 
00307         key.data = (void *)keyp;
00308         key.size = keylen;
00309 
00310         rc = db->del(db, &key, 0);
00311         rc = cvtdberr(dbi, "db->del", rc, _debug);
00312     }
00313 
00314     return rc;
00315 }
00316 
00317 static int db1cput(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
00318                 const void * keyp, size_t keylen,
00319                 const void * datap, size_t datalen,
00320                 /*@unused@*/ unsigned int flags)
00321 {
00322     DBT key, data;
00323     int rc = 0;
00324 
00325     memset(&key, 0, sizeof(key));
00326     memset(&data, 0, sizeof(data));
00327     key.data = (void *)keyp;
00328     key.size = keylen;
00329     data.data = (void *)datap;
00330     data.size = datalen;
00331 
00332     if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00333         FD_t pkgs = dbi->dbi_db;
00334         unsigned int offset;
00335 
00336         memcpy(&offset, key.data, sizeof(offset));
00337 
00338         if (offset == 0) {      /* XXX simulated offset 0 record */
00339             /* XXX hack: return offset as data, free in db1cput */
00340             if (data.size == sizeof(offset)) {
00341                 free(data.data);
00342             }
00343         } else {                /* XXX simulated DB_KEYLAST */
00344             Header h = headerLoad(data.data);
00345             int newSize = headerSizeof(h, HEADER_MAGIC_NO);
00346 
00347             (void)Fseek(pkgs, offset, SEEK_SET);
00348             fdSetContentLength(pkgs, newSize);
00349             rc = headerWrite(pkgs, h, HEADER_MAGIC_NO);
00350             fdSetContentLength(pkgs, -1);
00351             if (rc)
00352                 rc = EIO;
00353             headerFree(h);
00354         }
00355     } else {
00356         DB * db = dbi->dbi_db;
00357 
00358         rc = db->put(db, &key, &data, 0);
00359         rc = cvtdberr(dbi, "db->put", rc, _debug);
00360     }
00361 
00362     return rc;
00363 }
00364 
00365 static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
00366 {
00367     rpmdb rpmdb = dbi->dbi_rpmdb;
00368     const char * base = db1basename(dbi->dbi_rpmtag);
00369     const char * urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
00370     const char * fn;
00371     int rc = 0;
00372 
00373     (void) urlPath(urlfn, &fn);
00374 
00375     if (dbi->dbi_db) {
00376         if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00377             FD_t pkgs = dbi->dbi_db;
00378             rc = Fclose(pkgs);
00379         } else {
00380             DB * db = dbi->dbi_db;
00381             rc = db->close(db);
00382             rc = cvtdberr(dbi, "db->close", rc, _debug);
00383         }
00384         dbi->dbi_db = NULL;
00385     }
00386 
00387     rpmMessage(RPMMESS_DEBUG, _("closed  db file        %s\n"), urlfn);
00388     /* Remove temporary databases */
00389     if (dbi->dbi_temporary) {
00390         rpmMessage(RPMMESS_DEBUG, _("removed db file        %s\n"), urlfn);
00391         (void) unlink(fn);
00392     }
00393 
00394     db3Free(dbi);
00395     if (base)
00396         free((void *)base);
00397     if (urlfn)
00398         free((void *)urlfn);
00399     return rc;
00400 }
00401 
00402 static int db1open(rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
00403 {
00404     const char * base = NULL;
00405     const char * urlfn = NULL;
00406     const char * fn = NULL;
00407     dbiIndex dbi = NULL;
00408     extern struct _dbiVec db1vec;
00409     int rc = 0;
00410 
00411     if (dbip)
00412         *dbip = NULL;
00413     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
00414         return EFAULT;
00415     dbi->dbi_api = DB_VERSION_MAJOR;
00416 
00417     base = db1basename(rpmtag);
00418     urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
00419     (void) urlPath(urlfn, &fn);
00420     if (!(fn && *fn != '\0')) {
00421         rpmError(RPMERR_DBOPEN, _("bad db file %s\n"), urlfn);
00422         rc = EFAULT;
00423         goto exit;
00424     }
00425 
00426     rpmMessage(RPMMESS_DEBUG, _("opening db file        %s mode 0x%x\n"),
00427                 urlfn, dbi->dbi_mode);
00428 
00429     if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
00430         FD_t pkgs;
00431 
00432         pkgs = fadOpen(fn, dbi->dbi_mode, dbi->dbi_perms);
00433         if (Ferror(pkgs)) {
00434             rc = errno;         /* XXX check errno validity */
00435             goto exit;
00436         }
00437 
00438         /* XXX HACK: fcntl lock if db3 (DB_INIT_CDB | DB_INIT_LOCK) specified */
00439         if (dbi->dbi_lockdbfd || (dbi->dbi_eflags & 0x30)) {
00440             struct flock l;
00441 
00442             l.l_whence = 0;
00443             l.l_start = 0;
00444             l.l_len = 0;
00445             l.l_type = (dbi->dbi_mode & O_RDWR) ? F_WRLCK : F_RDLCK;
00446 
00447             if (Fcntl(pkgs, F_SETLK, (void *) &l)) {
00448                 rc = errno;     /* XXX check errno validity */
00449                 rpmError(RPMERR_FLOCK, _("cannot get %s lock on database\n"),
00450                     ((dbi->dbi_mode & O_RDWR) ? _("exclusive") : _("shared")));
00451                 goto exit;
00452             }
00453         }
00454 
00455         dbi->dbi_db = pkgs;
00456     } else {
00457         void * dbopeninfo = NULL;
00458         int dbimode = dbi->dbi_mode;
00459 
00460         if (dbi->dbi_temporary)
00461             dbimode |= (O_CREAT | O_RDWR);
00462 
00463         dbi->dbi_db = dbopen(fn, dbimode, dbi->dbi_perms,
00464                 db3_to_dbtype(dbi->dbi_type), dbopeninfo);
00465         if (dbi->dbi_db == NULL) rc = errno;
00466     }
00467 
00468 exit:
00469     if (rc == 0 && dbi->dbi_db != NULL && dbip) {
00470         dbi->dbi_vec = &db1vec;
00471         *dbip = dbi;
00472     } else
00473         db1close(dbi, 0);
00474 
00475     if (base) {
00476         free((void *)base);
00477         base = NULL;
00478     }
00479     if (urlfn) {
00480         free((void *)urlfn);
00481         urlfn = NULL;
00482     }
00483 
00484     return rc;
00485 }
00486 
00489 struct _dbiVec db1vec = {
00490     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
00491     db1open, db1close, db1sync, db1copen, db1cclose, db1cdel, db1cget, db1cput,
00492     db1byteswapped
00493 };

Generated at Mon May 21 08:53:39 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001