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