2fbea0032bc4ab8a58069177ef0da89532f8c447
[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    //cout << __PRETTY_FUNCTION__ << File << endl;
910    PrimaryFile = File;
911
912    ID = File;
913    Root = NULL;
914    Primary = NULL;
915    xmlChar *packages = NULL;
916    off_t pkgcount = 0;
917    
918
919    Primary = xmlReadFile(File.c_str(), NULL, XML_PARSE_NONET|XML_PARSE_NOBLANKS);
920    if ((Root = xmlDocGetRootElement(Primary)) == NULL) {
921       _error->Error(_("Failed to open package index %s"), PrimaryFile.c_str());
922       goto error;
923    }
924    if (xmlStrncmp(Root->name, (xmlChar*)"metadata", strlen("metadata")) != 0) {
925       _error->Error(_("Corrupted package index %s"), PrimaryFile.c_str());
926       goto error;
927    }
928
929    packages = xmlGetProp(Root, (xmlChar*)"packages");
930    iSize = atoi((char*)packages);
931    xmlFree(packages);
932    for (xmlNode *n = Root->children; n; n = n->next) {
933       if (n->type != XML_ELEMENT_NODE ||
934           xmlStrcmp(n->name, (xmlChar*)"package") != 0)
935          continue;
936       Pkgs.push_back(n);
937       pkgcount++;
938    }
939    PkgIter = Pkgs.begin();
940
941    // There seem to be broken version(s) of createrepo around which report
942    // to have one more package than is in the repository. Warn and work around.
943    if (iSize != pkgcount) {
944       _error->Warning(_("Inconsistent metadata, package count doesn't match in %s"), File.c_str());
945       iSize = pkgcount;
946    }
947
948    return;
949
950 error:
951    if (Primary) {
952       xmlFreeDoc(Primary);
953    }
954 }
955
956 bool RPMRepomdHandler::Skip()
957 {
958    if (PkgIter == Pkgs.end()) {
959       return false;
960    }
961    NodeP = *PkgIter;
962    iOffset = PkgIter - Pkgs.begin();
963
964    PkgIter++;
965    return true;
966 }
967
968 bool RPMRepomdHandler::Jump(off_t Offset)
969 {
970    if (Offset >= iSize) {
971       return false;
972    }
973    iOffset = Offset;
974    NodeP = Pkgs[Offset];
975    // This isn't strictly necessary as Skip() and Jump() aren't mixed
976    // in practise but doesn't hurt either...
977    PkgIter = Pkgs.begin() + Offset + 1;
978    return true;
979
980 }
981
982 void RPMRepomdHandler::Rewind()
983 {
984    iOffset = 0;
985    PkgIter = Pkgs.begin();
986 }
987
988 xmlNode *RPMRepomdHandler::FindNode(const string Name)
989 {
990    for (xmlNode *n = NodeP->children; n; n = n->next) {
991       if (xmlStrcmp(n->name, (xmlChar*)Name.c_str()) == 0) {
992          return n;
993       }
994    }
995    return NULL;
996 }
997
998 xmlNode *RPMRepomdHandler::FindNode(xmlNode *Node, const string Name)
999 {
1000    for (xmlNode *n = Node->children; n; n = n->next) {
1001       if (xmlStrcmp(n->name, (xmlChar*)Name.c_str()) == 0) {
1002          return n;
1003       }
1004    }
1005    return NULL;
1006 }
1007
1008 string RPMRepomdHandler::FindTag(xmlNode *Node, string Tag)
1009 {
1010    xmlNode *n = FindNode(Node, Tag);
1011    string str = "";
1012    if (n) {
1013       xmlChar *content = xmlNodeGetContent(n);
1014       if (content) {
1015          str = (char*)content;
1016          xmlFree(content);
1017       }
1018    }
1019    return str;
1020 }
1021
1022 string RPMRepomdHandler::GetProp(xmlNode *Node, char *Prop)
1023 {
1024    string str = "";
1025    if (Node) {
1026       xmlChar *prop = xmlGetProp(Node, (xmlChar*)Prop);
1027       if (prop) {
1028          str = (char*)prop;
1029          xmlFree(prop);
1030       }
1031    }
1032    return str;
1033 }
1034
1035 string RPMRepomdHandler::Group()
1036 {
1037    xmlNode *n = FindNode("format");
1038    return FindTag(n, "group");
1039 }
1040
1041 string RPMRepomdHandler::Vendor()
1042 {
1043    xmlNode *n = FindNode("format");
1044    return FindTag(n, "vendor");
1045 }
1046
1047 string RPMRepomdHandler::Release()
1048 {
1049    xmlNode *n = FindNode("version");
1050    return GetProp(n, "rel");
1051 }
1052
1053 string RPMRepomdHandler::Version()
1054 {
1055    xmlNode *n = FindNode("version");
1056    return GetProp(n, "ver");
1057 }
1058
1059 string RPMRepomdHandler::Epoch()
1060 {
1061    string epoch;
1062    xmlNode *n = FindNode("version");
1063    epoch = GetProp(n, "epoch");
1064    // XXX createrepo stomps epoch zero on packages without epoch, hide
1065    // them. Rpm treats zero and empty equally anyway so it doesn't matter.
1066    if (epoch == "0")
1067       epoch = "";
1068    return epoch;
1069 }
1070
1071 string RPMRepomdHandler::FileName()
1072 {
1073    xmlNode *n;
1074    string str = "";
1075    if ((n = FindNode("location"))) {
1076       xmlChar *prop = xmlGetProp(n, (xmlChar*)"href");
1077       str = basename((char*)prop);
1078       xmlFree(prop);
1079    }
1080    return str;
1081 }
1082
1083 string RPMRepomdHandler::Directory()
1084 {
1085    xmlNode *n;
1086    string str = "";
1087    if ((n = FindNode("location"))) {
1088       xmlChar *prop = xmlGetProp(n, (xmlChar*)"href");
1089       if (prop) {
1090          str = dirname((char*)prop);
1091          xmlFree(prop);
1092       }
1093    }
1094    return str;
1095 }
1096
1097 string RPMRepomdHandler::MD5Sum()
1098 {
1099    // XXX FIXME the method should be an abstract Checksum type using
1100    // md5 / sha1 appropriately, for now relying on hacks elsewhere..
1101    return SHA1Sum();
1102 }
1103
1104 string RPMRepomdHandler::SHA1Sum()
1105 {
1106    xmlNode *n;
1107    string str = "";
1108    if ((n = FindNode("checksum"))) {
1109       xmlChar *content = xmlNodeGetContent(n);
1110       str = (char*)content;
1111       xmlFree(content);
1112    }
1113    return str;
1114 }
1115 unsigned long RPMRepomdHandler::FileSize()
1116 {
1117    xmlNode *n;
1118    unsigned long size = 0;
1119    if ((n = FindNode("size"))) {
1120       xmlChar *prop = xmlGetProp(n, (xmlChar*)"package");
1121       size = atol((char*)prop);
1122       xmlFree(prop);
1123    } 
1124    return size;
1125 }
1126
1127 unsigned long RPMRepomdHandler::InstalledSize()
1128 {
1129    xmlNode *n;
1130    unsigned long size = 0;
1131    if ((n = FindNode("size"))) {
1132       xmlChar *prop = xmlGetProp(n, (xmlChar*)"installed");
1133       size = atol((char*)prop);
1134       xmlFree(prop);
1135    } 
1136    return size;
1137 }
1138
1139 string RPMRepomdHandler::SourceRpm()
1140 {
1141    xmlNode *n = FindNode("format");
1142    return FindTag(n, "sourcerpm");
1143 }
1144
1145 bool RPMRepomdHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
1146 {
1147    xmlNode *format = FindNode("format");
1148    xmlNode *dco = NULL;
1149
1150    switch (Type) {
1151       case pkgCache::Dep::Depends:
1152          dco = FindNode(format, "requires");
1153          break;
1154       case pkgCache::Dep::Conflicts:
1155          dco = FindNode(format, "conflicts");
1156          break;
1157       case pkgCache::Dep::Obsoletes:
1158          dco = FindNode(format, "obsoletes");
1159          break;
1160       case pkgCache::Dep::Provides:
1161          dco = FindNode(format, "provides");
1162          break;
1163    }
1164
1165    if (! dco) {
1166       return true;
1167    }
1168    for (xmlNode *n = dco->children; n; n = n->next) {
1169       int_32 RpmOp = 0;
1170       string deptype, depver;
1171       xmlChar *depname, *flags;
1172       if ((depname = xmlGetProp(n, (xmlChar*)"name")) == NULL) continue;
1173
1174       if ((flags = xmlGetProp(n, (xmlChar*)"flags"))) {
1175          deptype = string((char*)flags);
1176          xmlFree(flags);
1177
1178          xmlChar *epoch = xmlGetProp(n, (xmlChar*)"epoch");
1179          if (epoch) {
1180             depver += string((char*)epoch) + ":";
1181             xmlFree(epoch);
1182          }
1183          xmlChar *ver = xmlGetProp(n, (xmlChar*)"ver");
1184          if (ver) {
1185             depver += string((char*)ver);
1186             xmlFree(ver);
1187          }
1188          xmlChar *rel = xmlGetProp(n, (xmlChar*)"rel");
1189          if (rel) {
1190             depver += "-" + string((char*)rel);
1191             xmlFree(rel);
1192          }
1193
1194
1195          if (deptype == "EQ") {
1196             RpmOp = RPMSENSE_EQUAL;
1197          } else if (deptype == "GE") {
1198             RpmOp = RPMSENSE_GREATER | RPMSENSE_EQUAL;
1199          } else if (deptype == "GT") {
1200             RpmOp = RPMSENSE_GREATER;
1201          } else if (deptype == "LE") {
1202             RpmOp = RPMSENSE_LESS | RPMSENSE_EQUAL;
1203          } else if (deptype == "LT") {
1204             RpmOp = RPMSENSE_LESS;
1205          } else {
1206             // erm, unknown dependency type?
1207             return false;
1208          }
1209       } else {
1210          RpmOp = RPMSENSE_ANY;
1211       }
1212
1213       if (Type == pkgCache::Dep::Depends) {
1214          xmlChar *pre = xmlGetProp(n, (xmlChar*)"pre"); 
1215          if (pre) {
1216             RpmOp |= RPMSENSE_PREREQ;
1217             xmlFree(pre);
1218          }
1219       }
1220       bool res = PutDep((char*)depname, depver.c_str(), RpmOp, Type, Deps);
1221    }
1222    return true;
1223 }
1224
1225 bool RPMRepomdHandler::FileList(vector<string> &FileList)
1226 {
1227    xmlNode *format = FindNode("format");
1228    for (xmlNode *n = format->children; n; n = n->next) {
1229       if (xmlStrcmp(n->name, (xmlChar*)"file") != 0)  continue;
1230       xmlChar *Filename = xmlNodeGetContent(n);
1231       FileList.push_back(string((char*)Filename));
1232       xmlFree(Filename);
1233    }
1234    return true;
1235 }
1236
1237 RPMRepomdHandler::~RPMRepomdHandler()
1238 {
1239    xmlFreeDoc(Primary);
1240 }
1241
1242 RPMRepomdFLHandler::RPMRepomdFLHandler(string File) : RPMHandler()
1243 {
1244    //cout << __PRETTY_FUNCTION__ << File << endl;
1245    FilelistFile = File.substr(0, File.size() - 11) + "filelists.xml";
1246
1247    ID = File;
1248    Filelist = NULL;
1249    NodeP = NULL;
1250    iOffset = -1;
1251
1252    if (FileExists(FilelistFile)) {
1253       Filelist = xmlReaderForFile(FilelistFile.c_str(), NULL,
1254                                   XML_PARSE_NONET|XML_PARSE_NOBLANKS);
1255       if (Filelist == NULL) {
1256         xmlFreeTextReader(Filelist);
1257         _error->Error(_("Failed to open filelist index %s"), FilelistFile.c_str());
1258         goto error;
1259       }
1260
1261       // seek into first package in filelists.xml
1262       int ret = xmlTextReaderRead(Filelist);
1263       if (ret == 1) {
1264         xmlChar *pkgs = xmlTextReaderGetAttribute(Filelist, (xmlChar*)"packages");
1265         iSize = atoi((char*)pkgs);
1266         xmlFree(pkgs);
1267       }
1268       while (ret == 1) {
1269         if (xmlStrcmp(xmlTextReaderConstName(Filelist),
1270                      (xmlChar*)"package") == 0) {
1271            break;
1272         }
1273         ret = xmlTextReaderRead(Filelist);
1274       }
1275    }
1276    return;
1277
1278 error:
1279    if (Filelist) {
1280        xmlFreeTextReader(Filelist);
1281    }
1282 }
1283
1284 bool RPMRepomdFLHandler::Jump(off_t Offset)
1285 {
1286    //cerr << "RepomdFLHandler::Jump() called but not implemented!" << endl;
1287    return false;
1288 }
1289
1290 void RPMRepomdFLHandler::Rewind()
1291 {
1292    //cerr << "RepomdFLHandler::Rewind() called but not implemented!" << endl;
1293 }
1294
1295 bool RPMRepomdFLHandler::Skip()
1296 {
1297    if (iOffset +1 >= iSize) {
1298       return false;
1299    }
1300    if (iOffset >= 0) {
1301       xmlTextReaderNext(Filelist);
1302    }
1303    NodeP = xmlTextReaderExpand(Filelist);
1304    iOffset++;
1305
1306    return true;
1307 }
1308
1309 bool RPMRepomdFLHandler::FileList(vector<string> &FileList)
1310 {
1311    for (xmlNode *n = NodeP->children; n; n = n->next) {
1312       if (xmlStrcmp(n->name, (xmlChar*)"file") != 0)  continue;
1313       xmlChar *Filename = xmlNodeGetContent(n);
1314       FileList.push_back(string((char*)Filename));
1315       xmlFree(Filename);
1316    }
1317    return true;
1318 }
1319
1320 string RPMRepomdFLHandler::FindTag(char *Tag)
1321 {
1322      string str = "";
1323      if (NodeP) {
1324          xmlChar *attr = xmlGetProp(NodeP, (xmlChar*)Tag);
1325          if (attr) {
1326             str = (char*)attr;
1327             xmlFree(attr);
1328          }
1329      }
1330      return str;
1331 }
1332
1333 RPMRepomdFLHandler::~RPMRepomdFLHandler()
1334 {
1335    xmlFreeTextReader(Filelist);
1336 }
1337
1338 RPMSqliteHandler::RPMSqliteHandler(string File) : 
1339    Primary(NULL), Filelists(NULL)
1340 {
1341    //cout << __PRETTY_FUNCTION__ << endl;
1342    int rc = 0;
1343    char **res = NULL;
1344    int nrow, ncol = 0;
1345    string sql;
1346    
1347
1348    DBPath = File; 
1349    // ugh, pass this in to the constructor or something..
1350    FilesDBPath = File.substr(0, File.size() - 14) + "filelists.sqlite";
1351
1352    Primary = new SqliteDB(DBPath);
1353    Filelists = new SqliteDB(FilesDBPath);
1354
1355    Packages = Primary->Query();
1356
1357    // XXX without these indexes cache generation will take minutes.. ick
1358    Packages->Exec("create index requireIdx on requires (pkgKey)");
1359    Packages->Exec("create index provideIdx on provides (pkgKey)");
1360    Packages->Exec("create index obsoleteIdx on obsoletes (pkgKey)");
1361    Packages->Exec("create index conflictIdx on conflicts (pkgKey)");
1362
1363    Packages->Exec("select * from packages");
1364    iSize = Packages->Size();
1365    cout << "sqlite handler initialized, isize " << iSize << endl;
1366 }
1367
1368 RPMSqliteHandler::~RPMSqliteHandler()
1369 {
1370    if (Primary) delete Primary;
1371    if (Filelists) delete Filelists;
1372 }
1373
1374
1375 bool RPMSqliteHandler::Skip()
1376 {
1377    bool res = Packages->Step();
1378    if (res)
1379       iOffset++;
1380    return res;
1381 }
1382
1383 bool RPMSqliteHandler::Jump(off_t Offset)
1384 {
1385    bool res = Packages->Jump(Offset);
1386    if (!res)
1387       return false;
1388    iOffset = Packages->Offset();
1389    return true;
1390 }
1391
1392 void RPMSqliteHandler::Rewind()
1393 {
1394    Packages->Rewind();
1395    iOffset = 0;
1396 }
1397
1398 string RPMSqliteHandler::Name()
1399 {
1400    return Packages->GetCol("name");
1401 }
1402
1403 string RPMSqliteHandler::Version()
1404 {
1405    return Packages->GetCol("version");
1406 }
1407
1408 string RPMSqliteHandler::Release()
1409 {
1410    return Packages->GetCol("release");
1411 }
1412
1413 string RPMSqliteHandler::Epoch()
1414 {
1415    return Packages->GetCol("epoch");
1416 }
1417
1418 string RPMSqliteHandler::Arch()
1419 {
1420    return Packages->GetCol("arch");
1421 }
1422
1423 string RPMSqliteHandler::Group()
1424 {
1425    return Packages->GetCol("rpm_group");
1426 }
1427
1428 string RPMSqliteHandler::Packager()
1429 {
1430    return Packages->GetCol("rpm_packager");
1431 }
1432 string RPMSqliteHandler::Vendor()
1433 {
1434    return Packages->GetCol("rpm_vendor");
1435 }
1436
1437 string RPMSqliteHandler::Summary()
1438 {
1439    return Packages->GetCol("summary");
1440 }
1441
1442 string RPMSqliteHandler::Description()
1443 {
1444    return Packages->GetCol("description");
1445 }
1446
1447 string RPMSqliteHandler::SourceRpm()
1448 {
1449    return Packages->GetCol("rpm_sourcerpm");
1450 }
1451
1452 string RPMSqliteHandler::FileName()
1453 {
1454    return flNotDir(Packages->GetCol("location_href"));
1455 }
1456
1457 string RPMSqliteHandler::Directory()
1458 {
1459    return flNotFile(Packages->GetCol("location_href"));
1460 }
1461
1462 unsigned long RPMSqliteHandler::FileSize()
1463 {
1464    return Packages->GetColI("size_package");
1465 }
1466
1467 unsigned long RPMSqliteHandler::InstalledSize()
1468 {
1469    return Packages->GetColI("size_installed");
1470 }
1471
1472 string RPMSqliteHandler::MD5Sum()
1473 {
1474    return SHA1Sum();
1475 }
1476
1477 string RPMSqliteHandler::SHA1Sum()
1478 {
1479    return Packages->GetCol("checksum_value");
1480 }
1481
1482 bool RPMSqliteHandler::PRCO(unsigned int Type, vector<Dependency*> &Deps)
1483 {
1484    string what = "";
1485    switch (Type) {
1486       case pkgCache::Dep::Depends:
1487          what = "requires";
1488          break;
1489       case pkgCache::Dep::Conflicts:
1490          what = "conflicts";
1491          break;
1492       case pkgCache::Dep::Obsoletes:
1493          what = "obsoletes";
1494          break;
1495       case pkgCache::Dep::Provides:
1496          what = "provides";
1497          break;
1498    }
1499
1500    ostringstream sql;
1501    unsigned long pkgKey = Packages->GetColI("pkgKey");
1502    sql  << "select * from " << what << " where pkgKey=" << pkgKey << endl;
1503    SqliteQuery *prco = Primary->Query();
1504    if (!prco->Exec(sql.str())) {
1505       return false;
1506    }
1507
1508    while (prco->Step()) {
1509       int_32 RpmOp = 0;
1510       string deptype, depver = "";
1511
1512       //cout << *(PkgIter-1) << " prco " << res[i+0] << endl;
1513       if (prco->GetCol("flags").empty()) {
1514          RpmOp == RPMSENSE_ANY;
1515       } else {
1516          deptype = prco->GetCol("flags");
1517          if (deptype == "EQ") {
1518             RpmOp = RPMSENSE_EQUAL;
1519          } else if (deptype == "GE") {
1520             RpmOp = RPMSENSE_GREATER | RPMSENSE_EQUAL;
1521          } else if (deptype == "GT") {
1522             RpmOp = RPMSENSE_GREATER;
1523          } else if (deptype == "LE") {
1524             RpmOp = RPMSENSE_LESS | RPMSENSE_EQUAL;
1525          } else if (deptype == "LT") {
1526             RpmOp = RPMSENSE_LESS;
1527          } else {
1528             // erm, unknown dependency type?
1529             cout << "unknown dep!? " << deptype << endl;
1530             delete prco;
1531             return false;
1532          }
1533          if (! prco->GetCol("epoch").empty()) {
1534             depver += prco->GetCol("epoch") + ":";
1535          }
1536          if (! prco->GetCol("version").empty()) {
1537             depver += prco->GetCol("version");
1538          }
1539          if (! prco->GetCol("release").empty()) {
1540             depver += "-" + prco->GetCol("release");
1541          }
1542       }
1543       string depname = prco->GetCol("name");
1544       //cout << Name() << " (" << pkgKey << ") " << ": put dep " << depname << " " << RpmOp << " " << depver << endl;
1545       bool res = PutDep(depname.c_str(), depver.c_str(), RpmOp, Type, Deps);
1546    }
1547    delete prco;
1548    return true;
1549 }
1550
1551 bool RPMSqliteHandler::FileList(vector<string> &FileList)
1552 {
1553    ostringstream sql;
1554    unsigned long pkgKey = Packages->GetColI("pkgKey");
1555    sql  << "select * from filelist where pkgKey=" << pkgKey << endl;
1556    SqliteQuery *Files = Filelists->Query();
1557    if (!Files->Exec(sql.str())) {
1558       return false;
1559    }
1560
1561    string delimiters = "/";
1562    while (Files->Step()) {
1563       string dir = Files->GetCol("dirname");
1564       string filenames = Files->GetCol("filenames");
1565
1566       string::size_type lastPos = filenames.find_first_not_of(delimiters, 0);
1567       string::size_type pos     = filenames.find_first_of(delimiters, lastPos);
1568
1569       while (string::npos != pos || string::npos != lastPos)
1570       {
1571          FileList.push_back(dir + "/" + filenames.substr(lastPos, pos - lastPos));
1572          lastPos = filenames.find_first_not_of(delimiters, pos);
1573          pos = filenames.find_first_of(delimiters, lastPos);
1574       } 
1575    }
1576    delete Files;
1577    return true;
1578 }
1579
1580 #endif /* APT_WITH_REPOMD */
1581
1582
1583 // vim:sts=3:sw=3