Icky pooh.. partial revert of 64174eee41f502ed847e89fe52ba79311533e4f8
[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    if (! Repository->FindURI("primary_db").empty() && 
537        _config->FindB("Acquire::RepoMD::NoDB", false) == false) {
538       return true;
539    } 
540    return false;
541 }
542
543 string rpmRepomdIndex::ArchiveInfo(pkgCache::VerIterator Ver) const
544 {
545    string Res = ::URI::SiteOnly(URI) + ' ';
546    if (Dist[Dist.size() - 1] == '/')
547    {
548       if (Dist != "/")
549          Res += Dist;
550    }
551    else
552       Res += Dist + '/';
553    
554    Res += " ";
555    Res += Ver.ParentPkg().Name();
556    Res += " ";
557    Res += Ver.VerStr();
558    return Res;
559 }
560 pkgCache::PkgFileIterator rpmRepomdIndex::FindInCache(pkgCache &Cache) const
561 {
562    string FileName = IndexPath();
563    pkgCache::PkgFileIterator File = Cache.FileBegin();
564    for (; File.end() == false; File++)
565    {
566       if (FileName != File.FileName())
567          continue;
568       
569       struct stat St;
570       if (stat(File.FileName(),&St) != 0)
571          return pkgCache::PkgFileIterator(Cache);
572
573       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
574          return pkgCache::PkgFileIterator(Cache);
575       return File;
576    }
577    
578    return File;
579 }
580 string rpmRepomdIndex::ReleaseURI(string Type) const
581 {
582    string Res = URI + Dist;
583    assert( Res.size() > 0 );
584    if ( Res[Res.size() - 1] != '/' )
585      Res += '/';
586    Res += "repodata/";
587    Res += "repomd.xml";
588    return Res;
589 }
590
591 string rpmRepomdIndex::ReleaseInfo(string Type) const
592 {
593    string Info = ::URI::SiteOnly(URI) + ' ';
594    assert( Dist.size() > 0 );
595    if (Dist[Dist.size() - 1] == '/')
596    {
597       if (Dist != "/")
598          Info += Dist;
599    }
600    else
601       Info += Dist;   
602    Info += " ";
603    Info += Type;
604    return Info;
605 }
606
607 string rpmRepomdIndex::Info(string Type) const 
608 {
609    string Info = ::URI::SiteOnly(URI) + ' ';
610    string File;
611    assert( Dist.size() > 0 );
612    if (Dist[Dist.size() - 1] == '/')
613    {
614       if (Dist != "/")
615          Info += Dist;
616    }
617    else
618       Info += Dist + '/' ;   
619    Info += " ";
620    Info += flNotDir(Repository->FindURI(Type));
621    return Info;
622 }
623
624 string rpmRepomdIndex::IndexURI(string Type) const
625 {
626    string Res = URI + Dist;
627    assert( Dist.size() > 0 );
628    if (Dist[Dist.size() - 1] != '/') {
629          Res += "/";
630    }
631    string TypeURI = Repository->FindURI(Type);
632    if (! TypeURI.empty()) {
633       Res += TypeURI;
634    } else {
635       Res = "";
636    }
637    assert(Res.size() > 0);
638    return Res;
639 }
640
641 string rpmRepomdIndex::AutoType(string Type) const
642 {
643    if (HasDBExtension()) {
644       return Type + "_db";
645    }
646    return Type;
647 }
648
649 bool rpmRepomdIndex::GetReleases(pkgAcquire *Owner) const
650 {
651    if (!Repository->Acquire)
652       return true;
653    Repository->Acquire = false;
654    new pkgAcqIndexRel(Owner,Repository,ReleaseURI("repomd.xml"),
655                       ReleaseInfo("repomd.xml"), "repomd.xml", true);
656    return true;
657 }
658
659 bool rpmRepomdIndex::GetIndexes(pkgAcquire *Owner) const
660 {
661    bool AcqOther = _config->FindB("Acquire::RepoMD::OtherData", false);
662    bool AcqGroup = _config->FindB("Acquire::RepoMD::Group", false);
663    bool Res = false;
664    if (Repository->FindURI("primary").empty()) {
665       return _error->Error(_("Primary metadata not found in repository %s %s"),
666                         Repository->URI.c_str(), Repository->Dist.c_str());
667    }
668
669    new pkgAcqIndex(Owner,Repository,IndexURI(AutoType("primary")),
670                    Info(AutoType("primary")), "primary");
671    new pkgAcqIndex(Owner,Repository,IndexURI(AutoType("filelists")),
672                    Info(AutoType("filelists")), "filelists");
673    if (AcqOther) {
674       new pkgAcqIndex(Owner,Repository,IndexURI(AutoType("other")),
675                      Info(AutoType("other")), "other");
676    }
677
678    if (Res && AcqGroup) {
679       if (! Repository->FindURI("group").empty()) {
680          new pkgAcqIndex(Owner,Repository,IndexURI("group"),
681                            ReleaseInfo("comps.xml"), "comps.xml");
682       }
683    }
684    return true;
685 }
686
687 string rpmRepomdIndex::Describe(bool Short) const
688 {
689    char S[300];
690    if (Short == true)
691       snprintf(S,sizeof(S),"%s",Info(MainType()).c_str());
692    else
693       snprintf(S,sizeof(S),"%s (%s)",Info(MainType()).c_str(),
694          IndexFile(MainType()).c_str());
695    return S;
696 }
697
698 string rpmRepomdIndex::IndexPath() const
699 {
700    return IndexFile("primary");
701 }
702
703 string rpmRepomdIndex::IndexFile(string Type) const
704 {
705    return _config->FindDir("Dir::State::lists") +
706           URItoFileName(IndexURI(AutoType(Type)));
707 }
708
709
710 bool rpmRepomdIndex::Exists() const
711 {
712    return FileExists(IndexPath());
713 }
714
715 string rpmRepomdIndex::ReleasePath() const
716 {
717    return _config->FindDir("Dir::State::lists") +
718           URItoFileName(ReleaseURI("repomd.xml"));
719 }
720
721 RPMHandler* rpmRepomdIndex::CreateHandler() const
722 {
723    string TypeURI;
724    if (HasDBExtension()) {
725       return new RPMSqliteHandler(IndexFile("primary"));
726    } else {
727       return new RPMRepomdHandler(IndexFile("primary"));
728    }
729
730
731 bool rpmRepomdIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
732 {
733    string PackageFile = IndexPath();
734    RPMHandler *Handler = CreateHandler();
735
736    Prog.SubProgress(0,Info("primary"));
737    ::URI Tmp(URI);
738    if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false)
739    {
740       delete Handler;
741       return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str());
742    }
743
744    // Store the IMS information
745    pkgCache::PkgFileIterator File = Gen.GetCurFile();
746    struct stat St;
747    if (stat(PackageFile.c_str(),&St) != 0) 
748    {
749       delete Handler;
750       return _error->Errno("stat",_("Failed to stat %s"), PackageFile.c_str());
751    }
752    File->Size = St.st_size;
753    File->mtime = St.st_mtime;
754    
755    rpmRepomdParser Parser(Handler);
756    if (_error->PendingError() == true) 
757    {
758       delete Handler;
759       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
760    }
761    
762    if (Gen.MergeList(Parser) == false)
763    {
764       delete Handler;
765       return _error->Error(_("Problem with MergeList %s"),PackageFile.c_str());
766    }
767    
768    delete Handler;
769
770    // Check the release file
771    string RelFile = ReleasePath();
772    if (FileExists(RelFile) == true)
773    {
774       Parser.LoadReleaseInfo(File,RelFile,Dist);
775    }
776
777    return true;
778 }
779
780 bool rpmRepomdIndex::MergeFileProvides(pkgCacheGenerator &Gen,
781                                         OpProgress &Prog) const
782 {
783    string PackageFile = IndexPath();
784    RPMHandler *Handler = NULL;
785    if (HasDBExtension()) {
786       Handler = CreateHandler();
787    } else {
788       Handler = new RPMRepomdFLHandler(IndexFile("filelists"));
789    }
790    rpmListParser Parser(Handler);
791    if (_error->PendingError() == true) {
792       delete Handler;
793       return _error->Error(_("Problem opening %s"),PackageFile.c_str());
794    }
795    // We call SubProgress with Size(), since we won't call SelectFile() here.
796    Prog.SubProgress(Size(),Info("pkglist"));
797    if (Gen.MergeFileProvides(Parser) == false)
798       return _error->Error(_("Problem with MergeFileProvides %s"),
799                            PackageFile.c_str());
800    delete Handler;
801    return true;
802 }
803
804 rpmRepomdIndex::rpmRepomdIndex(string URI,string Dist,string Section, 
805                                pkgRepository *Repository):
806                                URI(URI), Dist(Dist), Section(Section),
807                                Repository(Repository)   
808 {
809    if (FileExists(ReleasePath())) {
810       Repository->ParseRelease(ReleasePath());
811    }
812 }
813
814 pkgSrcRecords::Parser *rpmRepomdIndex::CreateSrcParser() const
815 {
816    return new rpmSrcRecordParser(IndexPath(), this);
817 }
818
819 string rpmRepomdSrcIndex::SourceInfo(pkgSrcRecords::Parser const &Record,
820                                      pkgSrcRecords::File const &File) const
821 {
822    string Res;
823    Res = ::URI::SiteOnly(URI) + ' ';
824    if (Dist[Dist.size() - 1] == '/')
825    {
826       if (Dist != "/")
827          Res += Dist;
828    }      
829    else
830       Res += Dist + '/' + Section;
831    
832    Res += " ";
833    Res += Record.Package();
834    Res += " ";
835    Res += Record.Version();
836    if (File.Type.empty() == false)
837       Res += " (" + File.Type + ")";
838    return Res;
839 }
840
841 #endif /* APT_WITH_REPOMD */
842
843 // DatabaseIndex::rpmDatabaseIndex - Constructor                        /*{{{*/
844 // ---------------------------------------------------------------------
845 /* */
846 rpmDatabaseIndex::rpmDatabaseIndex()
847 {
848 }
849                                                                         /*}}}*/
850
851 string rpmDatabaseIndex::IndexPath() const
852 {
853    return rpmSys.GetDBHandler()->DataPath(false);
854 }
855
856 // DatabaseIndex::Size - Return the size of the index                   /*{{{*/
857 // ---------------------------------------------------------------------
858 /* */
859 off_t rpmDatabaseIndex::Size() const
860 {
861    return rpmSys.GetDBHandler()->Size();
862 }
863                                                                         /*}}}*/
864 // DatabaseIndex::CreateHandler - Create a RPMHandler for this file     /*{{{*/
865 // ---------------------------------------------------------------------
866 RPMHandler *rpmDatabaseIndex::CreateHandler() const
867 {
868    return rpmSys.GetDBHandler();
869 }
870                                                                         /*}}}*/
871 // DatabaseIndex::Merge - Load the index file into a cache              /*{{{*/
872 // ---------------------------------------------------------------------
873 /* */
874 bool rpmDatabaseIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
875 {
876    RPMDBHandler *Handler = rpmSys.GetDBHandler();
877    rpmListParser Parser(Handler);
878    if (_error->PendingError() == true)
879       return _error->Error(_("Problem opening RPM database"));
880    
881    Prog.SubProgress(0,"RPM Database");
882    if (Gen.SelectFile(Handler->DataPath(false),string(),*this,pkgCache::Flag::NotSource) == false)
883       return _error->Error(_("Problem with SelectFile RPM Database"));
884
885    // Store the IMS information
886    pkgCache::PkgFileIterator CFile = Gen.GetCurFile();
887    struct stat St;
888    if (stat(Handler->DataPath(false).c_str(),&St) != 0)
889       return _error->Errno("fstat",_("Failed to stat %s"), Handler->DataPath(false).c_str());
890    CFile->Size = St.st_size;
891    CFile->mtime = Handler->Mtime();
892    
893    if (Gen.MergeList(Parser) == false)
894       return _error->Error(_("Problem with MergeList %s"),
895                            Handler->DataPath(false).c_str());
896    return true;
897 }
898                                                                         /*}}}*/
899 // DatabaseIndex::MergeFileProvides - Process file dependencies if any  /*{{{*/
900 // ---------------------------------------------------------------------
901 /* */
902 bool rpmDatabaseIndex::MergeFileProvides(pkgCacheGenerator &Gen,
903                                          OpProgress &Prog) const
904 {
905    RPMDBHandler *Handler = rpmSys.GetDBHandler();
906    rpmListParser Parser(Handler);
907    if (_error->PendingError() == true)
908       return _error->Error(_("Problem opening RPM database"));
909    // We call SubProgress with Size(), since we won't call SelectFile() here.
910    Prog.SubProgress(Size(),"RPM Database");
911    if (Gen.MergeFileProvides(Parser) == false)
912       return _error->Error(_("Problem with MergeFileProvides %s"),
913                            Handler->DataPath(false).c_str());
914    return true;
915 }
916                                                                         /*}}}*/
917 // DatabaseIndex::FindInCache - Find this index                         /*{{{*/
918 // ---------------------------------------------------------------------
919 /* */
920 pkgCache::PkgFileIterator rpmDatabaseIndex::FindInCache(pkgCache &Cache) const
921 {
922    pkgCache::PkgFileIterator File = Cache.FileBegin();
923    for (; File.end() == false; File++)
924    {
925       if (rpmSys.GetDBHandler()->DataPath(false) != File.FileName())
926          continue;
927       struct stat St;
928       if (stat(File.FileName(),&St) != 0)
929          return pkgCache::PkgFileIterator(Cache);
930       if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
931          return pkgCache::PkgFileIterator(Cache);
932       return File;
933    }   
934    return File;
935 }
936                                                                         /*}}}*/
937
938 // Source List types for rpm                                            /*{{{*/
939
940 class rpmSLTypeGen : public pkgSourceList::Type
941 {
942    public:
943
944    rpmSLTypeGen()
945    {
946       Name = "rpm";
947       Label = "Standard RPM source tree";
948    }   
949
950    pkgRepository *FindRepository(string URI,string Dist,
951                                  const pkgSourceList::Vendor *Vendor) const
952    {
953       for (vector<pkgRepository *>::const_iterator iter = RepList.begin();
954            iter != RepList.end(); iter++) 
955       {
956          if ((*iter)->URI == URI && (*iter)->Dist == Dist) 
957          {       
958             if (Vendor != NULL)
959                (*iter)->FingerPrint = Vendor->FingerPrint;
960             return *iter;
961          }
962       }
963       return NULL;
964    }
965
966    pkgRepository *GetRepository(string URI,string Dist,
967                                 const pkgSourceList::Vendor *Vendor) const
968    {
969       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
970       if (Rep != NULL)
971          return Rep;
972
973       string BaseURI;
974       if (Dist[Dist.size() - 1] == '/')
975       {
976          if (Dist != "/")
977             BaseURI = URI + Dist;
978          else 
979             BaseURI = URI + '/';
980       }
981       else
982          BaseURI = URI + Dist + '/';
983
984       Rep = new pkgRepository(URI,Dist,Vendor,BaseURI);
985       RepList.push_back(Rep);
986       return Rep;
987    }
988 };
989
990
991 class rpmSLTypeRpm : public rpmSLTypeGen
992 {
993    public:
994
995    bool CreateItem(vector<pkgIndexFile *> &List,
996                    string URI, string Dist, string Section,
997                    pkgSourceList::Vendor const *Vendor) const 
998    {
999       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1000       List.push_back(new rpmPkgListIndex(URI,Dist,Section,Rep));
1001       return true;
1002    };
1003
1004    rpmSLTypeRpm()
1005    {
1006       Name = "rpm";
1007       Label = "Standard RPM binary tree";
1008    }   
1009 };
1010
1011 class rpmSLTypeSrpm : public rpmSLTypeGen
1012 {
1013    public:
1014
1015    bool CreateItem(vector<pkgIndexFile *> &List,
1016                    string URI, string Dist, string Section,
1017                    pkgSourceList::Vendor const *Vendor) const 
1018    {
1019       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1020       List.push_back(new rpmSrcListIndex(URI,Dist,Section,Rep));
1021       return true;
1022    };  
1023    
1024    rpmSLTypeSrpm()
1025    {
1026       Name = "rpm-src";
1027       Label = "Standard RPM source tree";
1028    }   
1029 };
1030
1031 class rpmSLTypeRpmDir : public rpmSLTypeGen
1032 {
1033    public:
1034
1035    bool CreateItem(vector<pkgIndexFile *> &List,
1036                    string URI, string Dist, string Section,
1037                    pkgSourceList::Vendor const *Vendor) const 
1038    {
1039       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1040       List.push_back(new rpmPkgDirIndex(URI,Dist,Section,Rep));
1041       return true;
1042    };
1043
1044    rpmSLTypeRpmDir()
1045    {
1046       Name = "rpm-dir";
1047       Label = "Local RPM directory tree";
1048    }   
1049 };
1050
1051 class rpmSLTypeSrpmDir : public rpmSLTypeGen
1052 {
1053    public:
1054
1055    bool CreateItem(vector<pkgIndexFile *> &List,
1056                    string URI, string Dist, string Section,
1057                    pkgSourceList::Vendor const *Vendor) const 
1058    {
1059       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1060       List.push_back(new rpmSrcDirIndex(URI,Dist,Section,Rep));
1061       return true;
1062    };
1063
1064    rpmSLTypeSrpmDir()
1065    {
1066       Name = "rpm-src-dir";
1067       Label = "Local SRPM directory tree";
1068    }   
1069 };
1070
1071 #ifdef APT_WITH_REPOMD
1072 class rpmSLTypeRepomd : public rpmSLTypeGen
1073 {
1074    public:
1075
1076    pkgRepository *GetRepository(string URI,string Dist,
1077                                 const pkgSourceList::Vendor *Vendor) const
1078    {
1079       pkgRepository *Rep = FindRepository(URI,Dist,Vendor);
1080       if (Rep != NULL)
1081          return Rep;
1082
1083       string BaseURI;
1084       if (Dist[Dist.size() - 1] == '/')
1085       {
1086          if (Dist != "/")
1087             BaseURI = URI + Dist;
1088          else 
1089             BaseURI = URI + '/';
1090       }
1091       else
1092          BaseURI = URI + Dist + '/';
1093
1094       Rep = new repomdRepository(URI,Dist,Vendor,BaseURI);
1095       RepList.push_back(Rep);
1096       return Rep;
1097    }
1098
1099    bool CreateItem(vector<pkgIndexFile *> &List,
1100                    string URI, string Dist, string Section,
1101                    pkgSourceList::Vendor const *Vendor) const 
1102    {
1103       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1104       List.push_back(new rpmRepomdPkgIndex(URI,Dist,Section,Rep));
1105       return true;
1106    };
1107
1108    bool ParseLine(vector<pkgIndexFile *> &List,
1109                   pkgSourceList::Vendor const *Vendor,
1110                   const char *Buffer,
1111                   unsigned long CurLine,string File) const
1112    {
1113       string URI;
1114       string Dist;
1115       if (ParseQuoteWord(Buffer,URI) == false)
1116          return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
1117       if (ParseQuoteWord(Buffer,Dist) == false)
1118          return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
1119
1120       if (FixupURI(URI) == false)
1121          return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
1122       
1123       Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
1124       Dist = SubstVar(Dist,"$(VERSION)",_config->Find("APT::DistroVersion"));
1125
1126       if (CreateItem(List,URI,Dist,"",Vendor) == false)
1127          return false;
1128
1129       return true;
1130    };
1131
1132
1133    rpmSLTypeRepomd()
1134    {
1135       Name = "repomd";
1136       Label = "RepoMD tree";
1137    }   
1138 };
1139 class rpmSLTypeRepomdSrc : public rpmSLTypeRepomd
1140 {
1141    public:
1142
1143    bool CreateItem(vector<pkgIndexFile *> &List,
1144                    string URI, string Dist, string Section,
1145                    pkgSourceList::Vendor const *Vendor) const 
1146    {
1147       pkgRepository *Rep = GetRepository(URI,Dist,Vendor);
1148       List.push_back(new rpmRepomdSrcIndex(URI,Dist,Section,Rep));
1149       return true;
1150    };
1151
1152    rpmSLTypeRepomdSrc()
1153    {
1154       Name = "repomd-src";
1155       Label = "RepoMD src tree";
1156    }   
1157 };
1158
1159 #endif /* APT_WITH_REPOMD */
1160
1161 rpmSLTypeRpm _apt_rpmType;
1162 rpmSLTypeSrpm _apt_rpmSrcType;
1163 rpmSLTypeRpmDir _apt_rpmDirType;
1164 rpmSLTypeSrpmDir _apt_rpmSrcDirType;
1165 #ifdef APT_WITH_REPOMD
1166 rpmSLTypeRepomd _apt_repomdType;
1167 rpmSLTypeRepomdSrc _apt_repomdSrcType;
1168 #endif
1169                                                                         /*}}}*/
1170 // Index File types for rpm                                             /*{{{*/
1171 class rpmIFTypeSrc : public pkgIndexFile::Type
1172 {
1173    public:
1174    
1175    rpmIFTypeSrc() {Label = "RPM Source Index";};
1176 };
1177 class rpmIFTypePkg : public pkgIndexFile::Type
1178 {
1179    public:
1180    
1181    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1182    {
1183       return new rpmRecordParser(File.FileName(),*File.Cache());
1184    };
1185    rpmIFTypePkg() {Label = "RPM Package Index";};
1186 };
1187 class rpmIFTypeDatabase : public pkgIndexFile::Type
1188 {
1189    public:
1190    
1191    virtual pkgRecords::Parser *CreatePkgParser(pkgCache::PkgFileIterator File) const
1192    {
1193       return new rpmRecordParser(File.FileName(),*File.Cache());
1194    };
1195    rpmIFTypeDatabase() {Label = "RPM Database";};
1196 };
1197 static rpmIFTypeSrc _apt_Src;
1198 static rpmIFTypePkg _apt_Pkg;
1199 static rpmIFTypeDatabase _apt_DB;
1200
1201 const pkgIndexFile::Type *rpmSrcListIndex::GetType() const
1202 {
1203    return &_apt_Src;
1204 }
1205 const pkgIndexFile::Type *rpmPkgListIndex::GetType() const
1206 {
1207    return &_apt_Pkg;
1208 }
1209 const pkgIndexFile::Type *rpmSrcDirIndex::GetType() const
1210 {
1211    return &_apt_Src;
1212 }
1213 const pkgIndexFile::Type *rpmPkgDirIndex::GetType() const
1214 {
1215    return &_apt_Pkg;
1216 }
1217 const pkgIndexFile::Type *rpmSinglePkgIndex::GetType() const
1218 {
1219    return &_apt_Pkg;
1220 }
1221 const pkgIndexFile::Type *rpmSingleSrcIndex::GetType() const
1222 {
1223    return &_apt_Src;
1224 }
1225 const pkgIndexFile::Type *rpmDatabaseIndex::GetType() const
1226 {
1227    return &_apt_DB;
1228 }
1229 #ifdef APT_WITH_REPOMD
1230 const pkgIndexFile::Type *rpmRepomdPkgIndex::GetType() const
1231 {
1232    return &_apt_Pkg;
1233 }
1234 const pkgIndexFile::Type *rpmRepomdSrcIndex::GetType() const
1235 {
1236    return &_apt_Src;
1237 }
1238 #endif
1239
1240                                                                         /*}}}*/
1241 #endif /* HAVE_RPM */
1242
1243 // vim:sts=3:sw=3