libzypp  10.5.0
librpmDb.cv3.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #if 0
00013 #include "librpm.h"
00014 extern "C"
00015 {
00016 #ifdef _RPM_5
00017 typedef rpmuint32_t rpm_count_t;
00018 #define HGEPtr_t void *
00019 #define headerGetEntryMinMemory headerGetEntry
00020 #define headerNVR(h,n,v,r) headerNEVRA(h,n,NULL,v,r,NULL)
00021 #else
00022 #ifdef _RPM_4_4
00023 typedef int32_t rpm_count_t;
00024 #define HGEPtr_t const void *
00025 #endif
00026 #endif
00027 }
00028 
00029 #include <iostream>
00030 
00031 #include "zypp/base/Logger.h"
00032 
00033 #include "zypp/target/rpm/librpmDb.h"
00034 #include "zypp/target/rpm/RpmCallbacks.h"
00035 #include "zypp/ZYppCallbacks.h"
00036 
00037 #define xmalloc malloc
00038 #define xstrdup strdup
00039 
00040 extern "C"
00041 {
00042 #include <string.h>
00043 
00044 #define FA_MAGIC      0x02050920
00045 
00046   struct faFileHeader
00047   {
00048     unsigned int magic;
00049     unsigned int firstFree;
00050   };
00051 
00052   struct faHeader
00053   {
00054     unsigned int size;
00055     unsigned int freeNext; /* offset of the next free block, 0 if none */
00056     unsigned int freePrev;
00057     unsigned int isFree;
00058 
00059     /* note that the u16's appear last for alignment/space reasons */
00060   };
00061 }
00062 
00063 namespace zypp
00064 {
00065 namespace target
00066 {
00067 namespace rpm
00068 {
00069 static int fadFileSize;
00070 
00071 static ssize_t Pread(FD_t fd, void * buf, size_t count, off_t offset)
00072 {
00073   if (Fseek(fd, offset, SEEK_SET) < 0)
00074     return -1;
00075   return Fread(buf, sizeof(char), count, fd);
00076 }
00077 
00078 static FD_t fadOpen(const char * path)
00079 {
00080   struct faFileHeader newHdr;
00081   FD_t fd;
00082   struct stat stb;
00083 
00084   fd = Fopen(path, "r.fdio");
00085   if (!fd || Ferror(fd))
00086     return NULL;
00087 
00088   if (fstat(Fileno(fd), &stb))
00089   {
00090     Fclose(fd);
00091     return NULL;
00092   }
00093   fadFileSize = stb.st_size;
00094 
00095   /* is this file brand new? */
00096   if (fadFileSize == 0)
00097   {
00098     Fclose(fd);
00099     return NULL;
00100   }
00101   if (Pread(fd, &newHdr, sizeof(newHdr), 0) != sizeof(newHdr))
00102   {
00103     Fclose(fd);
00104     return NULL;
00105   }
00106   if (newHdr.magic != FA_MAGIC)
00107   {
00108     Fclose(fd);
00109     return NULL;
00110   }
00111   /*@-refcounttrans@*/ return fd /*@=refcounttrans@*/ ;
00112 }
00113 
00114 static int fadNextOffset(FD_t fd, unsigned int lastOffset)
00115 {
00116   struct faHeader header;
00117   int offset;
00118 
00119   offset = (lastOffset)
00120            ? (lastOffset - sizeof(header))
00121            : sizeof(struct faFileHeader);
00122 
00123   if (offset >= fadFileSize)
00124     return 0;
00125 
00126   if (Pread(fd, &header, sizeof(header), offset) != sizeof(header))
00127     return 0;
00128 
00129   if (!lastOffset && !header.isFree)
00130     return (offset + sizeof(header));
00131 
00132   do
00133   {
00134     offset += header.size;
00135 
00136     if (Pread(fd, &header, sizeof(header), offset) != sizeof(header))
00137       return 0;
00138 
00139     if (!header.isFree) break;
00140   }
00141   while (offset < fadFileSize && header.isFree);
00142 
00143   if (offset < fadFileSize)
00144   {
00145     /* Sanity check this to make sure we're not going in loops */
00146     offset += sizeof(header);
00147 
00148     if (offset < 0 || (unsigned)offset <= lastOffset) return -1;
00149 
00150     return offset;
00151   }
00152   else
00153     return 0;
00154 }
00155 
00156 static int fadFirstOffset(FD_t fd)
00157 {
00158   return fadNextOffset(fd, 0);
00159 }
00160 
00161 /*@-boundsread@*/
00162 static int dncmp(const void * a, const void * b)
00163 /*@*/
00164 {
00165   const char *const * first = (const char *const *)a;
00166   const char *const * second = (const char *const *)b;
00167   return strcmp(*first, *second);
00168 }
00169 /*@=boundsread@*/
00170 
00171 /*@-bounds@*/
00172 #ifndef _RPM_4_X
00173 static void compressFilelist(Header h)
00174 /*@*/
00175 {
00176   char ** fileNames;
00177   const char ** dirNames;
00178   const char ** baseNames;
00179   int_32 * dirIndexes;
00180   rpmTagType fnt;
00181   rpm_count_t count;
00182   int xx;
00183   int dirIndex = -1;
00184 
00185   /*
00186    * This assumes the file list is already sorted, and begins with a
00187    * single '/'. That assumption isn't critical, but it makes things go
00188    * a bit faster.
00189    */
00190 
00191   if (headerIsEntry(h, RPMTAG_DIRNAMES))
00192   {
00193     xx = headerRemoveEntry(h, RPMTAG_OLDFILENAMES);
00194     return;             /* Already converted. */
00195   }
00196 
00197   HGEPtr_t hgePtr = NULL;
00198   if (!headerGetEntryMinMemory(h, RPMTAG_OLDFILENAMES, hTYP_t(&fnt), &hgePtr, &count))
00199     return;             /* no file list */
00200   fileNames = (char **)hgePtr;
00201   if (fileNames == NULL || count <= 0)
00202     return;
00203 
00204   dirNames = (const char **)alloca(sizeof(*dirNames) * count);  /* worst case */
00205   baseNames = (const char **)alloca(sizeof(*dirNames) * count);
00206   dirIndexes = (int_32 *)alloca(sizeof(*dirIndexes) * count);
00207 
00208   if (fileNames[0][0] != '/')
00209   {
00210     /* HACK. Source RPM, so just do things differently */
00211     dirIndex = 0;
00212     dirNames[dirIndex] = "";
00213     for (rpm_count_t i = 0; i < count; i++)
00214     {
00215       dirIndexes[i] = dirIndex;
00216       baseNames[i] = fileNames[i];
00217     }
00218     goto exit;
00219   }
00220 
00221   /*@-branchstate@*/
00222   for (rpm_count_t i = 0; i < count; i++)
00223   {
00224     const char ** needle;
00225     char savechar;
00226     char * baseName;
00227     int len;
00228 
00229     if (fileNames[i] == NULL)   /* XXX can't happen */
00230       continue;
00231     baseName = strrchr(fileNames[i], '/') + 1;
00232     len = baseName - fileNames[i];
00233     needle = dirNames;
00234     savechar = *baseName;
00235     *baseName = '\0';
00236     /*@-compdef@*/
00237     if (dirIndex < 0 ||
00238         (needle = (const char **)bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL)
00239     {
00240       char *s = (char *)alloca(len + 1);
00241       memcpy(s, fileNames[i], len + 1);
00242       s[len] = '\0';
00243       dirIndexes[i] = ++dirIndex;
00244       dirNames[dirIndex] = s;
00245     }
00246     else
00247       dirIndexes[i] = needle - dirNames;
00248     /*@=compdef@*/
00249 
00250     *baseName = savechar;
00251     baseNames[i] = baseName;
00252   }
00253   /*@=branchstate@*/
00254 
00255 exit:
00256   if (count > 0)
00257   {
00258     xx = headerAddEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
00259     xx = headerAddEntry(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00260              baseNames, count);
00261     xx = headerAddEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00262              dirNames, dirIndex + 1);
00263   }
00264 
00265   fileNames = (char**)headerFreeData(fileNames, fnt);
00266 
00267   xx = headerRemoveEntry(h, RPMTAG_OLDFILENAMES);
00268 }
00269 /*@=bounds@*/
00270 
00271 /*
00272  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
00273  * Retrofit an explicit "Provides: name = epoch:version-release".
00274  */
00275 void providePackageNVR(Header h)
00276 {
00277   const char *name, *version, *release;
00278   HGEPtr_t hgePtr = NULL;
00279   int_32 * epoch;
00280   const char *pEVR;
00281   char *p;
00282   int_32 pFlags = RPMSENSE_EQUAL;
00283   const char ** provides = NULL;
00284   const char ** providesEVR = NULL;
00285   rpmTagType pnt, pvt;
00286   int_32 * provideFlags = NULL;
00287   rpm_count_t providesCount;
00288   int xx;
00289   int bingo = 1;
00290 
00291   /* Generate provides for this package name-version-release. */
00292   xx = headerNVR(h, &name, &version, &release);
00293   if (!(name && version && release))
00294     return;
00295   pEVR = p = (char *)alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00296   *p = '\0';
00297   if (headerGetEntryMinMemory(h, RPMTAG_EPOCH, NULL, &hgePtr, NULL))
00298   {
00299     epoch = (int_32 *)hgePtr;
00300     sprintf(p, "%d:", *epoch);
00301     while (*p != '\0')
00302       p++;
00303   }
00304   (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00305 
00306   /*
00307    * Rpm prior to 3.0.3 does not have versioned provides.
00308    * If no provides at all are available, we can just add.
00309    */
00310   if (!headerGetEntryMinMemory(h, RPMTAG_PROVIDENAME, hTYP_t(&pnt), &hgePtr, &providesCount))
00311     goto exit;
00312   provides = (const char **)hgePtr;
00313 
00314   /*
00315    * Otherwise, fill in entries on legacy packages.
00316    */
00317   if (!headerGetEntryMinMemory(h, RPMTAG_PROVIDEVERSION, hTYP_t(&pvt), &hgePtr, NULL))
00318   {
00319     providesEVR = (const char **)hgePtr;
00320     for (rpm_count_t i = 0; i < providesCount; i++)
00321     {
00322       const char * vdummy = "";
00323       int_32 fdummy = RPMSENSE_ANY;
00324       xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00325                                   &vdummy, 1);
00326       xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00327                                   &fdummy, 1);
00328     }
00329     goto exit;
00330   }
00331 
00332   xx = headerGetEntryMinMemory(h, RPMTAG_PROVIDEFLAGS, NULL, &hgePtr, NULL);
00333   provideFlags = (int_32 *)hgePtr;
00334 
00335   /*@-nullderef@*/    /* LCL: providesEVR is not NULL */
00336   if (provides && providesEVR && provideFlags)
00337     for (rpm_count_t i = 0; i < providesCount; i++)
00338     {
00339       if (!(provides[i] && providesEVR[i]))
00340         continue;
00341       if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00342             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00343         continue;
00344       bingo = 0;
00345       break;
00346     }
00347   /*@=nullderef@*/
00348 
00349 exit:
00350   provides = (const char **)headerFreeData(provides, pnt);
00351   providesEVR = (const char **)headerFreeData(providesEVR, pvt);
00352 
00353   if (bingo)
00354   {
00355     xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00356                                 &name, 1);
00357     xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00358                                 &pFlags, 1);
00359     xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00360                                 &pEVR, 1);
00361   }
00362 }
00363 #else
00364 static void compressFilelist(Header h)
00365 {
00366     struct rpmtd_s fileNames;
00367     char ** dirNames;
00368     const char ** baseNames;
00369     uint32_t * dirIndexes;
00370     rpm_count_t count;
00371     int xx, i;
00372     int dirIndex = -1;
00373 
00374     /*
00375      * This assumes the file list is already sorted, and begins with a
00376      * single '/'. That assumption isn't critical, but it makes things go
00377      * a bit faster.
00378      */
00379 
00380     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00381         xx = headerDel(h, RPMTAG_OLDFILENAMES);
00382         return;         /* Already converted. */
00383     }
00384 
00385     if (!headerGet(h, RPMTAG_OLDFILENAMES, &fileNames, HEADERGET_MINMEM))
00386         return;
00387     count = rpmtdCount(&fileNames);
00388     if (count < 1)
00389         return;
00390 
00391     dirNames = (char**)malloc(sizeof(*dirNames) * count);      /* worst case */
00392     baseNames = (const char**)malloc(sizeof(*dirNames) * count);
00393     dirIndexes = (uint32_t*)malloc(sizeof(*dirIndexes) * count);
00394 
00395     /* HACK. Source RPM, so just do things differently */
00396     {   const char *fn = rpmtdGetString(&fileNames);
00397         if (fn && *fn != '/') {
00398             dirIndex = 0;
00399             dirNames[dirIndex] = xstrdup("");
00400             while ((i = rpmtdNext(&fileNames)) >= 0) {
00401                 dirIndexes[i] = dirIndex;
00402                 baseNames[i] = rpmtdGetString(&fileNames);
00403             }
00404             goto exit;
00405         }
00406     }
00407 
00408     while ((i = rpmtdNext(&fileNames)) >= 0) {
00409         char ** needle;
00410         char savechar;
00411         char * baseName;
00412         size_t len;
00413         const char *filename = rpmtdGetString(&fileNames);
00414 
00415         if (filename == NULL)   /* XXX can't happen */
00416             continue;
00417         baseName = strrchr((char*)filename, '/') + 1;
00418         len = baseName - filename;
00419         needle = dirNames;
00420         savechar = *baseName;
00421         *baseName = '\0';
00422         if (dirIndex < 0 ||
00423             (needle = (char**)bsearch(&filename, dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00424             char *s = (char*)malloc(len + 1);
00425             rstrlcpy(s, filename, len + 1);
00426             dirIndexes[i] = ++dirIndex;
00427             dirNames[dirIndex] = s;
00428         } else
00429             dirIndexes[i] = needle - dirNames;
00430 
00431         *baseName = savechar;
00432         baseNames[i] = baseName;
00433     }
00434 
00435 exit:
00436     if (count > 0) {
00437         headerPutUint32(h, RPMTAG_DIRINDEXES, dirIndexes, count);
00438         headerPutStringArray(h, RPMTAG_BASENAMES, baseNames, count);
00439         headerPutStringArray(h, RPMTAG_DIRNAMES,
00440                              (const char **) dirNames, dirIndex + 1);
00441     }
00442 
00443     rpmtdFreeData(&fileNames);
00444     for (i = 0; i <= dirIndex; i++) {
00445         free(dirNames[i]);
00446     }
00447     free(dirNames);
00448     free(baseNames);
00449     free(dirIndexes);
00450 
00451     xx = headerDel(h, RPMTAG_OLDFILENAMES);
00452 }
00453 
00454 /*
00455  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
00456  * Retrofit an explicit "Provides: name = epoch:version-release.
00457  */
00458 static void providePackageNVR(Header h)
00459 {
00460     const char *name;
00461     char *pEVR;
00462     rpmsenseFlags pFlags = RPMSENSE_EQUAL;
00463     int bingo = 1;
00464     struct rpmtd_s pnames;
00465     rpmds hds, nvrds;
00466 
00467     /* Generate provides for this package name-version-release. */
00468     pEVR = headerGetEVR(h, &name);
00469     if (!(name && pEVR))
00470         return;
00471 
00472     /*
00473      * Rpm prior to 3.0.3 does not have versioned provides.
00474      * If no provides at all are available, we can just add.
00475      */
00476     if (!headerGet(h, RPMTAG_PROVIDENAME, &pnames, HEADERGET_MINMEM)) {
00477         goto exit;
00478     }
00479 
00480     /*
00481      * Otherwise, fill in entries on legacy packages.
00482      */
00483     if (!headerIsEntry(h, RPMTAG_PROVIDEVERSION)) {
00484         while (rpmtdNext(&pnames) >= 0) {
00485             uint32_t fdummy = RPMSENSE_ANY;
00486 
00487             headerPutString(h, RPMTAG_PROVIDEVERSION, "");
00488             headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
00489         }
00490         goto exit;
00491     }
00492 
00493     /* see if we already have this provide */
00494     hds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
00495     nvrds = rpmdsSingle(RPMTAG_PROVIDENAME, name, pEVR, pFlags);
00496     if (rpmdsFind(hds, nvrds) >= 0) {
00497         bingo = 0;
00498     }
00499     rpmdsFree(hds);
00500     rpmdsFree(nvrds);
00501 
00502 exit:
00503     if (bingo) {
00504         const char *evr = pEVR;
00505         uint32_t fdummy = pFlags;
00506         headerPutString(h, RPMTAG_PROVIDENAME, name);
00507         headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
00508         headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &fdummy, 1);
00509     }
00510     rpmtdFreeData(&pnames);
00511     free(pEVR);
00512 }
00513 
00514 #endif
00515 
00519 
00520 using namespace std;
00521 
00522 #undef Y2LOG
00523 #define Y2LOG "librpmDb"
00524 
00525 /******************************************************************
00526 **
00527 **
00528 **      FUNCTION NAME : internal_convertV3toV4
00529 **      FUNCTION TYPE : int
00530 */
00531 void internal_convertV3toV4( const Pathname & v3db_r, const librpmDb::constPtr & v4db_r,
00532                              callback::SendReport<ConvertDBReport> & report )
00533 {
00534 //  Timecount _t( "convert V3 to V4" );
00535   MIL << "Convert rpm3 database to rpm4" << endl;
00536 
00537   // Check arguments
00538   FD_t fd = fadOpen( v3db_r.asString().c_str() );
00539   if ( fd == 0 )
00540   {
00541     Fclose( fd );
00542     ZYPP_THROW(RpmDbOpenException(Pathname("/"), v3db_r));
00543   }
00544 
00545   if ( ! v4db_r )
00546   {
00547     Fclose( fd );
00548     INT << "NULL rpmV4 database passed as argument!" << endl;
00549     ZYPP_THROW(RpmNullDatabaseException());
00550   }
00551 
00552   shared_ptr<RpmException> err = v4db_r->error();
00553   if ( err )
00554   {
00555     Fclose( fd );
00556     INT << "Can't access rpmV4 database " << v4db_r << endl;
00557     ZYPP_THROW(*err);
00558   }
00559 
00560   // open rpmV4 database for writing. v4db_r is ok so librpm should
00561   // be properly initialized.
00562   rpmdb db = 0;
00563   string rootstr( v4db_r->root().asString() );
00564   const char * root = ( rootstr == "/" ? NULL : rootstr.c_str() );
00565 
00566   int res = ::rpmdbOpen( root, &db, O_RDWR, 0644 );
00567   if ( res || ! db )
00568   {
00569     if ( db )
00570     {
00571       ::rpmdbClose( db );
00572     }
00573     Fclose( fd );
00574     ZYPP_THROW(RpmDbOpenException(root, v4db_r->dbPath()));
00575   }
00576 
00577   // Check ammount of packages to process.
00578   int max = 0;
00579   for ( int offset = fadFirstOffset(fd); offset; offset = fadNextOffset(fd, offset) )
00580   {
00581     ++max;
00582   }
00583   MIL << "Packages in rpmV3 database " << v3db_r << ": " << max << endl;
00584 
00585   unsigned failed      = 0;
00586   unsigned ignored     = 0;
00587   unsigned alreadyInV4 = 0;
00588   report->progress( (100 * (failed + ignored + alreadyInV4) / max), v3db_r );
00589 
00590   if ( !max )
00591   {
00592     Fclose( fd );
00593     ::rpmdbClose( db );
00594     return;
00595   }
00596 
00597   // Start conversion.
00598 #warning Add CBSuggest handling if needed, also on lines below
00599 //  CBSuggest proceed;
00600   bool proceed = true;
00601   for ( int offset = fadFirstOffset(fd); offset && proceed ;
00602         offset = fadNextOffset(fd, offset),
00603         report->progress( (100 * (failed + ignored + alreadyInV4) / max), v3db_r ) )
00604   {
00605 
00606     // have to use lseek instead of Fseek because headerRead
00607     // uses low level IO
00608     if ( lseek( Fileno( fd ), (off_t)offset, SEEK_SET ) == -1 )
00609     {
00610       ostream * reportAs = &(ERR);
00611       /*      proceed = report->dbReadError( offset );
00612             if ( proceed == CBSuggest::SKIP ) {
00613         // ignore this error
00614         ++ignored;
00615         reportAs = &(WAR << "IGNORED: ");
00616             } else {*/
00617       // PROCEED will fail after conversion; CANCEL immediately stop loop
00618       ++failed;
00619 //      }
00620       (*reportAs) << "rpmV3 database entry: Can't seek to offset " << offset << " (errno " << errno << ")" << endl;
00621       continue;
00622     }
00623     Header h = headerRead(fd, HEADER_MAGIC_NO);
00624     if ( ! h )
00625     {
00626       ostream * reportAs = &(ERR);
00627       /*      proceed = report->dbReadError( offset );
00628             if ( proceed == CBSuggest::SKIP ) {
00629         // ignore this error
00630         ++ignored;
00631         reportAs = &(WAR << "IGNORED: ");
00632             } else {*/
00633       // PROCEED will fail after conversion; CANCEL immediately stop loop
00634       ++failed;
00635 //      }
00636       (*reportAs) << "rpmV3 database entry: No header at offset " << offset << endl;
00637       continue;
00638     }
00639     compressFilelist(h);
00640     providePackageNVR(h);
00641     const char *name = 0;
00642     const char *version = 0;
00643     const char *release = 0;
00644     headerNVR(h, &name, &version, &release);
00645     string nrv( string(name) + "-" +  version + "-" + release );
00646     rpmdbMatchIterator mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00647     rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version);
00648     rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release);
00649     if (rpmdbNextIterator(mi))
00650     {
00651 //      report.dbInV4( nrv );
00652       WAR << "SKIP: rpmV3 database entry: " << nrv << " is already in rpmV4 database" << endl;
00653       rpmdbFreeIterator(mi);
00654       headerFree(h);
00655       ++alreadyInV4;
00656       continue;
00657     }
00658     rpmdbFreeIterator(mi);
00659 #ifdef _RPM_5
00660     if (rpmdbAdd(db, -1, h, 0))
00661 #else
00662     if (rpmdbAdd(db, -1, h, 0, 0))
00663 #endif
00664     {
00665 //      report.dbWriteError( nrv );
00666       proceed = false;//CBSuggest::CANCEL; // immediately stop loop
00667       ++failed;
00668       ERR << "rpmV4 database error: could not add " << nrv << " to rpmV4 database" << endl;
00669       headerFree(h);
00670       continue;
00671     }
00672     headerFree(h);
00673   }
00674 
00675   Fclose(fd);
00676   ::rpmdbClose(db);
00677 
00678   if ( failed )
00679   {
00680     ERR << "Convert rpm3 database to rpm4: Aborted after "
00681     << alreadyInV4 << " package(s) and " << (failed+ignored) << " error(s)."
00682     << endl;
00683     ZYPP_THROW(RpmDbConvertException());
00684   }
00685   else
00686   {
00687     MIL << "Convert rpm3 database to rpm4: " << max << " package(s) processed";
00688     if ( alreadyInV4 )
00689     {
00690       MIL << "; " << alreadyInV4 << " already present in rpmV4 database";
00691     }
00692     if ( ignored )
00693     {
00694       MIL << "; IGNORED: " << ignored << " unconverted due to error";
00695     }
00696     MIL << endl;
00697   }
00698 }
00699 #endif
00700 
00701 #include <iostream>
00702 
00703 #include "zypp/base/Logger.h"
00704 
00705 #include "zypp/target/rpm/librpmDb.h"
00706 #include "zypp/target/rpm/RpmCallbacks.h"
00707 #include "zypp/ZYppCallbacks.h"
00708 
00709 using namespace std;
00710 
00711 #undef Y2LOG
00712 #define Y2LOG "librpmDb"
00713 
00714 namespace zypp
00715 {
00716 namespace target
00717 {
00718 namespace rpm
00719 {
00720 /******************************************************************
00721 *
00722 *
00723 *       FUNCTION NAME : convertV3toV4
00724 *
00725 * \throws RpmException
00726 *
00727 */
00728 void convertV3toV4( const Pathname & v3db_r, const librpmDb::constPtr & v4db_r )
00729 {
00730   // report
00731   callback::SendReport<ConvertDBReport> report;
00732   report->start(v3db_r);
00733   try
00734   {
00735     // Does no longer work with rpm 4.9.
00736     // internal_convertV3toV4( v3db_r, v4db_r, report );
00737     INT << "Unsupported: Convert rpm3 database to rpm4" << endl;
00738     ZYPP_THROW(RpmDbOpenException(Pathname("/"), v3db_r));
00739   }
00740   catch (RpmException & excpt_r)
00741   {
00742     report->finish(v3db_r, ConvertDBReport::FAILED,excpt_r.asUserString());
00743     ZYPP_RETHROW(excpt_r);
00744   }
00745   report->finish(v3db_r, ConvertDBReport::NO_ERROR, "");
00746 }
00747 
00748 } // namespace rpm
00749 } // namespace target
00750 } // namespace zypp