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