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