- oops, repodb was missing ID so only single repo was considered
[apt.git] / apt-pkg / rpm / rpmhandler.cc
1
2 /*
3  ######################################################################
4
5  RPM database and hdlist related handling
6
7  ######################################################################
8  */
9
10 #include <config.h>
11
12 #ifdef HAVE_RPM
13
14 #include <fcntl.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <utime.h>
18 #include <unistd.h>
19 #include <assert.h>
20 #include <libgen.h>
21
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/configuration.h>
24 #include <apt-pkg/md5.h>
25 #include <apt-pkg/crc-16.h>
26
27 #include <apt-pkg/rpmhandler.h>
28 #include <apt-pkg/rpmpackagedata.h>
29
30 #ifdef APT_WITH_REPOMD
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #include <libxml/xmlreader.h>
34 #include <sstream>
35 #include <apt-pkg/sqlite.h>
36 #endif
37
38 #include <apti18n.h>
39
40 #if RPM_VERSION >= 0x040100
41 #include <rpm/rpmts.h>
42 #include <rpm/rpmdb.h>
43 #include <rpm/rpmds.h>
44 #include <rpm/rpmfi.h>
45 #define rpmxxInitIterator(a,b,c,d) rpmtsInitIterator(a,(rpmTag)b,c,d)
46 #else
47 #define rpmxxInitIterator(a,b,c,d) rpmdbInitIterator(a,b,c,d)
48 #endif
49
50 // An attempt to deal with false zero epochs from repomd. With older rpm's we
51 // can only blindly trust the repo admin created the repository with options
52 // suitable for those versions. For rpm >= 4.2.1 this is linked with
53 // promoteepoch behavior - if promoteepoch is used then epoch hiding must
54 // not happen.
55 bool HideZeroEpoch;
56
57 string RPMHandler::Epoch()
58 {
59    char str[512] = "";
60    int_32 count, type, *epoch;
61    void *val;
62    assert(HeaderP != NULL);
63    int rc = headerGetEntry(HeaderP, RPMTAG_EPOCH, &type, &val, &count);
64    epoch = (int_32*)val;
65    if (rc == 1 && count > 0) {
66       snprintf(str, sizeof(str), "%i", epoch[0]);
67    }
68    return string(str);
69 }
70
71 unsigned long RPMHandler::GetITag(rpmTag Tag)
72 {
73    int_32 count, type, *num;
74    void *val;
75    assert(HeaderP != NULL);
76    int rc = headerGetEntry(HeaderP, Tag,
77                            &type, (void**)&val, &count);
78    num = (int_32*)val;
79    return rc?num[0]:0;
80 }
81
82 string RPMHandler::GetSTag(rpmTag Tag)
83 {
84    char *str;
85    void *val;
86    int_32 count, type;
87    assert(HeaderP != NULL);
88    int rc = headerGetEntry(HeaderP, Tag,
89                            &type, (void**)&val, &count);
90    str = (char *)val;
91    return string(rc?str:"");
92 }
93
94 string RPMHandler::EVR()
95 {
96    string e = Epoch();
97    string v = Version();
98    string r = Release();
99    string evr = "";
100    if (e.empty() == true) {
101       evr = v + '-' + r;
102    } else if (HideZeroEpoch && e == "0") {
103       evr = v + '-' + r;
104    } else {
105       evr = e + ':' + v + '-' + r;
106    }
107    return evr;
108
109
110 unsigned int RPMHandler::DepOp(int_32 rpmflags)
111 {
112    unsigned int Op = 0;
113    int_32 flags = (rpmflags & RPMSENSE_SENSEMASK);
114    if (flags == RPMSENSE_ANY) {
115       Op = pkgCache::Dep::NoOp;
116    } else if (flags & RPMSENSE_LESS) {
117       if (flags & RPMSENSE_EQUAL)
118           Op = pkgCache::Dep::LessEq;
119       else
120           Op = pkgCache::Dep::Less;
121    } else if (flags & RPMSENSE_GREATER) {
122       if (flags & RPMSENSE_EQUAL)
123           Op = pkgCache::Dep::GreaterEq;
124       else
125           Op = pkgCache::Dep::Greater;
126    } else if (flags & RPMSENSE_EQUAL) {
127       Op = pkgCache::Dep::Equals;
128    } else {
129       /* can't happen, right? */
130       _error->Error(_("Impossible flags %d in %s"), rpmflags, Name().c_str());
131    }
132       
133    return Op;
134 }
135
136 bool RPMHandler::HasFile(const char *File)
137 {
138    if (*File == '\0')
139       return false;
140    
141    vector<string> Files;
142    FileList(Files);
143    for (vector<string>::iterator I = Files.begin(); I != Files.end(); I++) {
144       if (string(File) == (*I)) {
145          return true;
146       }
147    }
148    return false;
149 }
150
151 bool RPMHandler::InternalDep(const char *name, const char *ver, int_32 flag) 
152 {
153    if (strncmp(name, "rpmlib(", strlen("rpmlib(")) == 0) {
154 #if RPM_VERSION >= 0x040404
155      rpmds rpmlibProv = NULL;
156      rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
157                             name, ver?ver:NULL, flag);
158      rpmdsRpmlib(&rpmlibProv, NULL);
159      int res = rpmdsSearch(rpmlibProv, ds) >= 0;
160      rpmdsFree(ds);
161      rpmdsFree(rpmlibProv);
162 #elif RPM_VERSION >= 0x040100
163       rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
164                              name, ver?ver:NULL, flag);
165       int res = rpmCheckRpmlibProvides(ds);
166       rpmdsFree(ds);
167 #else
168       int res = rpmCheckRpmlibProvides(name, ver?ver:NULL,
169                                        flag);
170 #endif
171       if (res) 
172          return true;
173    }
174
175 #if RPM_VERSION >= 0x040404
176    // uhhuh, any of these changing would require full cache rebuild...
177    if (strncmp(name, "getconf(", strlen("getconf(")) == 0)
178    {
179      rpmds getconfProv = NULL;
180      rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
181                             name, ver?ver:NULL, flag);
182      rpmdsGetconf(&getconfProv, NULL);
183      int res = rpmdsSearch(getconfProv, ds);
184      rpmdsFree(ds);
185      rpmdsFree(getconfProv);
186      if (res) 
187          return true;
188    }
189
190    if (strncmp(name, "cpuinfo(", strlen("cpuinfo(")) == 0)
191    {
192      rpmds cpuinfoProv = NULL;
193      rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
194                             name, ver?ver:NULL, flag);
195      rpmdsCpuinfo(&cpuinfoProv, NULL);
196      int res = rpmdsSearch(cpuinfoProv, ds);
197      rpmdsFree(ds);
198      rpmdsFree(cpuinfoProv);
199      if (res) 
200          return true;
201    }
202
203    if (strncmp(name, "sysinfo(", strlen("sysinfo(")) == 0)
204    {
205      rpmds sysinfoProv = NULL;
206      rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
207                             name, ver?ver:NULL, flag);
208      rpmdsCpuinfo(&sysinfoProv, NULL);
209      int res = rpmdsSearch(sysinfoProv, ds);
210      rpmdsFree(ds);
211      rpmdsFree(sysinfoProv);
212      if (res)
213          return true;
214    }
215
216    if (strncmp(name, "uname(", strlen("uname(")) == 0)
217    {
218      rpmds unameProv = NULL;
219      rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
220                             name, ver?ver:NULL, flag);
221      rpmdsUname(&unameProv, NULL);
222      int res = rpmdsSearch(unameProv, ds);
223      rpmdsFree(ds);
224      rpmdsFree(unameProv);
225      if (res)
226          return true;
227    }
228
229    if (strlen(name) > 5 && name[strlen(name)-1] == ')' &&
230        ((strchr("Rr_", name[0]) != NULL &&
231          strchr("Ww_", name[1]) != NULL &&
232          strchr("Xx_", name[2]) != NULL &&
233          name[3] == '(') ||
234          strncmp(name, "exists(", strlen("exists(")) == 0 ||
235          strncmp(name, "executable(", strlen("executable(")) == 0 ||
236          strncmp(name, "readable(", strlen("readable(")) == 0 ||
237          strncmp(name, "writable(", strlen("writable("))== 0 ))
238    {
239       int res = rpmioAccess(name, NULL, X_OK);
240       if (res == 0)
241          return true;
242    }
243
244    /* TODO
245     * - /etc/rpm/sysinfo provides
246     * - macro probe provides 
247     * - actually implement soname() and access() dependencies
248     */
249    if (strncmp(name, "soname(", strlen("soname(")) == 0)
250    {
251       cout << "FIXME, ignoring soname() dependency: " << name << endl;
252       return true;
253    }
254 #endif
255    return false; 
256 }
257
258 bool RPMHandler::PutDep(const char *name, const char *ver, int_32 flags, 
259                         unsigned int Type, vector<Dependency*> &Deps)
260 {
261    if (InternalDep(name, ver, flags) == true) {
262       return true;
263    }
264
265    if (Type == pkgCache::Dep::Depends) {
266       if (flags & RPMSENSE_PREREQ)
267          Type = pkgCache::Dep::PreDepends;
268 #if RPM_VERSION >= 0x040403
269       else if (flags & RPMSENSE_MISSINGOK)
270          Type = pkgCache::Dep::Suggests;
271 #endif
272       else
273          Type = pkgCache::Dep::Depends;
274    }
275
276    Dependency *Dep = new Dependency;
277    Dep->Name = name;
278    Dep->Version = ver;
279
280    if (HideZeroEpoch && Dep->Version.substr(0, 2) == "0:") {
281       Dep->Version = Dep->Version.substr(2);
282    }
283
284    Dep->Op = DepOp(flags);
285    Dep->Type = Type;
286    Deps.push_back(Dep);
287    return true;
288 }
289
290
291 bool RPMHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
292 #if RPM_VERSION >= 0x040100
293 {
294    rpmTag deptype = RPMTAG_REQUIRENAME;
295    switch (Type) {
296       case pkgCache::Dep::Depends:
297          deptype = RPMTAG_REQUIRENAME;
298          break;
299       case pkgCache::Dep::Obsoletes:
300          deptype = RPMTAG_OBSOLETENAME;
301          break;
302       case pkgCache::Dep::Conflicts:
303          deptype = RPMTAG_CONFLICTNAME;
304          break;
305       case pkgCache::Dep::Provides:
306          deptype = RPMTAG_PROVIDENAME;
307          break;
308 #if RPM_VERSION >= 0x040403
309       case pkgCache::Dep::Suggests:
310          deptype = RPMTAG_SUGGESTNAME;
311          break;
312 #if 0 // Enhances dep type is not even known to apt, sigh..
313       case pkgCache::Dep::Enhances:
314          deptype = RPMTAG_ENHANCES;
315          break;
316 #endif
317 #endif
318       default:
319          /* can't happen... right? */
320          return false;
321          break;
322    }
323    rpmds ds = NULL;
324    ds = rpmdsNew(HeaderP, deptype, 0);
325    if (ds != NULL) {
326       while (rpmdsNext(ds) >= 0) {
327          bool r = PutDep(rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds), Type, Deps);
328       }
329    }
330    rpmdsFree(ds);
331    return true;
332 }
333 #else
334 bool RPMHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
335 {
336    char **namel = NULL;
337    char **verl = NULL;
338    int *flagl = NULL;
339    int res, type, count;
340    int_32 deptag, depver, depflags;
341    void *nameval = NULL;
342    void *verval = NULL;
343    void *flagval = NULL;
344
345    switch (Type) {
346       case pkgCache::Dep::Depends:
347          deptag = RPMTAG_REQUIRENAME;
348          depver = RPMTAG_REQUIREVERSION;
349          depflags = RPMTAG_REQUIREFLAGS;
350          break;
351       case pkgCache::Dep::Obsoletes:
352          deptag = RPMTAG_OBSOLETENAME;
353          depver = RPMTAG_OBSOLETEVERSION;
354          depflags = RPMTAG_OBSOLETEFLAGS;
355          break;
356       case pkgCache::Dep::Conflicts:
357          deptag = RPMTAG_CONFLICTNAME;
358          depver = RPMTAG_CONFLICTVERSION;
359          depflags = RPMTAG_CONFLICTFLAGS;
360          break;
361       case pkgCache::Dep::Provides:
362          deptag = RPMTAG_PROVIDENAME;
363          depver = RPMTAG_PROVIDEVERSION;
364          depflags = RPMTAG_PROVIDEFLAGS;
365          break;
366       default:
367          /* can't happen... right? */
368          return false;
369          break;
370    }
371    res = headerGetEntry(HeaderP, deptag, &type, (void **)&nameval, &count);
372    if (res != 1)
373       return true;
374    res = headerGetEntry(HeaderP, depver, &type, (void **)&verval, &count);
375    res = headerGetEntry(HeaderP, depflags, &type, (void **)&flagval, &count);
376
377    namel = (char**)nameval;
378    verl = (char**)verval;
379    flagl = (int*)flagval;
380
381    for (int i = 0; i < count; i++) {
382
383       bool res = PutDep(namel[i], verl[i], flagl[i], Type, Deps);
384    }
385    free(namel);
386    free(verl);
387    return true;
388       
389 }
390 #endif
391
392 // XXX rpmfi originates from somewhere around 2001 but what's the version?
393 #if RPM_VERSION >= 0x040100
394 bool RPMHandler::FileList(vector<string> &FileList)
395 {
396    rpmfi fi = NULL;
397    fi = rpmfiNew(NULL, HeaderP, RPMTAG_BASENAMES, 0);
398    if (fi != NULL) {
399       while (rpmfiNext(fi) >= 0) {
400         FileList.push_back(rpmfiFN(fi));
401       }
402    }
403    fi = rpmfiFree(fi);
404    return true;
405 }
406 #else
407 bool RPMHandler::FileList(vector<string> &FileList)
408 {
409    const char **names = NULL;
410    void *val = NULL;
411    int_32 count = 0;
412    bool ret = true;
413    rpmHeaderGetEntry(HeaderP, RPMTAG_OLDFILENAMES,
414                      NULL, (void **) &val, &count);
415    names = (const char **)val;
416    while (count--) {
417       FileList.push_back(names[count]);
418    }
419    free(names);
420    return ret;
421
422 }
423 #endif
424
425 RPMFileHandler::RPMFileHandler(string File)
426 {
427    ID = File;
428    FD = Fopen(File.c_str(), "r");
429    if (FD == NULL)
430    {
431       /*
432       _error->Error(_("could not open RPM package list file %s: %s"),
433                     File.c_str(), rpmErrorString());
434       */
435       return;
436    }
437    iSize = fdSize(FD);
438 }
439
440 RPMFileHandler::RPMFileHandler(FileFd *File)
441 {
442    FD = fdDup(File->Fd());
443    if (FD == NULL)
444    {
445       /*
446       _error->Error(_("could not create RPM file descriptor: %s"),
447                     rpmErrorString());
448       */
449       return;
450    }
451    iSize = fdSize(FD);
452 }
453
454 RPMFileHandler::~RPMFileHandler()
455 {
456    if (HeaderP != NULL)
457       headerFree(HeaderP);
458    if (FD != NULL)
459       Fclose(FD);
460 }
461
462 bool RPMFileHandler::Skip()
463 {
464    if (FD == NULL)
465       return false;
466    iOffset = lseek(Fileno(FD),0,SEEK_CUR);
467    if (HeaderP != NULL)
468        headerFree(HeaderP);
469    HeaderP = headerRead(FD, HEADER_MAGIC_YES);
470    return (HeaderP != NULL);
471 }
472
473 bool RPMFileHandler::Jump(off_t Offset)
474 {
475    if (FD == NULL)
476       return false;
477    if (lseek(Fileno(FD),Offset,SEEK_SET) != Offset)
478       return false;
479    return Skip();
480 }
481
482 void RPMFileHandler::Rewind()
483 {
484    if (FD == NULL)
485       return;
486    iOffset = lseek(Fileno(FD),0,SEEK_SET);
487    if (iOffset != 0)
488       _error->Error(_("could not rewind RPMFileHandler"));
489 }
490
491 string RPMFileHandler::FileName()
492 {
493    return GetSTag(CRPMTAG_FILENAME);
494 }
495
496 string RPMFileHandler::Directory()
497 {
498    return GetSTag(CRPMTAG_DIRECTORY);
499 }
500
501 unsigned long RPMFileHandler::FileSize()
502 {
503    return GetITag(CRPMTAG_FILESIZE);
504 }
505
506 string RPMFileHandler::MD5Sum()
507 {
508    return GetSTag(CRPMTAG_MD5);
509 }
510
511 bool RPMSingleFileHandler::Skip()
512 {
513    if (FD == NULL)
514       return false;
515    if (HeaderP != NULL) {
516       headerFree(HeaderP);
517       HeaderP = NULL;
518       return false;
519    }
520 #if RPM_VERSION >= 0x040100
521    rpmts TS = rpmtsCreate();
522    rpmtsSetVSFlags(TS, (rpmVSFlags_e)-1);
523    int rc = rpmReadPackageFile(TS, FD, sFilePath.c_str(), &HeaderP);
524    if (rc != RPMRC_OK && rc != RPMRC_NOTTRUSTED && rc != RPMRC_NOKEY) {
525       _error->Error(_("Failed reading file %s"), sFilePath.c_str());
526       HeaderP = NULL;
527    }
528    rpmtsFree(TS);
529 #else
530    int rc = rpmReadPackageHeader(FD, &HeaderP, 0, NULL, NULL);
531    if (rc) {
532       _error->Error(_("Failed reading file %s"), sFilePath.c_str());
533       HeaderP = NULL;
534    }
535 #endif
536    return (HeaderP != NULL);
537 }
538
539 bool RPMSingleFileHandler::Jump(off_t Offset)
540 {
541    assert(Offset == 0);
542    Rewind();
543    return RPMFileHandler::Jump(Offset);
544 }
545
546 void RPMSingleFileHandler::Rewind()
547 {
548    if (FD == NULL)
549       return;
550    if (HeaderP != NULL) {
551       HeaderP = NULL;
552       headerFree(HeaderP);
553    }
554    lseek(Fileno(FD),0,SEEK_SET);
555 }
556
557 unsigned long RPMSingleFileHandler::FileSize()
558 {
559    struct stat S;
560    if (stat(sFilePath.c_str(),&S) != 0)
561       return 0;
562    return S.st_size;
563 }
564
565 string RPMSingleFileHandler::MD5Sum()
566 {
567    MD5Summation MD5;
568    FileFd File(sFilePath, FileFd::ReadOnly);
569    MD5.AddFD(File.Fd(), File.Size());
570    File.Close();
571    return MD5.Result().Value();
572 }
573
574 RPMDirHandler::RPMDirHandler(string DirName)
575    : sDirName(DirName)
576 {
577    ID = DirName;
578 #if RPM_VERSION >= 0x040100
579    TS = NULL;
580 #endif
581    Dir = opendir(sDirName.c_str());
582    if (Dir == NULL)
583       return;
584    iSize = 0;
585    while (nextFileName() != NULL)
586       iSize += 1;
587    rewinddir(Dir);
588 #if RPM_VERSION >= 0x040100
589    TS = rpmtsCreate();
590    rpmtsSetVSFlags(TS, (rpmVSFlags_e)-1);
591 #endif
592 }
593
594 const char *RPMDirHandler::nextFileName()
595 {
596    for (struct dirent *Ent = readdir(Dir); Ent != 0; Ent = readdir(Dir))
597    {
598       const char *name = Ent->d_name;
599
600       if (name[0] == '.')
601          continue;
602
603       if (flExtension(name) != "rpm")
604          continue;
605
606       // Make sure it is a file and not something else
607       sFilePath = flCombine(sDirName,name);
608       struct stat St;
609       if (stat(sFilePath.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
610          continue;
611
612       sFileName = name;
613       
614       return name;
615    } 
616    return NULL;
617 }
618
619 RPMDirHandler::~RPMDirHandler()
620 {
621    if (HeaderP != NULL)
622       headerFree(HeaderP);
623 #if RPM_VERSION >= 0x040100
624    if (TS != NULL)
625       rpmtsFree(TS);
626 #endif
627    if (Dir != NULL)
628       closedir(Dir);
629 }
630
631 bool RPMDirHandler::Skip()
632 {
633    if (Dir == NULL)
634       return false;
635    if (HeaderP != NULL) {
636       headerFree(HeaderP);
637       HeaderP = NULL;
638    }
639    const char *fname = nextFileName();
640    bool Res = false;
641    for (; fname != NULL; fname = nextFileName()) {
642       iOffset++;
643       if (fname == NULL)
644          break;
645       FD_t FD = Fopen(sFilePath.c_str(), "r");
646       if (FD == NULL)
647          continue;
648 #if RPM_VERSION >= 0x040100
649       int rc = rpmReadPackageFile(TS, FD, fname, &HeaderP);
650       Fclose(FD);
651       if (rc != RPMRC_OK
652           && rc != RPMRC_NOTTRUSTED
653           && rc != RPMRC_NOKEY)
654          continue;
655 #else
656       int isSource;
657       int rc = rpmReadPackageHeader(FD, &HeaderP, &isSource, NULL, NULL);
658       Fclose(FD);
659       if (rc != 0)
660          continue;
661 #endif
662       Res = true;
663       break;
664    }
665    return Res;
666 }
667
668 bool RPMDirHandler::Jump(off_t Offset)
669 {
670    if (Dir == NULL)
671       return false;
672    rewinddir(Dir);
673    iOffset = 0;
674    while (1) {
675       if (iOffset+1 == Offset)
676          return Skip();
677       if (nextFileName() == NULL)
678          break;
679       iOffset++;
680    }
681    return false;
682 }
683
684 void RPMDirHandler::Rewind()
685 {
686    rewinddir(Dir);
687    iOffset = 0;
688 }
689
690 unsigned long RPMDirHandler::FileSize()
691 {
692    if (Dir == NULL)
693       return 0;
694    struct stat St;
695    if (stat(sFilePath.c_str(),&St) != 0) {
696       _error->Errno("stat",_("Unable to determine the file size"));
697       return 0;
698    }
699    return St.st_size;
700 }
701
702 string RPMDirHandler::MD5Sum()
703 {
704    if (Dir == NULL)
705       return "";
706    MD5Summation MD5;
707    FileFd File(sFilePath, FileFd::ReadOnly);
708    MD5.AddFD(File.Fd(), File.Size());
709    File.Close();
710    return MD5.Result().Value();
711 }
712
713
714 RPMDBHandler::RPMDBHandler(bool WriteLock)
715    : Handler(0), WriteLock(WriteLock)
716 {
717 #if RPM_VERSION >= 0x040000
718    RpmIter = NULL;
719 #endif
720    string Dir = _config->Find("RPM::RootDir");
721    
722    rpmReadConfigFiles(NULL, NULL);
723    ID = DataPath(false);
724
725    RPMPackageData::Singleton()->InitMinArchScore();
726
727    // Everytime we open a database for writing, it has its
728    // mtime changed, and kills our cache validity. As we never
729    // change any information in the database directly, we will
730    // restore the mtime and save our cache.
731    struct stat St;
732    stat(DataPath(false).c_str(), &St);
733    DbFileMtime = St.st_mtime;
734
735 #if RPM_VERSION >= 0x040100
736    Handler = rpmtsCreate();
737    rpmtsSetVSFlags(Handler, (rpmVSFlags_e)-1);
738    rpmtsSetRootDir(Handler, Dir.c_str());
739 #else
740    const char *RootDir = NULL;
741    if (!Dir.empty())
742       RootDir = Dir.c_str();
743    if (rpmdbOpen(RootDir, &Handler, O_RDONLY, 0644) != 0)
744    {
745       _error->Error(_("could not open RPM database"));
746       return;
747    }
748 #endif
749 #if RPM_VERSION >= 0x040000
750    RpmIter = rpmxxInitIterator(Handler, RPMDBI_PACKAGES, NULL, 0);
751    if (RpmIter == NULL) {
752       _error->Error(_("could not create RPM database iterator"));
753       return;
754    }
755    // iSize = rpmdbGetIteratorCount(RpmIter);
756    // This doesn't seem to work right now. Code in rpm (4.0.4, at least)
757    // returns a 0 from rpmdbGetIteratorCount() if rpmxxInitIterator() is
758    // called with RPMDBI_PACKAGES or with keyp == NULL. The algorithm
759    // below will be used until there's support for it.
760    iSize = 0;
761    rpmdbMatchIterator countIt;
762    countIt = rpmxxInitIterator(Handler, RPMDBI_PACKAGES, NULL, 0);
763    while (rpmdbNextIterator(countIt) != NULL)
764       iSize++;
765    rpmdbFreeIterator(countIt);
766 #else
767    iSize = St.st_size;
768
769 #endif
770
771
772    // Restore just after opening the database, and just after closing.
773    if (WriteLock) {
774       struct utimbuf Ut;
775       Ut.actime = DbFileMtime;
776       Ut.modtime = DbFileMtime;
777       utime(DataPath(false).c_str(), &Ut);
778    }
779 }
780
781 RPMDBHandler::~RPMDBHandler()
782 {
783 #if RPM_VERSION >= 0x040000
784    if (RpmIter != NULL)
785       rpmdbFreeIterator(RpmIter);
786 #else
787    if (HeaderP != NULL)
788        headerFree(HeaderP);
789 #endif
790
791    if (Handler != NULL) {
792 #if RPM_VERSION >= 0x040100
793       rpmtsFree(Handler);
794 #else
795       rpmdbClose(Handler);
796 #endif
797    }
798
799    // Restore just after opening the database, and just after closing.
800    if (WriteLock) {
801       struct utimbuf Ut;
802       Ut.actime = DbFileMtime;
803       Ut.modtime = DbFileMtime;
804       utime(DataPath(false).c_str(), &Ut);
805    }
806 }
807
808 string RPMDBHandler::DataPath(bool DirectoryOnly)
809 {
810    string File = "packages.rpm";
811    char *tmp = (char *) rpmExpand("%{_dbpath}", NULL);
812    string DBPath(_config->Find("RPM::RootDir")+tmp);
813    free(tmp);
814
815 #if RPM_VERSION >= 0x040000
816    if (rpmExpandNumeric("%{_dbapi}") >= 3)
817       File = "Packages";       
818 #endif
819    if (DirectoryOnly == true)
820        return DBPath;
821    else
822        return DBPath+"/"+File;
823 }
824
825 bool RPMDBHandler::Skip()
826 {
827 #if RPM_VERSION >= 0x040000
828    if (RpmIter == NULL)
829        return false;
830    HeaderP = rpmdbNextIterator(RpmIter);
831    iOffset = rpmdbGetIteratorOffset(RpmIter);
832    if (HeaderP == NULL)
833       return false;
834 #else
835    if (iOffset == 0)
836       iOffset = rpmdbFirstRecNum(Handler);
837    else
838       iOffset = rpmdbNextRecNum(Handler, iOffset);
839    if (HeaderP != NULL)
840    {
841       headerFree(HeaderP);
842       HeaderP = NULL;
843    }
844    if (iOffset == 0)
845        return false;
846    HeaderP = rpmdbGetRecord(Handler, iOffset);
847 #endif
848    return true;
849 }
850
851 bool RPMDBHandler::Jump(off_t Offset)
852 {
853    iOffset = Offset;
854 #if RPM_VERSION >= 0x040000
855    // rpmdb indexes are hardcoded uint32_t, the size must match here
856    uint_32 rpmOffset = iOffset;
857    if (RpmIter == NULL)
858       return false;
859    rpmdbFreeIterator(RpmIter);
860    if (iOffset == 0)
861       RpmIter = rpmxxInitIterator(Handler, RPMDBI_PACKAGES, NULL, 0);
862    else {
863       RpmIter = rpmxxInitIterator(Handler, RPMDBI_PACKAGES,
864                                   &rpmOffset, sizeof(rpmOffset));
865       iOffset = rpmOffset;
866    }
867    HeaderP = rpmdbNextIterator(RpmIter);
868 #else
869    HeaderP = rpmdbGetRecord(Handler, iOffset);
870 #endif
871    return true;
872 }
873
874 bool RPMDBHandler::JumpByName(string PkgName)
875 {
876    if (RpmIter == NULL) return false;
877    rpmdbFreeIterator(RpmIter);
878 #if RPM_VERSION >= 0x040100
879    RpmIter = rpmtsInitIterator(Handler, (rpmTag)RPMDBI_LABEL, PkgName.c_str(), 0);
880 #else
881    RpmIter = rpmdbInitIterator(Handler, RPMDBI_LABEL, PkgName.c_str(), 0);
882 #endif
883
884    HeaderP = rpmdbNextIterator(RpmIter);
885    return (HeaderP != NULL);
886 }
887
888 void RPMDBHandler::Rewind()
889 {
890 #if RPM_VERSION >= 0x040000
891    if (RpmIter == NULL)
892       return;
893    rpmdbFreeIterator(RpmIter);   
894    RpmIter = rpmxxInitIterator(Handler, RPMDBI_PACKAGES, NULL, 0);
895 #else
896    if (HeaderP != NULL)
897    {
898       headerFree(HeaderP);
899       HeaderP = NULL;
900    }
901 #endif
902    iOffset = 0;
903 }
904 #endif
905
906 #ifdef APT_WITH_REPOMD
907 RPMRepomdHandler::RPMRepomdHandler(string File)
908 {
909    PrimaryFile = File;
910
911    ID = File;
912    Root = NULL;
913    Primary = NULL;
914    xmlChar *packages = NULL;
915    off_t pkgcount = 0;
916    
917
918    Primary = xmlReadFile(File.c_str(), NULL, XML_PARSE_NONET|XML_PARSE_NOBLANKS);
919    if ((Root = xmlDocGetRootElement(Primary)) == NULL) {
920       _error->Error(_("Failed to open package index %s"), PrimaryFile.c_str());
921       goto error;
922    }
923    if (xmlStrncmp(Root->name, (xmlChar*)"metadata", strlen("metadata")) != 0) {
924       _error->Error(_("Corrupted package index %s"), PrimaryFile.c_str());
925       goto error;
926    }
927
928    packages = xmlGetProp(Root, (xmlChar*)"packages");
929    iSize = atoi((char*)packages);
930    xmlFree(packages);
931    for (xmlNode *n = Root->children; n; n = n->next) {
932       if (n->type != XML_ELEMENT_NODE ||
933           xmlStrcmp(n->name, (xmlChar*)"package") != 0)
934          continue;
935       Pkgs.push_back(n);
936       pkgcount++;
937    }
938    PkgIter = Pkgs.begin();
939
940    // There seem to be broken version(s) of createrepo around which report
941    // to have one more package than is in the repository. Warn and work around.
942    if (iSize != pkgcount) {
943       _error->Warning(_("Inconsistent metadata, package count doesn't match in %s"), File.c_str());
944       iSize = pkgcount;
945    }
946
947    return;
948
949 error:
950    if (Primary) {
951       xmlFreeDoc(Primary);
952    }
953 }
954
955 bool RPMRepomdHandler::Skip()
956 {
957    if (PkgIter == Pkgs.end()) {
958       return false;
959    }
960    NodeP = *PkgIter;
961    iOffset = PkgIter - Pkgs.begin();
962
963    PkgIter++;
964    return true;
965 }
966
967 bool RPMRepomdHandler::Jump(off_t Offset)
968 {
969    if (Offset >= iSize) {
970       return false;
971    }
972    iOffset = Offset;
973    NodeP = Pkgs[Offset];
974    // This isn't strictly necessary as Skip() and Jump() aren't mixed
975    // in practise but doesn't hurt either...
976    PkgIter = Pkgs.begin() + Offset + 1;
977    return true;
978
979 }
980
981 void RPMRepomdHandler::Rewind()
982 {
983    iOffset = 0;
984    PkgIter = Pkgs.begin();
985 }
986
987 xmlNode *RPMRepomdHandler::FindNode(const string Name)
988 {
989    for (xmlNode *n = NodeP->children; n; n = n->next) {
990       if (xmlStrcmp(n->name, (xmlChar*)Name.c_str()) == 0) {
991          return n;
992       }
993    }
994    return NULL;
995 }
996
997 xmlNode *RPMRepomdHandler::FindNode(xmlNode *Node, const string Name)
998 {
999    for (xmlNode *n = Node->children; n; n = n->next) {
1000       if (xmlStrcmp(n->name, (xmlChar*)Name.c_str()) == 0) {
1001          return n;
1002       }
1003    }
1004    return NULL;
1005 }
1006
1007 string RPMRepomdHandler::FindTag(xmlNode *Node, string Tag)
1008 {
1009    xmlNode *n = FindNode(Node, Tag);
1010    string str = "";
1011    if (n) {
1012       xmlChar *content = xmlNodeGetContent(n);
1013       if (content) {
1014          str = (char*)content;
1015          xmlFree(content);
1016       }
1017    }
1018    return str;
1019 }
1020
1021 string RPMRepomdHandler::GetProp(xmlNode *Node, char *Prop)
1022 {
1023    string str = "";
1024    if (Node) {
1025       xmlChar *prop = xmlGetProp(Node, (xmlChar*)Prop);
1026       if (prop) {
1027          str = (char*)prop;
1028          xmlFree(prop);
1029       }
1030    }
1031    return str;
1032 }
1033
1034 string RPMRepomdHandler::Group()
1035 {
1036    xmlNode *n = FindNode("format");
1037    return FindTag(n, "group");
1038 }
1039
1040 string RPMRepomdHandler::Vendor()
1041 {
1042    xmlNode *n = FindNode("format");
1043    return FindTag(n, "vendor");
1044 }
1045
1046 string RPMRepomdHandler::Release()
1047 {
1048    xmlNode *n = FindNode("version");
1049    return GetProp(n, "rel");
1050 }
1051
1052 string RPMRepomdHandler::Version()
1053 {
1054    xmlNode *n = FindNode("version");
1055    return GetProp(n, "ver");
1056 }
1057
1058 string RPMRepomdHandler::Epoch()
1059 {
1060    string epoch;
1061    xmlNode *n = FindNode("version");
1062    epoch = GetProp(n, "epoch");
1063    // XXX createrepo stomps epoch zero on packages without epoch, hide
1064    // them. Rpm treats zero and empty equally anyway so it doesn't matter.
1065    if (epoch == "0")
1066       epoch = "";
1067    return epoch;
1068 }
1069
1070 string RPMRepomdHandler::FileName()
1071 {
1072    xmlNode *n;
1073    string str = "";
1074    if ((n = FindNode("location"))) {
1075       xmlChar *prop = xmlGetProp(n, (xmlChar*)"href");
1076       str = basename((char*)prop);
1077       xmlFree(prop);
1078    }
1079    return str;
1080 }
1081
1082 string RPMRepomdHandler::Directory()
1083 {
1084    xmlNode *n;
1085    string str = "";
1086    if ((n = FindNode("location"))) {
1087       xmlChar *prop = xmlGetProp(n, (xmlChar*)"href");
1088       if (prop) {
1089          str = dirname((char*)prop);
1090          xmlFree(prop);
1091       }
1092    }
1093    return str;
1094 }
1095
1096 string RPMRepomdHandler::MD5Sum()
1097 {
1098    // XXX FIXME the method should be an abstract Checksum type using
1099    // md5 / sha1 appropriately, for now relying on hacks elsewhere..
1100    return SHA1Sum();
1101 }
1102
1103 string RPMRepomdHandler::SHA1Sum()
1104 {
1105    xmlNode *n;
1106    string str = "";
1107    if ((n = FindNode("checksum"))) {
1108       xmlChar *content = xmlNodeGetContent(n);
1109       str = (char*)content;
1110       xmlFree(content);
1111    }
1112    return str;
1113 }
1114 unsigned long RPMRepomdHandler::FileSize()
1115 {
1116    xmlNode *n;
1117    unsigned long size = 0;
1118    if ((n = FindNode("size"))) {
1119       xmlChar *prop = xmlGetProp(n, (xmlChar*)"package");
1120       size = atol((char*)prop);
1121       xmlFree(prop);
1122    } 
1123    return size;
1124 }
1125
1126 unsigned long RPMRepomdHandler::InstalledSize()
1127 {
1128    xmlNode *n;
1129    unsigned long size = 0;
1130    if ((n = FindNode("size"))) {
1131       xmlChar *prop = xmlGetProp(n, (xmlChar*)"installed");
1132       size = atol((char*)prop);
1133       xmlFree(prop);
1134    } 
1135    return size;
1136 }
1137
1138 string RPMRepomdHandler::SourceRpm()
1139 {
1140    xmlNode *n = FindNode("format");
1141    return FindTag(n, "sourcerpm");
1142 }
1143
1144 bool RPMRepomdHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
1145 {
1146    xmlNode *format = FindNode("format");
1147    xmlNode *dco = NULL;
1148
1149    switch (Type) {
1150       case pkgCache::Dep::Depends:
1151          dco = FindNode(format, "requires");
1152          break;
1153       case pkgCache::Dep::Conflicts:
1154          dco = FindNode(format, "conflicts");
1155          break;
1156       case pkgCache::Dep::Obsoletes:
1157          dco = FindNode(format, "obsoletes");
1158          break;
1159       case pkgCache::Dep::Provides:
1160          dco = FindNode(format, "provides");
1161          break;
1162    }
1163
1164    if (! dco) {
1165       return true;
1166    }
1167    for (xmlNode *n = dco->children; n; n = n->next) {
1168       int_32 RpmOp = 0;
1169       string deptype, depver;
1170       xmlChar *depname, *flags;
1171       if ((depname = xmlGetProp(n, (xmlChar*)"name")) == NULL) continue;
1172
1173       if ((flags = xmlGetProp(n, (xmlChar*)"flags"))) {
1174          deptype = string((char*)flags);
1175          xmlFree(flags);
1176
1177          xmlChar *epoch = xmlGetProp(n, (xmlChar*)"epoch");
1178          if (epoch) {
1179             depver += string((char*)epoch) + ":";
1180             xmlFree(epoch);
1181          }
1182          xmlChar *ver = xmlGetProp(n, (xmlChar*)"ver");
1183          if (ver) {
1184             depver += string((char*)ver);
1185             xmlFree(ver);
1186          }
1187          xmlChar *rel = xmlGetProp(n, (xmlChar*)"rel");
1188          if (rel) {
1189             depver += "-" + string((char*)rel);
1190             xmlFree(rel);
1191          }
1192
1193
1194          if (deptype == "EQ") {
1195             RpmOp = RPMSENSE_EQUAL;
1196          } else if (deptype == "GE") {
1197             RpmOp = RPMSENSE_GREATER | RPMSENSE_EQUAL;
1198          } else if (deptype == "GT") {
1199             RpmOp = RPMSENSE_GREATER;
1200          } else if (deptype == "LE") {
1201             RpmOp = RPMSENSE_LESS | RPMSENSE_EQUAL;
1202          } else if (deptype == "LT") {
1203             RpmOp = RPMSENSE_LESS;
1204          } else {
1205             // erm, unknown dependency type?
1206             return false;
1207          }
1208       } else {
1209          RpmOp = RPMSENSE_ANY;
1210       }
1211
1212       if (Type == pkgCache::Dep::Depends) {
1213          xmlChar *pre = xmlGetProp(n, (xmlChar*)"pre"); 
1214          if (pre) {
1215             RpmOp |= RPMSENSE_PREREQ;
1216             xmlFree(pre);
1217          }
1218       }
1219       bool res = PutDep((char*)depname, depver.c_str(), RpmOp, Type, Deps);
1220    }
1221    return true;
1222 }
1223
1224 bool RPMRepomdHandler::FileList(vector<string> &FileList)
1225 {
1226    xmlNode *format = FindNode("format");
1227    for (xmlNode *n = format->children; n; n = n->next) {
1228       if (xmlStrcmp(n->name, (xmlChar*)"file") != 0)  continue;
1229       xmlChar *Filename = xmlNodeGetContent(n);
1230       FileList.push_back(string((char*)Filename));
1231       xmlFree(Filename);
1232    }
1233    return true;
1234 }
1235
1236 RPMRepomdHandler::~RPMRepomdHandler()
1237 {
1238    xmlFreeDoc(Primary);
1239 }
1240
1241 RPMRepomdFLHandler::RPMRepomdFLHandler(string File) : RPMHandler()
1242 {
1243    FilelistFile = File.substr(0, File.size() - 11) + "filelists.xml";
1244
1245    ID = File;
1246    Filelist = NULL;
1247    NodeP = NULL;
1248    iOffset = -1;
1249
1250    if (FileExists(FilelistFile)) {
1251       Filelist = xmlReaderForFile(FilelistFile.c_str(), NULL,
1252                                   XML_PARSE_NONET|XML_PARSE_NOBLANKS);
1253       if (Filelist == NULL) {
1254         xmlFreeTextReader(Filelist);
1255         _error->Error(_("Failed to open filelist index %s"), FilelistFile.c_str());
1256         goto error;
1257       }
1258
1259       // seek into first package in filelists.xml
1260       int ret = xmlTextReaderRead(Filelist);
1261       if (ret == 1) {
1262         xmlChar *pkgs = xmlTextReaderGetAttribute(Filelist, (xmlChar*)"packages");
1263         iSize = atoi((char*)pkgs);
1264         xmlFree(pkgs);
1265       }
1266       while (ret == 1) {
1267         if (xmlStrcmp(xmlTextReaderConstName(Filelist),
1268                      (xmlChar*)"package") == 0) {
1269            break;
1270         }
1271         ret = xmlTextReaderRead(Filelist);
1272       }
1273    }
1274    return;
1275
1276 error:
1277    if (Filelist) {
1278        xmlFreeTextReader(Filelist);
1279    }
1280 }
1281
1282 bool RPMRepomdFLHandler::Jump(off_t Offset)
1283 {
1284    //cerr << "RepomdFLHandler::Jump() called but not implemented!" << endl;
1285    return false;
1286 }
1287
1288 void RPMRepomdFLHandler::Rewind()
1289 {
1290    //cerr << "RepomdFLHandler::Rewind() called but not implemented!" << endl;
1291 }
1292
1293 bool RPMRepomdFLHandler::Skip()
1294 {
1295    if (iOffset +1 >= iSize) {
1296       return false;
1297    }
1298    if (iOffset >= 0) {
1299       xmlTextReaderNext(Filelist);
1300    }
1301    NodeP = xmlTextReaderExpand(Filelist);
1302    iOffset++;
1303
1304    return true;
1305 }
1306
1307 bool RPMRepomdFLHandler::FileList(vector<string> &FileList)
1308 {
1309    for (xmlNode *n = NodeP->children; n; n = n->next) {
1310       if (xmlStrcmp(n->name, (xmlChar*)"file") != 0)  continue;
1311       xmlChar *Filename = xmlNodeGetContent(n);
1312       FileList.push_back(string((char*)Filename));
1313       xmlFree(Filename);
1314    }
1315    return true;
1316 }
1317
1318 string RPMRepomdFLHandler::FindTag(char *Tag)
1319 {
1320      string str = "";
1321      if (NodeP) {
1322          xmlChar *attr = xmlGetProp(NodeP, (xmlChar*)Tag);
1323          if (attr) {
1324             str = (char*)attr;
1325             xmlFree(attr);
1326          }
1327      }
1328      return str;
1329 }
1330
1331 RPMRepomdFLHandler::~RPMRepomdFLHandler()
1332 {
1333    xmlFreeTextReader(Filelist);
1334 }
1335
1336 RPMSqliteHandler::RPMSqliteHandler(string File) : 
1337    Primary(NULL), Filelists(NULL)
1338 {
1339    int rc = 0;
1340    char **res = NULL;
1341    int nrow, ncol = 0;
1342    string sql;
1343    
1344
1345    ID = File;
1346    DBPath = File; 
1347    // ugh, pass this in to the constructor or something..
1348    FilesDBPath = File.substr(0, File.size() - 14) + "filelists.sqlite";
1349
1350    Primary = new SqliteDB(DBPath);
1351    Filelists = new SqliteDB(FilesDBPath);
1352
1353    Packages = Primary->Query();
1354
1355    // XXX without these indexes cache generation will take minutes.. ick
1356    Packages->Exec("create index requireIdx on requires (pkgKey)");
1357    Packages->Exec("create index provideIdx on provides (pkgKey)");
1358    Packages->Exec("create index obsoleteIdx on obsoletes (pkgKey)");
1359    Packages->Exec("create index conflictIdx on conflicts (pkgKey)");
1360
1361    Packages->Exec("select * from packages");
1362    iSize = Packages->Size();
1363 }
1364
1365 RPMSqliteHandler::~RPMSqliteHandler()
1366 {
1367    if (Primary) delete Primary;
1368    if (Filelists) delete Filelists;
1369 }
1370
1371
1372 bool RPMSqliteHandler::Skip()
1373 {
1374    bool res = Packages->Step();
1375    if (res)
1376       iOffset++;
1377    return res;
1378 }
1379
1380 bool RPMSqliteHandler::Jump(off_t Offset)
1381 {
1382    bool res = Packages->Jump(Offset);
1383    if (!res)
1384       return false;
1385    iOffset = Packages->Offset();
1386    return true;
1387 }
1388
1389 void RPMSqliteHandler::Rewind()
1390 {
1391    Packages->Rewind();
1392    iOffset = 0;
1393 }
1394
1395 string RPMSqliteHandler::Name()
1396 {
1397    return Packages->GetCol("name");
1398 }
1399
1400 string RPMSqliteHandler::Version()
1401 {
1402    return Packages->GetCol("version");
1403 }
1404
1405 string RPMSqliteHandler::Release()
1406 {
1407    return Packages->GetCol("release");
1408 }
1409
1410 string RPMSqliteHandler::Epoch()
1411 {
1412    return Packages->GetCol("epoch");
1413 }
1414
1415 string RPMSqliteHandler::Arch()
1416 {
1417    return Packages->GetCol("arch");
1418 }
1419
1420 string RPMSqliteHandler::Group()
1421 {
1422    return Packages->GetCol("rpm_group");
1423 }
1424
1425 string RPMSqliteHandler::Packager()
1426 {
1427    return Packages->GetCol("rpm_packager");
1428 }
1429 string RPMSqliteHandler::Vendor()
1430 {
1431    return Packages->GetCol("rpm_vendor");
1432 }
1433
1434 string RPMSqliteHandler::Summary()
1435 {
1436    return Packages->GetCol("summary");
1437 }
1438
1439 string RPMSqliteHandler::Description()
1440 {
1441    return Packages->GetCol("description");
1442 }
1443
1444 string RPMSqliteHandler::SourceRpm()
1445 {
1446    return Packages->GetCol("rpm_sourcerpm");
1447 }
1448
1449 string RPMSqliteHandler::FileName()
1450 {
1451    return flNotDir(Packages->GetCol("location_href"));
1452 }
1453
1454 string RPMSqliteHandler::Directory()
1455 {
1456    return flNotFile(Packages->GetCol("location_href"));
1457 }
1458
1459 unsigned long RPMSqliteHandler::FileSize()
1460 {
1461    return Packages->GetColI("size_package");
1462 }
1463
1464 unsigned long RPMSqliteHandler::InstalledSize()
1465 {
1466    return Packages->GetColI("size_installed");
1467 }
1468
1469 string RPMSqliteHandler::MD5Sum()
1470 {
1471    return SHA1Sum();
1472 }
1473
1474 string RPMSqliteHandler::SHA1Sum()
1475 {
1476    return Packages->GetCol("checksum_value");
1477 }
1478
1479 bool RPMSqliteHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
1480 {
1481    string what = "";
1482    switch (Type) {
1483       case pkgCache::Dep::Depends:
1484          what = "requires";
1485          break;
1486       case pkgCache::Dep::Conflicts:
1487          what = "conflicts";
1488          break;
1489       case pkgCache::Dep::Obsoletes:
1490          what = "obsoletes";
1491          break;
1492       case pkgCache::Dep::Provides:
1493          what = "provides";
1494          break;
1495    }
1496
1497    ostringstream sql;
1498    unsigned long pkgKey = Packages->GetColI("pkgKey");
1499    sql  << "select * from " << what << " where pkgKey=" << pkgKey << endl;
1500    SqliteQuery *prco = Primary->Query();
1501    if (!prco->Exec(sql.str())) {
1502       return false;
1503    }
1504
1505    while (prco->Step()) {
1506       int_32 RpmOp = 0;
1507       string deptype, depver = "";
1508
1509       if (prco->GetCol("flags").empty()) {
1510          RpmOp == RPMSENSE_ANY;
1511       } else {
1512          deptype = prco->GetCol("flags");
1513          if (deptype == "EQ") {
1514             RpmOp = RPMSENSE_EQUAL;
1515          } else if (deptype == "GE") {
1516             RpmOp = RPMSENSE_GREATER | RPMSENSE_EQUAL;
1517          } else if (deptype == "GT") {
1518             RpmOp = RPMSENSE_GREATER;
1519          } else if (deptype == "LE") {
1520             RpmOp = RPMSENSE_LESS | RPMSENSE_EQUAL;
1521          } else if (deptype == "LT") {
1522             RpmOp = RPMSENSE_LESS;
1523          } else {
1524             // erm, unknown dependency type?
1525             cout << "unknown dep!? " << deptype << endl;
1526             delete prco;
1527             return false;
1528          }
1529          if (! prco->GetCol("epoch").empty()) {
1530             depver += prco->GetCol("epoch") + ":";
1531          }
1532          if (! prco->GetCol("version").empty()) {
1533             depver += prco->GetCol("version");
1534          }
1535          if (! prco->GetCol("release").empty()) {
1536             depver += "-" + prco->GetCol("release");
1537          }
1538       }
1539       string depname = prco->GetCol("name");
1540       bool res = PutDep(depname.c_str(), depver.c_str(), RpmOp, Type, Deps);
1541    }
1542    delete prco;
1543    return true;
1544 }
1545
1546 bool RPMSqliteHandler::FileList(vector<string> &FileList)
1547 {
1548    ostringstream sql;
1549    unsigned long pkgKey = Packages->GetColI("pkgKey");
1550    sql  << "select * from filelist where pkgKey=" << pkgKey << endl;
1551    SqliteQuery *Files = Filelists->Query();
1552    if (!Files->Exec(sql.str())) {
1553       return false;
1554    }
1555
1556    string delimiters = "/";
1557    while (Files->Step()) {
1558       string dir = Files->GetCol("dirname");
1559       string filenames = Files->GetCol("filenames");
1560
1561       string::size_type lastPos = filenames.find_first_not_of(delimiters, 0);
1562       string::size_type pos     = filenames.find_first_of(delimiters, lastPos);
1563
1564       while (string::npos != pos || string::npos != lastPos)
1565       {
1566          FileList.push_back(dir + "/" + filenames.substr(lastPos, pos - lastPos));
1567          lastPos = filenames.find_first_not_of(delimiters, pos);
1568          pos = filenames.find_first_of(delimiters, lastPos);
1569       } 
1570    }
1571    delete Files;
1572    return true;
1573 }
1574
1575 #endif /* APT_WITH_REPOMD */
1576
1577
1578 // vim:sts=3:sw=3