- initial rpm 4.4.4 support
[apt.git] / apt-pkg / rpm / rpmlistparser.cc
1 // Description
2 // $Id: rpmlistparser.cc,v 1.7 2003/01/29 18:55:03 niemeyer Exp $
3 // 
4 /* ######################################################################
5  * 
6  * Package Cache Generator - Generator for the cache structure.
7  * This builds the cache structure from the abstract package list parser. 
8  * 
9  ##################################################################### 
10  */
11
12
13 // Include Files
14 #include <config.h>
15
16 #ifdef HAVE_RPM
17
18 #include <apt-pkg/rpmlistparser.h>
19 #include <apt-pkg/rpmhandler.h>
20 #include <apt-pkg/rpmpackagedata.h>
21 #include <apt-pkg/rpmsystem.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/configuration.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/crc-16.h>
26 #include <apt-pkg/tagfile.h>
27
28 #include <apti18n.h>
29
30 #include <rpm/rpmlib.h>
31
32 #if RPM_VERSION >= 0x040100
33 #include <rpm/rpmds.h>
34 #endif
35
36 #define WITH_VERSION_CACHING 1
37
38 // ListParser::rpmListParser - Constructor                              /*{{{*/
39 // ---------------------------------------------------------------------
40 /* */
41 rpmListParser::rpmListParser(RPMHandler *Handler)
42         : Handler(Handler), VI(0)
43 {
44    Handler->Rewind();
45    header = NULL;
46    if (Handler->IsDatabase() == true)
47 #ifdef WITH_HASH_MAP
48       SeenPackages = new SeenPackagesType(517);
49 #else
50       SeenPackages = new SeenPackagesType;
51 #endif
52    else
53       SeenPackages = NULL;
54    RpmData = RPMPackageData::Singleton();
55 }
56                                                                         /*}}}*/
57
58 rpmListParser::~rpmListParser()
59 {
60    delete SeenPackages;
61 }
62
63 // ListParser::UniqFindTagWrite - Find the tag and write a unq string   /*{{{*/
64 // ---------------------------------------------------------------------
65 /* */
66 unsigned long rpmListParser::UniqFindTagWrite(int Tag)
67 {
68    char *Start;
69    char *Stop;
70    int type;
71    int count;
72    void *data;
73    
74    if (headerGetEntry(header, Tag, &type, &data, &count) != 1)
75       return 0;
76    
77    if (type == RPM_STRING_TYPE) 
78    {
79       Start = (char*)data;
80       Stop = Start + strlen(Start);
81    } else {
82       cout << "oh shit, not handled:"<<type<<" Package:"<<Package()<<endl;
83       abort();
84    }
85    
86    return WriteUniqString(Start,Stop - Start);
87 }
88                                                                         /*}}}*/
89 // ListParser::Package - Return the package name                        /*{{{*/
90 // ---------------------------------------------------------------------
91 /* This is to return the name of the package this section describes */
92 string rpmListParser::Package()
93 {
94    if (CurrentName.empty() == false)
95       return CurrentName;
96
97 #ifdef WITH_VERSION_CACHING
98    if (VI != NULL) {
99       CurrentName = VI->ParentPkg().Name();
100       return CurrentName;
101    }
102 #endif
103
104    char *str;
105    int type, count;
106    
107    Duplicated = false;
108    
109    if (headerGetEntry(header, RPMTAG_NAME, &type, (void**)&str, &count) != 1) 
110    {
111       _error->Error(_("Corrupt pkglist: no RPMTAG_NAME in header entry"));
112       return "";
113    } 
114
115    bool IsDup = false;
116    string Name = str;
117    
118    // If this package can have multiple versions installed at
119    // the same time, then we make it so that the name of the
120    // package is NAME+"#"+VERSION and also add a provides
121    // with the original name and version, to satisfy the 
122    // dependencies.
123    if (RpmData->IsDupPackage(Name) == true)
124       IsDup = true;
125    else if (SeenPackages != NULL) {
126       if (SeenPackages->find(Name.c_str()) != SeenPackages->end())
127       {
128          if (_config->FindB("RPM::Allow-Duplicated-Warning", true) == true)
129             _error->Warning(
130    _("There are multiple versions of \"%s\" in your system.\n"
131      "\n"
132      "This package won't be cleanly updated, unless you leave\n"
133      "only one version. To leave multiple versions installed,\n"
134      "you may remove that warning by setting the following\n"
135      "option in your configuration file:\n"
136      "\n"
137      "RPM::Allow-Duplicated { \"^%s$\"; };\n"
138      "\n"
139      "To disable these warnings completely set:\n"
140      "\n"
141      "RPM::Allow-Duplicated-Warning \"false\";\n")
142                               , Name.c_str(), Name.c_str());
143          RpmData->SetDupPackage(Name);
144          VirtualizePackage(Name);
145          IsDup = true;
146       }
147    }
148    if (IsDup == true)
149    {
150       Name += "#"+Version();
151       Duplicated = true;
152    } 
153    CurrentName = Name;
154    return Name;
155 }
156                                                                         /*}}}*/
157 // ListParser::Arch - Return the architecture string                    /*{{{*/
158 // ---------------------------------------------------------------------
159 string rpmListParser::Architecture()
160 {
161 #ifdef WITH_VERSION_CACHING
162    if (VI != NULL)
163       return VI->Arch();
164 #endif
165
166    int type, count;
167    char *arch;
168    int res;
169    res = headerGetEntry(header, RPMTAG_ARCH, &type, (void **)&arch, &count);
170    return string(res?arch:"");
171 }
172                                                                         /*}}}*/
173 // ListParser::Version - Return the version string                      /*{{{*/
174 // ---------------------------------------------------------------------
175 /* This is to return the string describing the version in RPM form,
176  version-release. If this returns the blank string then the
177  entry is assumed to only describe package properties */
178 string rpmListParser::Version()
179 {
180 #ifdef WITH_VERSION_CACHING
181    if (VI != NULL)
182       return VI->VerStr();
183 #endif
184
185    char *ver, *rel;
186    int_32 *ser;
187    bool has_epoch = false;
188    int type, count;
189    string str;
190    str.reserve(10);
191
192    if (headerGetEntry(header, RPMTAG_EPOCH, &type, (void **)&ser, &count) == 1
193        && count > 0) 
194       has_epoch = true;
195    
196    headerGetEntry(header, RPMTAG_VERSION, &type, (void **)&ver, &count);
197    headerGetEntry(header, RPMTAG_RELEASE, &type, (void **)&rel, &count);
198
199    if (has_epoch == true) {
200       char buf[32];
201       snprintf(buf, sizeof(buf), "%i", ser[0]);
202       str += buf;
203       str += ":";
204       str += ver;
205       str += "-";
206       str += rel;
207    }
208    else {
209       str += ver;
210       str += "-";
211       str += rel;
212    }
213    return str;
214 }
215                                                                         /*}}}*/
216 // ListParser::NewVersion - Fill in the version structure               /*{{{*/
217 // ---------------------------------------------------------------------
218 /* */
219 bool rpmListParser::NewVersion(pkgCache::VerIterator Ver)
220 {
221    int count, type;
222    int_32 *num;
223
224 #if WITH_VERSION_CACHING
225    // Cache it for future usage.
226    RpmData->SetVersion(Handler->GetID(), Offset(), Ver);
227 #endif
228    
229    // Parse the section
230    Ver->Section = UniqFindTagWrite(RPMTAG_GROUP);
231    Ver->Arch = UniqFindTagWrite(RPMTAG_ARCH);
232    
233    // Archive Size
234    Ver->Size = Handler->FileSize();
235    
236    // Unpacked Size (in kbytes)
237    headerGetEntry(header, RPMTAG_SIZE, &type, (void**)&num, &count);
238    Ver->InstalledSize = (unsigned)num[0];
239      
240    if (ParseDepends(Ver,pkgCache::Dep::Depends) == false)
241        return false;
242    if (ParseDepends(Ver,pkgCache::Dep::Conflicts) == false)
243        return false;
244    if (ParseDepends(Ver,pkgCache::Dep::Obsoletes) == false)
245        return false;
246 #ifdef OLD_FILEDEPS
247    if (ProcessFileProvides(Ver) == false)
248        return false;
249 #endif
250
251    if (ParseProvides(Ver) == false)
252        return false;
253
254    if (Handler->ProvideFileName() &&
255        NewProvides(Ver, Handler->FileName(), "") == false)
256          return false;
257
258    return true;
259 }
260                                                                         /*}}}*/
261 // ListParser::UsePackage - Update a package structure                  /*{{{*/
262 // ---------------------------------------------------------------------
263 /* This is called to update the package with any new information
264    that might be found in the section */
265 bool rpmListParser::UsePackage(pkgCache::PkgIterator Pkg,
266                                pkgCache::VerIterator Ver)
267 {
268    if (SeenPackages != NULL)
269       (*SeenPackages)[Pkg.Name()] = true;
270    if (Pkg->Section == 0)
271       Pkg->Section = UniqFindTagWrite(RPMTAG_GROUP);
272    if (_error->PendingError()) 
273        return false;
274    string PkgName = Pkg.Name();
275    string::size_type HashPos = PkgName.find('#');
276    if (HashPos != string::npos)
277       PkgName = PkgName.substr(0, HashPos);
278    Ver->Priority = RpmData->VerPriority(PkgName);
279    Pkg->Flags |= RpmData->PkgFlags(PkgName);
280    if (HashPos != string::npos && (Pkg->Flags & pkgCache::Flag::Essential))
281       Pkg->Flags = pkgCache::Flag::Important;
282    if (ParseStatus(Pkg,Ver) == false)
283        return false;
284    return true;
285 }
286                                                                         /*}}}*/
287 // ListParser::VersionHash - Compute a unique hash for this version     /*{{{*/
288 // ---------------------------------------------------------------------
289 /* */
290
291 /*
292 static int compare(const void *a, const void *b)
293 {   
294    return strcmp(*(char**)a, *(char**)b);
295 }
296 */
297
298 unsigned short rpmListParser::VersionHash()
299 {
300 #ifdef WITH_VERSION_CACHING
301    if (VI != NULL)
302       return (*VI)->Hash;
303 #endif
304       
305    int Sections[] = {
306           RPMTAG_VERSION,
307           RPMTAG_RELEASE,
308           RPMTAG_ARCH,
309           RPMTAG_REQUIRENAME,
310           RPMTAG_OBSOLETENAME,
311           RPMTAG_CONFLICTNAME,
312           0
313    };
314    unsigned long Result = INIT_FCS;
315    
316    for (const int *sec = Sections; *sec != 0; sec++)
317    {
318       char *Str;
319       int Len;
320       int type, count;
321       int res;
322       char **strings = NULL;
323       
324       res = headerGetEntry(header, *sec, &type, (void **)&strings, &count);
325       if (res != 1)
326          continue;
327       
328       switch (type) 
329       {
330       case RPM_STRING_ARRAY_TYPE:
331          //qsort(strings, count, sizeof(char*), compare);
332          while (count-- > 0) 
333          {
334             Str = strings[count];
335             Len = strlen(Str);
336
337             /* Suse patch.rpm hack. */
338             if (Len == 17 && *Str == 'r' && *sec == RPMTAG_REQUIRENAME &&
339                 strcmp(Str, "rpmlib(PatchRPMs)") == 0)
340                continue;
341             
342             Result = AddCRC16(Result,Str,Len);
343          }
344          free(strings);
345          break;
346          
347       case RPM_STRING_TYPE:
348          Str = (char*)strings;
349          Len = strlen(Str);
350          Result = AddCRC16(Result,Str,Len);
351          break;
352       }
353    }
354    
355    return Result;
356 }
357                                                                         /*}}}*/
358 // ListParser::ParseStatus - Parse the status field                     /*{{{*/
359 // ---------------------------------------------------------------------
360 bool rpmListParser::ParseStatus(pkgCache::PkgIterator Pkg,
361                                 pkgCache::VerIterator Ver)
362 {   
363    if (!Handler->IsDatabase())  // this means we're parsing an hdlist, so it's not installed
364       return true;
365    
366    // if we're reading from the rpmdb, then it's installed
367    // 
368    Pkg->SelectedState = pkgCache::State::Install;
369    Pkg->InstState = pkgCache::State::Ok;
370    Pkg->CurrentState = pkgCache::State::Installed;
371    
372    Pkg->CurrentVer = Ver.Index();
373    
374    return true;
375 }
376
377
378 bool rpmListParser::ParseDepends(pkgCache::VerIterator Ver,
379                                  char **namel, char **verl, int_32 *flagl,
380                                  int count, unsigned int Type)
381 {
382    int i = 0;
383    unsigned int Op = 0;
384    bool DepMode = false;
385    if (Type == pkgCache::Dep::Depends)
386       DepMode = true;
387    
388    for (; i < count; i++) 
389    {
390       if (DepMode == true) {
391          if (flagl[i] & RPMSENSE_PREREQ)
392             Type = pkgCache::Dep::PreDepends;
393          else
394             Type = pkgCache::Dep::Depends;
395       }
396 #if RPM_VERSION >= 0x040404
397       if (namel[i][0] == 'g' && strncmp(namel[i], "getconf", 7) == 0)
398       {
399         rpmds getconfProv = NULL;
400         rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
401                                namel[i], verl?verl[i]:NULL, flagl[i]);
402         rpmdsGetconf(&getconfProv, NULL);
403         int res = rpmdsSearch(getconfProv, ds) >= 0;
404         rpmdsFree(ds);
405         rpmdsFree(getconfProv);
406         if (res) continue;
407       }
408 #endif
409       
410       if (namel[i][0] == 'r' && strncmp(namel[i], "rpmlib", 6) == 0)
411       {
412 #if RPM_VERSION >= 0x040404
413         rpmds rpmlibProv = NULL;
414         rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
415                                namel[i], verl?verl[i]:NULL, flagl[i]);
416         rpmdsRpmlib(&rpmlibProv, NULL);
417         int res = rpmdsSearch(rpmlibProv, ds) >= 0;
418         rpmdsFree(ds);
419         rpmdsFree(rpmlibProv);
420 #elif RPM_VERSION >= 0x040100
421          rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
422                                 namel[i], verl?verl[i]:NULL, flagl[i]);
423          int res = rpmCheckRpmlibProvides(ds);
424          rpmdsFree(ds);
425 #else
426          int res = rpmCheckRpmlibProvides(namel[i], verl?verl[i]:NULL,
427                                           flagl[i]);
428 #endif
429          if (res) continue;
430       }
431
432       if (verl) 
433       {
434          if (!*verl[i]) 
435          {
436             Op = pkgCache::Dep::NoOp;
437          }
438          else 
439          {
440             if (flagl[i] & RPMSENSE_LESS) 
441             {
442                if (flagl[i] & RPMSENSE_EQUAL)
443                    Op = pkgCache::Dep::LessEq;
444                else
445                    Op = pkgCache::Dep::Less;
446             } 
447             else if (flagl[i] & RPMSENSE_GREATER) 
448             {
449                if (flagl[i] & RPMSENSE_EQUAL)
450                    Op = pkgCache::Dep::GreaterEq;
451                else
452                    Op = pkgCache::Dep::Greater;
453             } 
454             else if (flagl[i] & RPMSENSE_EQUAL) 
455             {
456                Op = pkgCache::Dep::Equals;
457             }
458          }
459          
460          if (NewDepends(Ver,namel[i],verl[i],Op,Type) == false)
461              return false;
462       } 
463       else 
464       {
465          if (NewDepends(Ver,namel[i],"",pkgCache::Dep::NoOp,Type) == false)
466              return false;
467       }
468    }
469    return true;
470 }
471                                                                         /*}}}*/
472 // ListParser::ParseDepends - Parse a dependency list                   /*{{{*/
473 // ---------------------------------------------------------------------
474 /* This is the higher level depends parser. It takes a tag and generates
475  a complete depends tree for the given version. */
476 bool rpmListParser::ParseDepends(pkgCache::VerIterator Ver,
477                                  unsigned int Type)
478 {
479    char **namel = NULL;
480    char **verl = NULL;
481    int *flagl = NULL;
482    int res, type, count;
483    
484    switch (Type) 
485    {
486    case pkgCache::Dep::Depends:
487       res = headerGetEntry(header, RPMTAG_REQUIRENAME, &type, 
488                            (void **)&namel, &count);
489       if (res != 1)
490           return true;
491       res = headerGetEntry(header, RPMTAG_REQUIREVERSION, &type, 
492                            (void **)&verl, &count);
493       res = headerGetEntry(header, RPMTAG_REQUIREFLAGS, &type,
494                            (void **)&flagl, &count);
495       break;
496       
497    case pkgCache::Dep::Obsoletes:
498       res = headerGetEntry(header, RPMTAG_OBSOLETENAME, &type,
499                            (void **)&namel, &count);
500       if (res != 1)
501           return true;
502       res = headerGetEntry(header, RPMTAG_OBSOLETEVERSION, &type,
503                            (void **)&verl, &count);
504       res = headerGetEntry(header, RPMTAG_OBSOLETEFLAGS, &type,
505                            (void **)&flagl, &count);      
506       break;
507
508    case pkgCache::Dep::Conflicts:
509       res = headerGetEntry(header, RPMTAG_CONFLICTNAME, &type, 
510                            (void **)&namel, &count);
511       if (res != 1)
512           return true;
513       res = headerGetEntry(header, RPMTAG_CONFLICTVERSION, &type, 
514                            (void **)&verl, &count);
515       res = headerGetEntry(header, RPMTAG_CONFLICTFLAGS, &type,
516                            (void **)&flagl, &count);
517       break;
518    }
519    
520    ParseDepends(Ver, namel, verl, flagl, count, Type);
521
522    free(namel);
523    free(verl);
524    
525    return true;
526 }
527                                                                         /*}}}*/
528 #ifdef OLD_FILEDEPS
529 bool rpmListParser::ProcessFileProvides(pkgCache::VerIterator Ver)
530 {
531    const char **names = NULL;    
532    int count = 0;
533
534    rpmHeaderGetEntry(header, RPMTAG_OLDFILENAMES, NULL, &names, &count);
535
536    while (count--) 
537    {
538       if (rpmSys.IsFileDep(string(names[count]))) 
539       {
540          if (!NewProvides(Ver, string(names[count]), string()))
541              return false;
542       }
543    }
544
545    return true;
546 }
547 #endif
548
549 bool rpmListParser::CollectFileProvides(pkgCache &Cache,
550                                         pkgCache::VerIterator Ver)
551 {
552    const char **names = NULL;
553    int_32 count = 0;
554    bool ret = true;
555    rpmHeaderGetEntry(header, RPMTAG_OLDFILENAMES,
556                      NULL, (void **) &names, &count);
557    while (count--) 
558    {
559       const char *FileName = names[count];
560       pkgCache::Package *P = Cache.FindPackage(FileName);
561       if (P != NULL) {
562          // Check if this is already provided.
563          bool Found = false;
564          for (pkgCache::PrvIterator Prv = Ver.ProvidesList();
565               Prv.end() == false; Prv++) {
566             if (strcmp(Prv.Name(), FileName) == 0) {
567                Found = true;
568                break;
569             }
570          }
571          if (Found == false && NewProvides(Ver, FileName, "") == false) {
572             ret = false;
573             break;
574          }
575       }
576    }
577    free(names);
578    return ret;
579 }
580
581 // ListParser::ParseProvides - Parse the provides list                  /*{{{*/
582 // ---------------------------------------------------------------------
583 /* */
584 bool rpmListParser::ParseProvides(pkgCache::VerIterator Ver)
585 {
586    int type, count;
587    char **namel = NULL;
588    char **verl = NULL;
589    int res;
590
591    res = headerGetEntry(header, RPMTAG_PROVIDENAME, &type,
592                         (void **)&namel, &count);
593    if (res != 1)
594        return true;
595    /*
596     res = headerGetEntry(header, RPMTAG_PROVIDEFLAGS, &type,
597     (void **)&flagl, &count);
598     if (res != 1)
599     return true;
600     */
601    res = headerGetEntry(header, RPMTAG_PROVIDEVERSION, &type, 
602                         (void **)&verl, NULL);
603    if (res != 1)
604         verl = NULL;
605
606    bool ret = true;
607    for (int i = 0; i < count; i++) 
608    {      
609       if (verl && *verl[i]) 
610       {
611          if (NewProvides(Ver,namel[i],verl[i]) == false) {
612             ret = false;
613             break;
614          }
615       } 
616       else 
617       {
618          if (NewProvides(Ver,namel[i],"") == false) {
619             ret = false;
620             break;
621          }
622       }
623    }
624
625    free(namel);
626    free(verl);
627     
628    return ret;
629 }
630                                                                         /*}}}*/
631 // ListParser::Step - Move to the next section in the file              /*{{{*/
632 // ---------------------------------------------------------------------
633 /* This has to be carefull to only process the correct architecture */
634 bool rpmListParser::Step()
635 {
636    while (Handler->Skip() == true)
637    {
638       header = Handler->GetHeader();
639       CurrentName = "";
640
641 #ifdef WITH_VERSION_CACHING
642       VI = RpmData->GetVersion(Handler->GetID(), Offset());
643       if (VI != NULL)
644          return true;
645 #endif
646       
647       string RealName = Package();
648       if (Duplicated == true)
649          RealName = RealName.substr(0,RealName.find('#'));
650       if (RpmData->IgnorePackage(RealName) == true)
651          continue;
652  
653 #if OLD_BESTARCH
654       bool archOk = false;
655       string tmp = rpmSys.BestArchForPackage(RealName);
656       if (tmp.empty() == true && // has packages for a single arch only
657           rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch.c_str()) > 0)
658          archOk = true;
659       else if (arch == tmp)
660          archOk = true;
661       if (Handler->IsDatabase() == true || archOk == true)
662          return true;
663 #else
664       if (Handler->IsDatabase() == true ||
665           RpmData->ArchScore(Architecture().c_str()) > 0)
666          return true;
667 #endif
668    }
669    header = NULL;
670    return false;
671 }
672                                                                         /*}}}*/
673 // ListParser::LoadReleaseInfo - Load the release information           /*{{{*/
674 // ---------------------------------------------------------------------
675 /* */
676 bool rpmListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
677                                     FileFd &File)
678 {
679    pkgTagFile Tags(&File);
680    pkgTagSection Section;
681    if (!Tags.Step(Section))
682        return false;
683    
684    const char *Start;
685    const char *Stop;
686    if (Section.Find("Archive",Start,Stop))
687        FileI->Archive = WriteUniqString(Start,Stop - Start);
688    if (Section.Find("Component",Start,Stop))
689        FileI->Component = WriteUniqString(Start,Stop - Start);
690    if (Section.Find("Version",Start,Stop))
691        FileI->Version = WriteUniqString(Start,Stop - Start);
692    if (Section.Find("Origin",Start,Stop))
693        FileI->Origin = WriteUniqString(Start,Stop - Start);
694    if (Section.Find("Label",Start,Stop))
695        FileI->Label = WriteUniqString(Start,Stop - Start);
696    if (Section.Find("Architecture",Start,Stop))
697        FileI->Architecture = WriteUniqString(Start,Stop - Start);
698    
699    if (Section.FindFlag("NotAutomatic",FileI->Flags,
700                         pkgCache::Flag::NotAutomatic) == false)
701        _error->Warning(_("Bad NotAutomatic flag"));
702    
703    return !_error->PendingError();
704 }
705                                                                         /*}}}*/
706
707 unsigned long rpmListParser::Size() 
708 {
709    uint_32 *size;
710    int type, count;
711    if (headerGetEntry(header, RPMTAG_SIZE, &type, (void **)&size, &count)!=1)
712        return 1;
713    return (size[0]+512)/1024;
714 }
715
716 // This is a slightly complex operation. It must take a package, and
717 // move every version to new packages, named accordingly to
718 // Allow-Duplicated rules.
719 void rpmListParser::VirtualizePackage(string Name)
720 {
721    pkgCache::PkgIterator FromPkgI = Owner->GetCache().FindPkg(Name);
722
723    // Should always be false
724    if (FromPkgI.end() == true)
725       return;
726
727    pkgCache::VerIterator FromVerI = FromPkgI.VersionList();
728    while (FromVerI.end() == false) {
729       string MangledName = Name+"#"+string(FromVerI.VerStr());
730
731       // Get the new package.
732       pkgCache::PkgIterator ToPkgI = Owner->GetCache().FindPkg(MangledName);
733       if (ToPkgI.end() == true) {
734          // Theoretically, all packages virtualized should pass here at least
735          // once for each new version in the list, since either the package was
736          // already setup as Allow-Duplicated (and this method would never be
737          // called), or the package doesn't exist before getting here. If
738          // we discover that this assumption is false, then we must do
739          // something to order the version list correctly, since the package
740          // could already have some other version there.
741          Owner->NewPackage(ToPkgI, MangledName);
742
743          // Should it get the flags from the original package? Probably not,
744          // or automatic Allow-Duplicated would work differently than
745          // hardcoded ones.
746          ToPkgI->Flags |= RpmData->PkgFlags(MangledName);
747          ToPkgI->Section = FromPkgI->Section;
748       }
749       
750       // Move the version to the new package.
751       FromVerI->ParentPkg = ToPkgI.Index();
752
753       // Put it at the end of the version list (about ordering,
754       // read the comment above).
755       map_ptrloc *ToVerLast = &ToPkgI->VersionList;
756       for (pkgCache::VerIterator ToVerLastI = ToPkgI.VersionList();
757            ToVerLastI.end() == false; ToVerLastI++)
758            ToVerLast = &ToVerLastI->NextVer;
759
760       *ToVerLast = FromVerI.Index();
761
762       // Provide the real package name with the current version.
763       NewProvides(FromVerI, Name, FromVerI.VerStr());
764
765       // Is this the current version of the old package? If yes, set it
766       // as the current version of the new package as well.
767       if (FromVerI == FromPkgI.CurrentVer()) {
768          ToPkgI->CurrentVer = FromVerI.Index();
769          ToPkgI->SelectedState = pkgCache::State::Install;
770          ToPkgI->InstState = pkgCache::State::Ok;
771          ToPkgI->CurrentState = pkgCache::State::Installed;
772       }
773
774       // Move the iterator before reseting the NextVer.
775       pkgCache::Version *FromVer = (pkgCache::Version*)FromVerI;
776       FromVerI++;
777       FromVer->NextVer = 0;
778    }
779
780    // Reset original package data.
781    FromPkgI->CurrentVer = 0;
782    FromPkgI->VersionList = 0;
783    FromPkgI->Section = 0;
784    FromPkgI->SelectedState = 0;
785    FromPkgI->InstState = 0;
786    FromPkgI->CurrentState = 0;
787 }
788
789 #endif /* HAVE_RPM */
790
791 // vim:sts=3:sw=3