aa7223adfe8abf6cb45d44e15d80325cb65fb267
[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         cout << "XXXX uname require: " << namel[i] << " res " << res << endl;
461         rpmdsFree(ds);
462         rpmdsFree(unameProv);
463         if (res) continue;
464       }
465
466       /* TODO
467        * - /etc/rpm/sysinfo provides
468        * - macro probe provides 
469        * - actually implement soname() and access() dependencies
470        */
471       if (strncmp(namel[i], "soname(", sizeof("soname(")-1) == 0)
472       {
473          cout << "FIXME, ignoring soname() dependency: " << namel[i] << endl;
474          continue;
475       }
476
477       if (strncmp(namel[i], "exists(", sizeof("exists(")-1) == 0 ||
478           strncmp(namel[i], "executable(", sizeof("executable(")-1) == 0 ||
479           strncmp(namel[i], "readable(", sizeof("readable(")-1) == 0 ||
480           strncmp(namel[i], "writable(", sizeof("writable(")-1)== 0 ) 
481       {
482          cout << "FIXME, ignoring access() dependency: " << namel[i] << endl;
483          continue;
484       }
485
486       
487
488 #endif
489       
490       if (strncmp(namel[i], "rpmlib(", sizeof("rpmlib(")-1) == 0)
491       {
492 #if RPM_VERSION >= 0x040404
493         rpmds rpmlibProv = NULL;
494         rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
495                                namel[i], verl?verl[i]:NULL, flagl[i]);
496         rpmdsRpmlib(&rpmlibProv, NULL);
497         int res = rpmdsSearch(rpmlibProv, ds) >= 0;
498         rpmdsFree(ds);
499         rpmdsFree(rpmlibProv);
500 #elif RPM_VERSION >= 0x040100
501          rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
502                                 namel[i], verl?verl[i]:NULL, flagl[i]);
503          int res = rpmCheckRpmlibProvides(ds);
504          rpmdsFree(ds);
505 #else
506          int res = rpmCheckRpmlibProvides(namel[i], verl?verl[i]:NULL,
507                                           flagl[i]);
508 #endif
509          if (res) continue;
510       }
511
512       if (verl) 
513       {
514          if (!*verl[i]) 
515          {
516             Op = pkgCache::Dep::NoOp;
517          }
518          else 
519          {
520             if (flagl[i] & RPMSENSE_LESS) 
521             {
522                if (flagl[i] & RPMSENSE_EQUAL)
523                    Op = pkgCache::Dep::LessEq;
524                else
525                    Op = pkgCache::Dep::Less;
526             } 
527             else if (flagl[i] & RPMSENSE_GREATER) 
528             {
529                if (flagl[i] & RPMSENSE_EQUAL)
530                    Op = pkgCache::Dep::GreaterEq;
531                else
532                    Op = pkgCache::Dep::Greater;
533             } 
534             else if (flagl[i] & RPMSENSE_EQUAL) 
535             {
536                Op = pkgCache::Dep::Equals;
537             }
538          }
539          
540          if (NewDepends(Ver,namel[i],verl[i],Op,Type) == false)
541              return false;
542       } 
543       else 
544       {
545          if (NewDepends(Ver,namel[i],"",pkgCache::Dep::NoOp,Type) == false)
546              return false;
547       }
548    }
549    return true;
550 }
551                                                                         /*}}}*/
552 // ListParser::ParseDepends - Parse a dependency list                   /*{{{*/
553 // ---------------------------------------------------------------------
554 /* This is the higher level depends parser. It takes a tag and generates
555  a complete depends tree for the given version. */
556 bool rpmListParser::ParseDepends(pkgCache::VerIterator Ver,
557                                  unsigned int Type)
558 {
559    char **namel = NULL;
560    char **verl = NULL;
561    int *flagl = NULL;
562    int res, type, count;
563    
564    switch (Type) 
565    {
566    case pkgCache::Dep::Depends:
567       res = headerGetEntry(header, RPMTAG_REQUIRENAME, &type, 
568                            (void **)&namel, &count);
569       if (res != 1)
570           return true;
571       res = headerGetEntry(header, RPMTAG_REQUIREVERSION, &type, 
572                            (void **)&verl, &count);
573       res = headerGetEntry(header, RPMTAG_REQUIREFLAGS, &type,
574                            (void **)&flagl, &count);
575       break;
576       
577    case pkgCache::Dep::Obsoletes:
578       res = headerGetEntry(header, RPMTAG_OBSOLETENAME, &type,
579                            (void **)&namel, &count);
580       if (res != 1)
581           return true;
582       res = headerGetEntry(header, RPMTAG_OBSOLETEVERSION, &type,
583                            (void **)&verl, &count);
584       res = headerGetEntry(header, RPMTAG_OBSOLETEFLAGS, &type,
585                            (void **)&flagl, &count);      
586       break;
587
588    case pkgCache::Dep::Conflicts:
589       res = headerGetEntry(header, RPMTAG_CONFLICTNAME, &type, 
590                            (void **)&namel, &count);
591       if (res != 1)
592           return true;
593       res = headerGetEntry(header, RPMTAG_CONFLICTVERSION, &type, 
594                            (void **)&verl, &count);
595       res = headerGetEntry(header, RPMTAG_CONFLICTFLAGS, &type,
596                            (void **)&flagl, &count);
597       break;
598 #if RPM_VERSION >= 0x040403
599    case pkgCache::Dep::Suggests:
600       res = headerGetEntry(header, RPMTAG_SUGGESTSNAME, &type, 
601                            (void **)&namel, &count);
602       if (res != 1)
603           return true;
604       res = headerGetEntry(header, RPMTAG_SUGGESTSVERSION, &type, 
605                            (void **)&verl, &count);
606       res = headerGetEntry(header, RPMTAG_SUGGESTSFLAGS, &type,
607                            (void **)&flagl, &count);
608       break;
609 #if 0 // Enhances is not even known to apt, sigh...
610    case pkgCache::Dep::Enhances:
611       res = headerGetEntry(header, RPMTAG_ENHANCESNAME, &type, 
612                            (void **)&namel, &count);
613       if (res != 1)
614           return true;
615       res = headerGetEntry(header, RPMTAG_ENHANCESVERSION, &type, 
616                            (void **)&verl, &count);
617       res = headerGetEntry(header, RPMTAG_ENHANCESFLAGS, &type,
618                            (void **)&flagl, &count);
619       break;
620 #endif
621 #endif
622    }
623    
624    ParseDepends(Ver, namel, verl, flagl, count, Type);
625
626    free(namel);
627    free(verl);
628    
629    return true;
630 }
631                                                                         /*}}}*/
632 #ifdef OLD_FILEDEPS
633 bool rpmListParser::ProcessFileProvides(pkgCache::VerIterator Ver)
634 {
635    const char **names = NULL;    
636    int count = 0;
637
638    rpmHeaderGetEntry(header, RPMTAG_OLDFILENAMES, NULL, &names, &count);
639
640    while (count--) 
641    {
642       if (rpmSys.IsFileDep(string(names[count]))) 
643       {
644          if (!NewProvides(Ver, string(names[count]), string()))
645              return false;
646       }
647    }
648
649    return true;
650 }
651 #endif
652
653 bool rpmListParser::CollectFileProvides(pkgCache &Cache,
654                                         pkgCache::VerIterator Ver)
655 {
656    const char **names = NULL;
657    int_32 count = 0;
658    bool ret = true;
659    rpmHeaderGetEntry(header, RPMTAG_OLDFILENAMES,
660                      NULL, (void **) &names, &count);
661    while (count--) 
662    {
663       const char *FileName = names[count];
664       pkgCache::Package *P = Cache.FindPackage(FileName);
665       if (P != NULL) {
666          // Check if this is already provided.
667          bool Found = false;
668          for (pkgCache::PrvIterator Prv = Ver.ProvidesList();
669               Prv.end() == false; Prv++) {
670             if (strcmp(Prv.Name(), FileName) == 0) {
671                Found = true;
672                break;
673             }
674          }
675          if (Found == false && NewProvides(Ver, FileName, "") == false) {
676             ret = false;
677             break;
678          }
679       }
680    }
681    free(names);
682    return ret;
683 }
684
685 // ListParser::ParseProvides - Parse the provides list                  /*{{{*/
686 // ---------------------------------------------------------------------
687 /* */
688 bool rpmListParser::ParseProvides(pkgCache::VerIterator Ver)
689 {
690    int type, count;
691    char **namel = NULL;
692    char **verl = NULL;
693    int res;
694
695    res = headerGetEntry(header, RPMTAG_PROVIDENAME, &type,
696                         (void **)&namel, &count);
697    if (res != 1)
698        return true;
699    /*
700     res = headerGetEntry(header, RPMTAG_PROVIDEFLAGS, &type,
701     (void **)&flagl, &count);
702     if (res != 1)
703     return true;
704     */
705    res = headerGetEntry(header, RPMTAG_PROVIDEVERSION, &type, 
706                         (void **)&verl, NULL);
707    if (res != 1)
708         verl = NULL;
709
710    bool ret = true;
711    for (int i = 0; i < count; i++) 
712    {      
713       if (verl && *verl[i]) 
714       {
715          if (NewProvides(Ver,namel[i],verl[i]) == false) {
716             ret = false;
717             break;
718          }
719       } 
720       else 
721       {
722          if (NewProvides(Ver,namel[i],"") == false) {
723             ret = false;
724             break;
725          }
726       }
727    }
728
729    free(namel);
730    free(verl);
731     
732    return ret;
733 }
734                                                                         /*}}}*/
735 // ListParser::Step - Move to the next section in the file              /*{{{*/
736 // ---------------------------------------------------------------------
737 /* This has to be carefull to only process the correct architecture */
738 bool rpmListParser::Step()
739 {
740    while (Handler->Skip() == true)
741    {
742       header = Handler->GetHeader();
743       CurrentName = "";
744
745 #ifdef WITH_VERSION_CACHING
746       VI = RpmData->GetVersion(Handler->GetID(), Offset());
747       if (VI != NULL)
748          return true;
749 #endif
750       
751       string RealName = Package();
752
753       if (Duplicated == true)
754          RealName = RealName.substr(0,RealName.find('#'));
755       if (RpmData->IgnorePackage(RealName) == true)
756          continue;
757  
758 #if OLD_BESTARCH
759       bool archOk = false;
760       string tmp = rpmSys.BestArchForPackage(RealName);
761       if (tmp.empty() == true && // has packages for a single arch only
762           rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch.c_str()) > 0)
763          archOk = true;
764       else if (arch == tmp)
765          archOk = true;
766       if (Handler->IsDatabase() == true || archOk == true)
767          return true;
768 #else
769       if (Handler->IsDatabase() == true ||
770           RpmData->ArchScore(Architecture().c_str()) > 0)
771          return true;
772 #endif
773    }
774    header = NULL;
775    return false;
776 }
777                                                                         /*}}}*/
778 // ListParser::LoadReleaseInfo - Load the release information           /*{{{*/
779 // ---------------------------------------------------------------------
780 /* */
781 bool rpmListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
782                                     FileFd &File)
783 {
784    pkgTagFile Tags(&File);
785    pkgTagSection Section;
786    if (!Tags.Step(Section))
787        return false;
788    
789    const char *Start;
790    const char *Stop;
791    if (Section.Find("Archive",Start,Stop))
792        FileI->Archive = WriteUniqString(Start,Stop - Start);
793    if (Section.Find("Component",Start,Stop))
794        FileI->Component = WriteUniqString(Start,Stop - Start);
795    if (Section.Find("Version",Start,Stop))
796        FileI->Version = WriteUniqString(Start,Stop - Start);
797    if (Section.Find("Origin",Start,Stop))
798        FileI->Origin = WriteUniqString(Start,Stop - Start);
799    if (Section.Find("Label",Start,Stop))
800        FileI->Label = WriteUniqString(Start,Stop - Start);
801    if (Section.Find("Architecture",Start,Stop))
802        FileI->Architecture = WriteUniqString(Start,Stop - Start);
803    
804    if (Section.FindFlag("NotAutomatic",FileI->Flags,
805                         pkgCache::Flag::NotAutomatic) == false)
806        _error->Warning(_("Bad NotAutomatic flag"));
807    
808    return !_error->PendingError();
809 }
810                                                                         /*}}}*/
811
812 unsigned long rpmListParser::Size() 
813 {
814    uint_32 *size;
815    int type, count;
816    if (headerGetEntry(header, RPMTAG_SIZE, &type, (void **)&size, &count)!=1)
817        return 1;
818    return (size[0]+512)/1024;
819 }
820
821 // This is a slightly complex operation. It must take a package, and
822 // move every version to new packages, named accordingly to
823 // Allow-Duplicated rules.
824 void rpmListParser::VirtualizePackage(string Name)
825 {
826    pkgCache::PkgIterator FromPkgI = Owner->GetCache().FindPkg(Name);
827
828    // Should always be false
829    if (FromPkgI.end() == true)
830       return;
831
832    pkgCache::VerIterator FromVerI = FromPkgI.VersionList();
833    while (FromVerI.end() == false) {
834       string MangledName = Name+"#"+string(FromVerI.VerStr());
835
836       // Get the new package.
837       pkgCache::PkgIterator ToPkgI = Owner->GetCache().FindPkg(MangledName);
838       if (ToPkgI.end() == true) {
839          // Theoretically, all packages virtualized should pass here at least
840          // once for each new version in the list, since either the package was
841          // already setup as Allow-Duplicated (and this method would never be
842          // called), or the package doesn't exist before getting here. If
843          // we discover that this assumption is false, then we must do
844          // something to order the version list correctly, since the package
845          // could already have some other version there.
846          Owner->NewPackage(ToPkgI, MangledName);
847
848          // Should it get the flags from the original package? Probably not,
849          // or automatic Allow-Duplicated would work differently than
850          // hardcoded ones.
851          ToPkgI->Flags |= RpmData->PkgFlags(MangledName);
852          ToPkgI->Section = FromPkgI->Section;
853       }
854       
855       // Move the version to the new package.
856       FromVerI->ParentPkg = ToPkgI.Index();
857
858       // Put it at the end of the version list (about ordering,
859       // read the comment above).
860       map_ptrloc *ToVerLast = &ToPkgI->VersionList;
861       for (pkgCache::VerIterator ToVerLastI = ToPkgI.VersionList();
862            ToVerLastI.end() == false; ToVerLastI++)
863            ToVerLast = &ToVerLastI->NextVer;
864
865       *ToVerLast = FromVerI.Index();
866
867       // Provide the real package name with the current version.
868       NewProvides(FromVerI, Name, FromVerI.VerStr());
869
870       // Is this the current version of the old package? If yes, set it
871       // as the current version of the new package as well.
872       if (FromVerI == FromPkgI.CurrentVer()) {
873          ToPkgI->CurrentVer = FromVerI.Index();
874          ToPkgI->SelectedState = pkgCache::State::Install;
875          ToPkgI->InstState = pkgCache::State::Ok;
876          ToPkgI->CurrentState = pkgCache::State::Installed;
877       }
878
879       // Move the iterator before reseting the NextVer.
880       pkgCache::Version *FromVer = (pkgCache::Version*)FromVerI;
881       FromVerI++;
882       FromVer->NextVer = 0;
883    }
884
885    // Reset original package data.
886    FromPkgI->CurrentVer = 0;
887    FromPkgI->VersionList = 0;
888    FromPkgI->Section = 0;
889    FromPkgI->SelectedState = 0;
890    FromPkgI->InstState = 0;
891    FromPkgI->CurrentState = 0;
892 }
893
894 #endif /* HAVE_RPM */
895
896 // vim:sts=3:sw=3