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