a2c5ba5413922ba56499c060e83ec2606fce458c
[apt.git] / apt-pkg / rpm / rpmindexfile.cc
1 // -*- mode: c++; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: rpmindexfile.cc,v 1.4 2002/11/27 16:22:40 niemeyer Exp $
4 /* ######################################################################
5
6    RPM Specific sources.list types and the three sorts of RPM
7    index files.
8    
9    ##################################################################### */
10                                                                         /*}}}*/
11 // Include Files                                                        /*{{{*/
12 #ifdef __GNUG__
13 #pragma implementation "apt-pkg/rpmindexfile.h"
14 #endif
15
16 #include <config.h>
17
18 #ifdef HAVE_RPM
19
20 #include <cassert>
21
22 #include <apt-pkg/rpmindexfile.h>
23 #include <apt-pkg/rpmsrcrecords.h>
24 #include <apt-pkg/rpmlistparser.h>
25 #include <apt-pkg/rpmrecords.h>
26 #include <apt-pkg/rpmsystem.h>
27 #include <apt-pkg/rpmhandler.h>
28 #include <apt-pkg/rpmpackagedata.h>
29 #include <apt-pkg/sourcelist.h>
30 #include <apt-pkg/configuration.h>
31 #include <apt-pkg/progress.h>
32 #include <apt-pkg/error.h>
33 #include <apt-pkg/strutl.h>
34 #include <apt-pkg/acquire-item.h>
35 #include <apt-pkg/repomd.h>
36
37 #include <apti18n.h>
38
39 #include <sys/stat.h>
40                                                                         /*}}}*/
41 vector<pkgRepository *> RepList;
42
43 // Hack to avoid potentially very expensive CreateHandler() calls from
44 // indexfile progress reporting. It's only used for progress so it doesn't
45 // really matter if it's even accurate. 
46 map<string,int> rpmIndexSizes;
47
48 off_t rpmIndexFile::Size() const
49 {
50    off_t Res;
51    string IP = IndexPath();
52
53    if (rpmIndexSizes.find(IP) == rpmIndexSizes.end()) {
54       RPMHandler *Handler = CreateHandler();
55       Res = Handler->Size();
56       delete Handler;
57    } else {
58       Res = rpmIndexSizes[IP];
59    }
60    return Res;
61 }
62
63 // rpmListIndex::Release* - Return the URI to the release file          /*{{{*/
64 // ---------------------------------------------------------------------
65 /* */
66 inline string rpmListIndex::ReleaseFile(string Type) const
67 {
68    return URItoFileName(ReleaseURI(Type));
69 }
70
71 string rpmListIndex::ReleaseURI(string Type) const
72 {
73    RPMPackageData *rpmdata = RPMPackageData::Singleton();
74    string Res;
75    if (Dist[Dist.size() - 1] == '/')
76    {
77       if (Dist != "/")
78          Res = URI + Dist;
79       else
80          Res = URI;
81    }
82    else
83       Res = URI + Dist + "/base/";
84
85    Res += Type;
86    
87    if (rpmdata->HasIndexTranslation() == true)
88    {
89       map<string,string> Dict;
90       Dict["uri"] = URI;
91       Dict["dist"] = Dist;
92       Dict["sect"] = "";
93       Dict["type"] = Type;
94       rpmdata->TranslateIndex(Res, Dict);
95    }
96
97    return Res;
98 }
99                                                                         /*}}}*/
100 // rpmListIndex::ReleaseInfo - One liner describing the index URI       /*{{{*/
101 // ---------------------------------------------------------------------
102 /* */
103 string rpmListIndex::ReleaseInfo(string Type) const 
104 {
105    string Info = ::URI::SiteOnly(URI) + ' ';
106    if (Dist[Dist.size() - 1] == '/')
107    {
108       if (Dist != "/")
109          Info += Dist;
110    }
111    else
112       Info += Dist;   
113    Info += " ";
114    Info += Type;
115    return Info;
116 }
117                                                                         /*}}}*/
118 // rpmListIndex::GetReleases - Fetch the index files                    /*{{{*/
119 // ---------------------------------------------------------------------
120 /* */
121 bool rpmListIndex::GetReleases(pkgAcquire *Owner) const
122 {
123    if (!Repository->Acquire)
124       return true;
125    Repository->Acquire = false;
126    new pkgAcqIndexRel(Owner,Repository,ReleaseURI("release"),
127                       ReleaseInfo("release"), "release", true);
128    return true;
129 }
130                                                                         /*}}}*/
131 // rpmListIndex::Info - One liner describing the index URI              /*{{{*/
132 // ---------------------------------------------------------------------
133 /* */
134 string rpmListIndex::Info(string Type) const 
135 {
136    string Info = ::URI::SiteOnly(URI) + ' ';
137    if (Dist[Dist.size() - 1] == '/')
138    {
139       if (Dist != "/")
140          Info += Dist;
141    }
142    else
143       Info += Dist + '/' + Section;   
144    Info += " ";
145    Info += Type;
146    return Info;
147 }
148                                                                         /*}}}*/
149 // rpmListIndex::Index* - Return the URI to the index files             /*{{{*/
150 // ---------------------------------------------------------------------
151 /* */
152 inline string rpmListIndex::IndexFile(string Type) const
153 {
154    return _config->FindDir("Dir::State::lists") +
155           URItoFileName(IndexURI(Type));
156 }
157
158
159 string rpmListIndex::IndexURI(string Type) const
160 {
161    RPMPackageData *rpmdata = RPMPackageData::Singleton();
162    string Res;
163    if (Dist[Dist.size() - 1] == '/')
164    {
165       if (Dist != "/")
166          Res = URI + Dist;
167       else 
168          Res = URI;
169    }
170    else
171       Res = URI + Dist + "/base/";
172    
173    Res += Type + '.' + Section;
174
175    if (rpmdata->HasIndexTranslation() == true)
176    {
177       map<string,string> Dict;
178       Dict["uri"] = URI;
179       Dict["dist"] = Dist; 
180       Dict["sect"] = Section;
181       Dict["type"] = Type;
182       rpmdata->TranslateIndex(Res, Dict);
183    }
184
185    return Res;
186 }
187                                                                         /*}}}*/
188 // rpmListIndex::Exists - Check if the index is available               /*{{{*/
189 // ---------------------------------------------------------------------
190 /* */
191 bool rpmListIndex::Exists() const
192 {
193    return FileExists(IndexPath());
194 }
195                                                                         /*}}}*/
196 // rpmListIndex::Describe - Give a descriptive path to the index        /*{{{*/
197 // ---------------------------------------------------------------------
198 /* */
199 string rpmListIndex::Describe(bool Short) const
200 {
201    char S[300];
202    if (Short == true)
203       snprintf(S,sizeof(S),"%s",Info(MainType()).c_str());
204    else
205       snprintf(S,sizeof(S),"%s (%s)",Info(MainType()).c_str(),
206          IndexFile(MainType()).c_str());
207    return S;
208 }
209                                                                         /*}}}*/
210
211 // SrcListIndex::SourceInfo - Short 1 liner describing a source         /*{{{*/
212 // ---------------------------------------------------------------------
213 string rpmSrcListIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
214                                    pkgSrcRecords::File const &File) const
215 {
216    string Res;
217    Res = ::URI::SiteOnly(URI) + ' ';
218    if (Dist[Dist.size() - 1] == '/')
219    {
220       if (Dist != "/")
221          Res += Dist;
222    }      
223    else
224       Res += Dist + '/' + Section;
225    
226    Res += " ";
227    Res += Record.Package();
228    Res += " ";
229    Res += Record.Version();
230    if (File.Type.empty() == false)
231       Res += " (" + File.Type + ")";
232    return Res;
233 }
234                                                                         /*}}}*/
235 // SrcListIndex::ArchiveURI - URI for the archive                       /*{{{*/
236 // ---------------------------------------------------------------------
237 string rpmSrcListIndex::ArchiveURI(string File) const
238 {
239    RPMPackageData *rpmdata = RPMPackageData::Singleton();
240    string Res;
241    
242    if (Dist[Dist.size() - 1] == '/')
243    {
244       if (Dist != "/")
245          Res = URI + Dist;
246       else
247          Res = URI;
248    }
249    else
250       Res = URI + Dist;
251    
252    if (File.find("/") != string::npos)
253       Res += '/' + File;
254    else
255       Res += "/SRPMS."+Section + '/' + File;
256
257    if (rpmdata->HasSourceTranslation() == true)
258    {
259       map<string,string> Dict;
260       Dict["uri"] = URI;
261       Dict["dist"] = Dist; 
262       Dict["sect"] = Section;
263       string::size_type pos = File.rfind("/");
264       if (pos != string::npos)
265          Dict["file"] = string(File, pos+1);
266       else
267          Dict["file"] = File;
268       
269       rpmdata->TranslateSource(Res, Dict);
270    }
271          
272    return Res;
273 }
274                                                                         /*}}}*/
275 // SrcListIndex::CreateSrcParser - Get a parser for the source files    /*{{{*/
276 // ---------------------------------------------------------------------
277 /* */
278 pkgSrcRecords::Parser *rpmSrcListIndex::CreateSrcParser() const
279 {
280    return new rpmSrcRecordParser(IndexPath(), this);
281 }
282                                                                         /*}}}*/
283 // SrcListIndex::GetIndexes - Fetch the index files                     /*{{{*/
284 // ---------------------------------------------------------------------
285 /* */
286 bool rpmSrcListIndex::GetIndexes(pkgAcquire *Owner) const
287 {
288    // Ignore indexes for repositories that could not be authenticated
289    if (Repository->IsAuthenticated() == true && 
290        Repository->HasRelease() == false)
291       return true;
292    new pkgAcqIndex(Owner,Repository,IndexURI("srclist"),Info("srclist"),
293                    "srclist");
294    return true;
295 }
296                                                                         /*}}}*/
297
298 // PkgListIndex::ArchiveInfo - Short version of the archive url         /*{{{*/
299 // ---------------------------------------------------------------------
300 /* This is a shorter version that is designed to be < 60 chars or so */
301 string rpmPkgListIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
302 {
303    string Res = ::URI::SiteOnly(URI) + ' ';
304    if (Dist[Dist.size() - 1] == '/')
305    {
306       if (Dist != "/")
307          Res += Dist;
308    }
309    else
310       Res += Dist + '/' + Section;
311    
312    Res += " ";
313    Res += Ver.ParentPkg().Name();
314    Res += " ";
315    Res += Ver.VerStr();
316    return Res;
317 }
318                                                                         /*}}}*/
319 // PkgListIndex::ArchiveURI - URI for the archive                       /*{{{*/
320 // ---------------------------------------------------------------------
321 string rpmPkgListIndex::ArchiveURI(string File) const
322 {
323    RPMPackageData *rpmdata = RPMPackageData::Singleton();
324    string Res;
325    if (Dist[Dist.size() - 1] == '/')
326    {
327       if (Dist != "/")
328          Res = URI + Dist;
329       else
330          Res = URI;
331    }
332    else
333       Res = URI + Dist;
334
335    if (File.find("/") != string::npos)
336       Res += '/' + File;
337    else
338       Res += "/RPMS." + Section + '/' + File;
339
340    if (rpmdata->HasBinaryTranslation() == true)
341    {
342       map<string,string> Dict;
343       Dict["uri"] = URI;
344       Dict["dist"] = Dist; 
345       Dict["sect"] = Section;
346       string::size_type pos = File.rfind("/");
347       if (pos != string::npos)
348          Dict["file"] = string(File, pos+1);
349       else
350          Dict["file"] = File;
351       rpmdata->TranslateBinary(Res, Dict);
352    }
353          
354    return Res;
355 }
356                                                                         /*}}}*/
357 // PkgListIndex::GetIndexes - Fetch the index files                     /*{{{*/
358 // ---------------------------------------------------------------------
359 /* */
360 bool rpmPkgListIndex::GetIndexes(pkgAcquire *Owner) const
361 {
362    // Ignore indexes for repositories that could not be authenticated
363    if (Repository->IsAuthenticated() == true && 
364        Repository->HasRelease() == false)
365       return true;
366    new pkgAcqIndex(Owner,Repository,IndexURI("pkglist"),Info("pkglist"),
367                    "pkglist");
368    new pkgAcqIndexRel(Owner,Repository,IndexURI("release"),Info("release"),
369                       "release");
370    return true;
371 }
372                                                                         /*}}}*/
373 // PkgListIndex::Merge - Load the index file into a cache               /*{{{*/
374 // ---------------------------------------------------------------------
375 /* */
376 bool rpmPkgListIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
377 {
378    string PackageFile = IndexPath();
379    RPMHandler *Handler = CreateHandler();
380
381    Prog.SubProgress(0,Info("primary"));
382    ::URI Tmp(URI);
383    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
384    {
385       delete Handler;
386       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
387    }
388
389    // Store the IMS information
390    pkgCache::PkgFileIterator File = Gen.GetCurFile();
391    struct stat St;
392    if (stat(PackageFile.c_str(),&St) != 0) 
393    {
394       delete Handler;
395       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
396    }
397    File->Size = St.st_size;
398    File->mtime = St.st_mtime;
399    
400    rpmListParser Parser(Handler);
401    if (_error->PendingError() == true) 
402    {
403       delete Handler;
404       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
405    }
406    
407    if (Gen.MergeList(Parser) == false)
408    {
409       delete Handler;
410       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
411    }
412    
413    delete Handler;
414
415    // Check the release file
416    string RelFile = ReleasePath();
417    if (FileExists(RelFile) == true)
418    {
419       FileFd Rel(RelFile,FileFd::ReadOnly);
420       if (_error->PendingError() == true)
421          return false;
422       Parser.LoadReleaseInfo(File,Rel);
423       Rel.Seek(0);
424    }
425
426    return true;
427 }
428                                                                         /*}}}*/
429 // PkgListIndex::MergeFileProvides - Process file dependencies if any   /*{{{*/
430 // ---------------------------------------------------------------------
431 /* */
432 bool rpmPkgListIndex::MergeFileProvides(pkgCacheGenerator &Gen,
433                                         OpProgress &Prog) const
434 {
435    string PackageFile = IndexPath();
436    RPMHandler *Handler = CreateHandler();
437    rpmListParser Parser(Handler);
438    if (_error->PendingError() == true) {
439       delete Handler;
440       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
441    }
442    // We call SubProgress with Size(), since we won't call SelectFile() here.
443    Prog.SubProgress(Size(),Info("pkglist"));
444    if (Gen.MergeFileProvides(Parser) == false)
445       return _error->Error(_("Problem with MergeFileProvides %s"),
446                            PackageFile.c_str());
447    delete Handler;
448    return true;
449 }
450                                                                         /*}}}*/
451 // PkgListIndex::FindInCache - Find this index                          /*{{{*/
452 // ---------------------------------------------------------------------
453 /* */
454 pkgCache::PkgFileIterator rpmPkgListIndex::FindInCache(pkgCache &Cache) const
455 {
456    string FileName = IndexPath();
457    pkgCache::PkgFileIterator File = Cache.FileBegin();
458    for (; File.end() == false; File++)
459    {
460       if (FileName != File.FileName())
461          continue;
462       
463       struct stat St;
464       if (stat(File.FileName(),&St) != 0)
465          return pkgCache::PkgFileIterator(Cache);
466
467       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
468          return pkgCache::PkgFileIterator(Cache);
469       return File;
470    }
471    
472    return File;
473 }
474                                                                         /*}}}*/
475
476 // PkgDirIndex::Index* - Return the URI to the index files              /*{{{*/
477 // ---------------------------------------------------------------------
478 /* */
479 string rpmPkgDirIndex::IndexPath() const
480 {
481    return ::URI(ArchiveURI("")).Path;
482 }
483                                                                         /*}}}*/
484 // PkgDirIndex::Release* - Return the URI to the index files            /*{{{*/
485 // ---------------------------------------------------------------------
486 /* */
487 string rpmPkgDirIndex::ReleasePath() const
488 {
489    return ::URI(IndexURI("release")).Path;
490 }
491                                                                         /*}}}*/
492 // SrcDirIndex::Index* - Return the URI to the index files              /*{{{*/
493 // ---------------------------------------------------------------------
494 /* */
495 string rpmSrcDirIndex::IndexPath() const
496 {
497    return ::URI(ArchiveURI("")).Path;
498 }
499                                                                         /*}}}*/
500
501 // SinglePkgIndex::ArchiveURI - URI for the archive                     /*{{{*/
502 // ---------------------------------------------------------------------
503 string rpmSinglePkgIndex::ArchiveURI(string File) const
504 {
505    char *cwd = getcwd(NULL,0);
506    if (File[0] == '.' && File[1] == '/')
507       File = string(File, 2);
508    string URI = "file://"+flCombine(cwd, File);
509    free(cwd);
510    return URI;
511 }
512                                                                         /*}}}*/
513 // SinglePkgIndex::ArchiveURI - URI for the archive                     /*{{{*/
514 // ---------------------------------------------------------------------
515 string rpmSingleSrcIndex::ArchiveURI(string File) const
516 {
517    char *cwd = getcwd(NULL,0);
518    if (File[0] == '.' && File[1] == '/')
519       File = string(File, 2);
520    string URI = "file://"+flCombine(cwd, File);
521    free(cwd);
522    return URI;
523 }
524
525 #ifdef APT_WITH_REPOMD
526 string rpmRepomdIndex::ArchiveURI(string File) const
527 {
528    string Res;
529
530    Res += URI + '/' + Dist + '/' + File;
531    return Res;
532 }
533
534 bool rpmRepomdIndex::HasDBExtension() const
535 {
536 #ifdef WITH_SQLITE3
537    if (! Repository->FindURI("primary_db").empty() && 
538        _config->FindB("Acquire::RepoMD::NoDB", false) == false) {
539       return true;
540    } 
541 #endif
542    return false;
543 }
544
545 string rpmRepomdIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
546 {
547    string Res = ::URI::SiteOnly(URI) + ' ';
548    if (Dist[Dist.size() - 1] == '/')
549    {
550       if (Dist != "/")
551          Res += Dist;
552    }
553    else
554       Res += Dist + '/';
555    
556    Res += " ";
557    Res += Ver.ParentPkg().Name();
558    Res += " ";
559    Res += Ver.VerStr();
560    return Res;
561 }
562 pkgCache::PkgFileIterator rpmRepomdIndex::FindInCache(pkgCache &Cache) const
563 {
564    string FileName = IndexPath();
565    pkgCache::PkgFileIterator File = Cache.FileBegin();
566    for (; File.end() == false; File++)
567    {
568       if (FileName != File.FileName())
569          continue;
570       
571       struct stat St;
572       if (stat(File.FileName(),&St) != 0)
573          return pkgCache::PkgFileIterator(Cache);
574
575       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
576          return pkgCache::PkgFileIterator(Cache);
577       return File;
578    }
579    
580    return File;
581 }
582 string rpmRepomdIndex::ReleaseURI(string Type) const
583 {
584    string Res = URI + Dist;
585    assert( Res.size() > 0 );
586    if ( Res[Res.size() - 1] != '/' )
587      Res += '/';
588    Res += "repodata/";
589    Res += "repomd.xml";
590    return Res;
591 }
592
593 string rpmRepomdIndex::ReleaseInfo(string Type) const
594 {
595    string Info = ::URI::SiteOnly(URI) + ' ';
596    assert( Dist.size() > 0 );
597    if (Dist[Dist.size() - 1] == '/')
598    {
599       if (Dist != "/")
600          Info += Dist;
601    }
602    else
603       Info += Dist;   
604    Info += " ";
605    Info += Type;
606    return Info;
607 }
608
609 string rpmRepomdIndex::Info(string Type) const 
610 {
611    string Info = ::URI::SiteOnly(URI) + ' ';
612    string File;
613    assert( Dist.size() > 0 );
614    if (Dist[Dist.size() - 1] == '/')
615    {
616       if (Dist != "/")
617          Info += Dist;
618    }
619    else
620       Info += Dist + '/' ;   
621    Info += " ";
622    Info += flNotDir(Repository->FindURI(Type));
623    return Info;
624 }
625
626 string rpmRepomdIndex::IndexURI(string Type) const
627 {
628    string Res = URI + Dist;
629    assert( Dist.size() > 0 );
630    if (Dist[Dist.size() - 1] != '/') {
631          Res += "/";
632    }
633    string TypeURI = Repository->FindURI(Type);
634    if (! TypeURI.empty()) {
635       Res += TypeURI;
636    } else {
637       Res = "";
638    }
639    assert(Res.size() > 0);
640    return Res;
641 }
642
643 string rpmRepomdIndex::AutoType(string Type) const
644 {
645    if (HasDBExtension()) {
646       return Type + "_db";
647    }
648    return Type;
649 }
650
651 bool rpmRepomdIndex::GetReleases(pkgAcquire *Owner) const
652 {
653    if (!Repository->Acquire)
654       return true;
655    Repository->Acquire = false;
656    new pkgAcqIndexRel(Owner,Repository,ReleaseURI("repomd.xml"),
657                       ReleaseInfo("repomd.xml"), "repomd.xml", true);
658    return true;
659 }
660
661 bool rpmRepomdIndex::GetIndexes(pkgAcquire *Owner) const
662 {
663    bool AcqOther = _config->FindB("Acquire::RepoMD::OtherData", false);
664    bool AcqGroup = _config->FindB("Acquire::RepoMD::Group", false);
665    bool Res = false;
666    if (Repository->FindURI("primary").empty()) {
667       return _error->Error(_("Primary metadata not found in repository %s %s"),
668                         Repository->URI.c_str(), Repository->Dist.c_str());
669    }
670
671    new pkgAcqIndex(Owner,Repository,IndexURI(AutoType("primary")),
672                    Info(AutoType("primary")), "primary");
673    new pkgAcqIndex(Owner,Repository,IndexURI(AutoType("filelists")),
674                    Info(AutoType("filelists")), "filelists");
675    if (AcqOther) {
676       new pkgAcqIndex(Owner,Repository,IndexURI(AutoType("other")),
677                      Info(AutoType("other")), "other");
678    }
679
680    if (Res && AcqGroup) {
681       if (! Repository->FindURI("group").empty()) {
682          new pkgAcqIndex(Owner,Repository,IndexURI("group"),
683                            ReleaseInfo("comps.xml"), "comps.xml");
684       }
685    }
686    return true;
687 }
688
689 string rpmRepomdIndex::Describe(bool Short) const
690 {
691    char S[300];
692    if (Short == true)
693       snprintf(S,sizeof(S),"%s",Info(MainType()).c_str());
694    else
695       snprintf(S,sizeof(S),"%s (%s)",Info(MainType()).c_str(),
696          IndexFile(MainType()).c_str());
697    return S;
698 }
699
700 string rpmRepomdIndex::IndexPath() const
701 {
702    return IndexFile("primary");
703 }
704
705 string rpmRepomdIndex::IndexFile(string Type) const
706 {
707    return _config->FindDir("Dir::State::lists") +
708           URItoFileName(IndexURI(AutoType(Type)));
709 }
710
711
712 bool rpmRepomdIndex::Exists() const
713 {
714    /* repomd requires release to be present to find any other files */
715    if (!FileExists(ReleasePath())) {
716       return false;
717    }
718    return FileExists(IndexPath());
719 }
720
721 string rpmRepomdIndex::ReleasePath() const
722 {
723    return _config->FindDir("Dir::State::lists") +
724           URItoFileName(ReleaseURI("repomd.xml"));
725 }
726
727 RPMHandler* rpmRepomdIndex::CreateHandler() const
728 {
729    string TypeURI;
730 #if WITH_SQLITE3
731    if (HasDBExtension()) {
732       return new RPMSqliteHandler(IndexFile("primary"));
733    }
734 #endif
735    return new RPMRepomdHandler(IndexFile("primary"));
736
737
738 bool rpmRepomdIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
739 {
740    string PackageFile = IndexPath();
741    RPMHandler *Handler = CreateHandler();
742
743    Prog.SubProgress(0,Info("primary"));
744    ::URI Tmp(URI);
745    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
746    {
747       delete Handler;
748       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
749    }
750
751    // Store the IMS information
752    pkgCache::PkgFileIterator File = Gen.GetCurFile();
753    struct stat St;
754    if (stat(PackageFile.c_str(),&St) != 0) 
755    {
756       delete Handler;
757       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
758    }
759    File->Size = St.st_size;
760    File->mtime = St.st_mtime;
761    
762    rpmRepomdParser Parser(Handler);
763    if (_error->PendingError() == true) 
764    {
765       delete Handler;
766       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
767    }
768    
769    if (Gen.MergeList(Parser) == false)
770    {
771       delete Handler;
772       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
773    }
774    
775    delete Handler;
776
777    // Check the release file
778    string RelFile = ReleasePath();
779    if (FileExists(RelFile) == true)
780    {
781       Parser.LoadReleaseInfo(File,RelFile,Dist);
782    }
783
784    return true;
785 }
786
787 bool rpmRepomdIndex::MergeFileProvides(pkgCacheGenerator &Gen,
788                                         OpProgress &Prog) const
789 {
790    string PackageFile = IndexPath();
791    RPMHandler *Handler = NULL;
792    if (HasDBExtension()) {
793       Handler = CreateHandler();
794    } else {
795       Handler = new RPMRepomdFLHandler(IndexFile("filelists"));
796    }
797    rpmListParser Parser(Handler);
798    if (_error->PendingError() == true) {
799       delete Handler;
800       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
801    }
802    // We call SubProgress with Size(), since we won't call SelectFile() here.
803    Prog.SubProgress(Size(),Info("pkglist"));
804    if (Gen.MergeFileProvides(Parser) == false)
805       return _error->Error(_("Problem with MergeFileProvides %s"),
806                            PackageFile.c_str());
807    delete Handler;
808    return true;
809 }
810
811 rpmRepomdIndex::rpmRepomdIndex(string URI,string Dist,string Section, 
812                                pkgRepository *Repository):
813                                URI(URI), Dist(Dist), Section(Section),
814                                Repository(Repository)   
815 {
816    if (FileExists(ReleasePath())) {
817       Repository->ParseRelease(ReleasePath());
818    }
819 }
820
821 pkgSrcRecords::Parser *rpmRepomdIndex::CreateSrcParser() const
822 {
823    return new rpmSrcRecordParser(IndexPath(), this);
824 }
825
826 string rpmRepomdSrcIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
827                                      pkgSrcRecords::File const &File) const
828 {
829    string Res;
830    Res = ::URI::SiteOnly(URI) + ' ';
831    if (Dist[Dist.size() - 1] == '/')
832    {
833       if (Dist != "/")
834          Res += Dist;
835    }      
836    else
837       Res += Dist + '/' + Section;
838    
839    Res += " ";
840    Res += Record.Package();
841    Res += " ";
842    Res += Record.Version();
843    if (File.Type.empty() == false)
844       Res += " (" + File.Type + ")";
845    return Res;
846 }
847
848 #endif /* APT_WITH_REPOMD */
849
850 // DatabaseIndex::rpmDatabaseIndex - Constructor                        /*{{{*/
851 // ---------------------------------------------------------------------
852 /* */
853 rpmDatabaseIndex::rpmDatabaseIndex()
854 {
855 }
856                                                                         /*}}}*/
857
858 string rpmDatabaseIndex::IndexPath() const
859 {
860    return rpmSys.GetDBHandler()->DataPath(false);
861 }
862
863 // DatabaseIndex::Size - Return the size of the index                   /*{{{*/
864 // ---------------------------------------------------------------------
865 /* */
866 off_t rpmDatabaseIndex::Size() const
867 {
868    return rpmSys.GetDBHandler()->Size();
869 }
870                                                                         /*}}}*/
871 // DatabaseIndex::CreateHandler - Create a RPMHandler for this file     /*{{{*/
872 // ---------------------------------------------------------------------
873 RPMHandler *rpmDatabaseIndex::CreateHandler() const
874 {
875    return rpmSys.GetDBHandler();
876 }
877                                                                         /*}}}*/
878 // DatabaseIndex::Merge - Load the index file into a cache              /*{{{*/
879 // ---------------------------------------------------------------------
880 /* */
881 bool rpmDatabaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
882 {
883    RPMDBHandler *Handler = rpmSys.GetDBHandler();
884    rpmListParser Parser(Handler);
885    if (_error->PendingError() == true)
886       return _error->Error(_("Problem opening RPM database"));
887    
888    Prog.SubProgress(0,"RPM Database");
889    if (Gen.SelectFile(Handler->DataPath(false),string(),*this,pkgCache::Flag::NotSource) == false)
890       return _error->Error(_("Problem with SelectFile RPM Database"));
891
892    // Store the IMS information
893    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
894    struct stat St;
895    if (stat(Handler->DataPath(false).c_str(),&St) != 0)
896       return _error->Errno("fstat",_("Failed to stat %s"), Handler->DataPath(false).c_str());
897    CFile->Size = St.st_size;
898    CFile->mtime = Handler->Mtime();
899    
900    if (Gen.MergeList(Parser) == false)
901       return _error->Error(_("Problem with MergeList %s"),
902                            Handler->DataPath(false).c_str());
903    return true;
904 }
905                                                                         /*}}}*/
906 // DatabaseIndex::MergeFileProvides - Process file dependencies if any  /*{{{*/
907 // ---------------------------------------------------------------------
908 /* */
909 bool rpmDatabaseIndex::MergeFileProvides(pkgCacheGenerator &Gen,
910                                          OpProgress &Prog) const
911 {
912    RPMDBHandler *Handler = rpmSys.GetDBHandler();
913    rpmListParser Parser(Handler);
914    if (_error->PendingError() == true)
915       return _error->Error(_("Problem opening RPM database"));
916    // We call SubProgress with Size(), since we won't call SelectFile() here.
917    Prog.SubProgress(Size(),"RPM Database");
918    if (Gen.MergeFileProvides(Parser) == false)
919       return _error->Error(_("Problem with MergeFileProvides %s"),
920                            Handler->DataPath(false).c_str());
921    return true;
922 }
923                                                                         /*}}}*/
924 // DatabaseIndex::FindInCache - Find this index                         /*{{{*/
925 // ---------------------------------------------------------------------
926 /* */
927 pkgCache::PkgFileIterator rpmDatabaseIndex::FindInCache(pkgCache &Cache) const
928 {
929    pkgCache::PkgFileIterator File = Cache.FileBegin();
930    for (; File.end() == false; File++)
931    {
932       if (rpmSys.GetDBHandler()->DataPath(false) != File.FileName())
933          continue;
934       struct stat St;
935       if (stat(File.FileName(),&St) != 0)
936          return pkgCache::PkgFileIterator(Cache);
937       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
938          return pkgCache::PkgFileIterator(Cache);
939       return File;
940    }   
941    return File;
942 }
943                                                                         /*}}}*/
944
945 // Source List types for rpm                                            /*{{{*/
946
947 class rpmSLTypeGen : public pkgSourceList::Type
948 {
949    public:
950
951    rpmSLTypeGen()
952    {
953       Name = "rpm";
954       Label = "Standard RPM source tree";
955    }   
956
957    pkgRepository *FindRepository(string URI,string Dist,
958                                  const pkgSourceList::Vendor *Vendor) const
959    {
960       for (vector<pkgRepository *>::const_iterator iter = RepList.begin();
961            iter != RepList.end(); iter++) 
962       {
963          if ((*iter)->URI == URI && (*iter)->Dist == Dist) 
964          {       
965             if (Vendor != NULL)
966                (*iter)->FingerPrint = Vendor->FingerPrint;
967             return *iter;
968          }
969       }
970       return NULL;
971    }
972
973    pkgRepository *GetRepository(string URI,string Dist,
974                                 const pkgSourceList::Vendor *Vendor) const
975    {
976       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
977       if (Rep != NULL)
978          return Rep;
979
980       string BaseURI;
981       if (Dist[Dist.size() - 1] == '/')
982       {
983          if (Dist != "/")
984             BaseURI = URI + Dist;
985          else 
986             BaseURI = URI + '/';
987       }
988       else
989          BaseURI = URI + Dist + '/';
990
991       Rep = new pkgRepository(URI,Dist,Vendor,BaseURI);
992       RepList.push_back(Rep);
993       return Rep;
994    }
995 };
996
997
998 class rpmSLTypeRpm : public rpmSLTypeGen
999 {
1000    public:
1001
1002    bool CreateItem(vector<pkgIndexFile *> &List,
1003                    string URI, string Dist, string Section,
1004                    pkgSourceList::Vendor const *Vendor) const 
1005    {
1006       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1007       List.push_back(new rpmPkgListIndex(URI,Dist,Section,Rep));
1008       return true;
1009    };
1010
1011    rpmSLTypeRpm()
1012    {
1013       Name = "rpm";
1014       Label = "Standard RPM binary tree";
1015    }   
1016 };
1017
1018 class rpmSLTypeSrpm : public rpmSLTypeGen
1019 {
1020    public:
1021
1022    bool CreateItem(vector<pkgIndexFile *> &List,
1023                    string URI, string Dist, string Section,
1024                    pkgSourceList::Vendor const *Vendor) const 
1025    {
1026       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1027       List.push_back(new rpmSrcListIndex(URI,Dist,Section,Rep));
1028       return true;
1029    };  
1030    
1031    rpmSLTypeSrpm()
1032    {
1033       Name = "rpm-src";
1034       Label = "Standard RPM source tree";
1035    }   
1036 };
1037
1038 class rpmSLTypeRpmDir : public rpmSLTypeGen
1039 {
1040    public:
1041
1042    bool CreateItem(vector<pkgIndexFile *> &List,
1043                    string URI, string Dist, string Section,
1044                    pkgSourceList::Vendor const *Vendor) const 
1045    {
1046       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1047       List.push_back(new rpmPkgDirIndex(URI,Dist,Section,Rep));
1048       return true;
1049    };
1050
1051    rpmSLTypeRpmDir()
1052    {
1053       Name = "rpm-dir";
1054       Label = "Local RPM directory tree";
1055    }   
1056 };
1057
1058 class rpmSLTypeSrpmDir : public rpmSLTypeGen
1059 {
1060    public:
1061
1062    bool CreateItem(vector<pkgIndexFile *> &List,
1063                    string URI, string Dist, string Section,
1064                    pkgSourceList::Vendor const *Vendor) const 
1065    {
1066       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1067       List.push_back(new rpmSrcDirIndex(URI,Dist,Section,Rep));
1068       return true;
1069    };
1070
1071    rpmSLTypeSrpmDir()
1072    {
1073       Name = "rpm-src-dir";
1074       Label = "Local SRPM directory tree";
1075    }   
1076 };
1077
1078 #ifdef APT_WITH_REPOMD
1079 class rpmSLTypeRepomd : public rpmSLTypeGen
1080 {
1081    public:
1082
1083    pkgRepository *GetRepository(string URI,string Dist,
1084                                 const pkgSourceList::Vendor *Vendor) const
1085    {
1086       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
1087       if (Rep != NULL)
1088          return Rep;
1089
1090       string BaseURI;
1091       if (Dist[Dist.size() - 1] == '/')
1092       {
1093          if (Dist != "/")
1094             BaseURI = URI + Dist;
1095          else 
1096             BaseURI = URI + '/';
1097       }
1098       else
1099          BaseURI = URI + Dist + '/';
1100
1101       Rep = new repomdRepository(URI,Dist,Vendor,BaseURI);
1102       RepList.push_back(Rep);
1103       return Rep;
1104    }
1105
1106    bool CreateItem(vector<pkgIndexFile *> &List,
1107                    string URI, string Dist, string Section,
1108                    pkgSourceList::Vendor const *Vendor) const 
1109    {
1110       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1111       List.push_back(new rpmRepomdPkgIndex(URI,Dist,Section,Rep));
1112       return true;
1113    };
1114
1115    bool ParseLine(vector<pkgIndexFile *> &List,
1116                   pkgSourceList::Vendor const *Vendor,
1117                   const char *Buffer,
1118                   unsigned long CurLine,string File) const
1119    {
1120       string URI;
1121       string Dist;
1122       if (ParseQuoteWord(Buffer,URI) == false)
1123          return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
1124       if (ParseQuoteWord(Buffer,Dist) == false)
1125          return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
1126
1127       if (FixupURI(URI) == false)
1128          return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
1129       
1130       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
1131       Dist = SubstVar(Dist,"$(VERSION)",_config->Find("APT::DistroVersion"));
1132
1133       if (CreateItem(List,URI,Dist,"",Vendor) == false)
1134          return false;
1135
1136       return true;
1137    };
1138
1139
1140    rpmSLTypeRepomd()
1141    {
1142       Name = "repomd";
1143       Label = "RepoMD tree";
1144    }   
1145 };
1146 class rpmSLTypeRepomdSrc : public rpmSLTypeRepomd
1147 {
1148    public:
1149
1150    bool CreateItem(vector<pkgIndexFile *> &List,
1151                    string URI, string Dist, string Section,
1152                    pkgSourceList::Vendor const *Vendor) const 
1153    {
1154       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1155       List.push_back(new rpmRepomdSrcIndex(URI,Dist,Section,Rep));
1156       return true;
1157    };
1158
1159    rpmSLTypeRepomdSrc()
1160    {
1161       Name = "repomd-src";
1162       Label = "RepoMD src tree";
1163    }   
1164 };
1165
1166 #endif /* APT_WITH_REPOMD */
1167
1168 rpmSLTypeRpm _apt_rpmType;
1169 rpmSLTypeSrpm _apt_rpmSrcType;
1170 rpmSLTypeRpmDir _apt_rpmDirType;
1171 rpmSLTypeSrpmDir _apt_rpmSrcDirType;
1172 #ifdef APT_WITH_REPOMD
1173 rpmSLTypeRepomd _apt_repomdType;
1174 rpmSLTypeRepomdSrc _apt_repomdSrcType;
1175 #endif
1176                                                                         /*}}}*/
1177 // Index File types for rpm                                             /*{{{*/
1178 class rpmIFTypeSrc : public pkgIndexFile::Type
1179 {
1180    public:
1181    
1182    rpmIFTypeSrc() {Label = "RPM Source Index";};
1183 };
1184 class rpmIFTypePkg : public pkgIndexFile::Type
1185 {
1186    public:
1187    
1188    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1189    {
1190       return new rpmRecordParser(File.FileName(),*File.Cache());
1191    };
1192    rpmIFTypePkg() {Label = "RPM Package Index";};
1193 };
1194 class rpmIFTypeDatabase : public pkgIndexFile::Type
1195 {
1196    public:
1197    
1198    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1199    {
1200       return new rpmRecordParser(File.FileName(),*File.Cache());
1201    };
1202    rpmIFTypeDatabase() {Label = "RPM Database";};
1203 };
1204 static rpmIFTypeSrc _apt_Src;
1205 static rpmIFTypePkg _apt_Pkg;
1206 static rpmIFTypeDatabase _apt_DB;
1207
1208 const pkgIndexFile::Type *rpmSrcListIndex::GetType() const
1209 {
1210    return &_apt_Src;
1211 }
1212 const pkgIndexFile::Type *rpmPkgListIndex::GetType() const
1213 {
1214    return &_apt_Pkg;
1215 }
1216 const pkgIndexFile::Type *rpmSrcDirIndex::GetType() const
1217 {
1218    return &_apt_Src;
1219 }
1220 const pkgIndexFile::Type *rpmPkgDirIndex::GetType() const
1221 {
1222    return &_apt_Pkg;
1223 }
1224 const pkgIndexFile::Type *rpmSinglePkgIndex::GetType() const
1225 {
1226    return &_apt_Pkg;
1227 }
1228 const pkgIndexFile::Type *rpmSingleSrcIndex::GetType() const
1229 {
1230    return &_apt_Src;
1231 }
1232 const pkgIndexFile::Type *rpmDatabaseIndex::GetType() const
1233 {
1234    return &_apt_DB;
1235 }
1236 #ifdef APT_WITH_REPOMD
1237 const pkgIndexFile::Type *rpmRepomdPkgIndex::GetType() const
1238 {
1239    return &_apt_Pkg;
1240 }
1241 const pkgIndexFile::Type *rpmRepomdSrcIndex::GetType() const
1242 {
1243    return &_apt_Src;
1244 }
1245 #endif
1246
1247                                                                         /*}}}*/
1248 #endif /* HAVE_RPM */
1249
1250 // vim:sts=3:sw=3