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