49256d4a05a89dd6b77075816ef292c334b2216a
[apt.git] / apt-pkg / rpm / rpmsrcrecords.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: rpmsrcrecords.cc,v 1.9 2003/01/29 15:19:02 niemeyer Exp $
4 /* ######################################################################
5    
6    SRPM Records - Parser implementation for RPM style source indexes
7       
8    ##################################################################### 
9  */
10                                                                         /*}}}*/
11 // Include Files                                                        /*{{{*/
12 #ifdef __GNUG__
13 #pragma implementation "apt-pkg/rpmsrcrecords.h"
14 #endif 
15
16 #include <config.h>
17
18 #ifdef HAVE_RPM
19
20 #include <assert.h>
21
22 #include <apt-pkg/rpmsrcrecords.h>
23 #include <apt-pkg/error.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/rpmhandler.h>
26 #include <apt-pkg/pkgcache.h>
27
28 #include <apti18n.h>
29
30 #if RPM_VERSION >= 0x040100
31 #include <rpm/rpmds.h>
32 #endif
33
34 // SrcRecordParser::rpmSrcRecordParser - Constructor                    /*{{{*/
35 // ---------------------------------------------------------------------
36 /* */
37 rpmSrcRecordParser::rpmSrcRecordParser(string File,pkgIndexFile const *Index)
38     : Parser(Index), HeaderP(0), Buffer(0), BufSize(0), BufUsed(0)
39 {
40    struct stat Buf;
41    if (stat(File.c_str(),&Buf) == 0 && S_ISDIR(Buf.st_mode))
42       Handler = new RPMDirHandler(File);
43    else if (flExtension(File) == "rpm")
44       Handler = new RPMSingleFileHandler(File);
45    else
46       Handler = new RPMFileHandler(File);
47 }
48                                                                         /*}}}*/
49 // SrcRecordParser::~rpmSrcRecordParser - Destructor                    /*{{{*/
50 // ---------------------------------------------------------------------
51 /* */
52 rpmSrcRecordParser::~rpmSrcRecordParser()
53 {
54    delete Handler;
55    free(Buffer);
56 }
57                                                                         /*}}}*/
58 // SrcRecordParser::Binaries - Return the binaries field                /*{{{*/
59 // ---------------------------------------------------------------------
60 /* This member parses the binaries field into a pair of class arrays and
61    returns a list of strings representing all of the components of the
62    binaries field. The returned array need not be freed and will be
63    reused by the next Binaries function call. */
64 const char **rpmSrcRecordParser::Binaries()
65 {
66    int i = 0;
67    char **bins;
68    int type, count;
69    assert(HeaderP != NULL);
70    int rc = headerGetEntry(HeaderP, CRPMTAG_BINARY,
71                            &type, (void**)&bins, &count);
72    if (rc != 1)
73        return NULL;
74    for (i = 0; (unsigned)i < sizeof(StaticBinList)/sizeof(char*) && i < count;
75         i++)
76       StaticBinList[i] = bins[i];
77    StaticBinList[i] = 0;
78    return StaticBinList;
79 }
80                                                                         /*}}}*/
81 // SrcRecordParser::Files - Return a list of files for this source      /*{{{*/
82 // ---------------------------------------------------------------------
83 /* This parses the list of files and returns it, each file is required to have
84    a complete source package */
85 bool rpmSrcRecordParser::Files(vector<pkgSrcRecords::File> &List)
86 {
87    assert(HeaderP != NULL);
88     
89    List.clear();
90    
91    pkgSrcRecords::File F;
92
93    F.MD5Hash = Handler->MD5Sum();
94    F.Size = Handler->FileSize();
95    F.Path = flCombine(Handler->Directory(), Handler->FileName());
96    F.Type = "srpm";
97
98    List.push_back(F);
99    
100    return true;
101 }
102                                                                         /*}}}*/
103
104 bool rpmSrcRecordParser::Restart()
105 {
106    Handler->Rewind();
107    return true;
108 }
109
110 bool rpmSrcRecordParser::Step() 
111 {
112    if (Handler->Skip() == false)
113        return false;
114    HeaderP = Handler->GetHeader();
115    return true;
116 }
117
118 bool rpmSrcRecordParser::Jump(unsigned long Off)
119 {
120    if (!Handler->Jump(Off))
121        return false;
122    HeaderP = Handler->GetHeader();
123    return true;
124 }
125
126 string rpmSrcRecordParser::Package() const
127 {
128    char *str;
129    int_32 count, type;
130    int rc = headerGetEntry(HeaderP, RPMTAG_NAME,
131                            &type, (void**)&str, &count);
132    return string(rc?str:"");
133 }
134
135 string rpmSrcRecordParser::Version() const
136 {
137    char *version, *release;
138    int_32 *epoch;
139    int type, count;
140    int rc;
141    
142    rc = headerGetEntry(HeaderP, RPMTAG_VERSION,
143                        &type, (void **)&version, &count);
144    if (rc != 1)
145    {
146       _error->Error(_("error parsing source list %s"), "(RPMTAG_VERSION)");
147       return "";
148    }
149    rc = headerGetEntry(HeaderP, RPMTAG_RELEASE,
150                        &type, (void **)&release, &count);
151    if (rc != 1)
152    {
153       _error->Error(_("error parsing source list %s"), "(RPMTAG_RELEASE)");
154       return "";
155    }
156
157    rc = headerGetEntry(HeaderP, RPMTAG_EPOCH,
158                            &type, (void **)&epoch, &count);
159    string ret;
160    if (rc == 1 && count > 0) 
161    {
162       char buf[32];
163       sprintf(buf, "%i", *epoch);
164       ret = string(buf)+":"+string(version)+"-"+string(release);
165    }
166    else 
167       ret = string(version)+"-"+string(release);
168    
169    return ret;
170 }
171     
172
173 // RecordParser::Maintainer - Return the maintainer email               /*{{{*/
174 // ---------------------------------------------------------------------
175 /* */
176 string rpmSrcRecordParser::Maintainer() const
177 {
178    char *str;
179    int_32 count, type;
180    int rc = headerGetEntry(HeaderP, RPMTAG_PACKAGER,
181                            &type, (void**)&str, &count);
182    return string(rc?str:"");
183 }
184
185 string rpmSrcRecordParser::Section() const
186 {
187    char *str;
188    int_32 count, type;
189    int rc = headerGetEntry(HeaderP, RPMTAG_GROUP,
190                            &type, (void**)&str, &count);
191    return string(rc?str:"");
192 }
193
194 unsigned long rpmSrcRecordParser::Offset() 
195 {
196     return Handler->Offset();
197 }
198
199 void rpmSrcRecordParser::BufCat(char *text)
200 {
201    if (text != NULL)
202       BufCat(text, text+strlen(text));
203 }
204
205 void rpmSrcRecordParser::BufCat(char *begin, char *end)
206 {
207    unsigned len = end - begin;
208     
209    if (BufUsed+len+1 >= BufSize)
210    {
211       BufSize += 512;
212       char *tmp = (char*)realloc(Buffer, BufSize);
213       if (tmp == NULL)
214       {
215          _error->Errno("realloc", _("Could not allocate buffer for record text"));
216          return;
217       }
218       Buffer = tmp;
219    }
220
221    strncpy(Buffer+BufUsed, begin, len);
222    BufUsed += len;
223 }
224
225 void rpmSrcRecordParser::BufCatTag(char *tag, char *value)
226 {
227    BufCat(tag);
228    BufCat(value);
229 }
230
231 void rpmSrcRecordParser::BufCatDep(char *pkg, char *version, int flags)
232 {
233    char buf[16];
234    char *ptr = (char*)buf;
235
236    BufCat(pkg);
237    if (*version) 
238    {
239       int c = 0;
240       *ptr++ = ' ';
241       *ptr++ = '(';
242       if (flags & RPMSENSE_LESS)
243       {
244          *ptr++ = '<';
245          c = '<';
246       }
247       if (flags & RPMSENSE_GREATER) 
248       {
249          *ptr++ = '>';
250          c = '>';
251       }
252       if (flags & RPMSENSE_EQUAL) 
253       {
254          *ptr++ = '=';
255       }/* else {
256          if (c)
257            fputc(c, f);
258       }*/
259       *ptr++ = ' ';
260       *ptr = '\0';
261
262       BufCat(buf);
263       BufCat(version);
264       BufCat(")");
265    }
266 }
267
268 void rpmSrcRecordParser::BufCatDescr(char *descr)
269 {
270    char *begin = descr;
271
272    while (*descr) 
273    {
274       if (*descr=='\n') 
275       {
276          BufCat(" ");
277          BufCat(begin, descr+1);
278          begin = descr+1;
279       }
280       descr++;
281    }
282    BufCat(" ");
283    BufCat(begin, descr);
284    BufCat("\n");
285 }
286
287 // SrcRecordParser::AsStr - The record in raw text
288 // -----------------------------------------------
289 string rpmSrcRecordParser::AsStr() 
290 {
291    // FIXME: This method is leaking memory from headerGetEntry().
292    int type, type2, type3, count;
293    char *str;
294    char **strv;
295    char **strv2;
296    int num;
297    int_32 *numv;
298    char buf[32];
299
300    BufUsed = 0;
301    
302    headerGetEntry(HeaderP, RPMTAG_NAME, &type, (void **)&str, &count);
303    BufCatTag("Package: ", str);
304
305    headerGetEntry(HeaderP, RPMTAG_GROUP, &type, (void **)&str, &count);
306    BufCatTag("\nSection: ", str);
307
308    headerGetEntry(HeaderP, RPMTAG_SIZE, &type, (void **)&numv, &count);
309    snprintf(buf, sizeof(buf), "%d", numv[0]);
310    BufCatTag("\nInstalled Size: ", buf);
311
312    str = NULL;
313    headerGetEntry(HeaderP, RPMTAG_PACKAGER, &type, (void **)&str, &count);
314    if (!str)
315        headerGetEntry(HeaderP, RPMTAG_VENDOR, &type, (void **)&str, &count);
316    BufCatTag("\nMaintainer: ", str);
317    
318    BufCat("\nVersion: ");
319    headerGetEntry(HeaderP, RPMTAG_VERSION, &type, (void **)&str, &count);
320    if (headerGetEntry(HeaderP, RPMTAG_EPOCH, &type, (void **)&numv, &count)==1)
321        snprintf(buf, sizeof(buf), "%i:%s-", numv[0], str);
322    else
323        snprintf(buf, sizeof(buf), "%s-", str);
324    BufCat(buf);
325    headerGetEntry(HeaderP, RPMTAG_RELEASE, &type, (void **)&str, &count);
326    BufCat(str);
327
328    headerGetEntry(HeaderP, RPMTAG_REQUIRENAME, &type, (void **)&strv, &count);
329    assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
330
331    headerGetEntry(HeaderP, RPMTAG_REQUIREVERSION, &type2, (void **)&strv2, &count);
332    headerGetEntry(HeaderP, RPMTAG_REQUIREFLAGS, &type3, (void **)&numv, &count);
333    
334    if (count > 0)
335    {
336       int i, j;
337
338       for (j = i = 0; i < count; i++) 
339       {
340          if ((numv[i] & RPMSENSE_PREREQ))
341          {
342             if (j == 0) 
343                 BufCat("\nPre-Depends: ");
344             else
345                 BufCat(", ");
346             BufCatDep(strv[i], strv2[i], numv[i]);
347             j++;
348          }
349       }
350
351       for (j = 0, i = 0; i < count; i++) 
352       {
353          if (!(numv[i] & RPMSENSE_PREREQ)) 
354          {
355             if (j == 0)
356                 BufCat("\nDepends: ");
357             else
358                 BufCat(", ");
359             BufCatDep(strv[i], strv2[i], numv[i]);
360             j++;
361          }
362       }
363    }
364    
365    headerGetEntry(HeaderP, RPMTAG_CONFLICTNAME, &type, (void **)&strv, &count);
366    assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
367
368    headerGetEntry(HeaderP, RPMTAG_CONFLICTVERSION, &type2, (void **)&strv2, &count);
369    headerGetEntry(HeaderP, RPMTAG_CONFLICTFLAGS, &type3, (void **)&numv, &count);
370    
371    if (count > 0) 
372    {
373       BufCat("\nConflicts: ");
374       for (int i = 0; i < count; i++) 
375       {
376          if (i > 0)
377              BufCat(", ");
378          BufCatDep(strv[i], strv2[i], numv[i]);
379       }
380    }
381
382    headerGetEntry(HeaderP, CRPMTAG_FILESIZE, &type, (void **)&num, &count);
383    snprintf(buf, sizeof(buf), "%d", num);
384    BufCatTag("\nSize: ", buf);
385
386    headerGetEntry(HeaderP, CRPMTAG_MD5, &type, (void **)&str, &count);
387    BufCatTag("\nMD5Sum: ", str);
388
389    headerGetEntry(HeaderP, CRPMTAG_FILENAME, &type, (void **)&str, &count);
390    BufCatTag("\nFilename: ", str);
391
392    headerGetEntry(HeaderP, RPMTAG_SUMMARY, &type, (void **)&str, &count);
393    BufCatTag("\nDescription: ", str);
394    BufCat("\n");
395    headerGetEntry(HeaderP, RPMTAG_DESCRIPTION, &type, (void **)&str, &count);
396    BufCatDescr(str);
397    BufCat("\n");
398    
399    return string(Buffer, BufUsed);
400 }
401
402
403 // SrcRecordParser::BuildDepends - Return the Build-Depends information /*{{{*/
404 // ---------------------------------------------------------------------
405 bool rpmSrcRecordParser::BuildDepends(vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps,
406                                       bool ArchOnly)
407 {
408    // FIXME: This method is leaking memory from headerGetEntry().
409    int RpmTypeTag[] = {RPMTAG_REQUIRENAME,
410                        RPMTAG_REQUIREVERSION,
411                        RPMTAG_REQUIREFLAGS,
412                        RPMTAG_CONFLICTNAME,
413                        RPMTAG_CONFLICTVERSION,
414                        RPMTAG_CONFLICTFLAGS};
415    int BuildType[] = {pkgSrcRecords::Parser::BuildDepend,
416                       pkgSrcRecords::Parser::BuildConflict};
417    BuildDepRec rec;
418
419    BuildDeps.clear();
420
421    for (unsigned char Type = 0; Type != 2; Type++)
422    {
423       char **namel = NULL;
424       char **verl = NULL;
425       int *flagl = NULL;
426       int res, type, count;
427
428       res = headerGetEntry(HeaderP, RpmTypeTag[0+Type*3], &type, 
429                          (void **)&namel, &count);
430       if (res != 1)
431          return true;
432       res = headerGetEntry(HeaderP, RpmTypeTag[1+Type*3], &type, 
433                          (void **)&verl, &count);
434       res = headerGetEntry(HeaderP, RpmTypeTag[2+Type*3], &type,
435                          (void **)&flagl, &count);
436       
437       for (int i = 0; i < count; i++) 
438       {
439 #if RPM_VERSION >= 0x040404
440          if (namel[i][0] == 'g' && strncmp(namel[i], "getconf", 7) == 0)
441          {
442             rpmds getconfProv = NULL;
443             rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
444                                    namel[i], verl?verl[i]:NULL, flagl[i]);
445             rpmdsGetconf(&getconfProv, NULL);
446             int res = rpmdsSearch(getconfProv, ds) >= 0;
447             rpmdsFree(ds);
448             rpmdsFree(getconfProv);
449             if (res) continue;
450          }
451 #endif
452          if (strncmp(namel[i], "rpmlib", 6) == 0) 
453          {
454 #if RPM_VERSION >= 0x040404
455             rpmds rpmlibProv = NULL;
456             rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
457                                    namel[i], verl?verl[i]:NULL, flagl[i]);
458             rpmdsRpmlib(&rpmlibProv, NULL);
459             rpmdsSearch(rpmlibProv, ds);
460             int res = rpmdsResult(ds);
461             rpmdsFree(ds);
462             rpmdsFree(rpmlibProv);
463 #elif RPM_VERSION >= 0x040100
464             rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME,
465                                    namel[i], verl?verl[i]:NULL, flagl[i]);
466             int res = rpmCheckRpmlibProvides(ds);
467             rpmdsFree(ds);
468 #else
469             int res = rpmCheckRpmlibProvides(namel[i], verl?verl[i]:NULL,
470                                              flagl[i]);
471 #endif
472             if (res) continue;
473          }
474
475          if (verl) 
476          {
477             if (!*verl[i]) 
478                rec.Op = pkgCache::Dep::NoOp;
479             else 
480             {
481                if (flagl[i] & RPMSENSE_LESS) 
482                {
483                   if (flagl[i] & RPMSENSE_EQUAL)
484                       rec.Op = pkgCache::Dep::LessEq;
485                   else
486                       rec.Op = pkgCache::Dep::Less;
487                } 
488                else if (flagl[i] & RPMSENSE_GREATER) 
489                {
490                   if (flagl[i] & RPMSENSE_EQUAL)
491                       rec.Op = pkgCache::Dep::GreaterEq;
492                   else
493                       rec.Op = pkgCache::Dep::Greater;
494                } 
495                else if (flagl[i] & RPMSENSE_EQUAL) 
496                   rec.Op = pkgCache::Dep::Equals;
497             }
498             
499             rec.Version = verl[i];
500          }
501          else
502          {
503             rec.Op = pkgCache::Dep::NoOp;
504             rec.Version = "";
505          }
506
507          rec.Type = BuildType[Type];
508          rec.Package = namel[i];
509          BuildDeps.push_back(rec);
510       }
511    }
512    return true;
513 }
514                                                                         /*}}}*/
515 #endif /* HAVE_RPM */
516
517 // vim:sts=3:sw=3